Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
7 changed files with 97 additions and 108 deletions
Showing only changes of commit 9c6d988fc3 - Show all commits

View File

@ -372,3 +372,5 @@ def get_cosemestres_diplomants(
cosemestres[fid] = cosem
return cosemestres

View File

@ -10,14 +10,6 @@ import numpy as np
class AggregatInterclasseTag(TableTag):
"""Interclasse l'ensemble des étudiants diplômés à une année
donnée (celle du jury), pour un aggrégat donné (par ex: 'S2', '3S')
en reportant :
* les moyennes obtenues sur la trajectoire qu'il ont suivi pour atteindre le numéro de semestre de fin de l'aggrégat (indépendamment de son
formsemestres)
* calculant le classement sur les étudiants diplômes
"""
# -------------------------------------------------------------------------------------------------------------------
def __init__(
@ -27,12 +19,26 @@ class AggregatInterclasseTag(TableTag):
trajectoires_jury_pe: TrajectoiresJuryPE,
trajectoires_taggues: dict[tuple, TrajectoireTag],
):
# Table nommée au nom de l'aggrégat (par ex: 3S)
TableTag.__init__(self, nom_aggregat)
"""
Interclasse l'ensemble des étudiants diplômés à une année
donnée (celle du jury), pour un aggrégat donné (par ex: 'S2', '3S')
en reportant :
* les moyennes obtenues sur la trajectoire qu'il ont suivi pour atteindre le numéro de semestre de fin de l'aggrégat (indépendamment de son
formsemestres)
* calculant le classement sur les étudiants diplômes
"""
TableTag.__init__(self)
# Le nom
self.aggregat = nom_aggregat
self.nom = self.get_repr()
"""Les étudiants diplômés et leurs trajectoires (cf. trajectoires.suivis)""" # TODO
self.diplomes_ids = etudiants.etudiants_diplomes
self.etudiants_diplomes = {etudid for etudid in self.diplomes_ids}
# pour les exports sous forme de dataFrame
self.etudiants = {etudid: etudiants.identites[etudid].etat_civil for etudid in self.diplomes_ids}
# Les trajectoires (et leur version tagguées), en ne gardant que celles associées à l'aggrégat
self.trajectoires: dict[int, Trajectoire] = {}
@ -73,9 +79,13 @@ class AggregatInterclasseTag(TableTag):
"nb_inscrits": len(moy_gen_tag),
}
# Est significatif ? (aka a-t-il des tags et des notes)
self.significatif = len(self.tags_sorted) > 0
def get_repr(self) -> str:
"""Une représentation textuelle"""
return f"Aggrégat {self.nom}"
return f"Aggrégat {self.aggregat}"
def do_taglist(self):
"""Synthétise les tags à partir des trajectoires_tagguées

View File

@ -121,7 +121,7 @@ class JuryPE(object):
with pd.ExcelWriter(output, engine="openpyxl") as writer:
for formsemestretag in self.semestres_taggues.values():
onglet = formsemestretag.nom
df = formsemestretag.df_semtag()
df = formsemestretag.df_moyennes_et_classements()
# écriture dans l'onglet
df.to_excel(writer, onglet, index=True, header=True)
output.seek(0)
@ -149,17 +149,22 @@ class JuryPE(object):
self.trajectoires, self.etudiants, self.semestres_taggues
)
if pe_affichage.PE_DEBUG:
# Intègre le bilan des trajectoires tagguées au zip final
# Intègre le bilan des trajectoires tagguées au zip final
output = io.BytesIO()
with pd.ExcelWriter(output, engine="openpyxl") as writer:
for trajectoire_tagguee in self.trajectoires_tagguees.values():
filename = trajectoire_tagguee.get_repr().replace(" ", "_") + ".csv"
# pe_affichage.pe_print(f" - Export csv de {filename} ")
self.add_file_to_zip(
zipfile,
filename,
trajectoire_tagguee.str_tagtable(),
path="details_semestres",
)
onglet = trajectoire_tagguee.get_repr()
df = trajectoire_tagguee.df_moyennes_et_classements()
# écriture dans l'onglet
df.to_excel(writer, onglet, index=True, header=True)
output.seek(0)
self.add_file_to_zip(
zipfile,
f"trajectoires_taggues_{self.diplome}.xlsx",
output.read(),
path="details",
)
# Génère les interclassements (par promo et) par (nom d') aggrégat
pe_affichage.pe_print("*** Génère les interclassements par aggrégat")
@ -167,17 +172,23 @@ class JuryPE(object):
self.etudiants, self.trajectoires, self.trajectoires_tagguees
)
if pe_affichage.PE_DEBUG:
# Intègre le bilan des aggrégats (par promo) au zip final
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
output = io.BytesIO()
with pd.ExcelWriter(output, engine="openpyxl") as writer:
for interclass_tag in self.interclassements_taggues.values():
filename = interclass_tag.get_repr().replace(" ", "_") + ".csv"
# pe_affichage.pe_print(f" - Export csv de {filename} ")
self.add_file_to_zip(
zipfile,
filename,
interclass_tag.str_tagtable(),
path="details_semestres",
)
if interclass_tag.significatif: # Avec des notes
onglet = interclass_tag.get_repr()
df = interclass_tag.df_moyennes_et_classements()
# écriture dans l'onglet
df.to_excel(writer, onglet, index=True, header=True)
output.seek(0)
self.add_file_to_zip(
zipfile,
f"interclassements_taggues_{self.diplome}.xlsx",
output.read(),
path="details",
)
# Synthèse des éléments du jury PE
self.synthese = self.synthetise_juryPE()
@ -437,7 +448,7 @@ def compute_trajectoires_tag(
nom = trajectoire.get_repr()
pe_affichage.pe_print(f" --> Aggrégat {nom}")
# Trajectoire_tagguee associée
trajectoire_tagguee = TrajectoireTag(nom, trajectoire, semestres_taggues)
trajectoire_tagguee = TrajectoireTag(trajectoire, semestres_taggues)
# Mémorise le résultat
trajectoires_tagguees[trajectoire_id] = trajectoire_tagguee

View File

@ -61,7 +61,7 @@ class SemestreTag(TableTag):
nom: Nom à donner au SemestreTag
formsemestre_id: Identifiant du ``FormSemestre`` sur lequel il se base
"""
# TableTag.__init__(self, nom=nom)
TableTag.__init__(self)
# Le semestre
self.formsemestre_id = formsemestre_id
@ -126,7 +126,7 @@ class SemestreTag(TableTag):
# Synthétise l'ensemble des moyennes dans un dataframe
self.tags_sorted = sorted(self.moyennes_tags) # les tags par ordre alphabétique
self.notes = (
self.df_tagtable()
self.df_notes()
) # Le dataframe synthétique des notes (=moyennes par tag)
pe_affichage.pe_print(f" => Traitement des tags {', '.join(self.tags_sorted)}")
@ -282,28 +282,7 @@ class SemestreTag(TableTag):
# Sinon - pas de notes à prendre en compte
return (note, coeff_norm)
def df_semtag(self):
"""Renvoie un dataframe listant toutes les moyennes,
les rangs des étudiants pour tous les tags dans le semestre taggué"""
etudiants = self.etudiants
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom"])
for tag in self.get_all_tags():
df = df.join(self.moyennes_tags[tag]["notes"].rename(f"Moy {tag}"))
df = df.join(self.moyennes_tags[tag]["classements"].rename(f"Class {tag}"))
return df
# ************************************************************************
# Fonctions diverses
# ************************************************************************
# *********************************************
# -----------------------------------------------------------------------------
def get_moduleimpl(modimpl_id) -> dict:
"""Renvoie l'objet modimpl dont l'id est modimpl_id"""
modimpl = db.session.get(ModuleImpl, modimpl_id)
@ -317,7 +296,6 @@ def get_moduleimpl(modimpl_id) -> dict:
return None
# **********************************************
def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float:
"""Renvoie la moyenne de l'UE d'un etudid dans laquelle se trouve
le module de modimpl_id

View File

@ -48,38 +48,13 @@ TAGS_RESERVES = ["but"]
class TableTag(object):
"""
Classe mémorisant les moyennes des étudiants à différents tags et permettant de
calculer des rangs et des statistiques.
Ses attributs sont:
* nom : Nom représentatif des données de la Table
* inscrlist : Les étudiants inscrits dans le TagTag avec leur information de la forme :
{ etudid : dictionnaire d'info extrait de Scodoc, ...}
* taglist : Liste triée des noms des tags
* resultats : Dictionnaire donnant les notes-moyennes de chaque étudiant par tag et la somme commulée
des coeff utilisées dans le calcul de la moyenne pondérée, sous la forme :
{ tag : { etudid: (note_moy, somme_coeff_norm),
...}
* rangs : Dictionnaire donnant les rang par tag de chaque étudiant de la forme :
{ tag : {etudid: rang, ...} }
* nbinscrits : Nombre d'inscrits dans le semestre (pas de distinction entre les tags)
* statistiques : Dictionnaire donnant les statistiques (moyenne, min, max) des résultats par tag de la forme :
{ tag : (moy, min, max), ...}
"""
def __init__(self, nom: str):
"""Les attributs basiques des TagTable, qui seront initialisés
dans les classes dérivées
def __init__(self):
"""Classe centralisant différentes méthodes communes aux
SemestreTag, TrajectoireTag, AggregatInterclassTag
"""
self.nom = nom
"""Les étudiants"""
self.etudiants = {}
"""Les moyennes par tag"""
self.moyennes_tags = {}
pass
# -----------------------------------------------------------------------------------------------------------
def get_all_tags(self):
@ -90,8 +65,21 @@ class TableTag(object):
"""
return sorted(self.moyennes_tags.keys())
def df_moyennes_et_classements(self):
"""Renvoie un dataframe listant toutes les moyennes,
et les classements des étudiants pour tous les tags
"""
def df_tagtable(self):
etudiants = self.etudiants
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom"])
for tag in self.get_all_tags():
df = df.join(self.moyennes_tags[tag]["notes"].rename(f"Moy {tag}"))
df = df.join(self.moyennes_tags[tag]["classements"].rename(f"Class {tag}"))
return df
def df_notes(self):
"""Renvoie un dataframe (etudid x tag) listant toutes les moyennes par tags
Returns:
@ -117,4 +105,3 @@ class TableTag(object):
df = df.join(self.moyennes_tags[tag]["classements"].rename(f"class {tag}"))
return df.to_csv(sep=";")

View File

@ -46,16 +46,17 @@ class Trajectoire:
"""
self.semestres_aggreges = self.semestres_aggreges | semestres
def get_repr(self):
def get_repr(self, verbose=True) -> str:
"""Représentation textuelle d'une trajectoire
basée sur ses semestres aggrégés"""
noms = []
for fid in self.semestres_aggreges:
semestre = self.semestres_aggreges[fid]
noms.append(f"S{semestre.semestre_id}({fid})")
noms = sorted(noms)
repr = f"{self.nom} ({self.semestre_final.formsemestre_id}) {self.semestre_final.date_fin.year}"
if noms:
if verbose and noms:
repr += " - " + "+".join(noms)
return repr

View File

@ -47,30 +47,30 @@ from app.pe.pe_tabletags import TableTag
class TrajectoireTag(TableTag):
"""Calcule les moyennes par tag d'une combinaison de semestres
(trajectoires), identifiée par un nom d'aggrégat (par ex: '3S') et
par un semestre terminal, pour extraire les classements par tag pour un
groupe d'étudiants donnés. Le groupe d'étudiants est formé par ceux ayant tous
participé au semestre terminal.
Par ex: fusion d'un parcours ['S1', 'S2', 'S3'] donnant un nom_combinaison = '3S'
"""
# -------------------------------------------------------------------------------------------------------------------
def __init__(
self,
nom: str,
trajectoire: Trajectoire,
semestres_taggues: dict[int, SemestreTag]
):
""" """
TableTag.__init__(self, nom=nom)
"""Calcule les moyennes par tag d'une combinaison de semestres
(trajectoires), identifiée par un nom d'aggrégat (par ex: '3S') et
par un semestre terminal, pour extraire les classements par tag pour un
groupe d'étudiants donnés. Le groupe d'étudiants est formé par ceux ayant tous
participé au semestre terminal.
"""La trajectoire associée"""
Par ex: fusion d'un parcours ['S1', 'S2', 'S3'] donnant un nom_combinaison = '3S'
"""
TableTag.__init__(self)
# La trajectoire associée
self.trajectoire_id = trajectoire.trajectoire_id
self.trajectoire = trajectoire
# 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
nt = load_formsemestre_results(self.formsemestre_terminal)
@ -114,10 +114,10 @@ class TrajectoireTag(TableTag):
"nb_inscrits": len(moy_gen_tag),
}
def get_repr(self):
def get_repr(self, verbose=False) -> str:
"""Renvoie une représentation textuelle (celle de la trajectoire sur laquelle elle
est basée)"""
return self.trajectoire.get_repr()
return self.trajectoire.get_repr(verbose=verbose)
def compute_notes_cube(self):
"""Construit le cube de notes (etudid x tags x semestre_aggregé)
@ -159,8 +159,6 @@ class TrajectoireTag(TableTag):
return etudids_x_tags_x_semestres
def do_taglist(self):
"""Synthétise les tags à partir des semestres (taggués) aggrégés
@ -173,6 +171,8 @@ 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