Compare commits

...

3 Commits

5 changed files with 109 additions and 40 deletions

View File

@ -1,5 +1,5 @@
Trimestre,Nom,Date,Exercice,Question,Competence,Domaine,Commentaire,Bareme,Est_nivele,Star Tice,Umberto Dingate,Starlin Crangle,Humbert Bourcq,Gabriella Handyside,Stewart Eaves,Erick Going,Ase Praton,Rollins Planks,Dunstan Sarjant,Stacy Guiton,Ange Stanes,Amabelle Elleton,Darn Broomhall,Dyan Chatto,Keane Rennebach,Nari Paulton,Brandy Wase,Jaclyn Firidolfi,Violette Lockney Trimestre,Nom,Date,Exercice,Question,Competence,Domaine,Commentaire,Bareme,Est_nivele,Star Tice,Umberto Dingate,Starlin Crangle,Humbert Bourcq,Gabriella Handyside,Stewart Eaves,Erick Going,Ase Praton,Rollins Planks,Dunstan Sarjant,Stacy Guiton,Ange Stanes,Amabelle Elleton,Darn Broomhall,Dyan Chatto,Keane Rennebach,Nari Paulton,Brandy Wase,Jaclyn Firidolfi,Violette Lockney
1,DS,12/01/2021,Exercice 1,1,Calculer,Plop,Coucou,1,1,,,1.0,0,1.0,2.0,3.0,0.0,3.0,3.0,2.0,,1.0,,,,,,, 1,DS,12/01/2021,Exercice 1,1,Calculer,Plop,Coucou,1,1,,,1,0,1,2,3,0,3,3,2,,1,,,,,,,
1,DS,12/01/2021,Exercice 1,2,Calculer,C'est trop chouette!,Coucou,1,1,,,1.0,2,,,3.0,3.0,,,,,2.0,,,,,,, 1,DS,12/01/2021,Exercice 1,2,Calculer,C'est trop chouette!,Coucou,1,1,,,1,2,,,3,3,,,,,2,,,,,,,
1,DS,12/01/2021,Exercice 1,3,Calculer,Null,Coucou,1,1,,,,3,2.0,,,,,,,,3.0,,,,,,, 1,DS,12/01/2021,Exercice 1,3,Calculer,Null,Coucou,1,1,,,,3,2,,,,,,,,3,,,,,,,
1,DS,12/01/2021,Exercice 1,3,Calculer,Nié,DChic,1,1,,,,2,,,,,,,,,,,,,,,, 1,DS,12/01/2021,Exercice 1,3,Calculer,Nié,DChic,1,1,,,,2,.,,,,,,,,,,,,,,,

1 Trimestre Nom Date Exercice Question Competence Domaine Commentaire Bareme Est_nivele Star Tice Umberto Dingate Starlin Crangle Humbert Bourcq Gabriella Handyside Stewart Eaves Erick Going Ase Praton Rollins Planks Dunstan Sarjant Stacy Guiton Ange Stanes Amabelle Elleton Darn Broomhall Dyan Chatto Keane Rennebach Nari Paulton Brandy Wase Jaclyn Firidolfi Violette Lockney
2 1 DS 12/01/2021 Exercice 1 1 Calculer Plop Coucou 1 1 1.0 1 0 1.0 1 2.0 2 3.0 3 0.0 0 3.0 3 3.0 3 2.0 2 1.0 1
3 1 DS 12/01/2021 Exercice 1 2 Calculer C'est trop chouette! Coucou 1 1 1.0 1 2 3.0 3 3.0 3 2.0 2
4 1 DS 12/01/2021 Exercice 1 3 Calculer Null Coucou 1 1 3 2.0 2 3.0 3
5 1 DS 12/01/2021 Exercice 1 3 Calculer Nié DChic 1 1 2 .

View File

