forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -100,7 +100,7 @@ def compute_sem_moys_apc_using_ects(
|
||||
|
||||
|
||||
def comp_ranks_series(notes: pd.Series) -> tuple[pd.Series, pd.Series]:
|
||||
"""Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur
|
||||
"""Calcul rangs à partir d'une série ("vecteur") de notes (index etudid, valeur
|
||||
numérique) en tenant compte des ex-aequos.
|
||||
|
||||
Result: couple (tuple)
|
||||
|
@ -273,7 +273,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
||||
return s.index[s.notna()]
|
||||
|
||||
def etud_parcours_ues_ids(self, etudid: int) -> set[int]:
|
||||
"""Ensemble les id des UEs que l'étudiant doit valider dans ce semestre compte tenu
|
||||
"""Ensemble des id des UEs que l'étudiant doit valider dans ce semestre compte tenu
|
||||
du parcours dans lequel il est inscrit.
|
||||
Se base sur le parcours dans ce semestre, et le référentiel de compétences.
|
||||
Note: il n'est pas nécessairement inscrit à toutes ces UEs.
|
||||
|
@ -85,16 +85,12 @@ class EtudiantsJuryPE:
|
||||
self.abandons_ids = {}
|
||||
"""Les etudids des étudiants redoublants/réorientés"""
|
||||
|
||||
def find_etudiants(self, formation_id: int):
|
||||
def find_etudiants(self):
|
||||
"""Liste des étudiants à prendre en compte dans le jury PE, en les recherchant
|
||||
de manière automatique par rapport à leur année de diplomation ``annee_diplome``
|
||||
dans la formation ``formation_id``. XXX TODO voir si on garde formation_id qui n'est pas utilisé ici
|
||||
de manière automatique par rapport à leur année de diplomation ``annee_diplome``.
|
||||
|
||||
Les données obtenues sont stockées dans les attributs de EtudiantsJuryPE.
|
||||
|
||||
|
||||
formation_id: L'identifiant de la formation (inutilisé)
|
||||
|
||||
*Remarque* : ex: JuryPE.get_etudiants_in_jury()
|
||||
"""
|
||||
cosemestres = pe_comp.get_cosemestres_diplomants(self.annee_diplome, None)
|
||||
|
@ -59,8 +59,9 @@ class AggregatInterclasseTag(TableTag):
|
||||
for etudid in self.diplomes_ids:
|
||||
self.suivi[etudid] = trajectoires_jury_pe.suivi[etudid][nom_aggregat]
|
||||
|
||||
"""Les tags"""
|
||||
|
||||
self.tags_sorted = self.do_taglist()
|
||||
"""Liste des tags (triés par ordre alphabétique)"""
|
||||
|
||||
# Construit la matrice de notes
|
||||
self.notes = self.compute_notes_matrice()
|
||||
@ -69,15 +70,7 @@ class AggregatInterclasseTag(TableTag):
|
||||
self.moyennes_tags = {}
|
||||
for tag in self.tags_sorted:
|
||||
moy_gen_tag = self.notes[tag]
|
||||
class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int
|
||||
self.moyennes_tags[tag] = {
|
||||
"notes": moy_gen_tag,
|
||||
"classements": class_gen_tag,
|
||||
"min": moy_gen_tag.min(),
|
||||
"max": moy_gen_tag.max(),
|
||||
"moy": moy_gen_tag.mean(),
|
||||
"nb_inscrits": len(moy_gen_tag),
|
||||
}
|
||||
self.moyennes_tags[tag] = self.comp_moy_et_stat(moy_gen_tag)
|
||||
|
||||
# Est significatif ? (aka a-t-il des tags et des notes)
|
||||
self.significatif = len(self.tags_sorted) > 0
|
||||
@ -125,4 +118,7 @@ class AggregatInterclasseTag(TableTag):
|
||||
etudids_communs, tags_communs
|
||||
]
|
||||
|
||||
# Force les nan
|
||||
df.fillna(np.nan)
|
||||
|
||||
return df
|
||||
|
@ -83,7 +83,7 @@ class JuryPE(object):
|
||||
# leur affichage dans les avis latex
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
def __init__(self, diplome, formation_id):
|
||||
def __init__(self, diplome):
|
||||
"""
|
||||
Création d'une table PE sur la base d'un semestre selectionné. De ce semestre est déduit :
|
||||
1. l'année d'obtention du DUT,
|
||||
@ -98,19 +98,16 @@ class JuryPE(object):
|
||||
self.diplome = diplome
|
||||
"L'année du diplome"
|
||||
|
||||
self.formation_id = formation_id
|
||||
"La formation associée au diplome"
|
||||
|
||||
self.nom_export_zip = f"Jury_PE_{self.diplome}"
|
||||
"Nom du zip où ranger les fichiers générés"
|
||||
|
||||
# Chargement des étudiants à prendre en compte dans le jury
|
||||
pe_affichage.pe_print(
|
||||
f"""*** Recherche et chargement des étudiants diplômés en {
|
||||
self.diplome} pour la formation {self.formation_id}"""
|
||||
self.diplome}"""
|
||||
)
|
||||
self.etudiants = EtudiantsJuryPE(self.diplome) # Les infos sur les étudiants
|
||||
self.etudiants.find_etudiants(self.formation_id)
|
||||
self.etudiants.find_etudiants()
|
||||
self.diplomes_ids = self.etudiants.diplomes_ids
|
||||
|
||||
self.zipdata = io.BytesIO()
|
||||
@ -610,7 +607,7 @@ def get_dict_synthese_aggregat(
|
||||
note = TableTag.get_note_for_df(bilan, etudid)
|
||||
|
||||
# Statistiques sur le groupe
|
||||
if note != np.nan:
|
||||
if not pd.isna(note) and note != np.nan:
|
||||
# Les moyennes de cette trajectoire
|
||||
donnees |= {
|
||||
(descr, "", "note"): note,
|
||||
@ -640,7 +637,7 @@ def get_dict_synthese_aggregat(
|
||||
if tag in interclassement_taggue.moyennes_tags:
|
||||
bilan = interclassement_taggue.moyennes_tags[tag]
|
||||
|
||||
if note != np.nan:
|
||||
if not pd.isna(note) and note != np.nan:
|
||||
nom_stat_promo = f"{NOM_STAT_PROMO} {diplome}"
|
||||
|
||||
donnees |= {
|
||||
|
@ -35,9 +35,12 @@ Created on Fri Sep 9 09:15:05 2016
|
||||
|
||||
@author: barasc
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
import app.pe.pe_etudiant
|
||||
from app import db, log
|
||||
from app.comp import res_sem, moy_ue, moy_sem
|
||||
from app.comp.moy_sem import comp_ranks_series
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.comp.res_sem import load_formsemestre_results
|
||||
from app.models import FormSemestre
|
||||
@ -49,8 +52,8 @@ import app.pe.pe_affichage as pe_affichage
|
||||
from app.pe.pe_tabletags import TableTag, TAGS_RESERVES
|
||||
import pandas as pd
|
||||
|
||||
class SemestreTag(TableTag):
|
||||
|
||||
class SemestreTag(TableTag):
|
||||
def __init__(self, formsemestre_id: int):
|
||||
"""
|
||||
Un SemestreTag représente les résultats des étudiants à un semestre, en donnant
|
||||
@ -89,47 +92,50 @@ class SemestreTag(TableTag):
|
||||
self.ues_inscr_parcours_df = self.nt.load_ues_inscr_parcours()
|
||||
self.dispense_ues = self.nt.dispense_ues
|
||||
|
||||
# Les tags (en supprimant les tags réservés)
|
||||
self.tags = get_synthese_tags_semestre(self.nt.formsemestre)
|
||||
for tag in TAGS_RESERVES:
|
||||
if tag in self.tags:
|
||||
del self.tags[tag]
|
||||
# Les tags :
|
||||
## Saisis par l'utilisateur
|
||||
self.tags_personnalises = get_synthese_tags_personnalises_semestre(
|
||||
self.nt.formsemestre
|
||||
)
|
||||
## Déduit des compétences
|
||||
self.tags_competences = get_noms_competences_from_ues(self.nt.formsemestre)
|
||||
|
||||
# Supprime les doublons dans les tags
|
||||
tags_reserves = TAGS_RESERVES + list(self.tags_competences.values())
|
||||
for tag in self.tags_personnalises:
|
||||
if tag in tags_reserves:
|
||||
del self.tags_personnalises[tag]
|
||||
pe_affichage.pe_print(f"Supprime le tag {tag}")
|
||||
|
||||
# Calcul des moyennes & les classements de chaque étudiant à chaque tag
|
||||
self.moyennes_tags = {}
|
||||
|
||||
for tag in self.tags:
|
||||
for tag in self.tags_personnalises:
|
||||
# pe_affichage.pe_print(f" -> Traitement du tag {tag}")
|
||||
moy_gen_tag = self.compute_moyenne_tag(tag)
|
||||
class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int
|
||||
self.moyennes_tags[tag] = {
|
||||
"notes": moy_gen_tag,
|
||||
"classements": class_gen_tag,
|
||||
"min": moy_gen_tag.min(),
|
||||
"max": moy_gen_tag.max(),
|
||||
"moy": moy_gen_tag.mean(),
|
||||
"nb_inscrits": len(moy_gen_tag),
|
||||
}
|
||||
self.moyennes_tags[tag] = self.comp_moy_et_stat(moy_gen_tag)
|
||||
|
||||
# Ajoute les moyennes générales de BUT pour le semestre considéré
|
||||
moy_gen_but = self.nt.etud_moy_gen
|
||||
class_gen_but = self.nt.etud_moy_gen_ranks_int
|
||||
self.moyennes_tags["but"] = {
|
||||
"notes": moy_gen_but,
|
||||
"classements": class_gen_but,
|
||||
"min": moy_gen_but.min(),
|
||||
"max": moy_gen_but.max(),
|
||||
"moy": moy_gen_but.mean(),
|
||||
"nb_inscrits": len(moy_gen_but),
|
||||
}
|
||||
moy_gen_but = pd.to_numeric(moy_gen_but, errors="coerce")
|
||||
self.moyennes_tags["but"] = self.comp_moy_et_stat(moy_gen_but)
|
||||
|
||||
# Ajoute les moyennes par compétence
|
||||
for ue_id, competence in self.tags_competences.items():
|
||||
moy_ue = self.nt.etud_moy_ue[ue_id]
|
||||
self.moyennes_tags[competence] = self.comp_moy_et_stat(moy_ue)
|
||||
|
||||
# Synthétise l'ensemble des moyennes dans un dataframe
|
||||
self.tags_sorted = sorted(self.moyennes_tags) # les tags par ordre alphabétique
|
||||
self.tags_sorted = sorted(
|
||||
self.moyennes_tags
|
||||
) # les tags (personnalisés+compétences) par ordre alphabétique
|
||||
self.notes = (
|
||||
self.df_notes()
|
||||
) # Le dataframe synthétique des notes (=moyennes par tag)
|
||||
|
||||
pe_affichage.pe_print(f" => Traitement des tags {', '.join(self.tags_sorted)}")
|
||||
pe_affichage.pe_print(
|
||||
f" => Traitement des tags {', '.join(self.tags_sorted)}"
|
||||
)
|
||||
|
||||
def get_repr(self):
|
||||
"""Nom affiché pour le semestre taggué"""
|
||||
@ -157,13 +163,13 @@ class SemestreTag(TableTag):
|
||||
|
||||
"""Désactive tous les modules qui ne sont pas pris en compte pour ce tag"""
|
||||
for i, modimpl in enumerate(self.formsemestre.modimpls_sorted):
|
||||
if modimpl.moduleimpl_id not in self.tags[tag]:
|
||||
if modimpl.moduleimpl_id not in self.tags_personnalises[tag]:
|
||||
modimpls_mask[i] = False
|
||||
|
||||
"""Applique la pondération des coefficients"""
|
||||
modimpl_coefs_ponderes_df = self.modimpl_coefs_df.copy()
|
||||
for modimpl_id in self.tags[tag]:
|
||||
ponderation = self.tags[tag][modimpl_id]["ponderation"]
|
||||
for modimpl_id in self.tags_personnalises[tag]:
|
||||
ponderation = self.tags_personnalises[tag][modimpl_id]["ponderation"]
|
||||
modimpl_coefs_ponderes_df[modimpl_id] *= ponderation
|
||||
|
||||
"""Calcule les moyennes pour le tag visé dans chaque UE (dataframe etudid x ues)"""
|
||||
@ -193,95 +199,6 @@ class SemestreTag(TableTag):
|
||||
|
||||
return moy_gen_tag
|
||||
|
||||
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
||||
"""Renvoie un couple donnant la note et le coeff normalisé d'un étudiant à un module d'id modimpl_id.
|
||||
La note et le coeff sont extraits :
|
||||
1) soit des données du semestre en normalisant le coefficient par rapport à la somme des coefficients des modules du semestre,
|
||||
2) soit des données des UE précédemment capitalisées, en recherchant un module de même CODE que le modimpl_id proposé,
|
||||
le coefficient normalisé l'étant alors par rapport au total des coefficients du semestre auquel appartient l'ue capitalisée
|
||||
|
||||
TODO:: A rependre si nécessaire
|
||||
"""
|
||||
|
||||
def get_ue_capitalisees(etudid) -> list[dict]:
|
||||
"""Renvoie la liste des capitalisation effectivement capitalisées par un étudiant"""
|
||||
if etudid in self.nt.validations.ue_capitalisees.index:
|
||||
return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records")
|
||||
return []
|
||||
|
||||
(note, coeff_norm) = (None, None)
|
||||
|
||||
modimpl = get_moduleimpl(modimpl_id) # Le module considéré
|
||||
if modimpl == None or profondeur < 0:
|
||||
return (None, None)
|
||||
|
||||
# Y-a-t-il eu capitalisation d'UE ?
|
||||
ue_capitalisees = get_ue_capitalisees(
|
||||
etudid
|
||||
) # les ue capitalisées des étudiants
|
||||
ue_capitalisees_id = {
|
||||
ue_cap["ue_id"] for ue_cap in ue_capitalisees
|
||||
} # les id des ue capitalisées
|
||||
|
||||
# Si le module ne fait pas partie des UE capitalisées
|
||||
if modimpl.module.ue.id not in ue_capitalisees_id:
|
||||
note = self.nt.get_etud_mod_moy(modimpl_id, etudid) # lecture de la note
|
||||
coeff = modimpl.module.coefficient or 0.0 # le coeff (! non compatible BUT)
|
||||
coeff_norm = (
|
||||
coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0
|
||||
) # le coeff normalisé
|
||||
|
||||
# Si le module fait partie d'une UE capitalisée
|
||||
elif len(ue_capitalisees) > 0:
|
||||
moy_ue_actuelle = get_moy_ue_from_nt(
|
||||
self.nt, etudid, modimpl_id
|
||||
) # la moyenne actuelle
|
||||
# A quel semestre correspond l'ue capitalisée et quelles sont ses notes ?
|
||||
fids_prec = [
|
||||
ue_cap["formsemestre_id"]
|
||||
for ue_cap in ue_capitalisees
|
||||
if ue_cap["ue_code"] == modimpl.module.ue.ue_code
|
||||
] # and ue['semestre_id'] == semestre_id]
|
||||
if len(fids_prec) > 0:
|
||||
# => le formsemestre_id du semestre dont vient la capitalisation
|
||||
fid_prec = fids_prec[0]
|
||||
# Lecture des notes de ce semestre
|
||||
# le tableau de note du semestre considéré:
|
||||
formsemestre_prec = FormSemestre.get_formsemestre(fid_prec)
|
||||
nt_prec: NotesTableCompat = res_sem.load_formsemestre_results(
|
||||
formsemestre_prec
|
||||
)
|
||||
|
||||
# Y-a-t-il un module équivalent c'est à dire correspondant au même code (le module_id n'étant pas significatif en cas de changement de PPN)
|
||||
|
||||
modimpl_prec = [
|
||||
modi
|
||||
for modi in nt_prec.formsemestre.modimpls_sorted
|
||||
if modi.module.code == modimpl.module.code
|
||||
]
|
||||
if len(modimpl_prec) > 0: # si une correspondance est trouvée
|
||||
modprec_id = modimpl_prec[0].id
|
||||
moy_ue_capitalisee = get_moy_ue_from_nt(nt_prec, etudid, modprec_id)
|
||||
if (
|
||||
moy_ue_capitalisee is None
|
||||
) or moy_ue_actuelle >= moy_ue_capitalisee: # on prend la meilleure ue
|
||||
note = self.nt.get_etud_mod_moy(
|
||||
modimpl_id, etudid
|
||||
) # lecture de la note
|
||||
coeff = modimpl.module.coefficient # le coeff
|
||||
# nota: self.somme_coeffs peut être None
|
||||
coeff_norm = (
|
||||
coeff / self.somme_coeffs if self.somme_coeffs else 0
|
||||
) # le coeff normalisé
|
||||
else:
|
||||
semtag_prec = SemestreTag(nt_prec, nt_prec.sem)
|
||||
(note, coeff_norm) = semtag_prec.get_noteEtCoeff_modimpl(
|
||||
modprec_id, etudid, profondeur=profondeur - 1
|
||||
) # lecture de la note via le semtag associé au modimpl capitalisé
|
||||
|
||||
# Sinon - pas de notes à prendre en compte
|
||||
return (note, coeff_norm)
|
||||
|
||||
|
||||
def get_moduleimpl(modimpl_id) -> dict:
|
||||
"""Renvoie l'objet modimpl dont l'id est modimpl_id"""
|
||||
@ -308,21 +225,13 @@ def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float:
|
||||
return ue_status["moy"]
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_synthese_tags_semestre(formsemestre: FormSemestre):
|
||||
def get_synthese_tags_personnalises_semestre(formsemestre: FormSemestre):
|
||||
"""Etant données les implémentations des modules du semestre (modimpls),
|
||||
synthétise les tags les concernant (tags saisis dans le programme pédagogique)
|
||||
synthétise les tags renseignés dans le programme pédagogique &
|
||||
associés aux modules du semestre,
|
||||
en les associant aux modimpls qui les concernent (modimpl_id) et
|
||||
aucoeff et pondération fournie avec le tag (par défaut 1 si non indiquée)).
|
||||
|
||||
{ tagname1: { modimpl_id1: { 'module_id': ...,
|
||||
'coeff': ...,
|
||||
'coeff_norm': ...,
|
||||
'ponderation': ...,
|
||||
'module_code': ...,
|
||||
'ue_xxx': ...},
|
||||
}
|
||||
}
|
||||
|
||||
Args:
|
||||
formsemestre: Le formsemestre à la base de la recherche des tags
|
||||
@ -364,3 +273,26 @@ def get_synthese_tags_semestre(formsemestre: FormSemestre):
|
||||
}
|
||||
|
||||
return synthese_tags
|
||||
|
||||
|
||||
def get_noms_competences_from_ues(formsemestre: FormSemestre) -> dict[int, str]:
|
||||
"""Partant d'un formsemestre, extrait le nom des compétences associés
|
||||
à (ou aux) parcours des étudiants du formsemestre.
|
||||
|
||||
Args:
|
||||
formsemestre: Un FormSemestre
|
||||
|
||||
Returns:
|
||||
Dictionnaire {ue_id: nom_competence} lisant tous les noms des compétences
|
||||
en les raccrochant à leur ue
|
||||
"""
|
||||
# Les résultats du semestre
|
||||
nt = load_formsemestre_results(formsemestre)
|
||||
|
||||
noms_competences = {}
|
||||
for ue in nt.ues:
|
||||
if ue.type != UE_SPORT:
|
||||
ordre = ue.niveau_competence.ordre
|
||||
nom = ue.niveau_competence.competence.titre
|
||||
noms_competences[ue.ue_id] = f"comp. {nom}"
|
||||
return noms_competences
|
||||
|
@ -40,6 +40,8 @@ Created on Thu Sep 8 09:36:33 2016
|
||||
import datetime
|
||||
import numpy as np
|
||||
|
||||
from app.comp.moy_sem import comp_ranks_series
|
||||
from app.pe import pe_affichage
|
||||
from app.scodoc import sco_utils as scu
|
||||
import pandas as pd
|
||||
|
||||
@ -104,6 +106,44 @@ class TableTag(object):
|
||||
|
||||
return df.to_csv(sep=";")
|
||||
|
||||
def comp_moy_et_stat(self, notes: pd.Series) -> dict:
|
||||
"""Calcule et structure les données nécessaires au PE pour une série
|
||||
de notes (souvent une moyenne par tag) dans un dictionnaire spécifique.
|
||||
|
||||
Partant des notes, sont calculés les classements (en ne tenant compte
|
||||
que des notes non nulles).
|
||||
|
||||
Args:
|
||||
notes: Une série de notes (avec des éventuels NaN)
|
||||
|
||||
Returns:
|
||||
Un dictionnaire stockant les notes, les classements, le min,
|
||||
le max, la moyenne, le nb de notes (donc d'inscrits)
|
||||
"""
|
||||
# Supprime d'éventuels chaines de caractères dans les notes
|
||||
notes = pd.to_numeric(notes, errors="coerce")
|
||||
|
||||
# Les indices des ... et les notes non nulles/pertinentes
|
||||
indices = notes.notnull()
|
||||
notes_non_nulles = notes[indices]
|
||||
|
||||
# Les classements sur les notes non nulles
|
||||
(_, class_gen_ue_non_nul) = comp_ranks_series(notes_non_nulles)
|
||||
|
||||
# Les classements (toutes notes confondues, avec NaN si pas de notes)
|
||||
class_gen_ue = pd.Series(np.nan, index=notes.index, dtype="Int64")
|
||||
class_gen_ue[indices] = class_gen_ue_non_nul[indices]
|
||||
|
||||
synthese = {
|
||||
"notes": notes,
|
||||
"classements": class_gen_ue,
|
||||
"min": notes.min(),
|
||||
"max": notes.max(),
|
||||
"moy": notes.mean(),
|
||||
"nb_inscrits": len(indices),
|
||||
}
|
||||
return synthese
|
||||
|
||||
@classmethod
|
||||
def get_min_for_df(cls, bilan: dict) -> float:
|
||||
"""Partant d'un dictionnaire `bilan` généralement une moyennes_tags pour un tag donné,
|
||||
@ -127,12 +167,15 @@ class TableTag(object):
|
||||
"""Partant d'un dictionnaire `bilan` généralement une moyennes_tags pour un tag donné,
|
||||
renvoie le classement ramené au nombre d'inscrits,
|
||||
pour un étudiant donné par son etudid"""
|
||||
return f"{bilan['classements'].loc[etudid]}/{bilan['nb_inscrits']}"
|
||||
|
||||
classement = bilan['classements'].loc[etudid]
|
||||
if not pd.isna(classement):
|
||||
return f"{classement}/{bilan['nb_inscrits']}"
|
||||
else:
|
||||
return pe_affichage.SANS_NOTE
|
||||
|
||||
@classmethod
|
||||
def get_note_for_df(cls, bilan: dict, etudid: int):
|
||||
"""Partant d'un dictionnaire `bilan` généralement une moyennes_tags pour un tag donné,
|
||||
renvoie la note (moyenne)
|
||||
pour un étudiant donné par son etudid"""
|
||||
return round(bilan["notes"].loc[etudid], 2)
|
||||
return round(bilan["notes"].loc[etudid], 2)
|
||||
|
@ -47,11 +47,8 @@ from app.pe.pe_tabletags import TableTag
|
||||
|
||||
|
||||
class TrajectoireTag(TableTag):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
trajectoire: Trajectoire,
|
||||
semestres_taggues: dict[int, SemestreTag]
|
||||
self, trajectoire: Trajectoire, semestres_taggues: dict[int, SemestreTag]
|
||||
):
|
||||
"""Calcule les moyennes par tag d'une combinaison de semestres
|
||||
(trajectoires), identifiée par un nom d'aggrégat (par ex: '3S') et
|
||||
@ -71,11 +68,13 @@ class TrajectoireTag(TableTag):
|
||||
# Le nom de la trajectoire tagguée (identique à la trajectoire)
|
||||
self.nom = self.get_repr()
|
||||
|
||||
"""Le formsemestre terminal et les semestres aggrégés"""
|
||||
self.formsemestre_terminal = trajectoire.semestre_final
|
||||
"""Le formsemestre terminal"""
|
||||
# Les résultats du formsemestre terminal
|
||||
nt = load_formsemestre_results(self.formsemestre_terminal)
|
||||
|
||||
self.semestres_aggreges = trajectoire.semestres_aggreges
|
||||
"""Les semestres aggrégés"""
|
||||
|
||||
self.semestres_tags_aggreges = {}
|
||||
"""Les semestres tags associés aux semestres aggrégés"""
|
||||
@ -87,32 +86,25 @@ class TrajectoireTag(TableTag):
|
||||
|
||||
"""Les étudiants (état civil + cursus connu)"""
|
||||
self.etuds = nt.etuds
|
||||
|
||||
# assert self.etuds == trajectoire.suivi # manque-t-il des étudiants ?
|
||||
self.etudiants = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
||||
|
||||
"""Les tags extraits de tous les semestres"""
|
||||
self.tags_sorted = self.do_taglist()
|
||||
"""Tags extraits de tous les semestres"""
|
||||
|
||||
"""Construit le cube de notes"""
|
||||
self.notes_cube = self.compute_notes_cube()
|
||||
"""Cube de notes"""
|
||||
|
||||
"""Calcul les moyennes par tag sous forme d'un dataframe"""
|
||||
etudids = list(self.etudiants.keys())
|
||||
self.notes = compute_tag_moy(self.notes_cube, etudids, self.tags_sorted)
|
||||
"""Calcul les moyennes par tag sous forme d'un dataframe"""
|
||||
|
||||
"""Synthétise les moyennes/classements par tag"""
|
||||
self.moyennes_tags = {}
|
||||
"""Synthétise les moyennes/classements par tag (qu'ils soient personnalisé ou de compétences)"""
|
||||
for tag in self.tags_sorted:
|
||||
moy_gen_tag = self.notes[tag]
|
||||
class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int
|
||||
self.moyennes_tags[tag] = {
|
||||
"notes": moy_gen_tag,
|
||||
"classements": class_gen_tag,
|
||||
"min": moy_gen_tag.min(),
|
||||
"max": moy_gen_tag.max(),
|
||||
"moy": moy_gen_tag.mean(),
|
||||
"nb_inscrits": len(moy_gen_tag),
|
||||
}
|
||||
self.moyennes_tags[tag] = self.comp_moy_et_stat(moy_gen_tag)
|
||||
|
||||
def get_repr(self, verbose=False) -> str:
|
||||
"""Renvoie une représentation textuelle (celle de la trajectoire sur laquelle elle
|
||||
@ -123,11 +115,11 @@ class TrajectoireTag(TableTag):
|
||||
"""Construit le cube de notes (etudid x tags x semestre_aggregé)
|
||||
nécessaire au calcul des moyennes de l'aggrégat
|
||||
"""
|
||||
nb_tags = len(self.tags_sorted)
|
||||
nb_etudiants = len(self.etuds)
|
||||
nb_semestres = len(self.semestres_tags_aggreges)
|
||||
# nb_tags = len(self.tags_sorted)
|
||||
# nb_etudiants = len(self.etuds)
|
||||
# nb_semestres = len(self.semestres_tags_aggreges)
|
||||
|
||||
"""Index du cube (etudids -> dim 0, tags -> dim 1)"""
|
||||
# Index du cube (etudids -> dim 0, tags -> dim 1)
|
||||
etudids = [etud.etudid for etud in self.etuds]
|
||||
tags = self.tags_sorted
|
||||
semestres_id = list(self.semestres_tags_aggreges.keys())
|
||||
@ -135,17 +127,17 @@ class TrajectoireTag(TableTag):
|
||||
dfs = {}
|
||||
|
||||
for frmsem_id in semestres_id:
|
||||
"""Partant d'un dataframe vierge"""
|
||||
# Partant d'un dataframe vierge
|
||||
df = pd.DataFrame(np.nan, index=etudids, columns=tags)
|
||||
|
||||
"""Charge les notes du semestre tag"""
|
||||
# Charge les notes du semestre tag
|
||||
notes = self.semestres_tags_aggreges[frmsem_id].notes
|
||||
|
||||
"""Les étudiants & les tags commun au dataframe final et aux notes du semestre)"""
|
||||
# Les étudiants & les tags commun au dataframe final et aux notes du semestre)
|
||||
etudids_communs = df.index.intersection(notes.index)
|
||||
tags_communs = df.columns.intersection(notes.columns)
|
||||
|
||||
"""Injecte les notes par tag"""
|
||||
# Injecte les notes par tag
|
||||
df.loc[etudids_communs, tags_communs] = notes.loc[
|
||||
etudids_communs, tags_communs
|
||||
]
|
||||
@ -154,7 +146,7 @@ class TrajectoireTag(TableTag):
|
||||
for col in df.columns:
|
||||
df[col] = pd.to_numeric(df[col], errors="coerce")
|
||||
|
||||
"""Stocke le df"""
|
||||
# Stocke le df
|
||||
dfs[frmsem_id] = df
|
||||
|
||||
"""Réunit les notes sous forme d'un cube etdids x tags x semestres"""
|
||||
@ -175,8 +167,6 @@ class TrajectoireTag(TableTag):
|
||||
return sorted(set(tags))
|
||||
|
||||
|
||||
|
||||
|
||||
def compute_tag_moy(set_cube: np.array, etudids: list, tags: list):
|
||||
"""Calcul de la moyenne par tag sur plusieurs semestres.
|
||||
La moyenne est un nombre (note/20), ou NaN si pas de notes disponibles
|
||||
@ -214,4 +204,6 @@ def compute_tag_moy(set_cube: np.array, etudids: list, tags: list):
|
||||
columns=tags, # les tags
|
||||
)
|
||||
|
||||
etud_moy_tag_df.fillna(np.nan)
|
||||
|
||||
return etud_moy_tag_df
|
||||
|
@ -78,7 +78,7 @@ def pe_view_sem_recap(formsemestre_id: int):
|
||||
sco=ScoData(formsemestre=formsemestre),
|
||||
)
|
||||
|
||||
jury = pe_jury.JuryPE(annee_diplome, formsemestre.formation.formation_id)
|
||||
jury = pe_jury.JuryPE(annee_diplome)
|
||||
if not jury.diplomes_ids:
|
||||
flash("aucun étudiant à considérer !")
|
||||
return redirect(
|
||||
|
@ -882,7 +882,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
||||
<form>
|
||||
<input type="checkbox" class="sco_tag_checkbox"
|
||||
{'checked' if show_tags else ''}
|
||||
>montrer les tags des modules</input>
|
||||
> Montrer les tags des modules voire en ajouter <i>(ceux correspondant aux titres des compétences étant ajoutés par défaut)</i></input>
|
||||
</form>
|
||||
"""
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user