Compare commits
6 Commits
a50901556e
...
9e0ea14d05
Author | SHA1 | Date | |
---|---|---|---|
9e0ea14d05 | |||
2031ade1ab | |||
6ed55c07d4 | |||
1d234ea5fc | |||
646314ad88 | |||
0739cfdae7 |
@ -15,10 +15,11 @@ layout = html.Div(
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
html.Main(
|
html.Main(
|
||||||
|
children=[
|
||||||
html.Section(
|
html.Section(
|
||||||
[
|
children=[
|
||||||
html.Div(
|
html.Div(
|
||||||
[
|
children=[
|
||||||
"Classe: ",
|
"Classe: ",
|
||||||
dcc.Dropdown(
|
dcc.Dropdown(
|
||||||
id="tribe",
|
id="tribe",
|
||||||
@ -31,45 +32,36 @@ layout = html.Div(
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
html.Div(
|
html.Div(
|
||||||
[
|
children=[
|
||||||
"Evaluation: ",
|
"Evaluation: ",
|
||||||
dcc.Dropdown(id="exam_select"),
|
dcc.Dropdown(id="exam_select"),
|
||||||
],
|
],
|
||||||
html.P(id="test"),
|
),
|
||||||
],
|
],
|
||||||
id="select",
|
id="selects",
|
||||||
),
|
),
|
||||||
html.Section(
|
html.Section(
|
||||||
[
|
children=[
|
||||||
html.Div(
|
html.Div(
|
||||||
dash_table.DataTable(
|
children=[],
|
||||||
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",
|
id="final_score_table_container",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
id="analysis",
|
id="analysis",
|
||||||
),
|
),
|
||||||
html.Section(
|
html.Section(
|
||||||
|
children=[
|
||||||
|
dash_table.DataTable(
|
||||||
id="scores_table",
|
id="scores_table",
|
||||||
|
columns=[],
|
||||||
|
style_data_conditional=[],
|
||||||
|
fixed_columns={},
|
||||||
|
editable=True,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
id="edit",
|
||||||
),
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
dcc.Store(id="scores"),
|
dcc.Store(id="scores"),
|
||||||
],
|
],
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
from dash.dependencies import Input, Output
|
from dash.dependencies import Input, Output, State
|
||||||
|
import dash
|
||||||
from dash.exceptions import PreventUpdate
|
from dash.exceptions import PreventUpdate
|
||||||
|
import dash_table
|
||||||
|
import json
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
from ...app import app
|
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(
|
@app.callback(
|
||||||
@ -15,12 +19,11 @@ from .models import get_tribes, get_exams
|
|||||||
],
|
],
|
||||||
[Input("tribe", "value")],
|
[Input("tribe", "value")],
|
||||||
)
|
)
|
||||||
def update_csvs(value):
|
def update_exams_choices(tribe):
|
||||||
if not value:
|
if not tribe:
|
||||||
raise PreventUpdate
|
raise PreventUpdate
|
||||||
exams = get_exams(value)
|
exams = get_exams(tribe)
|
||||||
exams.reset_index(inplace=True)
|
exams.reset_index(inplace=True)
|
||||||
print(exams.loc[0, "name"])
|
|
||||||
if not exams.empty:
|
if not exams.empty:
|
||||||
return [
|
return [
|
||||||
{"label": e["name"], "value": e.to_json()} for i, e in exams.iterrows()
|
{"label": e["name"], "value": e.to_json()} for i, e in exams.iterrows()
|
||||||
@ -30,24 +33,35 @@ def update_csvs(value):
|
|||||||
|
|
||||||
@app.callback(
|
@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):
|
def update_scores_store(exam):
|
||||||
if not data:
|
ctx = dash.callback_context
|
||||||
raise PreventUpdate
|
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)
|
return [
|
||||||
try:
|
[{"id": c, "name": c} for c in columns],
|
||||||
if scores.iloc[0]["Commentaire"] == "commentaire":
|
scores.to_dict("records"),
|
||||||
scores.drop([0], inplace=True)
|
[],
|
||||||
except KeyError:
|
{"headers": True, "data": len(fixed_columns)},
|
||||||
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")]
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# 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")
|
LOADER = CSVLoader("./test_config.yml")
|
||||||
|
|
||||||
@ -13,3 +14,17 @@ def get_tribes():
|
|||||||
def get_exams(tribe):
|
def get_exams(tribe):
|
||||||
return LOADER.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()
|
||||||
|
@ -43,6 +43,49 @@ class CSVLoader(Loader):
|
|||||||
""" Get config """
|
""" Get config """
|
||||||
return self._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):
|
def rename_columns(self, dataframe):
|
||||||
"""Rename dataframe column to match with `csv_fields`
|
"""Rename dataframe column to match with `csv_fields`
|
||||||
|
|
||||||
@ -84,8 +127,8 @@ class CSVLoader(Loader):
|
|||||||
:example:
|
:example:
|
||||||
>>> loader = CSVLoader("./test_config.yml")
|
>>> loader = CSVLoader("./test_config.yml")
|
||||||
>>> exams = loader.get_exams(["Tribe1"])
|
>>> exams = loader.get_exams(["Tribe1"])
|
||||||
>>> exams.columns
|
>>> all(exams.columns == loader.exam_columns)
|
||||||
Index(['name', 'date', 'term', 'origin', 'tribe', 'id'], dtype='object')
|
True
|
||||||
>>> exams
|
>>> exams
|
||||||
name date term origin tribe id
|
name date term origin tribe id
|
||||||
0 DS 12/01/2021 1 example/Tribe1/210112_DS.csv Tribe1 DS_Tribe1
|
0 DS 12/01/2021 1 example/Tribe1/210112_DS.csv Tribe1 DS_Tribe1
|
||||||
@ -118,10 +161,7 @@ class CSVLoader(Loader):
|
|||||||
:example:
|
:example:
|
||||||
>>> loader = CSVLoader("./test_config.yml")
|
>>> loader = CSVLoader("./test_config.yml")
|
||||||
>>> exams = loader.get_exams(["Tribe1"])
|
>>> exams = loader.get_exams(["Tribe1"])
|
||||||
>>> loader.get_exam_questions([exams.iloc[0]]).columns
|
>>> all(loader.get_exam_questions([exams.iloc[0]]).columns == loader.score_columns)
|
||||||
Index(['exercise', 'question', 'competence', 'theme', 'comment', 'score_rate',
|
|
||||||
'is_leveled', 'origin', 'exam_id', 'id'],
|
|
||||||
dtype='object')
|
|
||||||
>>> questions = loader.get_exam_questions(exams)
|
>>> questions = loader.get_exam_questions(exams)
|
||||||
>>> questions.iloc[0]
|
>>> questions.iloc[0]
|
||||||
exercise Exercice 1
|
exercise Exercice 1
|
||||||
@ -172,11 +212,8 @@ class CSVLoader(Loader):
|
|||||||
>>> exams = loader.get_exams(["Tribe1"])
|
>>> exams = loader.get_exams(["Tribe1"])
|
||||||
>>> questions = loader.get_exam_questions(exams)
|
>>> questions = loader.get_exam_questions(exams)
|
||||||
>>> scores = loader.get_questions_scores(questions)
|
>>> scores = loader.get_questions_scores(questions)
|
||||||
>>> scores.columns
|
>>> all(scores.columns == loader.score_columns)
|
||||||
Index(['term', 'exam', 'date', 'exercise', 'question', 'competence', 'theme',
|
True
|
||||||
'comment', 'score_rate', 'is_leveled', 'origin', 'exam_id',
|
|
||||||
'question_id', 'student_name', 'score'],
|
|
||||||
dtype='object')
|
|
||||||
>>> scores["student_name"].unique()
|
>>> scores["student_name"].unique()
|
||||||
array(['Star Tice', 'Umberto Dingate', 'Starlin Crangle',
|
array(['Star Tice', 'Umberto Dingate', 'Starlin Crangle',
|
||||||
'Humbert Bourcq', 'Gabriella Handyside', 'Stewart Eaves',
|
'Humbert Bourcq', 'Gabriella Handyside', 'Stewart Eaves',
|
||||||
@ -214,6 +251,24 @@ class CSVLoader(Loader):
|
|||||||
|
|
||||||
return pd.concat(scores)
|
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=[]):
|
def get_students(self, tribes=[]):
|
||||||
"""Get student list
|
"""Get student list
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user