301 lines
9.6 KiB
Python
301 lines
9.6 KiB
Python
#!/usr/bin/env python
|
|
# encoding: utf-8
|
|
|
|
import dash
|
|
import dash_html_components as html
|
|
import dash_core_components as dcc
|
|
import dash_table
|
|
import plotly.graph_objects as go
|
|
from datetime import date, datetime
|
|
import uuid
|
|
import pandas as pd
|
|
import yaml
|
|
from pathlib import Path
|
|
|
|
from ...scripts.getconfig import config
|
|
from ... import flat_df_students, pp_q_scores
|
|
from ...config import NO_ST_COLUMNS
|
|
from ..app import app
|
|
from ...scripts.exam import Exam
|
|
|
|
|
|
def get_students(csv):
|
|
return list(pd.read_csv(csv).T.to_dict().values())
|
|
|
|
|
|
COLORS = {
|
|
".": "black",
|
|
0: "#E7472B",
|
|
1: "#FF712B",
|
|
2: "#F2EC4C",
|
|
3: "#68D42F",
|
|
}
|
|
|
|
QUESTION_COLUMNS = [
|
|
{"id": "id", "name": "Question"},
|
|
{
|
|
"id": "competence",
|
|
"name": "Competence",
|
|
"presentation": "dropdown",
|
|
},
|
|
{"id": "theme", "name": "Domaine"},
|
|
{"id": "comment", "name": "Commentaire"},
|
|
{"id": "score_rate", "name": "Bareme"},
|
|
{"id": "is_leveled", "name": "Est_nivele"},
|
|
]
|
|
|
|
layout = html.Div(
|
|
[
|
|
html.Header(
|
|
children=[
|
|
html.H1("Bilan des élèves"),
|
|
],
|
|
),
|
|
html.Main(
|
|
children=[
|
|
html.Section(
|
|
children=[
|
|
html.Form(
|
|
id="select-student",
|
|
children=[
|
|
html.Label(
|
|
children=[
|
|
"Classe",
|
|
dcc.Dropdown(
|
|
id="tribe",
|
|
options=[
|
|
{"label": t["name"], "value": t["name"]}
|
|
for t in config["tribes"]
|
|
],
|
|
value=config["tribes"][0]["name"],
|
|
),
|
|
]
|
|
),
|
|
html.Label(
|
|
children=[
|
|
"Élève",
|
|
dcc.Dropdown(
|
|
id="student",
|
|
options=[
|
|
{"label": t["Nom"], "value": t["Nom"]}
|
|
for t in get_students(config["tribes"][0]["students"])
|
|
],
|
|
value=get_students(config["tribes"][0]["students"])[0]["Nom"],
|
|
),
|
|
]
|
|
),
|
|
html.Label(
|
|
children=[
|
|
"Trimestre",
|
|
dcc.Dropdown(
|
|
id="term",
|
|
options=[
|
|
{"label": i + 1, "value": i + 1}
|
|
for i in range(3)
|
|
],
|
|
value=1,
|
|
),
|
|
]
|
|
),
|
|
],
|
|
),
|
|
],
|
|
id="form",
|
|
),
|
|
html.Section(
|
|
children=[
|
|
html.H2("Évaluations"),
|
|
html.Div(
|
|
dash_table.DataTable(
|
|
id="exam_scores",
|
|
columns=[
|
|
{"id": "Nom", "name": "Évaluations"},
|
|
{"id": "Note", "name": "Note"},
|
|
{"id": "Bareme", "name": "Barème"},
|
|
],
|
|
data=[],
|
|
style_data_conditional=[
|
|
{
|
|
"if": {"row_index": "odd"},
|
|
"backgroundColor": "rgb(248, 248, 248)",
|
|
}
|
|
],
|
|
style_data={
|
|
"width": "100px",
|
|
"maxWidth": "100px",
|
|
"minWidth": "100px",
|
|
},
|
|
),
|
|
id="eval-table",
|
|
),
|
|
],
|
|
id="Évaluations",
|
|
),
|
|
html.Section(
|
|
children=[
|
|
html.Div(
|
|
id="competences-viz",
|
|
),
|
|
html.Div(
|
|
id="themes-vizz",
|
|
),
|
|
],
|
|
id="visualisation",
|
|
),
|
|
]
|
|
),
|
|
dcc.Store(id="student-scores"),
|
|
]
|
|
)
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
dash.dependencies.Output("student", "options"),
|
|
dash.dependencies.Output("student", "value"),
|
|
],
|
|
[
|
|
dash.dependencies.Input("tribe", "value")
|
|
],)
|
|
def update_students_list(tribe):
|
|
tribe_config = [t for t in config["tribes"] if t["name"] == tribe][0]
|
|
students = get_students(tribe_config["students"])
|
|
options = [
|
|
{"label": t["Nom"], "value": t["Nom"]}
|
|
for t in students
|
|
]
|
|
value = students[0]["Nom"]
|
|
return options, value
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
dash.dependencies.Output("student-scores", "data"),
|
|
],
|
|
[
|
|
dash.dependencies.Input("tribe", "value"),
|
|
dash.dependencies.Input("student", "value"),
|
|
dash.dependencies.Input("term", "value"),
|
|
],
|
|
)
|
|
def update_student_scores(tribe, student, term):
|
|
tribe_config = [t for t in config["tribes"] if t["name"] == tribe][0]
|
|
|
|
p = Path(tribe_config["name"])
|
|
csvs = list(p.glob("*.csv"))
|
|
|
|
dfs = []
|
|
for csv in csvs:
|
|
try:
|
|
scores = pd.read_csv(csv)
|
|
except pd.errors.ParserError:
|
|
pass
|
|
else:
|
|
if scores.iloc[0]["Commentaire"] == "commentaire" or scores.iloc[0].str.contains("PPRE").any():
|
|
scores.drop([0], inplace=True)
|
|
scores = flat_df_students(scores).dropna(subset=["Score"])
|
|
scores = scores[scores["Eleve"] == student]
|
|
scores = scores[scores["Trimestre"] == term]
|
|
dfs.append(scores)
|
|
|
|
df = pd.concat(dfs)
|
|
|
|
return [df.to_dict("records")]
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
dash.dependencies.Output("exam_scores", "data"),
|
|
],
|
|
[
|
|
dash.dependencies.Input("student-scores", "data"),
|
|
],
|
|
)
|
|
def update_exam_scores(data):
|
|
scores = pd.DataFrame.from_records(data)
|
|
scores = pp_q_scores(scores)
|
|
assessment_scores = scores.groupby(["Nom"]).agg({"Note": "sum", "Bareme": "sum"})
|
|
return [assessment_scores.reset_index().to_dict("records")]
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
dash.dependencies.Output("competences-viz", "children"),
|
|
],
|
|
[
|
|
dash.dependencies.Input("student-scores", "data"),
|
|
],
|
|
)
|
|
def update_competences_viz(data):
|
|
scores = pd.DataFrame.from_records(data)
|
|
scores = pp_q_scores(scores)
|
|
pt = pd.pivot_table(
|
|
scores,
|
|
index=["Competence"],
|
|
columns="Score",
|
|
aggfunc="size",
|
|
fill_value=0,
|
|
)
|
|
fig = go.Figure()
|
|
bars = [
|
|
{"score": -1, "name": "Pas de réponse", "color": COLORS["."]},
|
|
{"score": 0, "name": "Faux", "color": COLORS[0]},
|
|
{"score": 1, "name": "Peu juste", "color": COLORS[1]},
|
|
{"score": 2, "name": "Presque juste", "color": COLORS[2]},
|
|
{"score": 3, "name": "Juste", "color": COLORS[3]},
|
|
]
|
|
for b in bars:
|
|
try:
|
|
fig.add_bar(
|
|
x=list(config["competences"].keys()), y=pt[b["score"]], name=b["name"], marker_color=b["color"]
|
|
)
|
|
except KeyError:
|
|
pass
|
|
fig.update_layout(barmode="relative")
|
|
fig.update_layout(
|
|
height=500,
|
|
margin=dict(l=5, r=5, b=5, t=5),
|
|
)
|
|
return [dcc.Graph(figure=fig)]
|
|
|
|
@app.callback(
|
|
[
|
|
dash.dependencies.Output("themes-vizz", "children"),
|
|
],
|
|
[
|
|
dash.dependencies.Input("student-scores", "data"),
|
|
],
|
|
)
|
|
def update_themes_viz(data):
|
|
scores = pd.DataFrame.from_records(data)
|
|
scores = pp_q_scores(scores)
|
|
pt = pd.pivot_table(
|
|
scores,
|
|
index=["Domaine"],
|
|
columns="Score",
|
|
aggfunc="size",
|
|
fill_value=0,
|
|
)
|
|
fig = go.Figure()
|
|
bars = [
|
|
{"score": -1, "name": "Pas de réponse", "color": COLORS["."]},
|
|
{"score": 0, "name": "Faux", "color": COLORS[0]},
|
|
{"score": 1, "name": "Peu juste", "color": COLORS[1]},
|
|
{"score": 2, "name": "Presque juste", "color": COLORS[2]},
|
|
{"score": 3, "name": "Juste", "color": COLORS[3]},
|
|
]
|
|
for b in bars:
|
|
try:
|
|
fig.add_bar(
|
|
x=list(pt.index), y=pt[b["score"]], name=b["name"], marker_color=b["color"]
|
|
)
|
|
except KeyError:
|
|
pass
|
|
fig.update_layout(barmode="relative")
|
|
fig.update_layout(
|
|
height=500,
|
|
margin=dict(l=5, r=5, b=5, t=5),
|
|
)
|
|
return [dcc.Graph(figure=fig)]
|
|
|