ScoDoc/app/pe/pe_jury.py

753 lines
29 KiB
Python
Raw Normal View History

2024-01-25 17:17:01 +01:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
##############################################################################
# Module "Avis de poursuite d'étude"
# conçu et développé par Cléo Baras (IUT de Grenoble)
##############################################################################
"""
Created on Fri Sep 9 09:15:05 2016
@author: barasc
"""
# ----------------------------------------------------------
# Ensemble des fonctions et des classes
# permettant les calculs preliminaires (hors affichage)
# a l'edition d'un jury de poursuites d'etudes
# ----------------------------------------------------------
import io
import os
import time
2024-01-25 17:17:01 +01:00
from zipfile import ZipFile
import numpy as np
2024-02-08 22:09:11 +01:00
import pandas as pd
import app.pe.rcss.rcss_constantes as rcss_constants
2024-02-17 02:35:43 +01:00
from app.pe import pe_sxtag
from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE
2024-02-08 22:09:11 +01:00
import app.pe.pe_affichage as pe_affichage
2024-02-17 03:30:19 +01:00
import app.pe.pe_etudiant as pe_etudiant
import app.pe.rcss.pe_rcs as pe_rcs
2024-02-08 22:09:11 +01:00
from app.pe.pe_rcstag import RCSTag
2024-02-17 02:35:43 +01:00
from app.pe.pe_ressemtag import ResSemBUTTag
from app.pe.pe_interclasstag import RCSInterclasseTag
import app.pe.pe_rcss_jury as pe_rcss_jury
2024-01-25 17:17:01 +01:00
class JuryPE(object):
2024-02-08 22:09:11 +01:00
"""
Classe mémorisant toutes les informations nécessaires pour établir un jury de PE, sur la base
d'une année de diplôme. De ce semestre est déduit :
1. l'année d'obtention du DUT,
2. tous les étudiants susceptibles à ce stade (au regard de leur parcours) d'être diplomés.
2024-01-25 17:17:01 +01:00
2024-02-08 22:09:11 +01:00
Args:
diplome : l'année d'obtention du diplome BUT et du jury de PE (généralement février XXXX)
"""
def __init__(self, diplome: int):
pe_affichage.pe_start_log()
2024-01-25 17:17:01 +01:00
self.diplome = diplome
2024-01-26 10:18:46 +01:00
"L'année du diplome"
2024-01-25 17:17:01 +01:00
self.nom_export_zip = f"Jury_PE_{self.diplome}"
2024-01-26 10:18:46 +01:00
"Nom du zip où ranger les fichiers générés"
pe_affichage.pe_print(
f"Données de poursuite d'étude générées le {time.strftime('%d/%m/%Y à %H:%M')}\n"
)
# 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}"""
)
2024-02-17 03:30:19 +01:00
self.etudiants = pe_etudiant.EtudiantsJuryPE(
self.diplome
) # Les infos sur les étudiants
self.etudiants.find_etudiants()
self.diplomes_ids = self.etudiants.diplomes_ids
self.rcss_jury = pe_rcss_jury.RCSsJuryPE(self.diplome)
"""Les informations sur les regroupements de semestres"""
self.zipdata = io.BytesIO()
2024-01-26 10:18:46 +01:00
with ZipFile(self.zipdata, "w") as zipfile:
if not self.diplomes_ids:
pe_affichage.pe_print("*** Aucun étudiant diplômé")
else:
try:
self._gen_xls_diplomes(zipfile)
self._gen_xls_ressembuttags(zipfile)
self._gen_rcss()
self._gen_xls_sxtags(zipfile)
self._gen_rcrcfs()
self._gen_xls_rcrcss_tags(zipfile)
# self._gen_xls_interclassements_rcss(zipfile)
# self._gen_xls_synthese_jury_par_tag(zipfile)
# self._gen_xls_synthese_par_etudiant(zipfile)
except Exception as e:
raise e
# et le log
self._add_log_to_zip(zipfile)
# Fin !!!! Tada :)
2024-01-26 10:18:46 +01:00
def _gen_xls_diplomes(self, zipfile: ZipFile):
"Intègre le bilan des semestres taggués au zip"
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl"
) as writer:
if self.diplomes_ids:
onglet = "diplômés"
df_diplome = self.etudiants.df_administratif(self.diplomes_ids)
df_diplome.to_excel(writer, onglet, index=True, header=True)
if self.etudiants.abandons_ids:
onglet = "redoublants-réorientés"
df_abandon = self.etudiants.df_administratif(
self.etudiants.abandons_ids
)
df_abandon.to_excel(writer, onglet, index=True, header=True)
output.seek(0)
self.add_file_to_zip(
zipfile,
f"etudiants_{self.diplome}.xlsx",
output.read(),
path="details",
)
2024-02-17 02:35:43 +01:00
def _gen_xls_ressembuttags(self, zipfile: ZipFile):
"""Calcule les moyennes par tag des résultats des Semestres BUT"""
2024-02-17 03:30:19 +01:00
pe_affichage.pe_print(
"*** Génère les ResSemBUTTag (résultats des semestres BUT taggués)"
)
2024-02-17 02:35:43 +01:00
formsemestres = get_formsemestres_etudiants(self.etudiants)
2024-02-17 03:30:19 +01:00
pe_affichage.pe_print(
f"--> {len(formsemestres)} résultats de semestres à considérer"
2024-02-17 03:30:19 +01:00
)
2024-02-17 02:35:43 +01:00
2024-02-17 03:30:19 +01:00
self.ressembuttags = {}
2024-02-17 02:35:43 +01:00
for frmsem_id, formsemestre in formsemestres.items():
# Crée le semestre_tag et exécute les calculs de moyennes
2024-02-17 03:30:19 +01:00
self.ressembuttags[frmsem_id] = ResSemBUTTag(formsemestre)
# Intègre le bilan des semestres taggués au zip final
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl"
) as writer:
2024-02-17 02:35:43 +01:00
for res_sem_tag in self.ressembuttags.values():
onglet = res_sem_tag.get_repr(verbose=False)
df = res_sem_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,
2024-02-17 02:35:43 +01:00
f"ResSemBUTTags_{self.diplome}.xlsx",
output.read(),
path="details",
)
def _gen_rcss(self):
"""Génère les RCS (attribut `rcss_jury`), combinaisons de semestres
suivis par les étudiants au sens d'un nom de RCS (par ex: 'S2' ou '3S').
"""
pe_affichage.pe_print(
"*** Génère les RCS (différentes combinaisons de semestres) des étudiants"
)
self.rcss_jury.cree_rcss(self.etudiants)
2024-02-17 02:35:43 +01:00
def _gen_xls_sxtags(self, zipfile: ZipFile):
"""Génère les semestres taggués en s'appuyant sur les RCS de type Sx (pour
identifier les redoublements impactant les semestres taggués).
"""
# Génère les regroupements de semestres de type Sx
pe_affichage.pe_print(
"*** Génère les RCSValid (RCS de même Sx donnant lieu à validation du semestre)"
)
self.rcss_jury.cree_rcfs(self.etudiants)
# Génère les moyennes des RCS de type Sx
2024-02-17 02:35:43 +01:00
pe_affichage.pe_print("*** Calcule les moyennes des SxTag")
# Les SxTag (moyenne de Sx par UE)
2024-02-17 02:35:43 +01:00
self.sxtags = {}
for rcf_id, rcf in self.rcss_jury.rcfs.items():
# SxTag traduisant le RCF
sxtag_id = rcf_id
self.sxtags[sxtag_id] = pe_sxtag.SxTag(sxtag_id, rcf, self.ressembuttags)
# Intègre le bilan des semestres taggués au zip final
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
2024-02-17 03:30:19 +01:00
output, engine="openpyxl"
) as writer:
for sxtag in self.sxtags.values():
onglet = sxtag.get_repr(verbose=False)
df = sxtag.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"semestres_taggues_{self.diplome}.xlsx",
output.read(),
path="details",
)
def _gen_rcrcfs(self):
"""Génère les regroupements cohérents de RCFs qu'ont suivi chaque étudiant"""
pe_affichage.pe_print(
"*** Génère les RCRCF (regroupements de RCF de type Sx) amenant du S1 à un semestre final***"
)
self.rcss_jury.cree_rcrcfs(self.etudiants)
def _gen_xls_rcrcss_tags(self, zipfile: ZipFile):
"""Génère les RCS taggués traduisant les moyennes (orientées compétences)
de regroupements de semestre de type Sx, xA ou xS.
Stocke le résultat dans self.rccs_tag, un dictionnaire de
2024-02-17 02:35:43 +01:00
la forme ``{nom_aggregat: {fid_terminal: RCSTag(fid_terminal)} }``
Pour rappel : Chaque RCS est identifié par un nom d'aggrégat et par un formsemestre terminal.
Par exemple :
* combinaisons '3S' : S1+S2+S3 en prenant en compte tous les S3 qu'ont fréquenté les
étudiants du jury PE. Ces S3 marquent les formsemestre terminal de chaque combinaison.
Args:
etudiants: Les données des étudiants
semestres_tag: Les semestres tag (pour lesquels des moyennes par tag ont été calculés)
"""
# Génère les moyennes des RCS de type Sx
pe_affichage.pe_print("*** Calcule les moyennes des RC de RCFS")
self.rcss_tags = {}
for rcs_id, rcrcf in self.rcss_jury.rcrcfs.items():
self.rcss_tags[rcs_id] = RCSTag(rcrcf, self.sxtags)
# Intègre le bilan des trajectoires tagguées au zip final
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl"
) as writer:
for rcs_tag in self.rcss_tags.values():
onglet = rcs_tag.get_repr(verbose=False)
df = rcs_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"RCRCFs_{self.diplome}.xlsx",
output.read(),
path="details",
)
def _gen_xls_interclassements_rcss(self, zipfile: ZipFile):
"""Intègre le bilan des RCS (interclassé par promo) au zip"""
# 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")
self.interclassements_taggues = compute_interclassements(
self.etudiants, self.rcss_jury, self.rcss_tags
)
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl"
) as writer:
for interclass_tag in self.interclassements_taggues.values():
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",
)
def _gen_xls_synthese_jury_par_tag(self, zipfile: ZipFile):
"""Synthèse des éléments du jury PE tag par tag"""
# Synthèse des éléments du jury PE
self.synthese = self.synthetise_jury_par_tags()
# Export des données => mode 1 seule feuille -> supprimé
pe_affichage.pe_print("*** Export du jury de synthese par tags")
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl"
) as writer:
for onglet, df in self.synthese.items():
# écriture dans l'onglet:
df.to_excel(writer, onglet, index=True, header=True)
output.seek(0)
self.add_file_to_zip(
zipfile, f"synthese_jury_{self.diplome}_par_tag.xlsx", output.read()
)
def _gen_xls_synthese_par_etudiant(self, zipfile: ZipFile):
"""Synthèse des éléments du jury PE, étudiant par étudiant"""
# Synthèse des éléments du jury PE
synthese = self.synthetise_jury_par_etudiants()
# Export des données => mode 1 seule feuille -> supprimé
pe_affichage.pe_print("*** Export du jury de synthese par étudiants")
output = io.BytesIO()
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
output, engine="openpyxl"
) as writer:
for onglet, df in synthese.items():
# écriture dans l'onglet:
df.to_excel(writer, onglet, index=True, header=True)
output.seek(0)
self.add_file_to_zip(
zipfile, f"synthese_jury_{self.diplome}_par_etudiant.xlsx", output.read()
)
2024-01-25 17:17:01 +01:00
def _add_log_to_zip(self, zipfile):
"""Add a text file with the log messages"""
log_data = pe_affichage.pe_get_log()
self.add_file_to_zip(zipfile, "pe_log.txt", log_data)
2024-01-26 10:18:46 +01:00
def add_file_to_zip(self, zipfile: ZipFile, filename: str, data, path=""):
"""Add a file to given zip
2024-01-25 17:17:01 +01:00
All files under NOM_EXPORT_ZIP/
path may specify a subdirectory
Args:
2024-01-26 10:18:46 +01:00
zipfile: ZipFile
2024-01-25 17:17:01 +01:00
filename: Le nom du fichier à intégrer au zip
data: Les données du fichier
path: Un dossier dans l'arborescence du zip
"""
2024-01-25 19:42:22 +01:00
path_in_zip = os.path.join(path, filename) # self.nom_export_zip,
2024-01-26 10:18:46 +01:00
zipfile.writestr(path_in_zip, data)
2024-01-25 17:17:01 +01:00
2024-01-26 10:18:46 +01:00
def get_zipped_data(self) -> io.BytesIO | None:
2024-01-25 17:17:01 +01:00
"""returns file-like data with a zip of all generated (CSV) files.
2024-01-26 10:18:46 +01:00
Warning: reset stream to the begining.
2024-01-25 17:17:01 +01:00
"""
self.zipdata.seek(0)
return self.zipdata
def do_tags_list(self, interclassements: dict[str, RCSInterclasseTag]):
2024-01-25 17:17:01 +01:00
"""La liste des tags extraites des interclassements"""
tags = []
for aggregat in interclassements:
interclass = interclassements[aggregat]
if interclass.tags_sorted:
tags.extend(interclass.tags_sorted)
tags = sorted(set(tags))
return tags
# **************************************************************************************************************** #
# Méthodes pour la synthèse du juryPE
# *****************************************************************************************************************
def synthetise_jury_par_tags(self) -> dict[pd.DataFrame]:
"""Synthétise tous les résultats du jury PE dans des dataframes,
dont les onglets sont les tags"""
2024-01-25 17:17:01 +01:00
pe_affichage.pe_print("*** Synthèse finale des moyennes par tag***")
2024-01-25 17:17:01 +01:00
synthese = {}
pe_affichage.pe_print(" -> Synthèse des données administratives")
synthese["administratif"] = self.etudiants.df_administratif(self.diplomes_ids)
2024-01-25 17:17:01 +01:00
tags = self.do_tags_list(self.interclassements_taggues)
for tag in tags:
pe_affichage.pe_print(f" -> Synthèse du tag {tag}")
2024-01-25 17:17:01 +01:00
synthese[tag] = self.df_tag(tag)
return synthese
def df_tag(self, tag):
"""Génère le DataFrame synthétisant les moyennes/classements (groupe,
interclassement promo) pour tous les aggrégats prévus,
tels que fourni dans l'excel final.
Args:
tag: Un des tags (a minima `but`)
Returns:
"""
etudids = list(self.diplomes_ids)
# Les données des étudiants
donnees_etudiants = {}
2024-01-25 17:17:01 +01:00
for etudid in etudids:
etudiant = self.etudiants.identites[etudid]
donnees_etudiants[etudid] = {
("Identité", "", "Civilite"): etudiant.civilite_str,
("Identité", "", "Nom"): etudiant.nom,
("Identité", "", "Prenom"): etudiant.prenom,
2024-01-25 17:17:01 +01:00
}
df_synthese = pd.DataFrame.from_dict(donnees_etudiants, orient="index")
2024-01-25 17:17:01 +01:00
# Ajout des aggrégats
for aggregat in pe_rcs.TOUS_LES_RCS:
descr = app.pe.rcss.constantes.TYPES_RCS[aggregat]["descr"]
# Les trajectoires (tagguées) suivies par les étudiants pour l'aggrégat et le tag
# considéré
trajectoires_tagguees = []
for etudid in etudids:
trajectoire = self.rcss_jury.rcss_suivis[etudid][aggregat]
2024-01-25 17:17:01 +01:00
if trajectoire:
2024-02-17 02:35:43 +01:00
tid = trajectoire.sxtag_id
trajectoire_tagguee = self.rcss_tags[tid]
if (
tag in trajectoire_tagguee.moyennes_tags
and trajectoire_tagguee not in trajectoires_tagguees
):
trajectoires_tagguees.append(trajectoire_tagguee)
# Combien de notes vont être injectées ?
nbre_notes_injectees = 0
for traj in trajectoires_tagguees:
moy_traj = traj.moyennes_tags[tag]
inscrits_traj = moy_traj.inscrits_ids
etudids_communs = set(etudids) & set(inscrits_traj)
nbre_notes_injectees += len(etudids_communs)
# Si l'aggrégat est significatif (aka il y a des notes)
if nbre_notes_injectees > 0:
# Ajout des données classements & statistiques
nom_stat_promo = f"{NOM_STAT_PROMO} {self.diplome}"
donnees = pd.DataFrame(
index=etudids,
columns=[
[descr] * (1 + 4 * 2),
[""] + [NOM_STAT_GROUPE] * 4 + [nom_stat_promo] * 4,
["note"] + ["class.", "min", "moy", "max"] * 2,
],
)
for traj in trajectoires_tagguees:
# Les données des trajectoires_tagguees
moy_traj = traj.moyennes_tags[tag]
# Les étudiants communs entre tableur de synthèse et trajectoires
inscrits_traj = moy_traj.inscrits_ids
etudids_communs = list(set(etudids) & set(inscrits_traj))
# Les notes
champ = (descr, "", "note")
notes_traj = moy_traj.get_notes()
donnees.loc[etudids_communs, champ] = notes_traj.loc[
2024-02-08 22:09:11 +01:00
etudids_communs
]
# Les rangs
champ = (descr, NOM_STAT_GROUPE, "class.")
rangs = moy_traj.get_rangs_inscrits()
2024-02-08 22:09:11 +01:00
donnees.loc[etudids_communs, champ] = rangs.loc[etudids_communs]
# Les mins
champ = (descr, NOM_STAT_GROUPE, "min")
mins = moy_traj.get_min()
donnees.loc[etudids_communs, champ] = mins.loc[etudids_communs]
# Les max
champ = (descr, NOM_STAT_GROUPE, "max")
maxs = moy_traj.get_max()
donnees.loc[etudids_communs, champ] = maxs.loc[etudids_communs]
# Les moys
champ = (descr, NOM_STAT_GROUPE, "moy")
moys = moy_traj.get_moy()
donnees.loc[etudids_communs, champ] = moys.loc[etudids_communs]
# Ajoute les données d'interclassement
interclass = self.interclassements_taggues[aggregat]
moy_interclass = interclass.moyennes_tags[tag]
# Les étudiants communs entre tableur de synthèse et l'interclassement
inscrits_interclass = moy_interclass.inscrits_ids
etudids_communs = list(set(etudids) & set(inscrits_interclass))
# Les classements d'interclassement
champ = (descr, nom_stat_promo, "class.")
rangs = moy_interclass.get_rangs_inscrits()
donnees.loc[etudids_communs, champ] = rangs.loc[etudids_communs]
# Les mins
champ = (descr, nom_stat_promo, "min")
mins = moy_interclass.get_min()
donnees.loc[etudids_communs, champ] = mins.loc[etudids_communs]
# Les max
champ = (descr, nom_stat_promo, "max")
maxs = moy_interclass.get_max()
donnees.loc[etudids_communs, champ] = maxs.loc[etudids_communs]
# Les moys
champ = (descr, nom_stat_promo, "moy")
2024-02-12 09:26:23 +01:00
moys = moy_interclass.get_moy()
donnees.loc[etudids_communs, champ] = moys.loc[etudids_communs]
df_synthese = df_synthese.join(donnees)
2024-01-25 17:17:01 +01:00
# Fin de l'aggrégat
# Tri par nom/prénom
df_synthese.sort_values(
by=[("Identité", "", "Nom"), ("Identité", "", "Prenom")], inplace=True
)
return df_synthese
2024-01-25 17:17:01 +01:00
def synthetise_jury_par_etudiants(self) -> dict[pd.DataFrame]:
"""Synthétise tous les résultats du jury PE dans des dataframes,
dont les onglets sont les étudiants"""
pe_affichage.pe_print("*** Synthèse finale des moyennes par étudiants***")
synthese = {}
pe_affichage.pe_print(" -> Synthèse des données administratives")
synthese["administratif"] = self.etudiants.df_administratif(self.diplomes_ids)
etudids = list(self.diplomes_ids)
for etudid in etudids:
etudiant = self.etudiants.identites[etudid]
nom = etudiant.nom
prenom = etudiant.prenom[0] # initial du prénom
onglet = f"{nom} {prenom}. ({etudid})"
if len(onglet) > 32: # limite sur la taille des onglets
fin_onglet = f"{prenom}. ({etudid})"
onglet = f"{nom[:32-len(fin_onglet)-2]}." + fin_onglet
pe_affichage.pe_print(f" -> Synthèse de l'étudiant {etudid}")
synthese[onglet] = self.df_synthese_etudiant(etudid)
return synthese
def df_synthese_etudiant(self, etudid: int) -> pd.DataFrame:
"""Créé un DataFrame pour un étudiant donné par son etudid, retraçant
toutes ses moyennes aux différents tag et aggrégats"""
tags = self.do_tags_list(self.interclassements_taggues)
donnees = {}
for tag in tags:
# Une ligne pour le tag
donnees[tag] = {("", "", "tag"): tag}
for aggregat in pe_rcs.TOUS_LES_RCS:
# Le dictionnaire par défaut des moyennes
2024-02-03 10:46:14 +01:00
donnees[tag] |= get_defaut_dict_synthese_aggregat(
aggregat, self.diplome
)
# La trajectoire de l'étudiant sur l'aggrégat
trajectoire = self.rcss_jury.rcss_suivis[etudid][aggregat]
if trajectoire:
2024-02-17 02:35:43 +01:00
trajectoire_tagguee = self.rcss_tags[trajectoire.sxtag_id]
2024-02-03 10:46:14 +01:00
if tag in trajectoire_tagguee.moyennes_tags:
# L'interclassement
interclass = self.interclassements_taggues[aggregat]
2024-02-03 10:46:14 +01:00
# Injection des données dans un dictionnaire
donnees[tag] |= get_dict_synthese_aggregat(
aggregat,
trajectoire_tagguee,
interclass,
etudid,
tag,
self.diplome,
2024-02-03 10:46:14 +01:00
)
# Fin de l'aggrégat
# Construction du dataFrame
df = pd.DataFrame.from_dict(donnees, orient="index")
# Tri par nom/prénom
2024-02-03 10:46:14 +01:00
df.sort_values(by=[("", "", "tag")], inplace=True)
return df
2024-01-25 17:17:01 +01:00
2024-02-08 22:09:11 +01:00
2024-02-17 03:30:19 +01:00
def get_formsemestres_etudiants(etudiants: pe_etudiant.EtudiantsJuryPE) -> dict:
"""Ayant connaissance des étudiants dont il faut calculer les moyennes pour
2024-02-17 02:35:43 +01:00
le jury PE (attribut `self.etudiant_ids) et de leurs trajectoires (semestres
parcourus), renvoie un dictionnaire ``{fid: FormSemestre(fid)}``
contenant l'ensemble des formsemestres de leurs cursus, dont il faudra calculer
la moyenne.
Args:
etudiants: Les étudiants du jury PE
Returns:
Un dictionnaire de la forme `{fid: FormSemestre(fid)}`
"""
semestres = {}
for etudid in etudiants.etudiants_ids:
2024-02-17 02:35:43 +01:00
for cle in etudiants.trajectoires[etudid]:
if cle.startswith("S"):
2024-02-17 02:35:43 +01:00
semestres = semestres | etudiants.trajectoires[etudid][cle]
return semestres
2024-02-03 10:46:14 +01:00
2024-02-08 22:09:11 +01:00
2024-01-25 17:17:01 +01:00
def compute_interclassements(
2024-02-17 03:30:19 +01:00
etudiants: pe_etudiant.EtudiantsJuryPE,
trajectoires_jury_pe: pe_rcss_jury.RCSsJuryPE,
trajectoires_tagguees: dict[tuple, pe_rcs.RCS],
2024-01-25 17:17:01 +01:00
):
"""Interclasse les étudiants, (nom d') aggrégat par aggrégat,
pour fournir un classement sur la promo. Le classement est établi au regard du nombre
d'étudiants ayant participé au même aggrégat.
"""
aggregats_interclasses_taggues = {}
for nom_aggregat in pe_rcs.TOUS_LES_RCS:
pe_affichage.pe_print(f" --> Interclassement {nom_aggregat}")
interclass = RCSInterclasseTag(
2024-01-25 17:17:01 +01:00
nom_aggregat, etudiants, trajectoires_jury_pe, trajectoires_tagguees
)
aggregats_interclasses_taggues[nom_aggregat] = interclass
return aggregats_interclasses_taggues
def get_defaut_dict_synthese_aggregat(nom_rcs: str, diplome: int) -> dict:
"""Renvoie le dictionnaire de synthèse (à intégrer dans
un tableur excel) pour décrire les résultats d'un aggrégat
Args:
nom_rcs : Le nom du RCS visé
diplôme : l'année du diplôme
"""
# L'affichage de l'aggrégat dans le tableur excel
descr = pe_rcs.get_descr_rcs(nom_rcs)
nom_stat_promo = f"{NOM_STAT_PROMO} {diplome}"
donnees = {
(descr, "", "note"): SANS_NOTE,
# Les stat du groupe
(descr, NOM_STAT_GROUPE, "class."): SANS_NOTE,
(descr, NOM_STAT_GROUPE, "min"): SANS_NOTE,
(descr, NOM_STAT_GROUPE, "moy"): SANS_NOTE,
(descr, NOM_STAT_GROUPE, "max"): SANS_NOTE,
# Les stats de l'interclassement dans la promo
(descr, nom_stat_promo, "class."): SANS_NOTE,
(
descr,
nom_stat_promo,
"min",
): SANS_NOTE,
(
descr,
nom_stat_promo,
"moy",
): SANS_NOTE,
(
descr,
nom_stat_promo,
"max",
): SANS_NOTE,
}
return donnees
def get_dict_synthese_aggregat(
aggregat: str,
trajectoire_tagguee: RCSTag,
interclassement_taggue: RCSInterclasseTag,
etudid: int,
tag: str,
2024-02-03 10:46:14 +01:00
diplome: int,
):
"""Renvoie le dictionnaire (à intégrer au tableur excel de synthese)
traduisant les résultats (moy/class) d'un étudiant à une trajectoire tagguée associée
à l'aggrégat donné et pour un tag donné"""
donnees = {}
# L'affichage de l'aggrégat dans le tableur excel
descr = pe_rcs.get_descr_rcs(aggregat)
# La note de l'étudiant (chargement à venir)
note = np.nan
# Les données de la trajectoire tagguée pour le tag considéré
2024-02-03 10:46:14 +01:00
moy_tag = trajectoire_tagguee.moyennes_tags[tag]
# Les données de l'étudiant
note = moy_tag.get_note_for_df(etudid)
2024-02-03 10:46:14 +01:00
classement = moy_tag.get_class_for_df(etudid)
nmin = moy_tag.get_min_for_df()
nmax = moy_tag.get_max_for_df()
nmoy = moy_tag.get_moy_for_df()
2024-02-03 10:46:14 +01:00
# Statistiques sur le groupe
if not pd.isna(note) and note != np.nan:
# Les moyennes de cette trajectoire
donnees |= {
(descr, "", "note"): note,
(descr, NOM_STAT_GROUPE, "class."): classement,
(descr, NOM_STAT_GROUPE, "min"): nmin,
(descr, NOM_STAT_GROUPE, "moy"): nmoy,
(descr, NOM_STAT_GROUPE, "max"): nmax,
}
# L'interclassement
2024-02-03 10:46:14 +01:00
moy_tag = interclassement_taggue.moyennes_tags[tag]
classement = moy_tag.get_class_for_df(etudid)
nmin = moy_tag.get_min_for_df()
nmax = moy_tag.get_max_for_df()
nmoy = moy_tag.get_moy_for_df()
if not pd.isna(note) and note != np.nan:
nom_stat_promo = f"{NOM_STAT_PROMO} {diplome}"
donnees |= {
(descr, nom_stat_promo, "class."): classement,
(descr, nom_stat_promo, "min"): nmin,
(descr, nom_stat_promo, "moy"): nmoy,
(descr, nom_stat_promo, "max"): nmax,
}
return donnees