Compare commits

...

6 Commits

4 changed files with 177 additions and 101 deletions

View File

@ -7,70 +7,62 @@ from .models import get_tribes, get_exams
from .callbacks import *
layout = html.Div(
children=[
html.Header(
children=[
html.H1("Analyse des notes"),
html.P("Dernière sauvegarde", id="lastsave"),
],
),
html.Main(
html.Section(
[
html.Div(
[
"Classe: ",
dcc.Dropdown(
id="tribe",
options=[
{"label": t["name"], "value": t["name"]}
for t in get_tribes().values()
],
value=next(iter(get_tribes().values()))["name"],
),
],
),
html.Div(
[
"Evaluation: ",
dcc.Dropdown(id="exam_select"),
],
html.P(id="test"),
],
id="select",
),
html.Section(
[
html.Div(
dash_table.DataTable(
id="final_score_table",
columns=[
{"id": "Eleve", "name": "Élève"},
{"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="final_score_table_container",
children=[
html.Header(
children=[
html.H1("Analyse des notes"),
html.P("Dernière sauvegarde", id="lastsave"),
],
),
html.Main(
children=[
html.Section(
children=[
html.Div(
children=[
"Classe: ",
dcc.Dropdown(
id="tribe",
options=[
{"label": t["name"], "value": t["name"]}
for t in get_tribes().values()
],
value=next(iter(get_tribes().values()))["name"],
),
],
),
html.Div(
children=[
"Evaluation: ",
dcc.Dropdown(id="exam_select"),
],
),
],
id="selects",
),
html.Section(
children=[
html.Div(
children=[],
id="final_score_table_container",
),
],
id="analysis",
),
html.Section(
children=[
dash_table.DataTable(
id="scores_table",
columns=[],
style_data_conditional=[],
fixed_columns={},
editable=True,
)
],
id="edit",
),
],
id="analysis",
),
html.Section(
id="scores_table",
),
),
dcc.Store(id="scores"),
],
)
),
dcc.Store(id="scores"),
],
)

View File

@ -1,11 +1,15 @@
#!/usr/bin/env python
# encoding: utf-8
from dash.dependencies import Input, Output
from dash.dependencies import Input, Output, State
import dash
from dash.exceptions import PreventUpdate
import dash_table
import json
import pandas as pd
from ...app import app
from .models import get_tribes, get_exams
from .models import get_tribes, get_exams, get_unstack_scores, get_students_from_exam
@app.callback(
@ -15,12 +19,11 @@ from .models import get_tribes, get_exams
],
[Input("tribe", "value")],
)
def update_csvs(value):
if not value:
def update_exams_choices(tribe):
if not tribe:
raise PreventUpdate
exams = get_exams(value)
exams = get_exams(tribe)
exams.reset_index(inplace=True)
print(exams.loc[0, "name"])
if not exams.empty:
return [
{"label": e["name"], "value": e.to_json()} for i, e in exams.iterrows()
@ -30,24 +33,35 @@ def update_csvs(value):
@app.callback(
[
dash.dependencies.Output("final_score", "data"),
Output("scores_table", "columns"),
Output("scores_table", "data"),
Output("scores_table", "style_data_conditional"),
Output("scores_table", "fixed_columns"),
],
[
Input("exam_select", "value"),
],
[dash.dependencies.Input("scores_table", "data")],
)
def update_final_scores(data):
if not data:
raise PreventUpdate
def update_scores_store(exam):
ctx = dash.callback_context
if not exam:
return [[], [], [], {}]
exam = pd.DataFrame.from_dict([json.loads(exam)])
scores = get_unstack_scores(exam)
fixed_columns = [
"exercise",
"question",
"competence",
"theme",
"comment",
"score_rate",
"is_leveled",
]
columns = fixed_columns + list(get_students_from_exam(exam))
scores = pd.DataFrame.from_records(data)
try:
if scores.iloc[0]["Commentaire"] == "commentaire":
scores.drop([0], inplace=True)
except KeyError:
pass
scores = flat_df_students(scores).dropna(subset=["Score"])
if scores.empty:
return [{}]
scores = pp_q_scores(scores)
assessment_scores = scores.groupby(["Eleve"]).agg({"Note": "sum", "Bareme": "sum"})
return [assessment_scores.reset_index().to_dict("records")]
return [
[{"id": c, "name": c} for c in columns],
scores.to_dict("records"),
[],
{"headers": True, "data": len(fixed_columns)},
]

View File

@ -1,7 +1,8 @@
#!/usr/bin/env python
# encoding: utf-8
from ....database.filesystem.loader import CSVLoader
from recopytex.database.filesystem.loader import CSVLoader
from recopytex.lib.dataframe import column_values_to_column
LOADER = CSVLoader("./test_config.yml")
@ -13,3 +14,17 @@ def get_tribes():
def get_exams(tribe):
return LOADER.get_exams([tribe])
def get_record_scores(exam):
return LOADER.get_exam_scores(exam)
def get_unstack_scores(exam):
flat_scores = LOADER.get_exam_scores(exam)
kept_columns = [col for col in LOADER.score_columns if col != "score"]
return column_values_to_column(flat_scores, "student_name", "score", kept_columns)
def get_students_from_exam(exam):
flat_scores = LOADER.get_exam_scores(exam)
return flat_scores["student_name"].unique()

View File

@ -43,6 +43,49 @@ class CSVLoader(Loader):
""" Get config """
return self._config
@property
def exam_columns(self):
return pd.Index(["name", "date", "term", "origin", "tribe", "id"])
@property
def question_columns(self):
return pd.Index(
[
"exercise",
"question",
"competence",
"theme",
"comment",
"score_rate",
"is_leveled",
"origin",
"exam_id",
"id",
]
)
@property
def score_columns(self):
return pd.Index(
[
"term",
"exam",
"date",
"exercise",
"question",
"competence",
"theme",
"comment",
"score_rate",
"is_leveled",
"origin",
"exam_id",
"question_id",
"student_name",
"score",
]
)
def rename_columns(self, dataframe):
"""Rename dataframe column to match with `csv_fields`
@ -84,8 +127,8 @@ class CSVLoader(Loader):
:example:
>>> loader = CSVLoader("./test_config.yml")
>>> exams = loader.get_exams(["Tribe1"])
>>> exams.columns
Index(['name', 'date', 'term', 'origin', 'tribe', 'id'], dtype='object')
>>> all(exams.columns == loader.exam_columns)
True
>>> exams
name date term origin tribe id
0 DS 12/01/2021 1 example/Tribe1/210112_DS.csv Tribe1 DS_Tribe1
@ -118,10 +161,7 @@ class CSVLoader(Loader):
:example:
>>> loader = CSVLoader("./test_config.yml")
>>> exams = loader.get_exams(["Tribe1"])
>>> loader.get_exam_questions([exams.iloc[0]]).columns
Index(['exercise', 'question', 'competence', 'theme', 'comment', 'score_rate',
'is_leveled', 'origin', 'exam_id', 'id'],
dtype='object')
>>> all(loader.get_exam_questions([exams.iloc[0]]).columns == loader.score_columns)
>>> questions = loader.get_exam_questions(exams)
>>> questions.iloc[0]
exercise Exercice 1
@ -172,11 +212,8 @@ class CSVLoader(Loader):
>>> exams = loader.get_exams(["Tribe1"])
>>> questions = loader.get_exam_questions(exams)
>>> scores = loader.get_questions_scores(questions)
>>> scores.columns
Index(['term', 'exam', 'date', 'exercise', 'question', 'competence', 'theme',
'comment', 'score_rate', 'is_leveled', 'origin', 'exam_id',
'question_id', 'student_name', 'score'],
dtype='object')
>>> all(scores.columns == loader.score_columns)
True
>>> scores["student_name"].unique()
array(['Star Tice', 'Umberto Dingate', 'Starlin Crangle',
'Humbert Bourcq', 'Gabriella Handyside', 'Stewart Eaves',
@ -214,6 +251,24 @@ class CSVLoader(Loader):
return pd.concat(scores)
def get_exam_scores(self, exams=[]):
"""Get scores for all question of the exam
:param exams: list or dataframe of exams metadatas (need origin field to find the csv)
:example:
>>> loader = CSVLoader("./test_config.yml")
>>> exams = loader.get_exams(["Tribe1"])
>>> scores = loader.get_exam_scores(exams)
>>> scores.columns
Index(['term', 'exam', 'date', 'exercise', 'question', 'competence', 'theme',
'comment', 'score_rate', 'is_leveled', 'origin', 'exam_id',
'question_id', 'student_name', 'score'],
dtype='object')
"""
questions = self.get_exam_questions(exams)
return self.get_questions_scores(questions)
def get_students(self, tribes=[]):
"""Get student list