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
......
......@@ -54,6 +54,7 @@
"import yaml # for the config file\n",
"import warnings # to issue warnings when needed\n",
"import os.path # for easy work with file paths\n",
"import copy\n",
"\n",
"# Simple functions\n",
"from src.generate_data import generate_data_file\n",
......@@ -100,6 +101,7 @@
"\n",
"# import data\n",
"EVALS = {}\n",
"EVALS_RAW = {}\n",
"EVALS_DATE_CREATED = {}\n",
"\n",
"for semester in ALL_SEMESTERS.keys():\n",
......@@ -112,10 +114,14 @@
" EVALS_DATE_CREATED[semester] = datetime.strptime(date, '%d/%m/%Y')\n",
" \n",
" data = OrderedDict(data_json[\"data\"])\n",
" EVALS_RAW[semester] = copy.deepcopy(data)\n",
"\n",
" for uv, description in data.items():\n",
" if description[\"date_review\"] is not None and type(description[\"date_review\"]) != 'datetime.datetime':\n",
" description[\"date_review\"] = datetime.strptime(description[\"date_review\"], '%d/%m/%Y') \n",
" EVALS[semester] = pd.DataFrame.from_dict(data, orient = \"index\") \n",
" if description[\"date_review_teacher\"] is not None and type(description[\"date_review_teacher\"]) != 'datetime.datetime':\n",
" description[\"date_review_teacher\"] = datetime.strptime(description[\"date_review_teacher\"], '%d/%m/%Y')\n",
" if description[\"date_review_conseil\"] is not None and type(description[\"date_review_conseil\"]) != 'datetime.datetime':\n",
" description[\"date_review_conseil\"] = datetime.strptime(description[\"date_review_conseil\"], '%d/%m/%Y')\n",
" EVALS[semester] = pd.DataFrame.from_dict(data, orient = \"index\")\n",
" \n",
"EVALS_MAIN_SEM = EVALS[MAIN_SEMESTER]"
]
......@@ -257,9 +263,9 @@
" taux_eval = sem_data.loc[:, (\"nb_evals\",\"nb_etu_registered\")].min(axis=1)/sem_data[\"nb_etu_registered\"]\n",
" taux_eval = taux_eval.fillna(1) # Sometimes there 0 students in a course but there are evaluations\n",
" taux_eval = sum(taux_eval)/nb_uvs\n",
" uvs_with_evals = sem_data.loc[pd.notna(sem_data[\"date_review\"])]\n",
" uvs_with_evals = sem_data.loc[pd.notna(sem_data[\"date_review_teacher\"])]\n",
" nb_uvs_with_evals = len(uvs_with_evals.index)\n",
" uvs_with_com = sem_data.loc[sem_data[\"comment\"]>0]\n",
" uvs_with_com = sem_data.loc[sem_data[\"teacher_comment\"]>\"\"]\n",
" nb_uvs_with_com = len(uvs_with_com)\n",
" SEMESTERS_INFO[sem] = {\n",
" 'nb_uvs': nb_uvs,\n",
......@@ -351,12 +357,12 @@
"metadata": {},
"outputs": [],
"source": [
"uvs_with_evals = EVALS_MAIN_SEM.loc[pd.notna(EVALS_MAIN_SEM[\"date_review\"])]\n",
"uvs_with_evals = EVALS_MAIN_SEM.loc[pd.notna(EVALS_MAIN_SEM[\"date_review_teacher\"])]\n",
"graph_data = [\n",
" go.Scatter(\n",
" x=uvs_with_evals['date_review'].sort_values(),\n",
" x=uvs_with_evals['date_review_teacher'].sort_values(),\n",
" y=[100*float(i+1)/nb_uvs for i,e in enumerate(uvs_with_evals.index)],\n",
" text=uvs_with_evals.sort_values(by=['date_review']).index,\n",
" text=uvs_with_evals.sort_values(by=['date_review_teacher']).index,\n",
" marker=dict(color=ORANGE)\n",
" )\n",
"]\n",
......@@ -406,13 +412,13 @@
" sem_end_date = ALL_SEMESTERS[sem].toordinal()\n",
" nb_uvs = SEMESTERS_INFO[sem][\"nb_uvs\"]\n",
" sem_data = EVALS[sem]\n",
" uvs_with_evals = sem_data.loc[pd.notna(sem_data[\"date_review\"])]\n",
" uvs_with_evals = sem_data.loc[pd.notna(sem_data[\"date_review_teacher\"])]\n",
" \n",
" traces.append(\n",
" go.Scatter(\n",
" x=uvs_with_evals['date_review'].sort_values().apply(datetime.toordinal)-sem_end_date ,\n",
" x=uvs_with_evals['date_review_teacher'].sort_values().apply(datetime.toordinal)-sem_end_date ,\n",
" y=[100*float(i+1)/nb_uvs for i,e in enumerate(uvs_with_evals.index)],\n",
" text=uvs_with_evals.sort_values(by=['date_review']).index,\n",
" text=uvs_with_evals.sort_values(by=['date_review_teacher']).index,\n",
" name=sem\n",
" ) \n",
" )\n",
......@@ -607,13 +613,18 @@
"metadata": {},
"outputs": [],
"source": [
"tmp = EVALS_MAIN_SEM.apply((lambda r : get_mark_q(r[\"stats\"],10)), axis=1)\n",
"tmp = EVALS_MAIN_SEM.apply((lambda r : get_mark_q(r[\"stats\"],10)), axis=1).sort_values(ascending = False)\n",
"col = EVALS_MAIN_SEM.loc[tmp.index,\"teacher_comment\"]\n",
"col[col>\"\"] = POSSIBLE_ANSWERS_COL[3]\n",
"col[col==\"\"] = POSSIBLE_ANSWERS_COL[1]\n",
"col[col.isnull()] = POSSIBLE_ANSWERS_COL[0]\n",
"\n",
"graph_data = [\n",
" go.Scatter(\n",
" x=tmp.sort_values(ascending = False).index,\n",
" y=tmp.sort_values(ascending = False),\n",
" marker=dict(color=ORANGE)\n",
" x=tmp.index,\n",
" y=tmp,\n",
" marker=dict(color=col,symbol=\"cross\"),\n",
" mode = 'markers',\n",
" )\n",
"]\n",
"\n",
......@@ -685,6 +696,49 @@
"iplot(fig)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Vue précise de chaque UV"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simplified_data = {}\n",
"for sem in ALL_SEMESTERS_SORTED:\n",
" simplified_data[sem] = copy.deepcopy(EVALS_RAW[sem])\n",
" for uv in simplified_data[sem].keys():\n",
" stats = simplified_data[sem][uv]['stats']\n",
" if not isinstance(stats,list):\n",
" new_stats = [[stats[str(q)][ans] for ans in POSSIBLE_ANSWERS] for q in range(1,11)]\n",
" simplified_data[sem][uv]['stats'] = new_stats\n",
"\n",
"json_datas = json.dumps(simplified_data, ensure_ascii=False)\n",
"\n",
"a = \"<script>var evals_data =\"+ json_datas +\\\n",
" \";var POSSIBLE_ANSWERS=\"+json.dumps(POSSIBLE_ANSWERS)+\\\n",
" \"; var POSSIBLE_ANSWERS_COL=\"+json.dumps(POSSIBLE_ANSWERS_COL)+\\\n",
" \"; var POSSIBLE_ANSWERS_COEFFS=\"+json.dumps(POSSIBLE_ANSWERS_COEFFS)+\\\n",
" \"; var SCALE_MARK=\"+json.dumps(SCALE_MARK)+\\\n",
" \"</script>\"\n",
"HTML(a)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"script = open('./src/display_uv.html').read()\n",
"HTML(script)"
]
},
{
"cell_type": "code",
"execution_count": null,
......@@ -692,8 +746,6 @@
"outputs": [],
"source": [
"# Tweak css for displaying data \n",
"\n",
"from IPython.core.display import HTML\n",
"style = open('./src/style.css').read()\n",
"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) {
responses.push(stats[q][ans]);
}
traces_table.push({
x: questions,
y: responses,
name: POSSIBLE_ANSWERS[ans],
type: 'bar',
marker: {
color: POSSIBLE_ANSWERS_COL[ans]
}
})
}
var layout_table = {
title: "Évaluations de l'UV " + uv + " en " + semester,
barmode: 'stack', showlegend: false, yaxis: {
title: "Nombre d'évaluations"
}
};
Plotly.newPlot('graph-' + semester, traces_table, layout_table);
if (uv in evals_data[semester]) {
var teacher_date = evals_data[semester][uv]['date_review_teacher'];
var conseil_date = evals_data[semester][uv]['date_review_conseil'];
var teacher_comment = evals_data[semester][uv]['teacher_comment'];
var conseil_comment = evals_data[semester][uv]['conseil_comment'];
var conseil_color = '#ffa40580', teacher_color = '#ffa40580';
if (teacher_date === null) {
teacher_color = '#ff050580';
teacher_date = "<i>Les évaluations ne semblent par avoir été vues par le ou la responsable de l'enseignement ce semestre.</i>";
teacher_comment = '';
} else {
teacher_date = "Évaluations prises en compte par le responsable le : " + teacher_date;
}
if (conseil_date === null) {
conseil_color = '#ff050580';
conseil_date = "<i>Les évaluations ne semblent par avoir été vues par le conseil de perfectionnement ce semestre.</i>";
conseil_comment = '';
} else {
conseil_date = "Évaluations prises en compte par le conseil de perfectionnement le : " + teacher_date;
}
if (teacher_comment > '') {
teacher_color = '#05ff2b80';
}
if (conseil_comment > '') {
conseil_color = '#05ff2b80';
}
if (teacher_comment === '' || teacher_comment === null) {
teacher_comment = "<i>Aucun rapport saisi par le ou la responsable de l'enseignement ce semestre.</i>";
}
if (conseil_comment === '' || conseil_comment === null) {
conseil_comment = "<i>Aucun rapport des conseils de perfectionnement enregistré.</i>";
}
teacher_comment = teacher_comment.replace(/¿/g, "'");
conseil_comment = conseil_comment.replace(/¿/g, "'");
document.getElementById('com-resp-' + semester).innerHTML = comment_html(teacher_date, teacher_comment, teacher_color);
document.getElementById('com-conseil-' + semester).innerHTML = comment_html(conseil_date, conseil_comment, conseil_color);
}
}
}
}
var all_uvs = new Set();
for (semester in evals_data) {
for (uv in evals_data[semester]) {
all_uvs.add(uv);
}
}
all_uvs = Array.from(all_uvs).sort();
var select_uv = document.getElementById('UV-select')
for (ind in all_uvs) {
var uv = all_uvs[ind];
var opt = document.createElement('option');
opt.value = uv;
opt.innerHTML = uv;
select_uv.appendChild(opt);
}
var init_select = function () {
if (typeof Plotly === undefined) {
return setTimeout(function () { init_select(); }, 1000);
} else {
console.log("defined");
return setTimeout(function () {
document.getElementById('UV-select').value = all_uvs[0];
update_display(all_uvs[0]);
}, 1000);
}
}
init_select();
</script>
\ No newline at end of file
......@@ -136,7 +136,3 @@ button {
background-image: none !important;
}
select,
textarea {
border-radius: 0px !important;
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment