Commit 621a299b authored by Florent Chehab's avatar Florent Chehab
Browse files

UV details added

parent 18988014
*.html
analysis.html
.ipynb_checkpoints
proj_env
data
......
%% Cell type:raw id: tags:
<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('200');
$('.output_prompt').css({visibility: 'hidden'});
$('#toggleButton').val('Afficher le code source')
} else {
$('div.input').show('200');
$('.output_prompt').removeAttr('style');
$('#toggleButton').val('Cacher le code source')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide();
$('.output_prompt').css({visibility: 'hidden'});
$('table').addClass("table table-hover table-bordered table-striped");
});
</script>
<form action="javascript:code_toggle()">
<input type="submit" id="toggleButton" value="Afficher le code source" class="btn btn-info">
</form>
%% Cell type:markdown id: tags:
<center>
<img src="https://gitlab.utc.fr/LaTeX-UTC/Graphismes-UTC/raw/56dd9762de926727aa45c8279dcdf54a753335c8/logos/UTC/logo_UTC.png" alt="Logo UTC" width="200px"/>
<br>
<font size="15">Observatoire des évaluations d'UVs</font>
</center>
%% Cell type:code id: tags:
``` python
# For auto completion inside jupyter notebook
%config IPCompleter.greedy=True
import yaml # for the config file
import warnings # to issue warnings when needed
import os.path # for easy work with file paths
import copy
# Simple functions
from src.generate_data import generate_data_file
from src.tools import is_connected, to_mardown_table_str
# For managing dataa
import json
from collections import OrderedDict
from datetime import datetime
import pandas as pd
import numpy as np
# For plotting data
from IPython.core.display import HTML, display, Markdown
from plotly.offline import init_notebook_mode, plot, iplot
import plotly.graph_objs as go
# Some magic for file size optimization
if is_connected(debug=True):
# do not include plotly js directly
init_notebook_mode(connected=True)
else:
# include plotly js directly
import cufflinks as cf
cf.set_config_file(offline=True, world_readable=True, theme='ggplot')
# First we take care of the configuration file
CONFIGURATION = yaml.load(open('./config.yml'))
ALL_SEMESTERS = {info['sem']:info['end_date'] for info in CONFIGURATION["other_semesters"]}
ALL_SEMESTERS[CONFIGURATION["main_semester"]['sem']] = CONFIGURATION["main_semester"]['end_date']
MAIN_SEMESTER = CONFIGURATION["main_semester"]['sem']
OTHER_SEMESTERS = [d['sem'] for d in CONFIGURATION["other_semesters"]]
ALL_SEMESTERS_SORTED = sorted(list(ALL_SEMESTERS.keys()), key=lambda sem:sem[1:5]+str((ord(sem[0]) + 20)%26 ))
for semester in ALL_SEMESTERS.keys():
if not os.path.isfile('./data/' + semester + '.json'):
warnings.warn("Il manque des fichiers de données des évaluations d'UVs pour le semestre "
+ semester
+ ". Nous allons en générer pour pouvoir continer.")
generate_data_file(semester)
ALL_SEMESTERS[semester] = datetime.strptime(ALL_SEMESTERS[semester], '%d/%m/%Y')
# import data
EVALS = {}
EVALS_RAW = {}
EVALS_DATE_CREATED = {}
for semester in ALL_SEMESTERS.keys():
data_json = json.load(open('./data/' + semester + '.json'))
date = data_json["date"]
if data_json["semester"] != semester:
print(data_json["semester"], semester)
raise Exception("Incoherent data file naming !")
EVALS_DATE_CREATED[semester] = datetime.strptime(date, '%d/%m/%Y')
data = OrderedDict(data_json["data"])
EVALS_RAW[semester] = copy.deepcopy(data)
for uv, description in data.items():
if description["date_review"] is not None and type(description["date_review"]) != 'datetime.datetime':
description["date_review"] = datetime.strptime(description["date_review"], '%d/%m/%Y')
if description["date_review_teacher"] is not None and type(description["date_review_teacher"]) != 'datetime.datetime':
description["date_review_teacher"] = datetime.strptime(description["date_review_teacher"], '%d/%m/%Y')
if description["date_review_conseil"] is not None and type(description["date_review_conseil"]) != 'datetime.datetime':
description["date_review_conseil"] = datetime.strptime(description["date_review_conseil"], '%d/%m/%Y')
EVALS[semester] = pd.DataFrame.from_dict(data, orient = "index")
EVALS_MAIN_SEM = EVALS[MAIN_SEMESTER]
```
%% Cell type:code id: tags:
``` python
str_tmp = "</br><center><span style='font-size:40px'>Semestre d'étude : "
str_tmp += MAIN_SEMESTER
str_tmp += "</span><br><br>"
str_tmp += "<span style='font-size:30px'>Autre(s) semestre(s) pour comparaison : "
str_tmp += " ".join(x for x in OTHER_SEMESTERS)
str_tmp += "</span></center><br>"
HTML(str_tmp)
```
%% Cell type:markdown id: tags:
# Introduction
## Présentation des données
### Âge des données
%% Cell type:code id: tags:
``` python
str_tmp = "Les données pour chaque semestre ont été extraites aux dates : \n\n "
t = [["Semestre", "Date d'extraction"]]
for sem in EVALS_DATE_CREATED.keys():
t.append([sem, EVALS_DATE_CREATED[sem].strftime('%d/%m/%Y')])
Markdown(str_tmp + to_mardown_table_str(t))
```
%% Cell type:markdown id: tags:
### Structure des données
Pour chaque semestre, nous avons les informations des évaluations telles que visibles par les étudiants sur l'ENT aux dates d'extraction précisées ci-dessus. Nous connaissons notamment :
- Le code de l'UV ;
- L'intitulé de l'UV ;
- Le nombre d'étudiants inscrits ;
- Le nombre d'étudiants marqués comme _absents_ ;
- Le nombre d'étudiants qui ont obtenu l'UV ;
- Le nombre d'évaluations saisies par les étudiants ;
- Les statistiques pour chacune des questions (i.e. le nombre de '++', etc. pour chaque question) ;
- La longueur du commentaire saisi par le responsable de l'UV, s'il en a saisi un ;
- La date à laquelle le responsable de l'UV a « regardé » évaluations.
Voici un exemple pour l'UV MT23 :
%% Cell type:code id: tags:
``` python
print(EVALS_MAIN_SEM.loc["MT23"])
```
%% Cell type:markdown id: tags:
### Remarque
Lorsque les statistiques des évaluations d'UVs (le nombre de `++`, de `+`, etc.) seront analysées de manière quantitative la table de conversion _symétrique_ suivante sera employée :
| Sigle | Valeur associée |
|-------|-----------------|
| `++` | +3 |
| `+` | +1 |
| `-` | -1 |
| `--` | -3 |
%% Cell type:code id: tags:
``` python
POSSIBLE_ANSWERS = ["--","-","+","++"]
POSSIBLE_ANSWERS_COEFFS = [-3,-1,1,3]
def get_nb_evals(stats):
return sum([stats['1'][s] for s in POSSIBLE_ANSWERS])
def get_mark_q(stat, q):
if type(q) is int:
q = str(q)
return sum([stat[q][POSSIBLE_ANSWERS[i]] * POSSIBLE_ANSWERS_COEFFS[i] for i in range(len(POSSIBLE_ANSWERS_COEFFS))]) / get_nb_evals(stat)
POSSIBLE_ANSWERS_COL = ['rgb(255,48,48)','rgb(255,165,0)', 'rgb(144,238,144)', 'rgb(48,221,48)']
ORANGE = 'rgb(255,126,24)'
# Lets have some standard scales
SCALE_PERCENTAGE = [-1,101]
SCALE_MARK = [-3.1, 3.1]
```
%% Cell type:markdown id: tags:
## Informations générales
Lorsque'une analyse comparative est réalisée, elle est faite par rapport aux données des précédents semestres.
### Taux de réponse
%% Cell type:code id: tags:
``` python
t = [["Semestre","Nombre d'UVs", "Taux de réponse moyen des étudiants" , "Nombre d'UV qui ont été vu", "avec un commentaire"]]
SEMESTERS_INFO = {}
for sem in ALL_SEMESTERS_SORTED:
sem_data = EVALS[sem]
nb_uvs = len(sem_data.index)
taux_eval = sem_data.loc[:, ("nb_evals","nb_etu_registered")].min(axis=1)/sem_data["nb_etu_registered"]
taux_eval = taux_eval.fillna(1) # Sometimes there 0 students in a course but there are evaluations
taux_eval = sum(taux_eval)/nb_uvs
uvs_with_evals = sem_data.loc[pd.notna(sem_data["date_review"])]
uvs_with_evals = sem_data.loc[pd.notna(sem_data["date_review_teacher"])]
nb_uvs_with_evals = len(uvs_with_evals.index)
uvs_with_com = sem_data.loc[sem_data["comment"]>0]
uvs_with_com = sem_data.loc[sem_data["teacher_comment"]>""]
nb_uvs_with_com = len(uvs_with_com)
SEMESTERS_INFO[sem] = {
'nb_uvs': nb_uvs,
'nb_uvs_with_com': nb_uvs_with_com,
'nb_uvs_with_evals': nb_uvs_with_evals,
'taux_rep_avg': taux_eval
}
t.append([sem, str(nb_uvs),
"{0:.1f}%".format(taux_eval * 100),
str(nb_uvs_with_evals)+" ({0:.1f}%)".format(nb_uvs_with_evals / nb_uvs * 100),
str(nb_uvs_with_com)+" ({0:.1f}%)".format(nb_uvs_with_com / nb_uvs * 100)])
Markdown(to_mardown_table_str(t))
```
%% Cell type:code id: tags:
``` python
traces = []
for sem in ALL_SEMESTERS_SORTED:
info = SEMESTERS_INFO[sem]
traces += [go.Bar(
x=["Taux de réponse moyen des étudiants", "Taux d'UVs où les resps. ont 'vu' les éval.", "Taux d'UVs où le resp. a laissé un commentaire"],
y=[
info['taux_rep_avg']*100,
info['nb_uvs_with_evals']/info['nb_uvs'] *100,
info['nb_uvs_with_com']/info['nb_uvs']*100
],
name=sem
)]
layout = go.Layout(
barmode='group',
title = "Taux de réponses aux évaluations",
yaxis=dict(
range=SCALE_PERCENTAGE,
title='Pourcentage',
),
)
iplot(go.Figure(data=traces, layout=layout))
```
%% Cell type:code id: tags:
``` python
traces = []
for sem in ALL_SEMESTERS_SORTED:
sem_data = EVALS[sem]
taux_eval = sem_data.loc[:, ("nb_evals","nb_etu_registered")].min(axis=1)/sem_data["nb_etu_registered"]
taux_eval = taux_eval.fillna(1) # Sometimes there 0 students in a course but there are evaluations
traces += [go.Box(
y=taux_eval*100,
text=taux_eval.index,
name=sem
)]
layout = go.Layout(
title = "Taux de réponse moyen des étudiants aux évaluations",
yaxis=dict(
range=SCALE_PERCENTAGE,
title='Taux de réponse',
),
)
iplot(go.Figure(data=traces, layout=layout))
```
%% Cell type:markdown id: tags:
### Délai de réponse des responsables d'UVs
#### Pour le semestre d'étude principal
%% Cell type:code id: tags:
``` python
uvs_with_evals = EVALS_MAIN_SEM.loc[pd.notna(EVALS_MAIN_SEM["date_review"])]
uvs_with_evals = EVALS_MAIN_SEM.loc[pd.notna(EVALS_MAIN_SEM["date_review_teacher"])]
graph_data = [
go.Scatter(
x=uvs_with_evals['date_review'].sort_values(),
x=uvs_with_evals['date_review_teacher'].sort_values(),
y=[100*float(i+1)/nb_uvs for i,e in enumerate(uvs_with_evals.index)],
text=uvs_with_evals.sort_values(by=['date_review']).index,
text=uvs_with_evals.sort_values(by=['date_review_teacher']).index,
marker=dict(color=ORANGE)
)
]
layout = go.Layout(
title = "Délai de réponse des responsables d'UVs lors du semestre "+MAIN_SEMESTER,
yaxis=dict(
range=SCALE_PERCENTAGE,
title='Taux de réponse',
),
xaxis=dict(
title="Date"
)
)
iplot(go.Figure(data=graph_data, layout=layout))
```
%% Cell type:markdown id: tags:
#### En comparaison avec les précédents semestres
Pour cette comparaison, les dates sont renormalisées par rapport à la date correspondant au dernier jour des finaux du semestre en question. Les dates de fins des finaux sont les suivantes :
%% Cell type:code id: tags:
``` python
t = [["Semestre", "Date de la fin des finaux"]]
for sem in ALL_SEMESTERS_SORTED:
t.append([sem, ALL_SEMESTERS[sem].strftime('%d/%m/%Y')])
Markdown(to_mardown_table_str(t))
```
%% Cell type:code id: tags:
``` python
traces = []
for sem in ALL_SEMESTERS_SORTED:
sem_end_date = ALL_SEMESTERS[sem].toordinal()
nb_uvs = SEMESTERS_INFO[sem]["nb_uvs"]
sem_data = EVALS[sem]
uvs_with_evals = sem_data.loc[pd.notna(sem_data["date_review"])]
uvs_with_evals = sem_data.loc[pd.notna(sem_data["date_review_teacher"])]
traces.append(
go.Scatter(
x=uvs_with_evals['date_review'].sort_values().apply(datetime.toordinal)-sem_end_date ,
x=uvs_with_evals['date_review_teacher'].sort_values().apply(datetime.toordinal)-sem_end_date ,
y=[100*float(i+1)/nb_uvs for i,e in enumerate(uvs_with_evals.index)],
text=uvs_with_evals.sort_values(by=['date_review']).index,
text=uvs_with_evals.sort_values(by=['date_review_teacher']).index,
name=sem
)
)
layout = go.Layout(
title = "Délai de réponse",
yaxis=dict(
range=SCALE_PERCENTAGE,
title="Taux des resps. d'UVs qui ont 'vu' les évaluations",
),
xaxis=dict(
title="Nombre de jours après la fin des finaux."
)
)
iplot(go.Figure(data=traces, layout=layout))
```
%% Cell type:markdown id: tags:
# Analyse quantitative
Pour rappel voici les questions posées :
1. Clarté des objectifs et du programme de l'UV
2. Y a-t-il adéquation entre le programme annoncé et le programme réalisé ?
3. Ma maîtrise des antécédents et pré-requis nécessaires
4. Qualité pédagogique de l'équipe enseignante
5. Articulation et cohérence des activités
6. Qualité des supports pédagogiques
7. Adéquation des moyens matériels
8. Adéquation des contrôles et des évaluations
9. Quantité de travail demandée
10. Mon appréciation globale de l'UV
## Vue d'ensemble des questions
### Vue synthétique
%% Cell type:code id: tags:
``` python
def get_stat_by_question(question, s):
q = str(question)
res = 0
for i, row in EVALS_MAIN_SEM.iterrows():
res += row["stats"][q][s] / get_nb_evals(row["stats"])
return res / len(EVALS_MAIN_SEM.index) * 100
traces = []
for ans, col in zip(POSSIBLE_ANSWERS, POSSIBLE_ANSWERS_COL):
traces.append(
go.Bar(
x=["Question "+str(i) for i in range(1,11)],
y=[get_stat_by_question(i, ans) for i in range(1,11)],
name=ans,
marker=dict(color=col)
)
)
layout = go.Layout(
barmode='stack',
title="Pourcentage moyen de chaque type d'avis pour chaque question en "+MAIN_SEMESTER,
yaxis=dict(
range=SCALE_PERCENTAGE,
title="Pourcentage (cumulé)",
),
)
fig = go.Figure(data=traces, layout=layout)
iplot(fig)
```
%% Cell type:markdown id: tags:
### Vue détaillée
_Ici les évaluations (`++`, ...) sont converties en note numérique._
%% Cell type:code id: tags:
``` python
traces = []
for q in [str(i) for i in range(1,11)]:
traces.append(
go.Box(
y=[get_mark_q(row["stats"], q) for ind, row in EVALS_MAIN_SEM.iterrows()],
text=EVALS_MAIN_SEM.index,
name="Question "+q,
)
)
layout = go.Layout(
title = "Répartition des notes obetnues pour chaque question en " + MAIN_SEMESTER,
yaxis=dict(
range=SCALE_MARK,
title='Notes obtenues',
),
)
fig = go.Figure(data=traces, layout=layout)
iplot(fig)
```
%% Cell type:markdown id: tags:
## Analyse de la question 10 (Appréciation globale de l'UV)
### Analyse pour le semestre d'étude
%% Cell type:code id: tags:
``` python
Markdown("_("+MAIN_SEMESTER+")_")
```
%% Cell type:code id: tags:
``` python
def get_stat_per_q(row, q, stat):
return row["stats"][q][stat]
def get_nb_mm_q10(row):
return get_stat_per_q(row, "10", "--")
def get_nb_m_q10(row):
return get_stat_per_q(row, "10", "-")
def get_nb_m_or_mm_q10(row):
return get_nb_mm_q10(row) + get_nb_m_q10(row)
traces = []
tmp1 = EVALS_MAIN_SEM.apply(get_nb_mm_q10, axis=1) / EVALS_MAIN_SEM["nb_evals"]
traces.append(
go.Scatter(
x=tmp1.sort_values().index,
y=tmp1.sort_values()*100,
name="--"
)
)
tmp2 = EVALS_MAIN_SEM.apply(get_nb_m_or_mm_q10, axis=1) / EVALS_MAIN_SEM["nb_evals"]
traces.append(
go.Scatter(
x=tmp2[tmp1.sort_values().index].index,
y=tmp2[tmp1.sort_values().index]*100,
name="-- ou -"
)
)
layout = go.Layout(
title = "Visualisation du pourcentage d'avis négatifs -- et (- ou --) pour la question 10",
yaxis=dict(
range=SCALE_PERCENTAGE,
title="Pourcentage",
),
xaxis=dict(
title="UVs triées selon le pourcentage d'avis -- à la question 10",
)
)
iplot(go.Figure(data=traces, layout=layout))
```
%% Cell type:code id: tags:
``` python
tmp = EVALS_MAIN_SEM.apply((lambda r : get_mark_q(r["stats"],10)), axis=1)
tmp = EVALS_MAIN_SEM.apply((lambda r : get_mark_q(r["stats"],10)), axis=1).sort_values(ascending = False)
col = EVALS_MAIN_SEM.loc[tmp.index,"teacher_comment"]
col[col>""] = POSSIBLE_ANSWERS_COL[3]
col[col==""] = POSSIBLE_ANSWERS_COL[1]
col[col.isnull()] = POSSIBLE_ANSWERS_COL[0]
graph_data = [
go.Scatter(
x=tmp.sort_values(ascending = False).index,
y=tmp.sort_values(ascending = False),
marker=dict(color=ORANGE)
x=tmp.index,
y=tmp,
marker=dict(color=col,symbol="cross"),
mode = 'markers',
)
]
layout = go.Layout(
title="Visualisation de l'appréciation globale de chaque UV (question 10) sous forme de note moyenne",
yaxis=dict(
range=SCALE_MARK,
title="Pourcentage",
),
)
fig = go.Figure(data=graph_data, layout=layout)
iplot(fig)
```
%% Cell type:markdown id: tags:
### Comparaison avec les précédents semestres
%% Cell type:code id: tags:
``` python
q10_main_sem = EVALS_MAIN_SEM.apply((lambda r : get_mark_q(r["stats"],10)), axis=1).\
sort_values(ascending = False)
traces = []
for sem in OTHER_SEMESTERS:
tmp = []
eval_sem = EVALS[sem]
for uv in q10_main_sem.index:
if uv in eval_sem.index:
row = eval_sem[eval_sem.index==uv]
tmp.append(get_mark_q(row["stats"][uv],10))
else:
tmp.append(np.nan)
traces.append(
go.Scatter(
x=q10_main_sem.index,
y=tmp,
name=sem,
mode = 'markers',
)
)
traces.append(
go.Scatter(
x=q10_main_sem.index,
y=q10_main_sem,
name=MAIN_SEMESTER
)
)
layout = go.Layout(
title="Visualisation de l'appréciation globale de chaque UV (question 10) sous forme de note moyenne",
yaxis=dict(
range=SCALE_MARK,
title="Pourcentage",
),
)
fig = go.Figure(data=traces, layout=layout)
iplot(fig)
```
%% Cell type:markdown id: tags:
# Vue précise de chaque UV
%% Cell type:code id: tags:
``` python
# Tweak css for displaying data
simplified_data = {}
for sem in ALL_SEMESTERS_SORTED:
simplified_data[sem] = copy.deepcopy(EVALS_RAW[sem])
for uv in simplified_data[sem].keys():
stats = simplified_data[sem][uv]['stats']
if not isinstance(stats,list):
new_stats = [[stats[str(q)][ans] for ans in POSSIBLE_ANSWERS] for q in range(1,11)]
simplified_data[sem][uv]['stats'] = new_stats
json_datas = json.dumps(simplified_data, ensure_ascii=False)
a = "<script>var evals_data ="+ json_datas +\
";var POSSIBLE_ANSWERS="+json.dumps(POSSIBLE_ANSWERS)+\
"; var POSSIBLE_ANSWERS_COL="+json.dumps(POSSIBLE_ANSWERS_COL)+\
"; var POSSIBLE_ANSWERS_COEFFS="+json.dumps(POSSIBLE_ANSWERS_COEFFS)+\
"; var SCALE_MARK="+json.dumps(SCALE_MARK)+\
"</script>"
HTML(a)
```
from IPython.core.display import HTML
%% Cell type:code id: tags:
``` python
script = open('./src/display_uv.html').read()
HTML(script)
```
%% Cell type:code id: tags:
``` python
# Tweak css for displaying data
style = open('./src/style.css').read()
HTML("<style>"+style+"</style>")
```
......
<style type="text/css">
.tg {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
text-align: left;
}
.tg td {
font-size: 14px;
padding: 10px 5px;
border-style: solid;
border-width: 1px;
overflow: hidden;
word-break: normal;
border-color: black;
}
.tg th {
font-size: 14px;
font-weight: normal;
padding: 10px 5px;
border-style: solid;
border-width: 1px;
overflow: hidden;
word-break: normal;
border-color: black;
}
.tg .tg-gcw3 {
border-color: #000000
}
.styled-select select {
padding: 5px;
font-size: 16px;
line-height: 1;
border: 1px;
border-radius: 0;
height: 34px;
-webkit-appearance: none;
}
</style>
<script>
var table_header = function (content) {
return `
<table class="tg">
<tr>
<th class="tg-gcw3" style="width:10%;">Semestre</th>
<th class="tg-gcw3" style="width:50%;">Données</th>
<th class="tg-gcw3">Commentaires</th>
</tr>
${content}
</table>
`;
}
var table_row = function (semester, resp) {
return `
<tr>
<td class="tg-gcw3" rowspan="2">${semester}${resp}</td>
<td class="tg-gcw3" rowspan="2"><div id="details-${semester}"></div><div id="graph-${semester}"></div></td>
<td class="tg-gcw3"><div id="com-resp-${semester}"></div></td>
</tr>
<tr>
<td class="tg-gcw3"><div id="com-conseil-${semester}"></div></td>
</tr>
`;
}
var uv_intro = function (uv, name) {
return `
<center>
<h2> ${uv} : ${name} </h2>
</center>
`;
}
var uv_details = function (uv) {
var ratio = function (what) {
return (100 * what / (uv.nb_etu_registered - uv.nb_etu_abs)).toFixed(2);
}
return `<center><i>
${uv.nb_etu_registered} inscrits, ${uv.nb_etu_abs} absent(s), ${uv.nb_etu_passed} étudiants reçus à l'uv (Réussite : ${ratio(uv.nb_etu_passed)}%) - ${uv.nb_evals} évaluations (${ratio(uv.nb_evals)}%)
</i></center>
`;
}
var comment_html = function (date, comment, background_color) {
return `
<div style="background-color:${background_color};">${date}</div>
<div>${comment}</div>
`
}
</script>
<div class="styled-select">
Choix de l'UV :
<select id='UV-select' onchange="update_display(this.value);">
</select>
</div>
<br>
<div id="UV-intro">
</div>
<div id="evol">
<h3>
Évolutions temporelles des évaluations d'UVs
</h3>
<div id='evol-graph'>
</div>
<h3>
Et en détails
</h3>
<div id="data">
</div>
</div>
<script>
var questions = [];
for (var i = 1; i <= 10; i++) {
questions.push("Q. " + i);
}
var update_display = function (uv) {
// first update main graph
var traces_summary = [];
var questions_data = Array.from(Array(10), () => new Array(0));
var x = [];
for (semester in evals_data) {
x.push(semester);
if (uv in evals_data[semester]) {
var stats = evals_data[semester][uv]["stats"];
for (q in questions) {
var nb_evals = 0;
var val = 0;
for (ans in POSSIBLE_ANSWERS) {
nb_evals += stats[q][ans];
val += stats[q][ans] * POSSIBLE_ANSWERS_COEFFS[ans];
}
questions_data[q].push((val / nb_evals).toFixed(2));
}
} else {
for (q in questions) {
questions_data[q].push(null);
}
}
}
for (q in questions) {
traces_summary.push({
x: x,
y: questions_data[q],
name: questions[q],
type: 'scatter',
})
}
var layout = {
title: 'Évolutions temporelles des évaluations',
yaxis: { range: SCALE_MARK, title: "Note obtenue pour chaque questions" }
};
Plotly.newPlot('evol-graph', traces_summary, layout);
// Then generate table
var all_semester = []
for (semester in evals_data) {
all_semester.push(semester);
}
all_semester.reverse();
var html = '';
var tmp = '';
for (sem in all_semester) {
var semester = all_semester[sem];
var resp = '';
if (uv in evals_data[semester]) {
document.getElementById('UV-intro').innerHTML = uv_intro(uv, evals_data[semester][uv].name)
resp = '<br><br>' + evals_data[semester][uv].teacher_name;
}
tmp += table_row(semester, resp);
}
html = table_header(tmp);
document.getElementById('data').innerHTML = html;
// Finally : fill table
for (semester in evals_data) {
if (uv in evals_data[semester]) {
// details
document.getElementById('details-' + semester).innerHTML = uv_details(evals_data[semester][uv]);
// graph
var traces_table = [];
var stats = evals_data[semester][uv]["stats"];
for (ans in POSSIBLE_ANSWERS) {
var responses = [];
for (q in questions) {