Feat: question levels bar figure
This commit is contained in:
parent
36425e587e
commit
18f855ab83
@ -72,6 +72,14 @@ layout = html.Div(
|
||||
],
|
||||
id="fig_exam_histo_container",
|
||||
),
|
||||
html.Div(
|
||||
children=[
|
||||
dcc.Graph(
|
||||
id="fig_questions_bar",
|
||||
)
|
||||
],
|
||||
id="fig_questions_bar_container",
|
||||
),
|
||||
],
|
||||
id="analysis",
|
||||
),
|
||||
|
@ -18,7 +18,10 @@ from .models import (
|
||||
get_unstack_scores,
|
||||
get_students_from_exam,
|
||||
get_score_colors,
|
||||
get_level_color_bar,
|
||||
score_to_final_mark,
|
||||
stack_scores,
|
||||
pivot_score_on,
|
||||
)
|
||||
|
||||
|
||||
@ -90,8 +93,8 @@ def update_scores_store(exam):
|
||||
)
|
||||
def update_finale_score_table(scores):
|
||||
scores_df = pd.DataFrame.from_records(scores)
|
||||
# print(scores_df)
|
||||
return score_to_final_mark(scores_df)
|
||||
stacked_scores = stack_scores(scores_df)
|
||||
return score_to_final_mark(stacked_scores)
|
||||
|
||||
|
||||
@app.callback(
|
||||
@ -106,7 +109,6 @@ def update_finale_score_table(scores):
|
||||
def update_statictics_table(finale_score):
|
||||
df = pd.DataFrame.from_records(finale_score)
|
||||
statistics = df["mark"].describe().to_frame().T
|
||||
print(statistics)
|
||||
return [
|
||||
[{"id": c, "name": c} for c in statistics.columns],
|
||||
statistics.to_dict("records"),
|
||||
@ -155,3 +157,54 @@ def update_exam_histo(finale_scores):
|
||||
margin=dict(l=5, r=5, b=5, t=5),
|
||||
)
|
||||
return [fig]
|
||||
|
||||
|
||||
@app.callback(
|
||||
[
|
||||
Output("fig_questions_bar", "figure"),
|
||||
],
|
||||
[
|
||||
Input("scores_table", "data"),
|
||||
],
|
||||
)
|
||||
def update_questions_bar(finale_scores):
|
||||
scores = pd.DataFrame.from_records(finale_scores)
|
||||
scores = stack_scores(scores)
|
||||
|
||||
if scores.empty:
|
||||
return [go.Figure(data=[go.Scatter(x=[], y=[])])]
|
||||
|
||||
pt = pivot_score_on(scores, ["exercise", "question", "comment"], "score")
|
||||
print(pt)
|
||||
|
||||
# separation between exercises
|
||||
for i in {i for i in pt.index.get_level_values(0)}:
|
||||
pt.loc[(str(i), "", ""), :] = ""
|
||||
pt.sort_index(inplace=True)
|
||||
|
||||
# Bar label
|
||||
index = (
|
||||
pt.index.get_level_values(0).map(str)
|
||||
+ ":"
|
||||
+ pt.index.get_level_values(1).map(str)
|
||||
+ " "
|
||||
+ pt.index.get_level_values(2).map(str)
|
||||
)
|
||||
|
||||
fig = go.Figure()
|
||||
|
||||
bars = get_level_color_bar()
|
||||
|
||||
for b in bars:
|
||||
try:
|
||||
fig.add_bar(
|
||||
x=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 [fig]
|
||||
|
@ -70,6 +70,13 @@ def get_score_colors():
|
||||
return score_color
|
||||
|
||||
|
||||
def get_level_color_bar():
|
||||
return [
|
||||
{"score": s["value"], "name": s["comment"], "color": s["color"]}
|
||||
for s in SCORES_CONFIG.values()
|
||||
]
|
||||
|
||||
|
||||
is_none_score = lambda x: on_column.is_none_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(
|
||||
@ -80,8 +87,7 @@ score_to_mark = lambda x: on_column.score_to_mark(
|
||||
def score_to_final_mark(scores):
|
||||
""" Compute marks then reduce to final mark per student """
|
||||
|
||||
melted_scores = stack_scores(scores)
|
||||
filtered_scores = melted_scores[~melted_scores.apply(is_none_score, axis=1)]
|
||||
filtered_scores = scores[~scores.apply(is_none_score, axis=1)]
|
||||
filtered_scores = filtered_scores.assign(
|
||||
score=filtered_scores.apply(score_to_numeric_score, axis=1)
|
||||
)
|
||||
@ -93,3 +99,20 @@ def score_to_final_mark(scores):
|
||||
].sum()
|
||||
return [final_score.reset_index().to_dict("records")]
|
||||
|
||||
|
||||
def pivot_score_on(scores, index, columns, aggfunc="size"):
|
||||
"""Pivot scores on index, columns with aggfunc
|
||||
|
||||
It assumes thant scores are levels
|
||||
|
||||
"""
|
||||
filtered_scores = scores[~scores.apply(is_none_score, axis=1)]
|
||||
pt = pd.pivot_table(
|
||||
scores,
|
||||
index=index,
|
||||
columns=columns,
|
||||
aggfunc=aggfunc,
|
||||
fill_value=0,
|
||||
)
|
||||
return pt
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user