forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
0
app/pe/moys/__init__.py
Normal file
0
app/pe/moys/__init__.py
Normal file
325
app/pe/moys/pe_interclasstag.py
Normal file
325
app/pe/moys/pe_interclasstag.py
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# 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 Thu Sep 8 09:36:33 2016
|
||||||
|
|
||||||
|
@author: barasc
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from app.models import Identite
|
||||||
|
from app.pe.moys import pe_tabletags, pe_moy, pe_moytag, pe_sxtag
|
||||||
|
from app.pe.rcss import pe_rcs
|
||||||
|
import app.pe.pe_comp as pe_comp
|
||||||
|
|
||||||
|
|
||||||
|
class InterClassTag(pe_tabletags.TableTag):
|
||||||
|
"""
|
||||||
|
Interclasse l'ensemble des étudiants diplômés à une année
|
||||||
|
donnée (celle du jury), pour un RCS donné (par ex: 'S2', '3S'), qu'il soit
|
||||||
|
de type SemX ou RCSemX,
|
||||||
|
en reportant les moyennes obtenues sur à la version tagguée
|
||||||
|
du RCS (de type SxTag ou RCSTag).
|
||||||
|
Sont ensuite calculés les classements (uniquement)
|
||||||
|
sur les étudiants diplômes.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nom_rcs: Le nom de l'aggrégat
|
||||||
|
type_interclassement: Le type d'interclassement (par UE ou par compétences)
|
||||||
|
etudiants_diplomes: L'identité des étudiants diplômés
|
||||||
|
rcss: Un dictionnaire {(nom_rcs, fid_final): RCS} donnant soit
|
||||||
|
les SemX soit les RCSemX recencés par le jury PE
|
||||||
|
rcstag: Un dictionnaire {(nom_rcs, fid_final): RCSTag} donnant
|
||||||
|
soit les SxTag (associés aux SemX)
|
||||||
|
soit les RCSTags (associés au RCSemX) calculés par le jury PE
|
||||||
|
suivis: Un dictionnaire associé à chaque étudiant son rcss
|
||||||
|
(de la forme ``{etudid: {nom_rcs: RCS_suivi}}``)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
nom_rcs: str,
|
||||||
|
type_interclassement: str,
|
||||||
|
etudiants_diplomes: dict[int, Identite],
|
||||||
|
rcss: dict[(str, int) : pe_rcs.RCS],
|
||||||
|
rcstags: dict[(str, int) : pe_tabletags.TableTag],
|
||||||
|
suivis: dict[int:dict],
|
||||||
|
):
|
||||||
|
pe_tabletags.TableTag.__init__(self)
|
||||||
|
|
||||||
|
self.nom_rcs: str = nom_rcs
|
||||||
|
"""Le nom du RCS interclassé"""
|
||||||
|
|
||||||
|
# Le type d'interclassement
|
||||||
|
self.type = type_interclassement
|
||||||
|
|
||||||
|
# Les informations sur les étudiants diplômés
|
||||||
|
self.etuds: list[Identite] = list(etudiants_diplomes.values())
|
||||||
|
"""Identités des étudiants diplômés"""
|
||||||
|
self.add_etuds(self.etuds)
|
||||||
|
|
||||||
|
self.diplomes_ids = set(etudiants_diplomes.keys())
|
||||||
|
"""Etudids des étudiants diplômés"""
|
||||||
|
|
||||||
|
# Les RCS de l'aggrégat (SemX ou RCSemX)
|
||||||
|
self.rcss: dict[(str, int), pe_rcs.RCS] = {}
|
||||||
|
"""Ensemble des SemX ou des RCSemX associés à l'aggrégat"""
|
||||||
|
for (nom, fid), rcs in rcss.items():
|
||||||
|
if nom == nom_rcs:
|
||||||
|
self.rcss[(nom, fid)] = rcss
|
||||||
|
|
||||||
|
# Les données tagguées
|
||||||
|
self.rcstags: dict[(str, int), pe_tabletags.TableTag] = {}
|
||||||
|
"""Ensemble des SxTag ou des RCSTags associés à l'aggrégat"""
|
||||||
|
for rcs_id in self.rcss:
|
||||||
|
self.rcstags[rcs_id] = rcstags[rcs_id]
|
||||||
|
|
||||||
|
# Les RCS (SemX ou RCSemX) suivis par les étudiants du jury,
|
||||||
|
# en ne gardant que ceux associés aux diplomés
|
||||||
|
self.suivis: dict[int, pe_rcs.RCS] = {}
|
||||||
|
"""Association entre chaque étudiant et le SxTag ou RCSTag à prendre
|
||||||
|
pour l'aggrégat"""
|
||||||
|
for etudid in self.diplomes_ids:
|
||||||
|
self.suivis[etudid] = suivis[etudid][nom_rcs]
|
||||||
|
|
||||||
|
# Les données sur les tags
|
||||||
|
self.tags_sorted = self._do_taglist()
|
||||||
|
"""Liste des tags (triés par ordre alphabétique)"""
|
||||||
|
|
||||||
|
# Les données sur les UEs (si SxTag) ou compétences (si RCSTag)
|
||||||
|
self.champs_sorted = self._do_ues_ou_competences_list()
|
||||||
|
|
||||||
|
# Construit la matrice de notes
|
||||||
|
etudids_sorted = sorted(list(self.diplomes_ids))
|
||||||
|
|
||||||
|
self.nom = self.get_repr()
|
||||||
|
"""Représentation textuelle de l'interclassement"""
|
||||||
|
|
||||||
|
# Synthétise les moyennes/classements par tag
|
||||||
|
self.moyennes_tags: dict[str, pe_moytag.MoyennesTag] = {}
|
||||||
|
for tag in self.tags_sorted:
|
||||||
|
notes = self.compute_notes_matrice(tag, etudids_sorted, self.champs_sorted)
|
||||||
|
coeffs = self.compute_coeffs_matrice(
|
||||||
|
tag, etudids_sorted, self.champs_sorted
|
||||||
|
)
|
||||||
|
self.moyennes_tags[tag] = pe_moytag.MoyennesTag(
|
||||||
|
tag,
|
||||||
|
self.type,
|
||||||
|
notes,
|
||||||
|
coeffs, # limite les moyennes aux étudiants de la promo
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_repr(self) -> str:
|
||||||
|
"""Une représentation textuelle"""
|
||||||
|
return f"{self.nom_rcs} par {self.type}"
|
||||||
|
|
||||||
|
def _do_taglist(self):
|
||||||
|
"""Synthétise les tags à partir des TableTags (SXTag ou RCSTag)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Une liste de tags triés par ordre alphabétique
|
||||||
|
"""
|
||||||
|
tags = []
|
||||||
|
for rcstag in self.rcstags.values():
|
||||||
|
tags.extend(rcstag.tags_sorted)
|
||||||
|
return sorted(set(tags))
|
||||||
|
|
||||||
|
def compute_notes_matrice(
|
||||||
|
self, tag, etudids_sorted: list[int], champs_sorted: list[str]
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""Construit la matrice de notes (etudids x champs) en
|
||||||
|
reportant les moyennes obtenues par les étudiants
|
||||||
|
aux semestres de l'aggrégat pour le tag visé.
|
||||||
|
|
||||||
|
Les champs peuvent être des acronymes d'UEs ou des compétences.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
etudids_sorted: Les etudids des étudiants (diplômés) triés
|
||||||
|
champs_sorted: Les champs (UE ou compétences) à faire apparaitre dans la matrice
|
||||||
|
Return:
|
||||||
|
Le dataFrame (etudids x champs)
|
||||||
|
reportant les moyennes des étudiants aux champs
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Partant d'un dataframe vierge
|
||||||
|
df = pd.DataFrame(np.nan, index=etudids_sorted, columns=champs_sorted)
|
||||||
|
|
||||||
|
for rcstag in self.rcstags.values():
|
||||||
|
# Charge les moyennes au tag d'un RCStag
|
||||||
|
if tag in rcstag.moyennes_tags:
|
||||||
|
moytag: pd.DataFrame = rcstag.moyennes_tags[tag].matrice_notes
|
||||||
|
|
||||||
|
# Etudiants/Champs communs entre le RCSTag et les données interclassées
|
||||||
|
(
|
||||||
|
etudids_communs,
|
||||||
|
champs_communs,
|
||||||
|
) = pe_comp.find_index_and_columns_communs(df, moytag)
|
||||||
|
|
||||||
|
# Injecte les notes par tag
|
||||||
|
df.loc[etudids_communs, champs_communs] = moytag.loc[
|
||||||
|
etudids_communs, champs_communs
|
||||||
|
]
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def compute_coeffs_matrice(
|
||||||
|
self, tag, etudids_sorted: list[int], champs_sorted: list[str]
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""Idem que compute_notes_matrices mais pour les coeffs
|
||||||
|
|
||||||
|
Args:
|
||||||
|
etudids_sorted: Les etudids des étudiants (diplômés) triés
|
||||||
|
champs_sorted: Les champs (UE ou compétences) à faire apparaitre dans la matrice
|
||||||
|
Return:
|
||||||
|
Le dataFrame (etudids x champs)
|
||||||
|
reportant les moyennes des étudiants aux champs
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Partant d'un dataframe vierge
|
||||||
|
df = pd.DataFrame(np.nan, index=etudids_sorted, columns=champs_sorted)
|
||||||
|
|
||||||
|
for rcstag in self.rcstags.values():
|
||||||
|
if tag in rcstag.moyennes_tags:
|
||||||
|
# Charge les coeffs au tag d'un RCStag
|
||||||
|
coeffs: pd.DataFrame = rcstag.moyennes_tags[tag].matrice_notes
|
||||||
|
|
||||||
|
# Etudiants/Champs communs entre le RCSTag et les données interclassées
|
||||||
|
(
|
||||||
|
etudids_communs,
|
||||||
|
champs_communs,
|
||||||
|
) = pe_comp.find_index_and_columns_communs(df, coeffs)
|
||||||
|
|
||||||
|
# Injecte les coeffs par tag
|
||||||
|
df.loc[etudids_communs, champs_communs] = coeffs.loc[
|
||||||
|
etudids_communs, champs_communs
|
||||||
|
]
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def _do_ues_ou_competences_list(self) -> list[str]:
|
||||||
|
"""Synthétise les champs (UEs ou compétences) sur lesquels
|
||||||
|
sont calculés les moyennes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Un dictionnaire {'acronyme_ue' : 'compétences'}
|
||||||
|
"""
|
||||||
|
dict_champs = []
|
||||||
|
for rcstag in self.rcstags.values():
|
||||||
|
if isinstance(rcstag, pe_sxtag.SxTag):
|
||||||
|
champs = rcstag.acronymes_sorted
|
||||||
|
else: # pe_rcstag.RCSTag
|
||||||
|
champs = rcstag.competences_sorted
|
||||||
|
dict_champs.extend(champs)
|
||||||
|
return sorted(set(dict_champs))
|
||||||
|
|
||||||
|
def has_tags(self):
|
||||||
|
"""Indique si l'interclassement a des tags (cas d'un
|
||||||
|
interclassement sur un S5 qui n'a pas eu lieu)
|
||||||
|
"""
|
||||||
|
return len(self.tags_sorted) > 0
|
||||||
|
|
||||||
|
def _un_rcstag_significatif(self, rcsstags: dict[(str, int):pe_tabletags]):
|
||||||
|
"""Renvoie un rcstag significatif (ayant des tags et des notes aux tags)
|
||||||
|
parmi le dictionnaire de rcsstags"""
|
||||||
|
for rcstag_id, rcstag in rcsstags.items():
|
||||||
|
moystags: pe_moytag.MoyennesTag = rcstag.moyennes_tags
|
||||||
|
for tag, moystag in moystags.items():
|
||||||
|
tags_tries = moystag.get_all_significant_tags()
|
||||||
|
if tags_tries:
|
||||||
|
return moystag
|
||||||
|
return None
|
||||||
|
|
||||||
|
def compute_df_synthese_moyennes_tag(
|
||||||
|
self, tag, aggregat=None, type_colonnes=False
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""Construit le dataframe retraçant pour les données des moyennes
|
||||||
|
pour affichage dans la synthèse du jury PE. (cf. to_df())
|
||||||
|
|
||||||
|
Args:
|
||||||
|
etudids_sorted: Les etudids des étudiants (diplômés) triés
|
||||||
|
champs_sorted: Les champs (UE ou compétences) à faire apparaitre dans la matrice
|
||||||
|
Return:
|
||||||
|
Le dataFrame (etudids x champs)
|
||||||
|
reportant les moyennes des étudiants aux champs
|
||||||
|
"""
|
||||||
|
if aggregat:
|
||||||
|
assert (
|
||||||
|
aggregat == self.nom_rcs
|
||||||
|
), "L'interclassement ciblé ne correspond pas à l'aggrégat visé"
|
||||||
|
|
||||||
|
etudids_sorted = sorted(list(self.diplomes_ids))
|
||||||
|
|
||||||
|
if self.rcstags:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Un rcstag significatif pour initier les colonnes
|
||||||
|
moytag = self._un_rcstag_significatif(self.rcstags)
|
||||||
|
if not moytag:
|
||||||
|
return None
|
||||||
|
df_moytag = moytag.to_df(
|
||||||
|
aggregat=aggregat,
|
||||||
|
cohorte="Groupe",
|
||||||
|
)
|
||||||
|
colonnes = list(df_moytag.columns)
|
||||||
|
|
||||||
|
# Partant d'un dataframe vierge
|
||||||
|
df = pd.DataFrame(index=etudids_sorted, columns=colonnes) # colonnes)
|
||||||
|
for col in colonnes:
|
||||||
|
if "rang" in col:
|
||||||
|
df[col] = df[col].astype(str)
|
||||||
|
df.columns = list(range(len(colonnes)))
|
||||||
|
|
||||||
|
for rcstag in self.rcstags.values():
|
||||||
|
# Charge les moyennes au tag d'un RCStag (SemX ou RCSXTag)
|
||||||
|
if tag in rcstag.moyennes_tags:
|
||||||
|
# Les infos sur les moyennes du tag
|
||||||
|
moytag: pe_moytag.MoyennesTag = rcstag.moyennes_tags[tag]
|
||||||
|
df_moytag = moytag.to_df(
|
||||||
|
aggregat=aggregat,
|
||||||
|
cohorte="Groupe",
|
||||||
|
)
|
||||||
|
df_moytag.columns = list(range(len(colonnes)))
|
||||||
|
|
||||||
|
# Etudiants/Champs communs entre le df et les données interclassées
|
||||||
|
(
|
||||||
|
etudids_communs,
|
||||||
|
champs_communs, # les colonnes de synthèse
|
||||||
|
) = pe_comp.find_index_and_columns_communs(df, df_moytag)
|
||||||
|
|
||||||
|
# Injecte les données par tag
|
||||||
|
df.loc[etudids_communs, champs_communs] = df_moytag.loc[
|
||||||
|
etudids_communs, champs_communs
|
||||||
|
]
|
||||||
|
|
||||||
|
# Refixe les colonnes
|
||||||
|
df.columns = colonnes
|
||||||
|
return df
|
@ -1,13 +1,12 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from app import comp
|
|
||||||
from app.comp.moy_sem import comp_ranks_series
|
from app.comp.moy_sem import comp_ranks_series
|
||||||
from app.pe import pe_affichage
|
from app.pe import pe_affichage
|
||||||
|
|
||||||
|
|
||||||
class Moyenne:
|
class Moyenne:
|
||||||
CRITERES = [
|
COLONNES = [
|
||||||
"note",
|
"note",
|
||||||
"classement",
|
"classement",
|
||||||
"rang",
|
"rang",
|
||||||
@ -17,6 +16,9 @@ class Moyenne:
|
|||||||
"nb_etuds",
|
"nb_etuds",
|
||||||
"nb_inscrits",
|
"nb_inscrits",
|
||||||
]
|
]
|
||||||
|
"""Colonnes du df"""
|
||||||
|
|
||||||
|
COLONNES_SYNTHESE = ["note", "rang", "min", "max", "moy"]
|
||||||
|
|
||||||
def __init__(self, notes: pd.Series):
|
def __init__(self, notes: pd.Series):
|
||||||
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
||||||
@ -58,7 +60,7 @@ class Moyenne:
|
|||||||
df = pd.DataFrame(
|
df = pd.DataFrame(
|
||||||
np.nan,
|
np.nan,
|
||||||
index=self.etudids,
|
index=self.etudids,
|
||||||
columns=Moyenne.CRITERES,
|
columns=Moyenne.COLONNES,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Supprime d'éventuelles chaines de caractères dans les notes
|
# Supprime d'éventuelles chaines de caractères dans les notes
|
||||||
@ -67,14 +69,18 @@ class Moyenne:
|
|||||||
|
|
||||||
# Les nb d'étudiants & nb d'inscrits
|
# Les nb d'étudiants & nb d'inscrits
|
||||||
df["nb_etuds"] = len(self.etudids)
|
df["nb_etuds"] = len(self.etudids)
|
||||||
|
df["nb_etuds"] = df["nb_etuds"].astype(int)
|
||||||
|
|
||||||
# Les étudiants dont la note n'est pas nulle
|
# Les étudiants dont la note n'est pas nulle
|
||||||
inscrits_ids = notes[notes.notnull()].index.to_list()
|
inscrits_ids = notes[notes.notnull()].index.to_list()
|
||||||
df.loc[inscrits_ids, "nb_inscrits"] = len(inscrits_ids)
|
df.loc[inscrits_ids, "nb_inscrits"] = len(inscrits_ids)
|
||||||
|
# df["nb_inscrits"] = df["nb_inscrits"].astype(int)
|
||||||
|
|
||||||
# Le classement des inscrits
|
# Le classement des inscrits
|
||||||
notes_non_nulles = notes[inscrits_ids]
|
notes_non_nulles = notes[inscrits_ids]
|
||||||
(class_str, class_int) = comp_ranks_series(notes_non_nulles)
|
(class_str, class_int) = comp_ranks_series(notes_non_nulles)
|
||||||
df.loc[inscrits_ids, "classement"] = class_int
|
df.loc[inscrits_ids, "classement"] = class_int
|
||||||
|
# df["classement"] = df["classement"].astype(int)
|
||||||
|
|
||||||
# Le rang (classement/nb_inscrit)
|
# Le rang (classement/nb_inscrit)
|
||||||
df["rang"] = df["rang"].astype(str)
|
df["rang"] = df["rang"].astype(str)
|
||||||
@ -91,6 +97,10 @@ class Moyenne:
|
|||||||
|
|
||||||
return df
|
return df
|
||||||
|
|
||||||
|
def get_df_synthese(self):
|
||||||
|
"""Renvoie le df de synthese limité aux colonnes de synthese"""
|
||||||
|
return self.df[self.COLONNES_SYNTHESE]
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
"""Renvoie un dictionnaire de synthèse des moyennes/classements/statistiques générale (but)"""
|
"""Renvoie un dictionnaire de synthèse des moyennes/classements/statistiques générale (but)"""
|
||||||
synthese = {
|
synthese = {
|
||||||
@ -103,10 +113,6 @@ class Moyenne:
|
|||||||
}
|
}
|
||||||
return synthese
|
return synthese
|
||||||
|
|
||||||
def get_notes(self):
|
|
||||||
"""Série des notes, arrondies à 2 chiffres après la virgule"""
|
|
||||||
return self.df_gen["note"].round(2)
|
|
||||||
|
|
||||||
def get_rangs_inscrits(self) -> pd.Series:
|
def get_rangs_inscrits(self) -> pd.Series:
|
||||||
"""Série des rangs classement/nbre_inscrit"""
|
"""Série des rangs classement/nbre_inscrit"""
|
||||||
return self.df_gen["rang"]
|
return self.df_gen["rang"]
|
||||||
@ -151,91 +157,3 @@ class Moyenne:
|
|||||||
def is_significatif(self) -> bool:
|
def is_significatif(self) -> bool:
|
||||||
"""Indique si la moyenne est significative (c'est-à-dire à des notes)"""
|
"""Indique si la moyenne est significative (c'est-à-dire à des notes)"""
|
||||||
return self.synthese["nb_inscrits"] > 0
|
return self.synthese["nb_inscrits"] > 0
|
||||||
|
|
||||||
|
|
||||||
class MoyennesTag:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
tag: str,
|
|
||||||
matrice_notes: pd.DataFrame, # etudids x colonnes
|
|
||||||
matrice_coeffs: pd.DataFrame, # etudids x colonnes
|
|
||||||
):
|
|
||||||
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
|
||||||
d'étudiants à un tag donné, en différenciant les notes
|
|
||||||
obtenues aux UE et au général (toutes UEs confondues)
|
|
||||||
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tag: Un tag
|
|
||||||
matrice_notes: Les moyennes (etudid x acronymes_ues ou etudid x compétences) aux différentes UEs ou compétences
|
|
||||||
matrice_coeffs: Les coeff à appliquer pour le calcul de la moyenne générale
|
|
||||||
# notes_gen: Une série de notes (moyenne) sous forme d'un ``pd.Series`` (toutes UEs confondues)
|
|
||||||
"""
|
|
||||||
self.tag = tag
|
|
||||||
"""Le tag associé aux moyennes"""
|
|
||||||
|
|
||||||
# Les moyennes par UE
|
|
||||||
self.matrice_notes: pd.DataFrame = matrice_notes
|
|
||||||
"""Les notes aux UEs ou aux compétences (DataFrame)"""
|
|
||||||
|
|
||||||
self.matrice_coeffs_moy_gen: pd.DataFrame = matrice_coeffs
|
|
||||||
"""Les coeffs à appliquer pour le calcul des moyennes générales
|
|
||||||
(toutes UE ou compétences confondues). NaN si étudiant non inscrit"""
|
|
||||||
|
|
||||||
self.moyennes: dict[int, pd.DataFrame] = {}
|
|
||||||
"""Les dataframes retraçant les moyennes/classements/statistiques des étudiants aux UEs"""
|
|
||||||
colonnes = self.matrice_notes.columns
|
|
||||||
for col in colonnes: # if ue.type != UE_SPORT:
|
|
||||||
notes = matrice_notes[col]
|
|
||||||
self.moyennes[col] = Moyenne(notes)
|
|
||||||
|
|
||||||
# Les moyennes générales
|
|
||||||
notes_gen = pd.Series(np.nan, index=self.matrice_notes.index)
|
|
||||||
"""Les notes générales (moyenne toutes UEs confonudes)"""
|
|
||||||
if self.has_notes():
|
|
||||||
notes_gen = self.compute_moy_gen(
|
|
||||||
self.matrice_notes, self.matrice_coeffs_moy_gen
|
|
||||||
)
|
|
||||||
self.notes_gen = notes_gen
|
|
||||||
self.moyenne_gen = Moyenne(notes_gen)
|
|
||||||
"""Le dataframe retraçant les moyennes/classements/statistiques général"""
|
|
||||||
|
|
||||||
def has_notes(self):
|
|
||||||
"""Détermine si les moyennes (aux UEs ou aux compétences)
|
|
||||||
ont des notes
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True si la moytag a des notes, False sinon
|
|
||||||
"""
|
|
||||||
notes = self.matrice_notes
|
|
||||||
nbre_nan = notes.isna().sum().sum()
|
|
||||||
nbre_notes_potentielles = len(notes.index) * len(notes.columns)
|
|
||||||
if nbre_nan == nbre_notes_potentielles:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def compute_moy_gen(self, moys: pd.DataFrame, coeffs: pd.DataFrame) -> pd.Series:
|
|
||||||
"""Calcule la moyenne générale (toutes UE/compétences confondus)
|
|
||||||
pour le tag considéré, en pondérant les notes obtenues au UE
|
|
||||||
par les coeff (généralement les crédits ECTS).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
moys: Les moyennes etudids x acronymes_ues/compétences
|
|
||||||
coeff: Les coeff etudids x ueids/compétences
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Calcule la moyenne générale dans le semestre (pondérée par le ECTS)
|
|
||||||
try:
|
|
||||||
moy_gen_tag = comp.moy_sem.compute_sem_moys_apc_using_ects(
|
|
||||||
moys,
|
|
||||||
coeffs.fillna(0.0),
|
|
||||||
# formation_id=self.formsemestre.formation_id,
|
|
||||||
skip_empty_ues=True,
|
|
||||||
)
|
|
||||||
except TypeError as e:
|
|
||||||
raise TypeError(
|
|
||||||
"Pb dans le calcul de la moyenne toutes UEs/compétences confondues"
|
|
||||||
)
|
|
||||||
|
|
||||||
return moy_gen_tag
|
|
155
app/pe/moys/pe_moytag.py
Normal file
155
app/pe/moys/pe_moytag.py
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from app import comp
|
||||||
|
from app.comp.moy_sem import comp_ranks_series
|
||||||
|
from app.pe.moys import pe_moy
|
||||||
|
|
||||||
|
|
||||||
|
CODE_MOY_UE = "UEs"
|
||||||
|
CODE_MOY_COMPETENCES = "Compétences"
|
||||||
|
CHAMP_GENERAL = "Général" # Nom du champ de la moyenne générale
|
||||||
|
|
||||||
|
|
||||||
|
class MoyennesTag:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
tag: str,
|
||||||
|
type_moyenne: str,
|
||||||
|
matrice_notes: pd.DataFrame, # etudids x colonnes
|
||||||
|
matrice_coeffs: pd.DataFrame, # etudids x colonnes
|
||||||
|
):
|
||||||
|
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
||||||
|
d'étudiants à un tag donné, en différenciant les notes
|
||||||
|
obtenues aux UE et au général (toutes UEs confondues)
|
||||||
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag: Un tag
|
||||||
|
matrice_notes: Les moyennes (etudid x acronymes_ues ou etudid x compétences) aux différentes UEs ou compétences
|
||||||
|
matrice_coeffs: Les coeff à appliquer pour le calcul de la moyenne générale
|
||||||
|
# notes_gen: Une série de notes (moyenne) sous forme d'un ``pd.Series`` (toutes UEs confondues)
|
||||||
|
"""
|
||||||
|
self.tag = tag
|
||||||
|
"""Le tag associé aux moyennes"""
|
||||||
|
|
||||||
|
self.type = type_moyenne
|
||||||
|
"""Le type de moyennes (par UEs ou par compétences)"""
|
||||||
|
|
||||||
|
# Les moyennes par UE
|
||||||
|
self.matrice_notes: pd.DataFrame = matrice_notes
|
||||||
|
"""Les notes aux UEs ou aux compétences (DataFrame)"""
|
||||||
|
|
||||||
|
self.matrice_coeffs_moy_gen: pd.DataFrame = matrice_coeffs
|
||||||
|
"""Les coeffs à appliquer pour le calcul des moyennes générales
|
||||||
|
(toutes UE ou compétences confondues). NaN si étudiant non inscrit"""
|
||||||
|
|
||||||
|
self.moyennes: dict[int, pd.DataFrame] = {}
|
||||||
|
"""Les dataframes retraçant les moyennes/classements/statistiques des étudiants aux UEs"""
|
||||||
|
|
||||||
|
self.etudids = self.matrice_notes.index
|
||||||
|
"""Les étudids renseignés dans les moyennes"""
|
||||||
|
|
||||||
|
self.champs = self.matrice_notes.columns
|
||||||
|
"""Les champs (acronymes d'UE ou compétences) renseignés dans les moyennes"""
|
||||||
|
for col in self.champs: # if ue.type != UE_SPORT:
|
||||||
|
notes = matrice_notes[col]
|
||||||
|
self.moyennes[col] = pe_moy.Moyenne(notes)
|
||||||
|
|
||||||
|
# Les moyennes générales
|
||||||
|
notes_gen = pd.Series(np.nan, index=self.matrice_notes.index)
|
||||||
|
"""Les notes générales (moyenne toutes UEs confonudes)"""
|
||||||
|
if self.has_notes():
|
||||||
|
notes_gen = self.compute_moy_gen(
|
||||||
|
self.matrice_notes, self.matrice_coeffs_moy_gen
|
||||||
|
)
|
||||||
|
self.notes_gen = notes_gen
|
||||||
|
self.moyenne_gen = pe_moy.Moyenne(notes_gen)
|
||||||
|
"""Le dataframe retraçant les moyennes/classements/statistiques général"""
|
||||||
|
|
||||||
|
def has_notes(self):
|
||||||
|
"""Détermine si les moyennes (aux UEs ou aux compétences)
|
||||||
|
ont des notes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True si la moytag a des notes, False sinon
|
||||||
|
"""
|
||||||
|
notes = self.matrice_notes
|
||||||
|
nbre_nan = notes.isna().sum().sum()
|
||||||
|
nbre_notes_potentielles = len(notes.index) * len(notes.columns)
|
||||||
|
if nbre_nan == nbre_notes_potentielles:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def compute_moy_gen(self, moys: pd.DataFrame, coeffs: pd.DataFrame) -> pd.Series:
|
||||||
|
"""Calcule la moyenne générale (toutes UE/compétences confondus)
|
||||||
|
pour le tag considéré, en pondérant les notes obtenues au UE
|
||||||
|
par les coeff (généralement les crédits ECTS).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
moys: Les moyennes etudids x acronymes_ues/compétences
|
||||||
|
coeff: Les coeff etudids x ueids/compétences
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Calcule la moyenne générale dans le semestre (pondérée par le ECTS)
|
||||||
|
try:
|
||||||
|
moy_gen_tag = comp.moy_sem.compute_sem_moys_apc_using_ects(
|
||||||
|
moys,
|
||||||
|
coeffs.fillna(0.0),
|
||||||
|
# formation_id=self.formsemestre.formation_id,
|
||||||
|
skip_empty_ues=True,
|
||||||
|
)
|
||||||
|
except TypeError as e:
|
||||||
|
raise TypeError(
|
||||||
|
"Pb dans le calcul de la moyenne toutes UEs/compétences confondues"
|
||||||
|
)
|
||||||
|
|
||||||
|
return moy_gen_tag
|
||||||
|
|
||||||
|
def to_df(self, aggregat=None, cohorte=None) -> pd.DataFrame:
|
||||||
|
"""Renvoie le df synthétisant l'ensemble des données
|
||||||
|
connues
|
||||||
|
Adapte les intitulés des colonnes aux données fournies
|
||||||
|
(nom d'aggrégat, type de cohorte).
|
||||||
|
"""
|
||||||
|
|
||||||
|
etudids_sorted = sorted(self.etudids)
|
||||||
|
|
||||||
|
df = pd.DataFrame(index=etudids_sorted)
|
||||||
|
|
||||||
|
# Ajout des notes pour tous les champs
|
||||||
|
champs = list(self.champs)
|
||||||
|
for champ in champs:
|
||||||
|
df_champ = self.moyennes[champ].get_df_synthese() # le dataframe
|
||||||
|
# Renomme les colonnes
|
||||||
|
cols = [
|
||||||
|
get_colonne_df(aggregat, self.tag, champ, cohorte, critere)
|
||||||
|
for critere in pe_moy.Moyenne.COLONNES_SYNTHESE
|
||||||
|
]
|
||||||
|
df_champ.columns = cols
|
||||||
|
df = df.join(df_champ)
|
||||||
|
|
||||||
|
# Ajoute la moy générale
|
||||||
|
df_moy_gen = self.moyenne_gen.get_df_synthese()
|
||||||
|
cols = [
|
||||||
|
get_colonne_df(aggregat, self.tag, CHAMP_GENERAL, cohorte, critere)
|
||||||
|
for critere in pe_moy.Moyenne.COLONNES_SYNTHESE
|
||||||
|
]
|
||||||
|
df_moy_gen.columns = cols
|
||||||
|
df = df.join(df_moy_gen)
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def get_colonne_df(aggregat, tag, champ, cohorte, critere):
|
||||||
|
"""Renvoie le tuple (aggregat, tag, champ, cohorte, critere)
|
||||||
|
utilisé pour désigner les colonnes du df"""
|
||||||
|
liste_champs = []
|
||||||
|
if aggregat:
|
||||||
|
liste_champs += [aggregat]
|
||||||
|
liste_champs += [tag, champ]
|
||||||
|
if cohorte:
|
||||||
|
liste_champs += [cohorte]
|
||||||
|
liste_champs += [critere]
|
||||||
|
return tuple(liste_champs)
|
@ -36,19 +36,17 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
@author: barasc
|
@author: barasc
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app.comp.res_sem import load_formsemestre_results
|
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre
|
||||||
from app.pe import pe_affichage
|
from app.pe import pe_affichage
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from app.pe.rcss import pe_rcs, pe_rcsemx
|
from app.pe.rcss import pe_rcs, pe_rcsemx
|
||||||
import app.pe.pe_sxtag as pe_sxtag
|
import app.pe.moys.pe_sxtag as pe_sxtag
|
||||||
import app.pe.pe_comp as pe_comp
|
import app.pe.pe_comp as pe_comp
|
||||||
from app.pe.pe_tabletags import TableTag
|
from app.pe.moys import pe_tabletags, pe_moytag
|
||||||
from app.pe.pe_moytag import MoyennesTag
|
|
||||||
|
|
||||||
|
|
||||||
class RCSTag(TableTag):
|
class RCSTag(pe_tabletags.TableTag):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, rcsemx: pe_rcsemx.RCSemX, sxstags: dict[(str, int) : pe_sxtag.SxTag]
|
self, rcsemx: pe_rcsemx.RCSemX, sxstags: dict[(str, int) : pe_sxtag.SxTag]
|
||||||
):
|
):
|
||||||
@ -62,7 +60,7 @@ class RCSTag(TableTag):
|
|||||||
rcsemx: Le RCSemX (identifié par un nom et l'id de son semestre terminal)
|
rcsemx: Le RCSemX (identifié par un nom et l'id de son semestre terminal)
|
||||||
sxstags: Les données sur les SemX taggués
|
sxstags: Les données sur les SemX taggués
|
||||||
"""
|
"""
|
||||||
TableTag.__init__(self)
|
pe_tabletags.TableTag.__init__(self)
|
||||||
|
|
||||||
self.rcs_id: tuple(str, int) = rcsemx.rcs_id
|
self.rcs_id: tuple(str, int) = rcsemx.rcs_id
|
||||||
"""Identifiant du RCSTag (identique au RCSemX sur lequel il s'appuie)"""
|
"""Identifiant du RCSTag (identique au RCSemX sur lequel il s'appuie)"""
|
||||||
@ -121,10 +119,9 @@ class RCSTag(TableTag):
|
|||||||
pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}")
|
pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}")
|
||||||
|
|
||||||
# Les moyennes
|
# Les moyennes
|
||||||
self.moyennes_tags: dict[str, MoyennesTag] = {}
|
self.moyennes_tags: dict[str, pe_moytag.MoyennesTag] = {}
|
||||||
"""Synthétise les moyennes/classements par tag (qu'ils soient personnalisé ou de compétences)"""
|
"""Synthétise les moyennes/classements par tag (qu'ils soient personnalisé ou de compétences)"""
|
||||||
for tag in self.tags_sorted:
|
for tag in self.tags_sorted:
|
||||||
print(tag)
|
|
||||||
# Cube de notes (etudids_sorted x compétences_sorted x sxstags)
|
# Cube de notes (etudids_sorted x compétences_sorted x sxstags)
|
||||||
notes_df, notes_cube = self.compute_notes_comps_cube(
|
notes_df, notes_cube = self.compute_notes_comps_cube(
|
||||||
tag, self.etudids_sorted, self.competences_sorted, self.sxstags
|
tag, self.etudids_sorted, self.competences_sorted, self.sxstags
|
||||||
@ -147,8 +144,11 @@ class RCSTag(TableTag):
|
|||||||
coeffs_cube, notes_cube, self.etudids_sorted, self.competences_sorted
|
coeffs_cube, notes_cube, self.etudids_sorted, self.competences_sorted
|
||||||
)
|
)
|
||||||
# Mémorise les moyennes et les coeff associés
|
# Mémorise les moyennes et les coeff associés
|
||||||
self.moyennes_tags[tag] = MoyennesTag(
|
self.moyennes_tags[tag] = pe_moytag.MoyennesTag(
|
||||||
tag, moys_competences, matrice_coeffs_moy_gen
|
tag,
|
||||||
|
pe_moytag.CODE_MOY_COMPETENCES,
|
||||||
|
moys_competences,
|
||||||
|
matrice_coeffs_moy_gen,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
@ -37,16 +37,13 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
"""
|
"""
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from app import db, ScoValueError
|
from app import ScoValueError
|
||||||
from app import comp
|
from app import comp
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
from app.comp.res_sem import load_formsemestre_results
|
|
||||||
from app.models import FormSemestre, UniteEns
|
from app.models import FormSemestre, UniteEns
|
||||||
from app.models.moduleimpls import ModuleImpl
|
|
||||||
import app.pe.pe_affichage as pe_affichage
|
import app.pe.pe_affichage as pe_affichage
|
||||||
import app.pe.pe_etudiant as pe_etudiant
|
import app.pe.pe_etudiant as pe_etudiant
|
||||||
import app.pe.pe_tabletags as pe_tabletags
|
from app.pe.moys import pe_tabletags, pe_moytag
|
||||||
from app.pe.pe_moytag import MoyennesTag
|
|
||||||
from app.scodoc import sco_tag_module
|
from app.scodoc import sco_tag_module
|
||||||
from app.scodoc import codes_cursus as sco_codes
|
from app.scodoc import codes_cursus as sco_codes
|
||||||
|
|
||||||
@ -126,17 +123,20 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
|||||||
# pe_affichage.pe_print(f" -> Traitement du tag {tag}")
|
# pe_affichage.pe_print(f" -> Traitement du tag {tag}")
|
||||||
infos_tag = tags_dict["personnalises"][tag]
|
infos_tag = tags_dict["personnalises"][tag]
|
||||||
moy_ues_tag = self.compute_moy_ues_tag(infos_tag)
|
moy_ues_tag = self.compute_moy_ues_tag(infos_tag)
|
||||||
self.moyennes_tags[tag] = MoyennesTag(
|
self.moyennes_tags[tag] = pe_moytag.MoyennesTag(
|
||||||
tag, moy_ues_tag, self.matrice_coeffs_moy_gen
|
tag, pe_moytag.CODE_MOY_UE, moy_ues_tag, self.matrice_coeffs_moy_gen
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ajoute les moyennes par UEs + la moyenne générale (but)
|
# Ajoute les moyennes par UEs + la moyenne générale (but)
|
||||||
moy_gen = self.compute_moy_gen()
|
moy_gen = self.compute_moy_gen()
|
||||||
self.moyennes_tags["but"] = MoyennesTag(
|
self.moyennes_tags["but"] = pe_moytag.MoyennesTag(
|
||||||
"but", moy_gen, self.matrice_coeffs_moy_gen # , moy_gen_but
|
"but",
|
||||||
|
pe_moytag.CODE_MOY_UE,
|
||||||
|
moy_gen,
|
||||||
|
self.matrice_coeffs_moy_gen, # , moy_gen_but
|
||||||
)
|
)
|
||||||
|
|
||||||
self.tags_sorted = self.get_all_tags()
|
self.tags_sorted = self.get_all_significant_tags()
|
||||||
"""Tags (personnalisés+compétences) par ordre alphabétique"""
|
"""Tags (personnalisés+compétences) par ordre alphabétique"""
|
||||||
|
|
||||||
def get_repr(self, verbose=False) -> str:
|
def get_repr(self, verbose=False) -> str:
|
||||||
@ -302,11 +302,12 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
|||||||
dict_tags["auto"] = {"but": {}}
|
dict_tags["auto"] = {"but": {}}
|
||||||
|
|
||||||
noms_tags_auto = sorted(list(set(dict_tags["auto"].keys()))) # + noms_tags_comp
|
noms_tags_auto = sorted(list(set(dict_tags["auto"].keys()))) # + noms_tags_comp
|
||||||
|
aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto])
|
||||||
|
aff_tags_perso = ", ".join([f"👜{nom}" for nom in noms_tags_perso])
|
||||||
# Affichage
|
# Affichage
|
||||||
pe_affichage.pe_print(
|
pe_affichage.pe_print(
|
||||||
f"* Tags du programme de formation : {', '.join(noms_tags_perso)} "
|
f"* Tags du programme de formation : {aff_tags_perso} + "
|
||||||
+ f"Tags automatiques : {', '.join(noms_tags_auto)}"
|
+ f"Tags automatiques : {aff_tags_auto}"
|
||||||
)
|
)
|
||||||
return dict_tags
|
return dict_tags
|
||||||
|
|
@ -37,16 +37,15 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from app.pe import pe_affichage, pe_comp
|
from app.pe import pe_affichage, pe_comp
|
||||||
import app.pe.pe_ressemtag as pe_ressemtag
|
import app.pe.moys.pe_ressemtag as pe_ressemtag
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from app.pe.pe_tabletags import TableTag
|
from app.pe.moys import pe_moytag, pe_tabletags
|
||||||
from app.pe.pe_moytag import MoyennesTag
|
|
||||||
import app.pe.rcss.pe_trajectoires as pe_trajectoires
|
import app.pe.rcss.pe_trajectoires as pe_trajectoires
|
||||||
|
|
||||||
|
|
||||||
class SxTag(TableTag):
|
class SxTag(pe_tabletags.TableTag):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
sxtag_id: (str, int),
|
sxtag_id: (str, int),
|
||||||
@ -80,7 +79,7 @@ class SxTag(TableTag):
|
|||||||
les semestres à regrouper et les résultats/moyennes par tag des
|
les semestres à regrouper et les résultats/moyennes par tag des
|
||||||
semestres
|
semestres
|
||||||
"""
|
"""
|
||||||
TableTag.__init__(self)
|
pe_tabletags.TableTag.__init__(self)
|
||||||
|
|
||||||
assert sxtag_id and len(sxtag_id) == 2 and sxtag_id[1] in ressembuttags
|
assert sxtag_id and len(sxtag_id) == 2 and sxtag_id[1] in ressembuttags
|
||||||
|
|
||||||
@ -186,8 +185,11 @@ class SxTag(TableTag):
|
|||||||
self.__aff_profil_coeff_ects(tag)
|
self.__aff_profil_coeff_ects(tag)
|
||||||
|
|
||||||
# Mémorise les infos pour la moyennes au tag
|
# Mémorise les infos pour la moyennes au tag
|
||||||
self.moyennes_tags[tag] = MoyennesTag(
|
self.moyennes_tags[tag] = pe_moytag.MoyennesTag(
|
||||||
tag, matrice_moys_ues, self.matrice_coeffs_moy_gen
|
tag,
|
||||||
|
pe_moytag.CODE_MOY_UE,
|
||||||
|
matrice_moys_ues,
|
||||||
|
self.matrice_coeffs_moy_gen,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __aff_profil_coeff_ects(self, tag):
|
def __aff_profil_coeff_ects(self, tag):
|
204
app/pe/moys/pe_tabletags.py
Normal file
204
app/pe/moys/pe_tabletags.py
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
# -*- 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 Thu Sep 8 09:36:33 2016
|
||||||
|
|
||||||
|
@author: barasc
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from app.models import Identite
|
||||||
|
from app.pe.moys import pe_moytag
|
||||||
|
|
||||||
|
TAGS_RESERVES = ["but"]
|
||||||
|
|
||||||
|
CHAMPS_ADMINISTRATIFS = ["Civilité", "Nom", "Prénom"]
|
||||||
|
|
||||||
|
|
||||||
|
class TableTag(object):
|
||||||
|
def __init__(self):
|
||||||
|
"""Classe centralisant différentes méthodes communes aux
|
||||||
|
SemestreTag, TrajectoireTag, AggregatInterclassTag
|
||||||
|
"""
|
||||||
|
# Les étudiants
|
||||||
|
# self.etuds: list[Identite] = None # A venir
|
||||||
|
"""Les étudiants"""
|
||||||
|
# self.etudids: list[int] = {}
|
||||||
|
"""Les etudids"""
|
||||||
|
|
||||||
|
def add_etuds(self, etuds: list[Identite]):
|
||||||
|
"""Mémorise les informations sur les étudiants
|
||||||
|
|
||||||
|
Args:
|
||||||
|
etuds: la liste des identités de l'étudiant
|
||||||
|
"""
|
||||||
|
# self.etuds = etuds
|
||||||
|
self.etudids = list({etud.etudid for etud in etuds})
|
||||||
|
|
||||||
|
def get_all_significant_tags(self):
|
||||||
|
"""Liste des tags de la table, triée par ordre alphabétique,
|
||||||
|
extraite des clés du dictionnaire ``moyennes_tags``, en ne
|
||||||
|
considérant que les moyennes ayant des notes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Liste de tags triés par ordre alphabétique
|
||||||
|
"""
|
||||||
|
tags = []
|
||||||
|
tag: str = ""
|
||||||
|
moytag: pe_moytag.MoyennesTag = None
|
||||||
|
for tag, moytag in self.moyennes_tags.items():
|
||||||
|
if moytag.has_notes():
|
||||||
|
tags.append(tag)
|
||||||
|
return sorted(tags)
|
||||||
|
|
||||||
|
def to_df(
|
||||||
|
self,
|
||||||
|
administratif=True,
|
||||||
|
aggregat=None,
|
||||||
|
tags_cibles=None,
|
||||||
|
cohorte=None,
|
||||||
|
type_colonnes=True,
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""Renvoie un dataframe listant toutes les données
|
||||||
|
des moyennes/classements/nb_inscrits/min/max/moy
|
||||||
|
des étudiants aux différents tags.
|
||||||
|
|
||||||
|
tags_cibles limitent le dataframe aux tags indiqués
|
||||||
|
type_colonnes indiquent si les colonnes doivent être passées en multiindex
|
||||||
|
|
||||||
|
Args:
|
||||||
|
administratif: Indique si les données administratives sont incluses
|
||||||
|
aggregat: l'aggrégat représenté
|
||||||
|
tags_cibles: la liste des tags ciblés
|
||||||
|
cohorte: la cohorte représentée
|
||||||
|
Returns:
|
||||||
|
Le dataframe complet de synthèse
|
||||||
|
"""
|
||||||
|
if not self.is_significatif():
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Les tags visés
|
||||||
|
tags_tries = self.get_all_significant_tags()
|
||||||
|
if not tags_cibles:
|
||||||
|
tags_cibles = tags_tries
|
||||||
|
tags_cibles = sorted(tags_cibles)
|
||||||
|
|
||||||
|
# Les tags visés avec des notes
|
||||||
|
|
||||||
|
# Les étudiants visés
|
||||||
|
if administratif:
|
||||||
|
df = df_administratif(self.etuds, aggregat, cohorte)
|
||||||
|
else:
|
||||||
|
df = pd.DataFrame(index=self.etudids)
|
||||||
|
|
||||||
|
# Ajout des données par tags
|
||||||
|
for tag in tags_cibles:
|
||||||
|
moy_tag_df = self.moyennes_tags[tag].to_df(aggregat, cohorte)
|
||||||
|
df = df.join(moy_tag_df)
|
||||||
|
|
||||||
|
# Tri par nom, prénom
|
||||||
|
if administratif:
|
||||||
|
colonnes_tries = [
|
||||||
|
_get_champ_administratif(champ, aggregat, cohorte)
|
||||||
|
for champ in CHAMPS_ADMINISTRATIFS[1:]
|
||||||
|
] # Nom + Prénom
|
||||||
|
df = df.sort_values(by=colonnes_tries)
|
||||||
|
|
||||||
|
# Conversion des colonnes en multiindex
|
||||||
|
if type_colonnes:
|
||||||
|
df.columns = pd.MultiIndex.from_tuples(df.columns)
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def has_etuds(self):
|
||||||
|
"""Indique si un tabletag contient des étudiants"""
|
||||||
|
return len(self.etuds) > 0
|
||||||
|
|
||||||
|
def is_significatif(self):
|
||||||
|
"""Indique si une tabletag a des données"""
|
||||||
|
# A des étudiants
|
||||||
|
if not self.etuds:
|
||||||
|
return False
|
||||||
|
# A des tags avec des notes
|
||||||
|
tags_tries = self.get_all_significant_tags()
|
||||||
|
if not tags_tries:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_champ_administratif(champ, aggregat=None, cohorte=None):
|
||||||
|
"""Pour un champ donné, renvoie l'index (ou le multindex)
|
||||||
|
à intégrer au dataframe"""
|
||||||
|
liste = []
|
||||||
|
if aggregat:
|
||||||
|
liste += [aggregat]
|
||||||
|
liste += ["Administratif", "Identité"]
|
||||||
|
if cohorte:
|
||||||
|
liste += [champ]
|
||||||
|
liste += [champ]
|
||||||
|
return tuple(liste)
|
||||||
|
|
||||||
|
|
||||||
|
def df_administratif(
|
||||||
|
etuds: list[Identite], aggregat=None, cohorte=None
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""Renvoie un dataframe donnant les données administratives
|
||||||
|
des étudiants du TableTag
|
||||||
|
|
||||||
|
Args:
|
||||||
|
etuds: Identité des étudiants générant les données administratives
|
||||||
|
"""
|
||||||
|
identites = {etud.etudid: etud for etud in etuds}
|
||||||
|
|
||||||
|
donnees = {}
|
||||||
|
etud: Identite = None
|
||||||
|
for etudid, etud in identites.items():
|
||||||
|
data = {
|
||||||
|
CHAMPS_ADMINISTRATIFS[0]: etud.civilite_str,
|
||||||
|
CHAMPS_ADMINISTRATIFS[1]: etud.nom,
|
||||||
|
CHAMPS_ADMINISTRATIFS[2]: etud.prenom_str,
|
||||||
|
}
|
||||||
|
donnees[etudid] = {
|
||||||
|
_get_champ_administratif(champ, aggregat, cohorte): data[champ]
|
||||||
|
for champ in CHAMPS_ADMINISTRATIFS
|
||||||
|
}
|
||||||
|
|
||||||
|
colonnes = [
|
||||||
|
_get_champ_administratif(champ, aggregat, cohorte)
|
||||||
|
for champ in CHAMPS_ADMINISTRATIFS
|
||||||
|
]
|
||||||
|
df = pd.DataFrame.from_dict(donnees, orient="index", columns=colonnes)
|
||||||
|
df = df.sort_values(by=colonnes[1:])
|
||||||
|
return df
|
@ -1,160 +0,0 @@
|
|||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 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 Thu Sep 8 09:36:33 2016
|
|
||||||
|
|
||||||
@author: barasc
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from app.pe.pe_tabletags import TableTag
|
|
||||||
from app.pe.pe_moytag import MoyennesTag
|
|
||||||
import app.pe.pe_etudiant as pe_etudiant
|
|
||||||
import app.pe.rcss.pe_rcs as pe_rcs
|
|
||||||
import app.pe.pe_rcss_jury as pe_rcss_jury
|
|
||||||
import app.pe.pe_rcstag as pe_rcstag
|
|
||||||
|
|
||||||
|
|
||||||
class RCSInterclasseTag(TableTag):
|
|
||||||
"""
|
|
||||||
Interclasse l'ensemble des étudiants diplômés à une année
|
|
||||||
donnée (celle du jury), pour un RCS 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
|
|
||||||
formsemestre)
|
|
||||||
* calculant le classement sur les étudiants diplômes
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
nom_rcs: str,
|
|
||||||
etudiants: pe_etudiant.EtudiantsJuryPE,
|
|
||||||
rcss_jury_pe: pe_rcss_jury.RCSsJuryPE,
|
|
||||||
rcss_tags: dict[tuple, pe_rcstag.RCSTag],
|
|
||||||
):
|
|
||||||
TableTag.__init__(self)
|
|
||||||
|
|
||||||
self.nom_rcs = nom_rcs
|
|
||||||
"""Le nom du RCS interclassé"""
|
|
||||||
|
|
||||||
self.nom = self.get_repr()
|
|
||||||
"""Représentation textuelle de l'interclassement"""
|
|
||||||
|
|
||||||
self.diplomes_ids = etudiants.etudiants_diplomes
|
|
||||||
"""Identité des étudiants diplômés"""
|
|
||||||
|
|
||||||
self.etudiants_diplomes = {etudid for etudid in self.diplomes_ids}
|
|
||||||
"""Etudids des étudiants diplômés"""
|
|
||||||
|
|
||||||
# Les RCSemX et leur versions taggués SxTag, en ne gardant que
|
|
||||||
# celles associées à l'aggrégat
|
|
||||||
self.rcss: dict[int, pe_rcs.RCS] = {}
|
|
||||||
"""Ensemble des trajectoires associées à l'aggrégat"""
|
|
||||||
for trajectoire_id in rcss_jury_pe.trajectoires:
|
|
||||||
trajectoire = rcss_jury_pe.trajectoires[trajectoire_id]
|
|
||||||
if trajectoire_id[0] == nom_rcs:
|
|
||||||
self.rcss[trajectoire_id] = trajectoire
|
|
||||||
|
|
||||||
self.trajectoires_taggues: dict[int, pe_rcs.RCS] = {}
|
|
||||||
"""Ensemble des trajectoires tagguées associées à l'aggrégat"""
|
|
||||||
for trajectoire_id in self.rcss:
|
|
||||||
self.trajectoires_taggues[trajectoire_id] = rcss_tags[trajectoire_id]
|
|
||||||
|
|
||||||
# Les trajectoires suivies par les étudiants du jury, en ne gardant que
|
|
||||||
# celles associées aux diplomés
|
|
||||||
self.suivi: dict[int, pe_rcs.RCS] = {}
|
|
||||||
"""Association entre chaque étudiant et la trajectoire tagguée à prendre en
|
|
||||||
compte pour l'aggrégat"""
|
|
||||||
for etudid in self.diplomes_ids:
|
|
||||||
self.suivi[etudid] = rcss_jury_pe.trajectoires_suivies[etudid][nom_rcs]
|
|
||||||
|
|
||||||
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()
|
|
||||||
"""Matrice des notes de l'aggrégat"""
|
|
||||||
|
|
||||||
# Synthétise les moyennes/classements par tag
|
|
||||||
self.moyennes_tags: dict[str, MoyennesTag] = {}
|
|
||||||
for tag in self.tags_sorted:
|
|
||||||
moy_gen_tag = self.notes[tag]
|
|
||||||
self.moyennes_tags[tag] = MoyennesTag(tag, 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_rcs}"
|
|
||||||
|
|
||||||
def do_taglist(self):
|
|
||||||
"""Synthétise les tags à partir des trajectoires_tagguées
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Une liste de tags triés par ordre alphabétique
|
|
||||||
"""
|
|
||||||
tags = []
|
|
||||||
for trajectoire in self.trajectoires_taggues.values():
|
|
||||||
tags.extend(trajectoire.tags_sorted)
|
|
||||||
return sorted(set(tags))
|
|
||||||
|
|
||||||
def compute_notes_matrice(self):
|
|
||||||
"""Construit la matrice de notes (etudid x tags)
|
|
||||||
retraçant les moyennes obtenues par les étudiants dans les semestres associés à
|
|
||||||
l'aggrégat (une trajectoire ayant pour numéro de semestre final, celui de l'aggrégat).
|
|
||||||
"""
|
|
||||||
# nb_tags = len(self.tags_sorted) unused ?
|
|
||||||
# nb_etudiants = len(self.diplomes_ids)
|
|
||||||
|
|
||||||
# Index de la matrice (etudids -> dim 0, tags -> dim 1)
|
|
||||||
etudids = list(self.diplomes_ids)
|
|
||||||
tags = self.tags_sorted
|
|
||||||
|
|
||||||
# Partant d'un dataframe vierge
|
|
||||||
df = pd.DataFrame(np.nan, index=etudids, columns=tags)
|
|
||||||
|
|
||||||
for trajectoire in self.trajectoires_taggues.values():
|
|
||||||
# Charge les moyennes par tag de la trajectoire tagguée
|
|
||||||
notes = trajectoire.notes
|
|
||||||
# Etudiants/Tags communs entre la trajectoire_tagguée et les données interclassées
|
|
||||||
etudids_communs = df.index.intersection(notes.index)
|
|
||||||
tags_communs = df.columns.intersection(notes.columns)
|
|
||||||
|
|
||||||
# Injecte les notes par tag
|
|
||||||
df.loc[etudids_communs, tags_communs] = notes.loc[
|
|
||||||
etudids_communs, tags_communs
|
|
||||||
]
|
|
||||||
|
|
||||||
return df
|
|
@ -51,13 +51,18 @@ import numpy as np
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from app.pe.rcss import pe_rcs
|
from app.pe.rcss import pe_rcs
|
||||||
from app.pe import pe_sxtag
|
from app.pe.moys import pe_sxtag
|
||||||
from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE
|
from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE
|
||||||
import app.pe.pe_affichage as pe_affichage
|
import app.pe.pe_affichage as pe_affichage
|
||||||
import app.pe.pe_etudiant as pe_etudiant
|
import app.pe.pe_etudiant as pe_etudiant
|
||||||
from app.pe.pe_rcstag import RCSTag
|
from app.pe.moys import (
|
||||||
from app.pe.pe_ressemtag import ResSemBUTTag
|
pe_tabletags,
|
||||||
from app.pe.pe_interclasstag import RCSInterclasseTag
|
pe_ressemtag,
|
||||||
|
pe_sxtag,
|
||||||
|
pe_rcstag,
|
||||||
|
pe_interclasstag,
|
||||||
|
pe_moytag,
|
||||||
|
)
|
||||||
import app.pe.pe_rcss_jury as pe_rcss_jury
|
import app.pe.pe_rcss_jury as pe_rcss_jury
|
||||||
|
|
||||||
|
|
||||||
@ -85,8 +90,7 @@ class JuryPE(object):
|
|||||||
)
|
)
|
||||||
# Chargement des étudiants à prendre en compte dans le jury
|
# Chargement des étudiants à prendre en compte dans le jury
|
||||||
pe_affichage.pe_print(
|
pe_affichage.pe_print(
|
||||||
f"""*** Recherche et chargement des étudiants diplômés en {
|
f"""*** Recherche des étudiants diplômés 🎓 en {self.diplome}"""
|
||||||
self.diplome}"""
|
|
||||||
)
|
)
|
||||||
self.etudiants = pe_etudiant.EtudiantsJuryPE(
|
self.etudiants = pe_etudiant.EtudiantsJuryPE(
|
||||||
self.diplome
|
self.diplome
|
||||||
@ -110,8 +114,8 @@ class JuryPE(object):
|
|||||||
self._gen_xls_sxtags(zipfile)
|
self._gen_xls_sxtags(zipfile)
|
||||||
self._gen_rcsemxs()
|
self._gen_rcsemxs()
|
||||||
self._gen_xls_rcstags(zipfile)
|
self._gen_xls_rcstags(zipfile)
|
||||||
# self._gen_xls_interclassements_rcss(zipfile)
|
self._gen_xls_interclasstags(zipfile)
|
||||||
# self._gen_xls_synthese_jury_par_tag(zipfile)
|
self._gen_xls_synthese_jury_par_tag(zipfile)
|
||||||
# self._gen_xls_synthese_par_etudiant(zipfile)
|
# self._gen_xls_synthese_par_etudiant(zipfile)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
@ -159,7 +163,7 @@ class JuryPE(object):
|
|||||||
self.ressembuttags = {}
|
self.ressembuttags = {}
|
||||||
for frmsem_id, formsemestre in formsemestres.items():
|
for frmsem_id, formsemestre in formsemestres.items():
|
||||||
# Crée le semestre_tag et exécute les calculs de moyennes
|
# Crée le semestre_tag et exécute les calculs de moyennes
|
||||||
self.ressembuttags[frmsem_id] = ResSemBUTTag(formsemestre)
|
self.ressembuttags[frmsem_id] = pe_ressemtag.ResSemBUTTag(formsemestre)
|
||||||
|
|
||||||
# Intègre le bilan des semestres taggués au zip final
|
# Intègre le bilan des semestres taggués au zip final
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
@ -170,7 +174,7 @@ class JuryPE(object):
|
|||||||
for res_sem_tag in self.ressembuttags.values():
|
for res_sem_tag in self.ressembuttags.values():
|
||||||
onglet = res_sem_tag.get_repr(verbose=True)
|
onglet = res_sem_tag.get_repr(verbose=True)
|
||||||
onglets += []
|
onglets += []
|
||||||
df = res_sem_tag.df_moyennes_et_classements()
|
df = res_sem_tag.to_df()
|
||||||
# écriture dans l'onglet
|
# écriture dans l'onglet
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||||
@ -219,7 +223,6 @@ class JuryPE(object):
|
|||||||
for rcf_id, rcf in self.rcss_jury.semXs.items():
|
for rcf_id, rcf in self.rcss_jury.semXs.items():
|
||||||
# SxTag traduisant le RCF
|
# SxTag traduisant le RCF
|
||||||
sxtag_id = rcf_id
|
sxtag_id = rcf_id
|
||||||
|
|
||||||
self.sxtags[sxtag_id] = pe_sxtag.SxTag(sxtag_id, rcf, self.ressembuttags)
|
self.sxtags[sxtag_id] = pe_sxtag.SxTag(sxtag_id, rcf, self.ressembuttags)
|
||||||
|
|
||||||
# Intègre le bilan des semestres taggués au zip final
|
# Intègre le bilan des semestres taggués au zip final
|
||||||
@ -230,20 +233,21 @@ class JuryPE(object):
|
|||||||
onglets = []
|
onglets = []
|
||||||
for sxtag in self.sxtags.values():
|
for sxtag in self.sxtags.values():
|
||||||
onglet = sxtag.get_repr(verbose=False)
|
onglet = sxtag.get_repr(verbose=False)
|
||||||
onglets += [onglet]
|
if sxtag.is_significatif():
|
||||||
df = sxtag.df_moyennes_et_classements()
|
df = sxtag.to_df()
|
||||||
# écriture dans l'onglet
|
onglets += [onglet]
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||||
|
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
|
if onglets:
|
||||||
self.add_file_to_zip(
|
self.add_file_to_zip(
|
||||||
zipfile,
|
zipfile,
|
||||||
f"semestres_taggues_{self.diplome}.xlsx",
|
f"semestres_taggues_{self.diplome}.xlsx",
|
||||||
output.read(),
|
output.read(),
|
||||||
path="details",
|
path="details",
|
||||||
)
|
)
|
||||||
|
|
||||||
def _gen_rcsemxs(self):
|
def _gen_rcsemxs(self):
|
||||||
"""Génère les regroupements cohérents de RCFs qu'ont suivi chaque étudiant"""
|
"""Génère les regroupements cohérents de RCFs qu'ont suivi chaque étudiant"""
|
||||||
@ -279,7 +283,7 @@ class JuryPE(object):
|
|||||||
|
|
||||||
self.rcss_tags = {}
|
self.rcss_tags = {}
|
||||||
for rcs_id, rcsemx in self.rcss_jury.rcsemxs.items():
|
for rcs_id, rcsemx in self.rcss_jury.rcsemxs.items():
|
||||||
self.rcss_tags[rcs_id] = RCSTag(rcsemx, self.sxtags)
|
self.rcss_tags[rcs_id] = pe_rcstag.RCSTag(rcsemx, self.sxtags)
|
||||||
|
|
||||||
# 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()
|
output = io.BytesIO()
|
||||||
@ -289,27 +293,67 @@ class JuryPE(object):
|
|||||||
onglets = []
|
onglets = []
|
||||||
for rcs_tag in self.rcss_tags.values():
|
for rcs_tag in self.rcss_tags.values():
|
||||||
onglet = rcs_tag.get_repr(verbose=False)
|
onglet = rcs_tag.get_repr(verbose=False)
|
||||||
onglets += [onglet]
|
if rcs_tag.is_significatif():
|
||||||
df = rcs_tag.df_moyennes_et_classements()
|
df = rcs_tag.to_df()
|
||||||
# écriture dans l'onglet
|
onglets += [onglet]
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
|
|
||||||
self.add_file_to_zip(
|
if onglets:
|
||||||
zipfile,
|
self.add_file_to_zip(
|
||||||
f"RCRCFs_{self.diplome}.xlsx",
|
zipfile,
|
||||||
output.read(),
|
f"RCRCFs_{self.diplome}.xlsx",
|
||||||
path="details",
|
output.read(),
|
||||||
)
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
def _gen_xls_interclassements_rcss(self, zipfile: ZipFile):
|
def _gen_xls_interclasstags(self, zipfile: ZipFile):
|
||||||
"""Intègre le bilan des RCS (interclassé par promo) au zip"""
|
"""Génère les interclassements sur la promo de diplômés
|
||||||
# Génère les interclassements (par promo et) par (nom d') aggrégat
|
par (nom d') aggrégat
|
||||||
pe_affichage.pe_print("*** Génère les interclassements")
|
en distinguant les interclassements par accronymes d'UEs (sur les SxTag)
|
||||||
self.interclassements_taggues = compute_interclassements(
|
et ceux par compétences (sur les RCSTag).
|
||||||
self.etudiants, self.rcss_jury, self.rcss_tags
|
"""
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
"*** Génère les interclassements sur chaque type de RCS/agrgégat"
|
||||||
)
|
)
|
||||||
|
self.interclasstags = {
|
||||||
|
pe_moytag.CODE_MOY_UE: {},
|
||||||
|
pe_moytag.CODE_MOY_COMPETENCES: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
etudiants_diplomes = self.etudiants.etudiants_diplomes
|
||||||
|
|
||||||
|
# Les interclassements par UE
|
||||||
|
for Sx in pe_rcs.TOUS_LES_SEMESTRES:
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
f"--> Interclassement par (acronyme d')UEs pour le RCS {Sx}"
|
||||||
|
)
|
||||||
|
interclass = pe_interclasstag.InterClassTag(
|
||||||
|
Sx,
|
||||||
|
pe_moytag.CODE_MOY_UE,
|
||||||
|
etudiants_diplomes,
|
||||||
|
self.rcss_jury.semXs,
|
||||||
|
self.sxtags,
|
||||||
|
self.rcss_jury.semXs_suivis,
|
||||||
|
)
|
||||||
|
self.interclasstags[pe_moytag.CODE_MOY_UE][Sx] = interclass
|
||||||
|
|
||||||
|
# Les interclassements par compétences
|
||||||
|
for nom_rcs in pe_rcs.TOUS_LES_RCS:
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
f"--> Interclassement par compétences pour le RCS {nom_rcs}"
|
||||||
|
)
|
||||||
|
interclass = pe_interclasstag.InterClassTag(
|
||||||
|
nom_rcs,
|
||||||
|
pe_moytag.CODE_MOY_COMPETENCES,
|
||||||
|
etudiants_diplomes,
|
||||||
|
self.rcss_jury.rcsemxs,
|
||||||
|
self.rcss_tags,
|
||||||
|
self.rcss_jury.rcsemxs_suivis,
|
||||||
|
)
|
||||||
|
self.interclasstags[pe_moytag.CODE_MOY_COMPETENCES][nom_rcs] = interclass
|
||||||
|
|
||||||
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
|
# Intègre le bilan des aggrégats (interclassé par promo) au zip final
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
@ -317,23 +361,29 @@ class JuryPE(object):
|
|||||||
output, engine="openpyxl"
|
output, engine="openpyxl"
|
||||||
) as writer:
|
) as writer:
|
||||||
onglets = []
|
onglets = []
|
||||||
for interclass_tag in self.interclassements_taggues.values():
|
for type_interclass in [
|
||||||
if interclass_tag.significatif: # Avec des notes
|
pe_moytag.CODE_MOY_UE,
|
||||||
onglet = interclass_tag.get_repr()
|
pe_moytag.CODE_MOY_COMPETENCES,
|
||||||
onglets += [onglet]
|
]:
|
||||||
df = interclass_tag.df_moyennes_et_classements()
|
interclasstag = self.interclasstags[type_interclass]
|
||||||
# écriture dans l'onglet
|
for nom_rcs, interclass in interclasstag.items():
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
onglet = interclass.get_repr()
|
||||||
|
if interclass.is_significatif():
|
||||||
|
df = interclass.to_df(cohorte="Promo")
|
||||||
|
onglets += [onglet]
|
||||||
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||||
|
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
|
|
||||||
self.add_file_to_zip(
|
if onglets:
|
||||||
zipfile,
|
self.add_file_to_zip(
|
||||||
f"interclassements_taggues_{self.diplome}.xlsx",
|
zipfile,
|
||||||
output.read(),
|
f"InterClassTags_{self.diplome}.xlsx",
|
||||||
path="details",
|
output.read(),
|
||||||
)
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
def _gen_xls_synthese_jury_par_tag(self, zipfile: ZipFile):
|
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 tag par tag"""
|
||||||
@ -347,7 +397,8 @@ class JuryPE(object):
|
|||||||
output, engine="openpyxl"
|
output, engine="openpyxl"
|
||||||
) as writer:
|
) as writer:
|
||||||
onglets = []
|
onglets = []
|
||||||
for onglet, df in self.synthese.items():
|
for (tag, type_moy), df in self.synthese.items():
|
||||||
|
onglet = f"{tag} {type_moy}"
|
||||||
onglets += [onglet]
|
onglets += [onglet]
|
||||||
# écriture dans l'onglet:
|
# écriture dans l'onglet:
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
@ -407,15 +458,18 @@ class JuryPE(object):
|
|||||||
self.zipdata.seek(0)
|
self.zipdata.seek(0)
|
||||||
return self.zipdata
|
return self.zipdata
|
||||||
|
|
||||||
def do_tags_list(self, interclassements: dict[str, RCSInterclasseTag]):
|
def _do_tags_list(self, interclassements: dict[str, dict]):
|
||||||
"""La liste des tags extraites des interclassements"""
|
"""La liste des tags extraites des interclassements"""
|
||||||
tags = []
|
tags = []
|
||||||
for aggregat in interclassements:
|
# Pour chaque type d'interclassements
|
||||||
interclass = interclassements[aggregat]
|
for type in interclassements:
|
||||||
if interclass.tags_sorted:
|
interclassement = interclassements[type]
|
||||||
tags.extend(interclass.tags_sorted)
|
for aggregat in interclassement:
|
||||||
tags = sorted(set(tags))
|
interclass = interclassement[aggregat]
|
||||||
return tags
|
if interclass.tags_sorted:
|
||||||
|
tags.extend(interclass.tags_sorted)
|
||||||
|
tags = sorted(set(tags))
|
||||||
|
return tags
|
||||||
|
|
||||||
# **************************************************************************************************************** #
|
# **************************************************************************************************************** #
|
||||||
# Méthodes pour la synthèse du juryPE
|
# Méthodes pour la synthèse du juryPE
|
||||||
@ -423,154 +477,79 @@ class JuryPE(object):
|
|||||||
|
|
||||||
def synthetise_jury_par_tags(self) -> dict[pd.DataFrame]:
|
def synthetise_jury_par_tags(self) -> dict[pd.DataFrame]:
|
||||||
"""Synthétise tous les résultats du jury PE dans des dataframes,
|
"""Synthétise tous les résultats du jury PE dans des dataframes,
|
||||||
dont les onglets sont les tags"""
|
dont les onglets sont les tags et des types de calcul de moyennes
|
||||||
|
(par UEs ou par compétences)"""
|
||||||
|
|
||||||
pe_affichage.pe_print("*** Synthèse finale des moyennes par tag***")
|
pe_affichage.pe_print(
|
||||||
|
"*** Synthèse finale des moyennes par tag et par type de moyennes (UEs ou Compétences)***"
|
||||||
|
)
|
||||||
|
|
||||||
synthese = {}
|
synthese = {}
|
||||||
pe_affichage.pe_print(" -> Synthèse des données administratives")
|
pe_affichage.pe_print(" -> Synthèse des données administratives")
|
||||||
synthese["administratif"] = self.etudiants.df_administratif(self.diplomes_ids)
|
synthese["administratif"] = self.etudiants.df_administratif(self.diplomes_ids)
|
||||||
|
|
||||||
tags = self.do_tags_list(self.interclassements_taggues)
|
tags = self._do_tags_list(self.interclasstags)
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
pe_affichage.pe_print(f" -> Synthèse du tag {tag}")
|
for type_moy in [pe_moytag.CODE_MOY_UE, pe_moytag.CODE_MOY_COMPETENCES]:
|
||||||
synthese[tag] = self.df_tag(tag)
|
pe_affichage.pe_print(f" -> Synthèse du tag {tag} par {type_moy}")
|
||||||
|
synthese[(tag, type_moy)] = self.df_tag_type(tag, type_moy)
|
||||||
return synthese
|
return synthese
|
||||||
|
|
||||||
def df_tag(self, tag):
|
def df_tag_type(self, tag, type_moy, type_colonnes=True):
|
||||||
"""Génère le DataFrame synthétisant les moyennes/classements (groupe,
|
"""Génère le DataFrame synthétisant les moyennes/classements (groupe +
|
||||||
interclassement promo) pour tous les aggrégats prévus,
|
interclassement promo) pour tous les aggrégats prévus, en fonction
|
||||||
|
du type (UEs ou Compétences) de données souhaitées,
|
||||||
tels que fourni dans l'excel final.
|
tels que fourni dans l'excel final.
|
||||||
|
|
||||||
|
Si type=UEs => tous les sxtag du tag
|
||||||
|
Si type=Compétences => tous les rcstag du tag
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tag: Un des tags (a minima `but`)
|
tag: Un des tags (a minima `but`)
|
||||||
|
type_moy: Un type de moyenne
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
etudids = list(self.diplomes_ids)
|
|
||||||
|
|
||||||
# Les données des étudiants
|
# Les données des étudiants
|
||||||
donnees_etudiants = {}
|
etuds = [etud for etudid, etud in self.etudiants.etudiants_diplomes.items()]
|
||||||
for etudid in etudids:
|
df = pe_tabletags.df_administratif(etuds, aggregat="", cohorte="")
|
||||||
etudiant = self.etudiants.identites[etudid]
|
|
||||||
donnees_etudiants[etudid] = {
|
|
||||||
("Identité", "", "Civilite"): etudiant.civilite_str,
|
|
||||||
("Identité", "", "Nom"): etudiant.nom,
|
|
||||||
("Identité", "", "Prenom"): etudiant.prenom,
|
|
||||||
}
|
|
||||||
df_synthese = pd.DataFrame.from_dict(donnees_etudiants, orient="index")
|
|
||||||
|
|
||||||
# Ajout des aggrégats
|
if type_moy == pe_moytag.CODE_MOY_UE:
|
||||||
for aggregat in pe_rcs.TOUS_LES_RCS:
|
aggregats = pe_rcs.TOUS_LES_SEMESTRES
|
||||||
descr = app.pe.rcss.pe_rcs.TYPES_RCS[aggregat]["descr"]
|
else:
|
||||||
|
aggregats = pe_rcs.TOUS_LES_RCS
|
||||||
|
|
||||||
# Les trajectoires (tagguées) suivies par les étudiants pour l'aggrégat et le tag
|
for aggregat in aggregats:
|
||||||
# considéré
|
print(aggregat)
|
||||||
trajectoires_tagguees = []
|
# Descr de l'aggrégat
|
||||||
for etudid in etudids:
|
descr = pe_rcs.TYPES_RCS[aggregat]["descr"]
|
||||||
trajectoire = self.rcss_jury.trajectoires_suivies[etudid][aggregat]
|
|
||||||
if trajectoire:
|
|
||||||
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 ?
|
# L'interclassement associé
|
||||||
nbre_notes_injectees = 0
|
interclass = self.interclasstags[type_moy][aggregat]
|
||||||
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 interclass.is_significatif():
|
||||||
if nbre_notes_injectees > 0:
|
# Le dataframe du classement sur le groupe
|
||||||
# Ajout des données classements & statistiques
|
df_groupe = interclass.compute_df_synthese_moyennes_tag(
|
||||||
nom_stat_promo = f"{NOM_STAT_PROMO} {self.diplome}"
|
tag, aggregat=aggregat, type_colonnes=False
|
||||||
donnees = pd.DataFrame(
|
|
||||||
index=etudids,
|
|
||||||
columns=[
|
|
||||||
[descr] * (1 + 4 * 2),
|
|
||||||
[""] + [NOM_STAT_GROUPE] * 4 + [nom_stat_promo] * 4,
|
|
||||||
["note"] + ["class.", "min", "moy", "max"] * 2,
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
df = df.join(df_groupe)
|
||||||
|
|
||||||
for traj in trajectoires_tagguees:
|
# Le dataframe du classement sur la promo
|
||||||
# Les données des trajectoires_tagguees
|
df_promo = interclass.to_df(
|
||||||
moy_traj = traj.moyennes_tags[tag]
|
administratif=False,
|
||||||
|
aggregat=aggregat,
|
||||||
|
tags_cibles=[tag],
|
||||||
|
cohorte="Promo",
|
||||||
|
type_colonnes=False,
|
||||||
|
)
|
||||||
|
df = df.join(df_promo)
|
||||||
|
|
||||||
# Les étudiants communs entre tableur de synthèse et trajectoires
|
# Conversion des colonnes en multiindex
|
||||||
inscrits_traj = moy_traj.inscrits_ids
|
if type_colonnes:
|
||||||
etudids_communs = list(set(etudids) & set(inscrits_traj))
|
df.columns = pd.MultiIndex.from_tuples(df.columns)
|
||||||
|
return df
|
||||||
# Les notes
|
# Fin de l'aggrégat
|
||||||
champ = (descr, "", "note")
|
|
||||||
notes_traj = moy_traj.get_notes()
|
|
||||||
donnees.loc[etudids_communs, champ] = notes_traj.loc[
|
|
||||||
etudids_communs
|
|
||||||
]
|
|
||||||
|
|
||||||
# Les rangs
|
|
||||||
champ = (descr, NOM_STAT_GROUPE, "class.")
|
|
||||||
rangs = moy_traj.get_rangs_inscrits()
|
|
||||||
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")
|
|
||||||
moys = moy_interclass.get_moy()
|
|
||||||
donnees.loc[etudids_communs, champ] = moys.loc[etudids_communs]
|
|
||||||
|
|
||||||
df_synthese = df_synthese.join(donnees)
|
|
||||||
# Fin de l'aggrégat
|
|
||||||
|
|
||||||
# Tri par nom/prénom
|
|
||||||
df_synthese.sort_values(
|
|
||||||
by=[("Identité", "", "Nom"), ("Identité", "", "Prenom")], inplace=True
|
|
||||||
)
|
|
||||||
return df_synthese
|
|
||||||
|
|
||||||
def synthetise_jury_par_etudiants(self) -> dict[pd.DataFrame]:
|
def synthetise_jury_par_etudiants(self) -> dict[pd.DataFrame]:
|
||||||
"""Synthétise tous les résultats du jury PE dans des dataframes,
|
"""Synthétise tous les résultats du jury PE dans des dataframes,
|
||||||
@ -600,7 +579,7 @@ class JuryPE(object):
|
|||||||
def df_synthese_etudiant(self, etudid: int) -> pd.DataFrame:
|
def df_synthese_etudiant(self, etudid: int) -> pd.DataFrame:
|
||||||
"""Créé un DataFrame pour un étudiant donné par son etudid, retraçant
|
"""Créé un DataFrame pour un étudiant donné par son etudid, retraçant
|
||||||
toutes ses moyennes aux différents tag et aggrégats"""
|
toutes ses moyennes aux différents tag et aggrégats"""
|
||||||
tags = self.do_tags_list(self.interclassements_taggues)
|
tags = self._do_tags_list(self.interclasstags)
|
||||||
|
|
||||||
donnees = {}
|
donnees = {}
|
||||||
|
|
||||||
@ -620,7 +599,7 @@ class JuryPE(object):
|
|||||||
trajectoire_tagguee = self.rcss_tags[trajectoire.sxtag_id]
|
trajectoire_tagguee = self.rcss_tags[trajectoire.sxtag_id]
|
||||||
if tag in trajectoire_tagguee.moyennes_tags:
|
if tag in trajectoire_tagguee.moyennes_tags:
|
||||||
# L'interclassement
|
# L'interclassement
|
||||||
interclass = self.interclassements_taggues[aggregat]
|
interclass = self.interclasstags[aggregat]
|
||||||
|
|
||||||
# Injection des données dans un dictionnaire
|
# Injection des données dans un dictionnaire
|
||||||
donnees[tag] |= get_dict_synthese_aggregat(
|
donnees[tag] |= get_dict_synthese_aggregat(
|
||||||
@ -662,25 +641,6 @@ def get_formsemestres_etudiants(etudiants: pe_etudiant.EtudiantsJuryPE) -> dict:
|
|||||||
return semestres
|
return semestres
|
||||||
|
|
||||||
|
|
||||||
def compute_interclassements(
|
|
||||||
etudiants: pe_etudiant.EtudiantsJuryPE,
|
|
||||||
trajectoires_jury_pe: pe_rcss_jury.RCSsJuryPE,
|
|
||||||
trajectoires_tagguees: dict[tuple, pe_rcs.RCS],
|
|
||||||
):
|
|
||||||
"""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(
|
|
||||||
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:
|
def get_defaut_dict_synthese_aggregat(nom_rcs: str, diplome: int) -> dict:
|
||||||
"""Renvoie le dictionnaire de synthèse (à intégrer dans
|
"""Renvoie le dictionnaire de synthèse (à intégrer dans
|
||||||
un tableur excel) pour décrire les résultats d'un aggrégat
|
un tableur excel) pour décrire les résultats d'un aggrégat
|
||||||
@ -723,8 +683,8 @@ def get_defaut_dict_synthese_aggregat(nom_rcs: str, diplome: int) -> dict:
|
|||||||
|
|
||||||
def get_dict_synthese_aggregat(
|
def get_dict_synthese_aggregat(
|
||||||
aggregat: str,
|
aggregat: str,
|
||||||
trajectoire_tagguee: RCSTag,
|
trajectoire_tagguee: pe_rcstag.RCSTag,
|
||||||
interclassement_taggue: RCSInterclasseTag,
|
interclassement_taggue: pe_interclasstag.InterClassTag,
|
||||||
etudid: int,
|
etudid: int,
|
||||||
tag: str,
|
tag: str,
|
||||||
diplome: int,
|
diplome: int,
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
# -*- 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 Thu Sep 8 09:36:33 2016
|
|
||||||
|
|
||||||
@author: barasc
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
from app.models import Identite
|
|
||||||
|
|
||||||
TAGS_RESERVES = ["but"]
|
|
||||||
|
|
||||||
|
|
||||||
class TableTag(object):
|
|
||||||
def __init__(self):
|
|
||||||
"""Classe centralisant différentes méthodes communes aux
|
|
||||||
SemestreTag, TrajectoireTag, AggregatInterclassTag
|
|
||||||
"""
|
|
||||||
# Les étudiants
|
|
||||||
# self.etuds: list[Identite] = None # A venir
|
|
||||||
"""Les étudiants"""
|
|
||||||
# self.etudids: list[int] = {}
|
|
||||||
"""Les etudids"""
|
|
||||||
|
|
||||||
def add_etuds(self, etuds: list[Identite]):
|
|
||||||
"""Mémorise les informations sur les étudiants
|
|
||||||
|
|
||||||
Args:
|
|
||||||
etuds: la liste des identités de l'étudiant
|
|
||||||
"""
|
|
||||||
# self.etuds = etuds
|
|
||||||
self.etudids = list({etud.etudid for etud in etuds})
|
|
||||||
|
|
||||||
def get_all_tags(self):
|
|
||||||
"""Liste des tags de la table, triée par ordre alphabétique,
|
|
||||||
extraite des clés du dictionnaire ``moyennes_tags`` connues (tags en doublon
|
|
||||||
possible).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Liste de tags triés par ordre alphabétique
|
|
||||||
"""
|
|
||||||
return sorted(list(self.moyennes_tags.keys()))
|
|
||||||
|
|
||||||
def df_moyennes_et_classements(self) -> pd.DataFrame:
|
|
||||||
"""Renvoie un dataframe listant toutes les moyennes,
|
|
||||||
et les classements des étudiants pour tous les tags.
|
|
||||||
|
|
||||||
Est utilisé pour afficher le détail d'un tableau taggué
|
|
||||||
(semestres, trajectoires ou aggrégat)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Le dataframe des notes et des classements
|
|
||||||
"""
|
|
||||||
|
|
||||||
etudiants = {etud.etudid: [etud.nom, etud.prenom] for etud in self.etuds}
|
|
||||||
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom", "prenom"])
|
|
||||||
|
|
||||||
tags_tries = self.get_all_tags()
|
|
||||||
for tag in tags_tries:
|
|
||||||
moy_tag = self.moyennes_tags[tag]
|
|
||||||
for acronyme in moy_tag.moyennes:
|
|
||||||
moy = moy_tag.moyennes[acronyme] # une moyenne
|
|
||||||
df = df.join(moy.synthese["notes"].rename(f"Moy {tag}-{acronyme}"))
|
|
||||||
df = df.join(
|
|
||||||
moy.synthese["classements"].rename(f"Class {tag}-{acronyme}")
|
|
||||||
)
|
|
||||||
moy_gen = moy_tag.moyenne_gen
|
|
||||||
df = df.join(moy_gen.synthese["notes"].rename(f"Moy {tag} (gen)"))
|
|
||||||
df = df.join(moy_gen.synthese["classements"].rename(f"Class {tag} (gen)"))
|
|
||||||
|
|
||||||
df.sort_values(by=["nom", "prenom"])
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def df_notes(self) -> pd.DataFrame | None:
|
|
||||||
"""Renvoie un dataframe (etudid x tag) listant toutes les moyennes par tags
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Un dataframe etudids x tag (avec tag par ordre alphabétique)
|
|
||||||
"""
|
|
||||||
tags_tries = self.get_all_tags()
|
|
||||||
if tags_tries:
|
|
||||||
dict_series = {}
|
|
||||||
for tag in tags_tries:
|
|
||||||
# Les moyennes associés au tag
|
|
||||||
moy_tag = self.moyennes_tags[tag]
|
|
||||||
dict_series[tag] = moy_tag.synthese["notes"]
|
|
||||||
df = pd.DataFrame(dict_series)
|
|
||||||
return df
|
|
@ -10,7 +10,7 @@ Created on 01-2024
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre
|
||||||
from app.pe import pe_sxtag, pe_affichage
|
from app.pe.moys import pe_sxtag
|
||||||
from app.pe.rcss import pe_rcs, pe_trajectoires
|
from app.pe.rcss import pe_rcs, pe_trajectoires
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user