forked from ScoDoc/DocScoDoc
Calcul moyenne UE BUT progressif (admet modules sans notes)
This commit is contained in:
parent
270d03057f
commit
11b3f64319
@ -120,8 +120,13 @@ class ResultatsSemestreBUT:
|
|||||||
"total": ue.ects,
|
"total": ue.ects,
|
||||||
},
|
},
|
||||||
"competence": None, # XXX TODO lien avec référentiel
|
"competence": None, # XXX TODO lien avec référentiel
|
||||||
"moyenne": fmt_note(self.etud_moy_ue[ue.id].mean()),
|
"moyenne": {
|
||||||
"bonus": None, # XXX TODO
|
"value": fmt_note(self.etud_moy_ue[ue.id][etud.id]),
|
||||||
|
"min": fmt_note(self.etud_moy_ue[ue.id].min()),
|
||||||
|
"max": fmt_note(self.etud_moy_ue[ue.id].max()),
|
||||||
|
"moy": fmt_note(self.etud_moy_ue[ue.id].mean()),
|
||||||
|
},
|
||||||
|
"bonus": 17.8, # None, # XXX TODO
|
||||||
"malus": None, # XXX TODO voir ce qui est ici
|
"malus": None, # XXX TODO voir ce qui est ici
|
||||||
"capitalise": None, # "AAAA-MM-JJ" TODO
|
"capitalise": None, # "AAAA-MM-JJ" TODO
|
||||||
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources),
|
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources),
|
||||||
|
@ -186,25 +186,25 @@ def compute_ue_moys(
|
|||||||
modimpl_coefs = modimpl_coefs_df.values
|
modimpl_coefs = modimpl_coefs_df.values
|
||||||
# Duplique les inscriptions sur les UEs:
|
# Duplique les inscriptions sur les UEs:
|
||||||
modimpl_inscr_stacked = np.stack([modimpl_inscr] * nb_ues, axis=2)
|
modimpl_inscr_stacked = np.stack([modimpl_inscr] * nb_ues, axis=2)
|
||||||
|
|
||||||
# Enlève les NaN du numérateur:
|
# Enlève les NaN du numérateur:
|
||||||
# si on veut prendre en compte les module avec notes neutralisées ?
|
# si on veut prendre en compte les modules avec notes neutralisées ?
|
||||||
# sem_cube_no_nan = np.nan_to_num(sem_cube, nan=0.0)
|
sem_cube_no_nan = np.nan_to_num(sem_cube, nan=0.0)
|
||||||
|
|
||||||
# Ne prend pas en compte les notes des étudiants non inscrits au module:
|
# Ne prend pas en compte les notes des étudiants non inscrits au module:
|
||||||
# Annule les notes:
|
# Annule les notes:
|
||||||
sem_cube_inscrits = np.where(modimpl_inscr_stacked, sem_cube, 0.0)
|
sem_cube_inscrits = np.where(modimpl_inscr_stacked, sem_cube_no_nan, 0.0)
|
||||||
# Annule les coefs des modules où l'étudiant n'est pas inscrit:
|
# Annule les coefs des modules où l'étudiant n'est pas inscrit:
|
||||||
modimpl_coefs_etuds = np.where(
|
modimpl_coefs_etuds = np.where(
|
||||||
modimpl_inscr_stacked, np.stack([modimpl_coefs.T] * nb_etuds), 0.0
|
modimpl_inscr_stacked, np.stack([modimpl_coefs.T] * nb_etuds), 0.0
|
||||||
)
|
)
|
||||||
|
# Annule les coefs des modules NaN
|
||||||
|
modimpl_coefs_etuds_no_nan = np.where(np.isnan(sem_cube), 0.0, modimpl_coefs_etuds)
|
||||||
#
|
#
|
||||||
# Version vectorisée
|
# Version vectorisée
|
||||||
#
|
#
|
||||||
etud_moy_ue = np.sum(modimpl_coefs_etuds * sem_cube_inscrits, axis=1) / np.sum(
|
etud_moy_ue = np.sum(
|
||||||
modimpl_coefs_etuds, axis=1
|
modimpl_coefs_etuds_no_nan * sem_cube_inscrits, axis=1
|
||||||
)
|
) / np.sum(modimpl_coefs_etuds_no_nan, axis=1)
|
||||||
return pd.DataFrame(
|
return pd.DataFrame(
|
||||||
etud_moy_ue, index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index
|
etud_moy_ue, index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index
|
||||||
)
|
)
|
||||||
|
@ -528,21 +528,18 @@ def module_edit(module_id=None):
|
|||||||
("formation_id", {"input_type": "hidden"}),
|
("formation_id", {"input_type": "hidden"}),
|
||||||
("ue_id", {"input_type": "hidden"}),
|
("ue_id", {"input_type": "hidden"}),
|
||||||
("module_id", {"input_type": "hidden"}),
|
("module_id", {"input_type": "hidden"}),
|
||||||
|
(
|
||||||
|
"ue_matiere_id",
|
||||||
|
{
|
||||||
|
"input_type": "menu" if not is_apc else "hidden",
|
||||||
|
"title": "Matière",
|
||||||
|
"explanation": "un module appartient à une seule matière.",
|
||||||
|
"labels": mat_names,
|
||||||
|
"allowed_values": ue_mat_ids,
|
||||||
|
"enabled": unlocked and not is_apc, # pas d'édition des matieres en BUT
|
||||||
|
},
|
||||||
|
),
|
||||||
]
|
]
|
||||||
if not is_apc:
|
|
||||||
descr += [
|
|
||||||
(
|
|
||||||
"ue_matiere_id",
|
|
||||||
{
|
|
||||||
"input_type": "menu",
|
|
||||||
"title": "Matière",
|
|
||||||
"explanation": "un module appartient à une seule matière.",
|
|
||||||
"labels": mat_names,
|
|
||||||
"allowed_values": ue_mat_ids,
|
|
||||||
"enabled": unlocked,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
if is_apc:
|
if is_apc:
|
||||||
# le semestre du module est toujours celui de son UE
|
# le semestre du module est toujours celui de son UE
|
||||||
descr += [
|
descr += [
|
||||||
|
@ -816,7 +816,7 @@ def _add_apc_columns(
|
|||||||
etuds_moy_module = moy_mod.compute_module_moy(
|
etuds_moy_module = moy_mod.compute_module_moy(
|
||||||
evals_notes, evals_poids, evaluations, evaluations_completes
|
evals_notes, evals_poids, evaluations, evaluations_completes
|
||||||
)
|
)
|
||||||
|
ue_coefs = models.ModuleImpl.query.get(moduleimpl_id).module.ue_coefs
|
||||||
for row in rows:
|
for row in rows:
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
moy_ue = etuds_moy_module[ue.id].get(row["etudid"], "?")
|
moy_ue = etuds_moy_module[ue.id].get(row["etudid"], "?")
|
||||||
@ -826,4 +826,7 @@ def _add_apc_columns(
|
|||||||
col_id = f"moy_ue_{ue.id}"
|
col_id = f"moy_ue_{ue.id}"
|
||||||
titles[col_id] = ue.acronyme
|
titles[col_id] = ue.acronyme
|
||||||
columns_ids.append(col_id)
|
columns_ids.append(col_id)
|
||||||
row_coefs[f"moy_ue_{ue.id}"] = "m"
|
row_coefs[f"moy_ue_{ue.id}"] = [uc for uc in ue_coefs if uc.ue_id == ue.id][
|
||||||
|
0
|
||||||
|
].coef
|
||||||
|
row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = ' class="coef_mod_ue" '
|
||||||
|
@ -1066,6 +1066,12 @@ table.notes_evaluation td.moy_ue {
|
|||||||
color:rgb(1, 116, 96);
|
color:rgb(1, 116, 96);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.coef_mod_ue {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
color: rgb(1, 116, 96);
|
||||||
|
}
|
||||||
|
|
||||||
h2.formsemestre, #gtrcontent h2 {
|
h2.formsemestre, #gtrcontent h2 {
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
font-size: 130%;
|
font-size: 130%;
|
||||||
|
@ -1,59 +1,59 @@
|
|||||||
/* Il manque :
|
/* Il manque :
|
||||||
- rangs
|
- rangs
|
||||||
- Synthèse : moyenne UE
|
- Synthèse : moyenne UE
|
||||||
- Synthèse : min, max, moy classe
|
- Synthèse : min, max, moy classe
|
||||||
- Synthèse : absences
|
- Synthèse : absences
|
||||||
- Eval : absences
|
- Eval : absences
|
||||||
|
|
||||||
Moi :
|
Moi :
|
||||||
"show_codemodules" :true,
|
"show_codemodules" :true,
|
||||||
"show_minmax": true,
|
"show_minmax": true,
|
||||||
"show_minmax_eval": true,
|
"show_minmax_eval": true,
|
||||||
"show_minmax_mod": false,
|
"show_minmax_mod": false,
|
||||||
"show_mod_rangs": false,
|
"show_mod_rangs": false,
|
||||||
"show_moypromo": true,
|
"show_moypromo": true,
|
||||||
"show_rangs": true,
|
"show_rangs": true,
|
||||||
"show_ue_cap_current": true,
|
"show_ue_cap_current": true,
|
||||||
"show_ue_cap_details": true,
|
"show_ue_cap_details": true,
|
||||||
"show_ue_rangs": true,
|
"show_ue_rangs": true,
|
||||||
"show_uevalid": true,
|
"show_uevalid": true,
|
||||||
*/
|
*/
|
||||||
/*****************************/
|
/*****************************/
|
||||||
/* Gestionnaire d'événements */
|
/* Gestionnaire d'événements */
|
||||||
/*****************************/
|
/*****************************/
|
||||||
document.querySelectorAll(".CTA_Liste").forEach(e => {
|
document.querySelectorAll(".CTA_Liste").forEach(e => {
|
||||||
e.addEventListener("click", listeOnOff)
|
e.addEventListener("click", listeOnOff)
|
||||||
})
|
})
|
||||||
|
|
||||||
function listeOnOff() {
|
function listeOnOff() {
|
||||||
this.parentElement.parentElement.classList.toggle("listeOff")
|
this.parentElement.parentElement.classList.toggle("listeOff")
|
||||||
}
|
}
|
||||||
/*****************************/
|
/*****************************/
|
||||||
/* Recupération et affichage */
|
/* Recupération et affichage */
|
||||||
/*****************************/
|
/*****************************/
|
||||||
|
|
||||||
fetch(dataSrc)
|
fetch(dataSrc)
|
||||||
.then(r => { return r.json() })
|
.then(r => { return r.json() })
|
||||||
.then(json => showData(json))
|
.then(json => showData(json))
|
||||||
|
|
||||||
function showData(data) {
|
function showData(data) {
|
||||||
showInformations(data);
|
showInformations(data);
|
||||||
showSemestre(data);
|
showSemestre(data);
|
||||||
showSynthese(data);
|
showSynthese(data);
|
||||||
showEvaluations(data);
|
showEvaluations(data);
|
||||||
|
|
||||||
setOptions(data.options);
|
setOptions(data.options);
|
||||||
|
|
||||||
document.body.classList.add("ready");
|
document.body.classList.add("ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************/
|
/********************************/
|
||||||
/* Informations sur l'étudiant */
|
/* Informations sur l'étudiant */
|
||||||
/********************************/
|
/********************************/
|
||||||
function showInformations(data) {
|
function showInformations(data) {
|
||||||
document.querySelector(".studentPic").src = data.etudiant.photo_url || "default_Student.svg";
|
document.querySelector(".studentPic").src = data.etudiant.photo_url || "default_Student.svg";
|
||||||
|
|
||||||
let output = `
|
let output = `
|
||||||
<div class=info_etudiant>
|
<div class=info_etudiant>
|
||||||
<div class=civilite>
|
<div class=civilite>
|
||||||
${civilite(data.etudiant.civilite)}
|
${civilite(data.etudiant.civilite)}
|
||||||
@ -70,16 +70,16 @@ function showInformations(data) {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
document.querySelector(".infoEtudiant").innerHTML = output;
|
document.querySelector(".infoEtudiant").innerHTML = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************/
|
/*******************************/
|
||||||
/* Information sur le semestre */
|
/* Information sur le semestre */
|
||||||
/*******************************/
|
/*******************************/
|
||||||
function showSemestre(data) {
|
function showSemestre(data) {
|
||||||
document.querySelector("h2").innerHTML += data.semestre.numero;
|
document.querySelector("h2").innerHTML += data.semestre.numero;
|
||||||
document.querySelector(".dateInscription").innerHTML += ISOToDate(data.semestre.inscription);
|
document.querySelector(".dateInscription").innerHTML += ISOToDate(data.semestre.inscription);
|
||||||
let output = `
|
let output = `
|
||||||
<div>
|
<div>
|
||||||
<div class=enteteSemestre>Moyenne</div><div class=enteteSemestre>${data.semestre.notes.value}</div>
|
<div class=enteteSemestre>Moyenne</div><div class=enteteSemestre>${data.semestre.notes.value}</div>
|
||||||
<div class=rang>Rang :</div><div class=rang>${data.semestre.rang.value} / ${data.semestre.rang.total}</div>
|
<div class=rang>Rang :</div><div class=rang>${data.semestre.rang.value} / ${data.semestre.rang.total}</div>
|
||||||
@ -88,7 +88,7 @@ function showSemestre(data) {
|
|||||||
<div>Min. promo. :</div><div>${data.semestre.notes.min}</div>
|
<div>Min. promo. :</div><div>${data.semestre.notes.min}</div>
|
||||||
</div>
|
</div>
|
||||||
${data.semestre.groupes.map(groupe => {
|
${data.semestre.groupes.map(groupe => {
|
||||||
return `
|
return `
|
||||||
<div>
|
<div>
|
||||||
<div class=enteteSemestre>Groupe</div><div class=enteteSemestre>${groupe.nom}</div>
|
<div class=enteteSemestre>Groupe</div><div class=enteteSemestre>${groupe.nom}</div>
|
||||||
<div class=rang>Rang :</div><div class=rang>${groupe.rang.value} / ${groupe.rang.total}</div>
|
<div class=rang>Rang :</div><div class=rang>${groupe.rang.value} / ${groupe.rang.total}</div>
|
||||||
@ -97,25 +97,25 @@ function showSemestre(data) {
|
|||||||
<div>Min. groupe :</div><div>${groupe.notes.min}</div>
|
<div>Min. groupe :</div><div>${groupe.notes.min}</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}).join("")
|
}).join("")
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
document.querySelector(".infoSemestre").innerHTML = output;
|
document.querySelector(".infoSemestre").innerHTML = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************/
|
/*******************************/
|
||||||
/* Synthèse */
|
/* Synthèse */
|
||||||
/*******************************/
|
/*******************************/
|
||||||
function showSynthese(data) {
|
function showSynthese(data) {
|
||||||
let output = ``;
|
let output = ``;
|
||||||
Object.entries(data.ues).forEach(([ue, dataUE]) => {
|
Object.entries(data.ues).forEach(([ue, dataUE]) => {
|
||||||
output += `
|
output += `
|
||||||
<div class=ue>
|
<div class=ue>
|
||||||
<h3>
|
<h3>
|
||||||
${(dataUE.competence) ? dataUE.competence + " - " : ""}${ue}
|
${(dataUE.competence) ? dataUE.competence + " - " : ""}${ue}
|
||||||
</h3>
|
</h3>
|
||||||
<div>
|
<div>
|
||||||
<div class=moyenne>Moyenne : ${dataUE.moyenne?.value || "-"}</div>
|
<div class=moyenne>Moyenn : ${dataUE.moyenne?.value || "-"}</div>
|
||||||
<div class=info>
|
<div class=info>
|
||||||
Bonus : ${dataUE.bonus || 0} -
|
Bonus : ${dataUE.bonus || 0} -
|
||||||
Malus : ${dataUE.malus || 0}
|
Malus : ${dataUE.malus || 0}
|
||||||
@ -132,15 +132,15 @@ function showSynthese(data) {
|
|||||||
${synthese(dataUE.ressources)}
|
${synthese(dataUE.ressources)}
|
||||||
${synthese(dataUE.saes)}
|
${synthese(dataUE.saes)}
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
document.querySelector(".synthese").innerHTML = output;
|
document.querySelector(".synthese").innerHTML = output;
|
||||||
|
|
||||||
function synthese(modules) {
|
function synthese(modules) {
|
||||||
let output = "";
|
let output = "";
|
||||||
Object.entries(modules).forEach(([module, dataModule]) => {
|
Object.entries(modules).forEach(([module, dataModule]) => {
|
||||||
let titre = data.ressources[module]?.titre || data.saes[module]?.titre;
|
let titre = data.ressources[module]?.titre || data.saes[module]?.titre;
|
||||||
let url = data.ressources[module]?.url || data.saes[module]?.url;
|
let url = data.ressources[module]?.url || data.saes[module]?.url;
|
||||||
output += `
|
output += `
|
||||||
<div class=syntheseModule>
|
<div class=syntheseModule>
|
||||||
<div><a href="${url}">${module} - ${titre}</a></div>
|
<div><a href="${url}">${module} - ${titre}</a></div>
|
||||||
<div>
|
<div>
|
||||||
@ -149,21 +149,21 @@ function showSynthese(data) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*******************************/
|
/*******************************/
|
||||||
/* Evaluations */
|
/* Evaluations */
|
||||||
/*******************************/
|
/*******************************/
|
||||||
function showEvaluations(data) {
|
function showEvaluations(data) {
|
||||||
document.querySelector(".evaluations").innerHTML = module(data.ressources);
|
document.querySelector(".evaluations").innerHTML = module(data.ressources);
|
||||||
document.querySelector(".sae").innerHTML += module(data.saes);
|
document.querySelector(".sae").innerHTML += module(data.saes);
|
||||||
|
|
||||||
function module(module) {
|
function module(module) {
|
||||||
let output = "";
|
let output = "";
|
||||||
Object.entries(module).forEach(([numero, content]) => {
|
Object.entries(module).forEach(([numero, content]) => {
|
||||||
output += `
|
output += `
|
||||||
<div>
|
<div>
|
||||||
<div class=module>
|
<div class=module>
|
||||||
<h3><a href="${content.url}">${numero} - ${content.titre}</a></h3>
|
<h3><a href="${content.url}">${numero} - ${content.titre}</a></h3>
|
||||||
@ -183,14 +183,14 @@ function showEvaluations(data) {
|
|||||||
${evaluation(content.evaluations)}
|
${evaluation(content.evaluations)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluation(evaluations) {
|
function evaluation(evaluations) {
|
||||||
let output = "";
|
let output = "";
|
||||||
evaluations.forEach(eval => {
|
evaluations.forEach(eval => {
|
||||||
output += `
|
output += `
|
||||||
<div class=eval>
|
<div class=eval>
|
||||||
<div>${eval.description}</div>
|
<div>${eval.description}</div>
|
||||||
<div>
|
<div>
|
||||||
@ -203,28 +203,28 @@ function showEvaluations(data) {
|
|||||||
<div>Moy. promo.</div><div>${eval.note.moy}</div>
|
<div>Moy. promo.</div><div>${eval.note.moy}</div>
|
||||||
<div>Min. promo.</div><div>${eval.note.min}</div>
|
<div>Min. promo.</div><div>${eval.note.min}</div>
|
||||||
${Object.entries(eval.poids).map(([UE, poids]) => {
|
${Object.entries(eval.poids).map(([UE, poids]) => {
|
||||||
return `
|
return `
|
||||||
<div>Poids ${UE}</div>
|
<div>Poids ${UE}</div>
|
||||||
<div>${poids}</div>
|
<div>${poids}</div>
|
||||||
`;
|
`;
|
||||||
}).join("")}
|
}).join("")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************/
|
/********************/
|
||||||
/* Options */
|
/* Options */
|
||||||
/********************/
|
/********************/
|
||||||
function setOptions(options) {
|
function setOptions(options) {
|
||||||
Object.entries(options).forEach(([option, value]) => {
|
Object.entries(options).forEach(([option, value]) => {
|
||||||
if (value === false) {
|
if (value === false) {
|
||||||
document.body.classList.add(option.replace("show", "hide"))
|
document.body.classList.add(option.replace("show", "hide"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -232,13 +232,13 @@ function setOptions(options) {
|
|||||||
/* Fonctions d'aide */
|
/* Fonctions d'aide */
|
||||||
/********************/
|
/********************/
|
||||||
function civilite(txt) {
|
function civilite(txt) {
|
||||||
switch (txt) {
|
switch (txt) {
|
||||||
case "M": return "M.";
|
case "M": return "M.";
|
||||||
case "F": return "Mme";
|
case "F": return "Mme";
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ISOToDate(ISO) {
|
function ISOToDate(ISO) {
|
||||||
return ISO.split("-").reverse().join("/");
|
return ISO.split("-").reverse().join("/");
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,7 @@ def test_ue_moy(test_client):
|
|||||||
# EXC à un module
|
# EXC à un module
|
||||||
n1, n2 = 5.0, NOTES_NEUTRALISE
|
n1, n2 = 5.0, NOTES_NEUTRALISE
|
||||||
etud_moy_ue = change_notes(n1, n2)
|
etud_moy_ue = change_notes(n1, n2)
|
||||||
# Pour le moment, une note NEUTRALISE va entrainer le non-calcul
|
assert (etud_moy_ue.values == n1).all()
|
||||||
# des moyennes.
|
|
||||||
assert np.isnan(etud_moy_ue.values).all()
|
|
||||||
# Désinscrit l'étudiant du module 2:
|
# Désinscrit l'étudiant du module 2:
|
||||||
inscr = ModuleImplInscription.query.filter_by(
|
inscr = ModuleImplInscription.query.filter_by(
|
||||||
moduleimpl_id=evaluation2.moduleimpl.id, etudid=etudid
|
moduleimpl_id=evaluation2.moduleimpl.id, etudid=etudid
|
||||||
|
Loading…
Reference in New Issue
Block a user