@ -68,6 +68,7 @@ layout = html.Div(
children=[ children=[
dcc.Graph( dcc.Graph(
id="fig_exam_histo", id="fig_exam_histo",
config={"displayModeBar": False},
) )
], ],
id="fig_exam_histo_container", id="fig_exam_histo_container",
@ -76,6 +77,7 @@ layout = html.Div(
children=[ children=[
dcc.Graph( dcc.Graph(
id="fig_questions_bar", id="fig_questions_bar",
config={"displayModeBar": False},
) )
], ],
id="fig_questions_bar_container", id="fig_questions_bar_container",

View File

@ -205,5 +205,12 @@ def update_questions_bar(finale_scores):
fig.update_layout( fig.update_layout(
height=500, height=500,
margin=dict(l=5, r=5, b=5, t=5), margin=dict(l=5, r=5, b=5, t=5),
) legend=dict(
orientation="h",
yanchor="bottom",
y=1.02,
xanchor="right",
x=1
)
)
return [fig] return [fig]

View File

@ -72,22 +72,31 @@ def get_score_colors():
def get_level_color_bar(): def get_level_color_bar():
return [ return [
{"score": s["value"], "name": s["comment"], "color": s["color"]} {"score": str(s["value"]), "name": s["comment"], "color": s["color"]}
for s in SCORES_CONFIG.values() for s in SCORES_CONFIG.values()
] ]
is_none_score = lambda x: on_column.is_none_score(x, SCORES_CONFIG) is_none_score = lambda x: on_column.is_none_score(x, SCORES_CONFIG)
format_score = lambda x: on_column.format_score(x, SCORES_CONFIG)
score_to_numeric_score = lambda x: on_column.score_to_numeric_score(x, SCORES_CONFIG) score_to_numeric_score = lambda x: on_column.score_to_numeric_score(x, SCORES_CONFIG)
score_to_mark = lambda x: on_column.score_to_mark( score_to_mark = lambda x: on_column.score_to_mark(
x, max([v["value"] for v in SCORES_CONFIG.values() if isinstance(v["value"], int)]) x, max([v["value"] for v in SCORES_CONFIG.values() if isinstance(v["value"], int)])
) )
def filter_clean_score(scores):
filtered_scores = scores[~scores.apply(is_none_score, axis=1)]
filtered_scores = filtered_scores.assign(
score=filtered_scores.apply(format_score, axis=1)
)
return filtered_scores
def score_to_final_mark(scores): def score_to_final_mark(scores):
""" Compute marks then reduce to final mark per student """ """ Compute marks then reduce to final mark per student """
filtered_scores = scores[~scores.apply(is_none_score, axis=1)] filtered_scores = filter_clean_score(scores)
filtered_scores = filtered_scores.assign( filtered_scores = filtered_scores.assign(
score=filtered_scores.apply(score_to_numeric_score, axis=1) score=filtered_scores.apply(score_to_numeric_score, axis=1)
) )
@ -106,9 +115,10 @@ def pivot_score_on(scores, index, columns, aggfunc="size"):
It assumes thant scores are levels It assumes thant scores are levels
""" """
filtered_scores = scores[~scores.apply(is_none_score, axis=1)] filtered_scores = filter_clean_score(scores)
filtered_scores["score"] = filtered_scores["score"].astype(str)
pt = pd.pivot_table( pt = pd.pivot_table(
scores, filtered_scores,
index=index, index=index,
columns=columns, columns=columns,
aggfunc=aggfunc, aggfunc=aggfunc,

View File

@ -43,6 +43,57 @@ def is_none_score(x, score_config):
return x["score"] in none_values or pd.isnull(x["score"]) return x["score"] in none_values or pd.isnull(x["score"])
def format_score(x, score_config):
"""Make sure that score have the appropriate format
>>> import pandas as pd
>>> d = {"Eleve":["E1"]*6,
... "score_rate": [1]*6,
... "is_leveled":[0]+[1]*5,
... "score":[0.33, ".", "a", 1, 2, 3],
... }
>>> score_config = {
... 'BAD': {'value': 0, 'numeric_value': 0},
... 'FEW': {'value': 1, 'numeric_value': 1},
... 'NEARLY': {'value': 2, 'numeric_value': 2},
... 'GOOD': {'value': 3, 'numeric_value': 3},
... 'NOTFILLED': {'value': '', 'numeric_value': 'None'},
... 'NOANSWER': {'value': '.', 'numeric_value': 0},
... 'ABS': {'value': 'a', 'numeric_value': 'None'}
... }
>>> df = pd.DataFrame(d)
>>> df.apply(lambda x:format_score(x, score_config), axis=1)
0 0.33
1 .
2 a
3 1
4 2
5 3
dtype: object
>>> format_score({"score": "1.0", "is_leveled": 1}, score_config)
1
>>> format_score({"score": "3.0", "is_leveled": 1}, score_config)
3
>>> format_score({"score": 4, "is_leveled": 1}, score_config)
Traceback (most recent call last):
...
ValueError: 4 (<class 'int'>) can't be a score
"""
if not x["is_leveled"]:
return float(x["score"])
try:
score = int(float(x["score"]))
except ValueError:
score = str(x["score"])
if score in [v["value"] for v in score_config.values()]:
return score
raise ValueError(f"{x['score']} ({type(x['score'])}) can't be a score")
def score_to_numeric_score(x, score_config): def score_to_numeric_score(x, score_config):
"""Convert a score to the corresponding numeric value """Convert a score to the corresponding numeric value
@ -81,7 +132,7 @@ def score_to_numeric_score(x, score_config):
def score_to_mark(x, score_max, rounding=lambda x: round(x, 2)): def score_to_mark(x, score_max, rounding=lambda x: round(x, 2)):
"""Compute the mark from the score """Compute the mark from "score" which have to be filtered and in numeric form
if the item is leveled then the score is multiply by the score_rate if the item is leveled then the score is multiply by the score_rate
otherwise it copies the score otherwise it copies the score
@ -92,39 +143,38 @@ def score_to_mark(x, score_max, rounding=lambda x: round(x, 2)):
:return: the mark :return: the mark
>>> import pandas as pd >>> import pandas as pd
>>> d = {"Eleve":["E1"]*6 + ["E2"]*6, >>> d = {"Eleve":["E1"]*7,
... "score_rate":[1]*2+[2]*2+[2]*2 + [1]*2+[2]*2+[2]*2, ... "score_rate": [1]*7,
... "is_leveled":[0]*4+[1]*2 + [0]*4+[1]*2, ... "is_leveled":[0]+[1]*6,
... "score":[1, 0.33, 2, 1.5, 1, 3, 0.666, 1, 1.5, 1.2, 2, 3], ... "score":[0.33, "", ".", "a", 1, 2, 3],
... }
>>> score_config = {
... 'BAD': {'value': 0, 'numeric_value': 0},
... 'FEW': {'value': 1, 'numeric_value': 1},
... 'NEARLY': {'value': 2, 'numeric_value': 2},
... 'GOOD': {'value': 3, 'numeric_value': 3},
... 'NOTFILLED': {'value': '', 'numeric_value': 'None'},
... 'NOANSWER': {'value': '.', 'numeric_value': 0},
... 'ABS': {'value': 'a', 'numeric_value': 'None'}
... } ... }
>>> df = pd.DataFrame(d) >>> df = pd.DataFrame(d)
>>> df.loc[0] >>> df = df[~df.apply(lambda x:is_none_score(x, score_config), axis=1)]
Eleve E1 >>> df["score"] = df.apply(lambda x:score_to_numeric_score(x, score_config), axis=1)
score_rate 1 >>> df.apply(lambda x:score_to_mark(x, 3), axis=1)
is_leveled 0 0 0.33
score 1.0 2 0.00
Name: 0, dtype: object 4 0.33
>>> score_to_mark(df.loc[0], 3) 5 0.67
1.0 6 1.00
>>> df.loc[10] dtype: float64
Eleve E2
score_rate 2
is_leveled 1
score 2.0
Name: 10, dtype: object
>>> score_to_mark(df.loc[10], 3)
1.33
>>> from .on_value import round_half_point >>> from .on_value import round_half_point
>>> score_to_mark(df.loc[10], 3, round_half_point) >>> df.apply(lambda x:score_to_mark(x, 3, round_half_point), axis=1)
1.5 0 0.5
>>> df.loc[1] 2 0.0
Eleve E1 4 0.5
score_rate 1 5 0.5
is_leveled 0 6 1.0
score 0.33 dtype: float64
Name: 1, dtype: object
>>> score_to_mark(df.loc[1], 3)
0.33
""" """
if x["is_leveled"]: if x["is_leveled"]:
if x["score"] not in list(range(score_max + 1)): if x["score"] not in list(range(score_max + 1)):