forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -1,5 +1,16 @@
|
|||||||
from app.models import Formation, FormSemestre
|
from app.models import Formation, FormSemestre
|
||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
|
from app import log
|
||||||
|
|
||||||
|
PE_DEBUG = 0
|
||||||
|
|
||||||
|
if not PE_DEBUG:
|
||||||
|
# log to notes.log
|
||||||
|
def pe_print(*a, **kw):
|
||||||
|
# kw is ignored. log always add a newline
|
||||||
|
log(" ".join(a))
|
||||||
|
else:
|
||||||
|
pe_print = print # print function
|
||||||
|
|
||||||
|
|
||||||
def nom_semestre_etape(semestre: FormSemestre, avec_fid=False) -> str:
|
def nom_semestre_etape(semestre: FormSemestre, avec_fid=False) -> str:
|
||||||
@ -29,7 +40,7 @@ def nom_semestre_etape(semestre: FormSemestre, avec_fid=False) -> str:
|
|||||||
f"{semestre.date_debut.year}-{semestre.date_fin.year}",
|
f"{semestre.date_debut.year}-{semestre.date_fin.year}",
|
||||||
]
|
]
|
||||||
if avec_fid:
|
if avec_fid:
|
||||||
description.append(f"({semestre.forsemestre_id})")
|
description.append(f"({semestre.formsemestre_id})")
|
||||||
|
|
||||||
return " ".join(description)
|
return " ".join(description)
|
||||||
|
|
||||||
|
@ -45,21 +45,11 @@ import unicodedata
|
|||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc.sco_logos import find_logo
|
from app.scodoc.sco_logos import find_logo
|
||||||
|
|
||||||
PE_DEBUG = 0
|
|
||||||
|
|
||||||
if not PE_DEBUG:
|
|
||||||
# log to notes.log
|
|
||||||
def pe_print(*a, **kw):
|
|
||||||
# kw is ignored. log always add a newline
|
|
||||||
log(" ".join(a))
|
|
||||||
|
|
||||||
else:
|
|
||||||
pe_print = print # print function
|
|
||||||
|
|
||||||
|
|
||||||
# Generated LaTeX files are encoded as:
|
# Generated LaTeX files are encoded as:
|
||||||
|
@ -35,10 +35,9 @@ Created on 17/01/2024
|
|||||||
|
|
||||||
@author: barasc
|
@author: barasc
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import app.pe.pe_comp as pe_comp
|
|
||||||
from app.models import FormSemestre, Identite
|
from app.models import FormSemestre, Identite
|
||||||
from app.pe.pe_comp import pe_print
|
import app.pe.pe_affichage as pe_affichage
|
||||||
|
import app.pe.pe_comp as pe_comp
|
||||||
|
|
||||||
|
|
||||||
class EtudiantsJuryPE:
|
class EtudiantsJuryPE:
|
||||||
@ -86,17 +85,17 @@ class EtudiantsJuryPE:
|
|||||||
cosemestres = pe_comp.get_cosemestres_diplomants(self.annee_diplome, None)
|
cosemestres = pe_comp.get_cosemestres_diplomants(self.annee_diplome, None)
|
||||||
self.cosemestres = cosemestres
|
self.cosemestres = cosemestres
|
||||||
|
|
||||||
pe_comp.pe_print(f"1) Recherche des coSemestres -> {len(cosemestres)} trouvés")
|
pe_affichage.pe_print(f"1) Recherche des coSemestres -> {len(cosemestres)} trouvés")
|
||||||
|
|
||||||
pe_comp.pe_print("2) Liste des étudiants dans les différents co-semestres")
|
pe_affichage.pe_print("2) Liste des étudiants dans les différents co-semestres")
|
||||||
self.etudiants_ids = get_etudiants_dans_semestres(cosemestres)
|
self.etudiants_ids = get_etudiants_dans_semestres(cosemestres)
|
||||||
pe_comp.pe_print(
|
pe_affichage.pe_print(
|
||||||
" => %d étudiants trouvés dans les cosemestres" % len(self.etudiants_ids)
|
" => %d étudiants trouvés dans les cosemestres" % len(self.etudiants_ids)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Analyse des parcours étudiants pour déterminer leur année effective de diplome
|
# Analyse des parcours étudiants pour déterminer leur année effective de diplome
|
||||||
# avec prise en compte des redoublements, des abandons, ....
|
# avec prise en compte des redoublements, des abandons, ....
|
||||||
pe_comp.pe_print("3) Analyse des parcours individuels des étudiants")
|
pe_affichage.pe_print("3) Analyse des parcours individuels des étudiants")
|
||||||
|
|
||||||
no_etud = 0
|
no_etud = 0
|
||||||
for no_etud, etudid in enumerate(self.etudiants_ids):
|
for no_etud, etudid in enumerate(self.etudiants_ids):
|
||||||
@ -110,10 +109,6 @@ class EtudiantsJuryPE:
|
|||||||
# Analyse son parcours pour atteindre chaque semestre de la formation
|
# Analyse son parcours pour atteindre chaque semestre de la formation
|
||||||
self.structure_cursus_etudiant(etudid)
|
self.structure_cursus_etudiant(etudid)
|
||||||
|
|
||||||
if (no_etud + 1) % 10 == 0:
|
|
||||||
pe_comp.pe_print(f"{no_etud + 1}")
|
|
||||||
no_etud += 1
|
|
||||||
pe_comp.pe_print()
|
|
||||||
|
|
||||||
# Les étudiants à prendre dans le diplôme, étudiants ayant abandonnés non compris
|
# Les étudiants à prendre dans le diplôme, étudiants ayant abandonnés non compris
|
||||||
self.etudiants_diplomes = self.get_etudiants_diplomes()
|
self.etudiants_diplomes = self.get_etudiants_diplomes()
|
||||||
@ -126,23 +121,23 @@ class EtudiantsJuryPE:
|
|||||||
"""Les formsemestres (des étudiants) dont il faut calculer les moyennes"""
|
"""Les formsemestres (des étudiants) dont il faut calculer les moyennes"""
|
||||||
|
|
||||||
# Synthèse
|
# Synthèse
|
||||||
pe_comp.pe_print(
|
pe_affichage.pe_print(
|
||||||
f" => {len(self.etudiants_diplomes)} étudiants à diplômer en {self.annee_diplome}"
|
f" => {len(self.etudiants_diplomes)} étudiants à diplômer en {self.annee_diplome}"
|
||||||
)
|
)
|
||||||
nbre_abandons = len(self.etudiants_ids) - len(self.etudiants_diplomes)
|
nbre_abandons = len(self.etudiants_ids) - len(self.etudiants_diplomes)
|
||||||
pe_comp.pe_print(f" => {nbre_abandons} étudiants éliminer pour abandon")
|
pe_affichage.pe_print(f" => {nbre_abandons} étudiants non considérés (redoublement, réorientation, abandon")
|
||||||
pe_comp.pe_print(
|
pe_affichage.pe_print(
|
||||||
f" => {len(self.formsemestres_jury_ids)} semestres dont il faut calculer la moyenne"
|
f" => {len(self.formsemestres_jury_ids)} semestres dont il faut calculer la moyenne"
|
||||||
)
|
)
|
||||||
pe_comp.pe_print(
|
# pe_affichage.pe_print(
|
||||||
" => quelques étudiants futurs diplômés : "
|
# " => quelques étudiants futurs diplômés : "
|
||||||
+ ", ".join([str(etudid) for etudid in list(self.etudiants_diplomes)[:10]])
|
# + ", ".join([str(etudid) for etudid in list(self.etudiants_diplomes)[:10]])
|
||||||
)
|
# )
|
||||||
pe_comp.pe_print(
|
# pe_affichage.pe_print(
|
||||||
" => semestres dont il faut calculer les moyennes : "
|
# " => semestres dont il faut calculer les moyennes : "
|
||||||
+ ", ".join([str(fid) for fid in list(self.formsemestres_jury_ids)])
|
# + ", ".join([str(fid) for fid in list(self.formsemestres_jury_ids)])
|
||||||
)
|
# )
|
||||||
# Les abandons :
|
# Les abandons (pour debug)
|
||||||
self.abandons = sorted(
|
self.abandons = sorted(
|
||||||
[
|
[
|
||||||
cursus["nom"]
|
cursus["nom"]
|
||||||
@ -416,7 +411,7 @@ def get_etudiants_dans_semestres(semestres: dict[int, FormSemestre]) -> set:
|
|||||||
for sem in semestres.values(): # pour chacun des semestres de la liste
|
for sem in semestres.values(): # pour chacun des semestres de la liste
|
||||||
etudiants_du_sem = {ins.etudid for ins in sem.inscriptions}
|
etudiants_du_sem = {ins.etudid for ins in sem.inscriptions}
|
||||||
|
|
||||||
pe_print(f" --> {sem} : {len(etudiants_du_sem)} etudiants")
|
pe_affichage.pe_print(f" --> {sem} : {len(etudiants_du_sem)} etudiants")
|
||||||
etudiants_ids = (
|
etudiants_ids = (
|
||||||
etudiants_ids | etudiants_du_sem
|
etudiants_ids | etudiants_du_sem
|
||||||
) # incluant la suppression des doublons
|
) # incluant la suppression des doublons
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
from app.comp import moy_sem
|
||||||
from app.pe.pe_tabletags import TableTag
|
from app.pe.pe_tabletags import TableTag
|
||||||
from app.pe.pe_etudiant import EtudiantsJuryPE
|
from app.pe.pe_etudiant import EtudiantsJuryPE
|
||||||
from app.pe.pe_trajectoire import Trajectoire, TrajectoiresJuryPE
|
from app.pe.pe_trajectoire import Trajectoire, TrajectoiresJuryPE
|
||||||
from app.pe.pe_trajectoiretag import TrajectoireTag
|
from app.pe.pe_trajectoiretag import TrajectoireTag
|
||||||
from app.comp import moy_sem
|
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -46,29 +46,19 @@ import io
|
|||||||
import os
|
import os
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from app.scodoc.gen_tables import SeqGenTable
|
||||||
from app.comp import res_sem
|
|
||||||
from app.comp.res_compat import NotesTableCompat
|
|
||||||
from app.models import FormSemestre
|
|
||||||
from app.models.etudiants import Identite
|
|
||||||
|
|
||||||
from app.scodoc.gen_tables import GenTable, SeqGenTable
|
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
from app.pe.pe_etudiant import EtudiantsJuryPE
|
from app.pe.pe_etudiant import EtudiantsJuryPE
|
||||||
from app.pe.pe_trajectoire import TrajectoiresJuryPE, Trajectoire
|
from app.pe.pe_trajectoire import TrajectoiresJuryPE, Trajectoire
|
||||||
import app.pe.pe_comp as pe_comp
|
import app.pe.pe_comp as pe_comp
|
||||||
|
import app.pe.pe_affichage as pe_affichage
|
||||||
from app.pe.pe_semtag import SemestreTag
|
from app.pe.pe_semtag import SemestreTag
|
||||||
from app.pe.pe_interclasstag import AggregatInterclasseTag
|
from app.pe.pe_interclasstag import AggregatInterclasseTag
|
||||||
from app.pe.pe_trajectoiretag import TrajectoireTag
|
from app.pe.pe_trajectoiretag import TrajectoireTag
|
||||||
import app.pe.pe_affichage as pe_affichage
|
import app.pe.pe_affichage as pe_affichage
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
|
||||||
class JuryPE(object):
|
class JuryPE(object):
|
||||||
"""Classe mémorisant toutes les informations nécessaires pour établir un jury de PE.
|
"""Classe mémorisant toutes les informations nécessaires pour établir un jury de PE.
|
||||||
Modèle basé sur NotesTable.
|
Modèle basé sur NotesTable.
|
||||||
@ -112,7 +102,7 @@ class JuryPE(object):
|
|||||||
self.zipdata = io.BytesIO()
|
self.zipdata = io.BytesIO()
|
||||||
with ZipFile(self.zipdata, "w") as zipfile:
|
with ZipFile(self.zipdata, "w") as zipfile:
|
||||||
# Chargement des étudiants à prendre en compte dans le jury
|
# Chargement des étudiants à prendre en compte dans le jury
|
||||||
pe_comp.pe_print(
|
pe_affichage.pe_print(
|
||||||
f"""*** Recherche et chargement des étudiants diplômés en {
|
f"""*** Recherche et chargement des étudiants diplômés en {
|
||||||
self.diplome} pour la formation {self.formation_id}"""
|
self.diplome} pour la formation {self.formation_id}"""
|
||||||
)
|
)
|
||||||
@ -123,42 +113,47 @@ class JuryPE(object):
|
|||||||
self.diplomes_ids = self.etudiants.diplomes_ids
|
self.diplomes_ids = self.etudiants.diplomes_ids
|
||||||
|
|
||||||
# Génère les semestres taggués (avec le calcul des moyennes) pour le jury PE
|
# Génère les semestres taggués (avec le calcul des moyennes) pour le jury PE
|
||||||
pe_comp.pe_print("*** Génère les semestres taggués")
|
pe_affichage.pe_print("*** Génère les semestres taggués")
|
||||||
self.semestres_taggues = compute_semestres_tag(self.etudiants)
|
self.semestres_taggues = compute_semestres_tag(self.etudiants)
|
||||||
|
|
||||||
if pe_comp.PE_DEBUG:
|
|
||||||
# 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()
|
||||||
|
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
||||||
for formsemestretag in self.semestres_taggues.values():
|
for formsemestretag in self.semestres_taggues.values():
|
||||||
filename = formsemestretag.nom.replace(" ", "_") + ".csv"
|
onglet = formsemestretag.nom
|
||||||
pe_comp.pe_print(f" - Export csv de {filename} ")
|
df = formsemestretag.df_semtag()
|
||||||
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
self.add_file_to_zip(
|
self.add_file_to_zip(
|
||||||
zipfile,
|
zipfile,
|
||||||
filename,
|
f"semestres_taggues_{self.diplome}.xlsx",
|
||||||
formsemestretag.str_tagtable(),
|
output.read(),
|
||||||
path="details_semestres",
|
path="details",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Génère les trajectoires (combinaison de semestres suivis
|
# Génère les trajectoires (combinaison de semestres suivis
|
||||||
# par un étudiant pour atteindre le semestre final d'un aggrégat)
|
# par un étudiant pour atteindre le semestre final d'un aggrégat)
|
||||||
pe_comp.pe_print(
|
pe_affichage.pe_print(
|
||||||
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants"
|
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants"
|
||||||
)
|
)
|
||||||
self.trajectoires = TrajectoiresJuryPE(self.diplome)
|
self.trajectoires = TrajectoiresJuryPE(self.diplome)
|
||||||
self.trajectoires.cree_trajectoires(self.etudiants)
|
self.trajectoires.cree_trajectoires(self.etudiants)
|
||||||
|
|
||||||
# Génère les moyennes par tags des trajectoires
|
# Génère les moyennes par tags des trajectoires
|
||||||
pe_comp.pe_print(
|
pe_affichage.pe_print(
|
||||||
"*** Calcule les moyennes par tag des trajectoires possibles"
|
"*** Calcule les moyennes par tag des trajectoires possibles"
|
||||||
)
|
)
|
||||||
self.trajectoires_tagguees = compute_trajectoires_tag(
|
self.trajectoires_tagguees = compute_trajectoires_tag(
|
||||||
self.trajectoires, self.etudiants, self.semestres_taggues
|
self.trajectoires, self.etudiants, self.semestres_taggues
|
||||||
)
|
)
|
||||||
|
|
||||||
if pe_comp.PE_DEBUG:
|
if pe_affichage.PE_DEBUG:
|
||||||
# Intègre le bilan des trajectoires tagguées au zip final
|
# Intègre le bilan des trajectoires tagguées au zip final
|
||||||
for trajectoire_tagguee in self.trajectoires_tagguees.values():
|
for trajectoire_tagguee in self.trajectoires_tagguees.values():
|
||||||
filename = trajectoire_tagguee.get_repr().replace(" ", "_") + ".csv"
|
filename = trajectoire_tagguee.get_repr().replace(" ", "_") + ".csv"
|
||||||
pe_comp.pe_print(f" - Export csv de {filename} ")
|
# pe_affichage.pe_print(f" - Export csv de {filename} ")
|
||||||
self.add_file_to_zip(
|
self.add_file_to_zip(
|
||||||
zipfile,
|
zipfile,
|
||||||
filename,
|
filename,
|
||||||
@ -167,16 +162,16 @@ class JuryPE(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Génère les interclassements (par promo et) par (nom d') aggrégat
|
# Génère les interclassements (par promo et) par (nom d') aggrégat
|
||||||
pe_comp.pe_print("*** Génère les interclassements par aggrégat")
|
pe_affichage.pe_print("*** Génère les interclassements par aggrégat")
|
||||||
self.interclassements_taggues = compute_interclassements(
|
self.interclassements_taggues = compute_interclassements(
|
||||||
self.etudiants, self.trajectoires, self.trajectoires_tagguees
|
self.etudiants, self.trajectoires, self.trajectoires_tagguees
|
||||||
)
|
)
|
||||||
|
|
||||||
if pe_comp.PE_DEBUG:
|
if pe_affichage.PE_DEBUG:
|
||||||
# Intègre le bilan des aggrégats (par promo) au zip final
|
# Intègre le bilan des aggrégats (par promo) au zip final
|
||||||
for interclass_tag in self.interclassements_taggues.values():
|
for interclass_tag in self.interclassements_taggues.values():
|
||||||
filename = interclass_tag.get_repr().replace(" ", "_") + ".csv"
|
filename = interclass_tag.get_repr().replace(" ", "_") + ".csv"
|
||||||
pe_comp.pe_print(f" - Export csv de {filename} ")
|
# pe_affichage.pe_print(f" - Export csv de {filename} ")
|
||||||
self.add_file_to_zip(
|
self.add_file_to_zip(
|
||||||
zipfile,
|
zipfile,
|
||||||
filename,
|
filename,
|
||||||
@ -188,7 +183,7 @@ class JuryPE(object):
|
|||||||
self.synthese = self.synthetise_juryPE()
|
self.synthese = self.synthetise_juryPE()
|
||||||
|
|
||||||
# Export des données => mode 1 seule feuille -> supprimé
|
# Export des données => mode 1 seule feuille -> supprimé
|
||||||
pe_comp.pe_print("*** Export du jury de synthese")
|
pe_affichage.pe_print("*** Export du jury de synthese")
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
|
|
||||||
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
with pd.ExcelWriter(output, engine="openpyxl") as writer:
|
||||||
@ -241,15 +236,15 @@ class JuryPE(object):
|
|||||||
def synthetise_juryPE(self):
|
def synthetise_juryPE(self):
|
||||||
"""Synthétise tous les résultats du jury PE dans des dataframes"""
|
"""Synthétise tous les résultats du jury PE dans des dataframes"""
|
||||||
|
|
||||||
pe_comp.pe_print("*** Synthèse finale des moyennes ***")
|
pe_affichage.pe_print("*** Synthèse finale des moyennes ***")
|
||||||
|
|
||||||
synthese = {}
|
synthese = {}
|
||||||
pe_comp.pe_print(" -> Synthèse des données administratives")
|
pe_affichage.pe_print(" -> Synthèse des données administratives")
|
||||||
synthese["administratif"] = self.df_administratif()
|
synthese["administratif"] = self.df_administratif()
|
||||||
|
|
||||||
tags = self.do_tags_list(self.interclassements_taggues)
|
tags = self.do_tags_list(self.interclassements_taggues)
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
pe_comp.pe_print(f" -> Synthèse du tag {tag}")
|
pe_affichage.pe_print(f" -> Synthèse du tag {tag}")
|
||||||
synthese[tag] = self.df_tag(tag)
|
synthese[tag] = self.df_tag(tag)
|
||||||
return synthese
|
return synthese
|
||||||
|
|
||||||
@ -325,7 +320,7 @@ class JuryPE(object):
|
|||||||
donnees[etudid] |= {
|
donnees[etudid] |= {
|
||||||
f"{aggregat} notes ": "-",
|
f"{aggregat} notes ": "-",
|
||||||
f"{aggregat} class. (groupe)": "-",
|
f"{aggregat} class. (groupe)": "-",
|
||||||
f"{aggregat} min/moy/max (groupe)": "-",
|
f"{aggregat} min | moy | max (groupe)": "-",
|
||||||
}
|
}
|
||||||
if trajectoire:
|
if trajectoire:
|
||||||
trajectoire_tagguee = self.trajectoires_tagguees[
|
trajectoire_tagguee = self.trajectoires_tagguees[
|
||||||
@ -335,24 +330,23 @@ class JuryPE(object):
|
|||||||
bilan = trajectoire_tagguee.moyennes_tags[tag]
|
bilan = trajectoire_tagguee.moyennes_tags[tag]
|
||||||
|
|
||||||
donnees[etudid] |= {
|
donnees[etudid] |= {
|
||||||
f"{aggregat} notes ": round(bilan['notes'].loc[etudid], 2),
|
f"{aggregat} notes ": round(bilan["notes"].loc[etudid], 2),
|
||||||
f"{aggregat} class. (groupe)": f"{bilan['classements'].loc[etudid]}/{bilan['nb_inscrits']}",
|
f"{aggregat} class. (groupe)": f"{bilan['classements'].loc[etudid]}/{bilan['nb_inscrits']}",
|
||||||
f"{aggregat} min/moy/max (groupe)": f"{bilan['min']:.1f}/{bilan['moy']:.1f}/{bilan['max']:.1f}",
|
f"{aggregat} min | moy | max (groupe)": f"{bilan['min']:.1f} | {bilan['moy']:.1f} | {bilan['max']:.1f}",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
"""L'interclassement"""
|
"""L'interclassement"""
|
||||||
interclass = self.interclassements_taggues[aggregat]
|
interclass = self.interclassements_taggues[aggregat]
|
||||||
donnees[etudid] |= {
|
donnees[etudid] |= {
|
||||||
f"{aggregat} class. (promo)": "-",
|
f"{aggregat} class. (promo)": "-",
|
||||||
f"{aggregat} min/moy/max (promo)": "-",
|
f"{aggregat} min | moy | max (promo)": "-",
|
||||||
}
|
}
|
||||||
if tag in interclass.moyennes_tags:
|
if tag in interclass.moyennes_tags:
|
||||||
bilan = interclass.moyennes_tags[tag]
|
bilan = interclass.moyennes_tags[tag]
|
||||||
|
|
||||||
donnees[etudid] |= {
|
donnees[etudid] |= {
|
||||||
f"{aggregat} class. (promo)": f"{bilan['classements'].loc[etudid]}/{bilan['nb_inscrits']}",
|
f"{aggregat} class. (promo)": f"{bilan['classements'].loc[etudid]}/{bilan['nb_inscrits']}",
|
||||||
f"{aggregat} min/moy/max (promo)": f"{bilan['min']:.1f}/{bilan['moy']:.1f}/{bilan['max']:.1f}",
|
f"{aggregat} min | moy | max (promo)": f"{bilan['min']:.1f} | {bilan['moy']:.1f} | {bilan['max']:.1f}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fin de l'aggrégat
|
# Fin de l'aggrégat
|
||||||
@ -390,7 +384,7 @@ def compute_semestres_tag(etudiants: EtudiantsJuryPE) -> dict:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
"""Création des semestres taggués, de type 'S1', 'S2', ..."""
|
"""Création des semestres taggués, de type 'S1', 'S2', ..."""
|
||||||
pe_comp.pe_print("*** Création des semestres taggués")
|
pe_affichage.pe_print("*** Création des semestres taggués")
|
||||||
|
|
||||||
formsemestres = etudiants.get_formsemestres(
|
formsemestres = etudiants.get_formsemestres(
|
||||||
semestres_recherches=pe_comp.TOUS_LES_SEMESTRES
|
semestres_recherches=pe_comp.TOUS_LES_SEMESTRES
|
||||||
@ -398,19 +392,11 @@ def compute_semestres_tag(etudiants: EtudiantsJuryPE) -> dict:
|
|||||||
|
|
||||||
semestres_tags = {}
|
semestres_tags = {}
|
||||||
for frmsem_id, formsemestre in formsemestres.items():
|
for frmsem_id, formsemestre in formsemestres.items():
|
||||||
"""Choix d'un nom pour le semestretag"""
|
|
||||||
nom = "S%d %d %d-%d" % (
|
|
||||||
formsemestre.semestre_id,
|
|
||||||
frmsem_id,
|
|
||||||
formsemestre.date_debut.year,
|
|
||||||
formsemestre.date_fin.year,
|
|
||||||
)
|
|
||||||
|
|
||||||
pe_comp.pe_print(f" --> Semestre taggué {nom} sur la base de {formsemestre}")
|
|
||||||
|
|
||||||
# Crée le semestre_tag et exécute les calculs de moyennes
|
# Crée le semestre_tag et exécute les calculs de moyennes
|
||||||
formsemestretag = SemestreTag(nom, frmsem_id)
|
formsemestretag = SemestreTag(frmsem_id)
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
f" --> Semestre taggué {formsemestretag.nom} sur la base de {formsemestre}"
|
||||||
|
)
|
||||||
# Stocke le semestre taggué
|
# Stocke le semestre taggué
|
||||||
semestres_tags[frmsem_id] = formsemestretag
|
semestres_tags[frmsem_id] = formsemestretag
|
||||||
|
|
||||||
@ -443,23 +429,16 @@ def compute_trajectoires_tag(
|
|||||||
semestres_tag: Les semestres tag (pour lesquels des moyennes par tag ont été calculés)
|
semestres_tag: Les semestres tag (pour lesquels des moyennes par tag ont été calculés)
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
Un dictionnaire de la forme {nom_aggregat: {fid_terminal: SetTag(fid_terminal)} }
|
Un dictionnaire de la forme ``{nom_aggregat: {fid_terminal: SetTag(fid_terminal)} }``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pe_comp.pe_print(" *** Création des aggrégats ")
|
|
||||||
|
|
||||||
trajectoires_tagguees = {}
|
trajectoires_tagguees = {}
|
||||||
|
|
||||||
for trajectoire_id in trajectoires.trajectoires:
|
for trajectoire_id, trajectoire in trajectoires.trajectoires.items():
|
||||||
trajectoire = trajectoires.trajectoires[trajectoire_id]
|
|
||||||
nom = trajectoire.get_repr()
|
nom = trajectoire.get_repr()
|
||||||
|
pe_affichage.pe_print(f" --> Aggrégat {nom}")
|
||||||
pe_comp.pe_print(f" --> Fusion {nom}")
|
# Trajectoire_tagguee associée
|
||||||
|
|
||||||
trajectoire_tagguee = TrajectoireTag(nom, trajectoire, semestres_taggues)
|
trajectoire_tagguee = TrajectoireTag(nom, trajectoire, semestres_taggues)
|
||||||
"""Trajectoire_tagguee associée"""
|
# Mémorise le résultat
|
||||||
|
|
||||||
"""Mémorise le résultat"""
|
|
||||||
trajectoires_tagguees[trajectoire_id] = trajectoire_tagguee
|
trajectoires_tagguees[trajectoire_id] = trajectoire_tagguee
|
||||||
|
|
||||||
return trajectoires_tagguees
|
return trajectoires_tagguees
|
||||||
@ -474,11 +453,9 @@ def compute_interclassements(
|
|||||||
pour fournir un classement sur la promo. Le classement est établi au regard du nombre
|
pour fournir un classement sur la promo. Le classement est établi au regard du nombre
|
||||||
d'étudiants ayant participé au même aggrégat.
|
d'étudiants ayant participé au même aggrégat.
|
||||||
"""
|
"""
|
||||||
pe_comp.pe_print(" Interclassement sur la promo")
|
|
||||||
|
|
||||||
aggregats_interclasses_taggues = {}
|
aggregats_interclasses_taggues = {}
|
||||||
for nom_aggregat in pe_comp.TOUS_LES_SEMESTRES + pe_comp.TOUS_LES_AGGREGATS:
|
for nom_aggregat in pe_comp.TOUS_LES_SEMESTRES + pe_comp.TOUS_LES_AGGREGATS:
|
||||||
pe_comp.pe_print(f" --> {nom_aggregat}")
|
pe_affichage.pe_print(f" --> Interclassement {nom_aggregat}")
|
||||||
interclass = AggregatInterclasseTag(
|
interclass = AggregatInterclasseTag(
|
||||||
nom_aggregat, etudiants, trajectoires_jury_pe, trajectoires_tagguees
|
nom_aggregat, etudiants, trajectoires_jury_pe, trajectoires_tagguees
|
||||||
)
|
)
|
||||||
|
@ -45,61 +45,61 @@ from app.models.moduleimpls import ModuleImpl
|
|||||||
|
|
||||||
from app.scodoc import sco_tag_module
|
from app.scodoc import sco_tag_module
|
||||||
from app.scodoc.codes_cursus import UE_SPORT
|
from app.scodoc.codes_cursus import UE_SPORT
|
||||||
import app.pe.pe_comp as pe_comp
|
import app.pe.pe_affichage as pe_affichage
|
||||||
from app.pe.pe_tabletags import (TableTag, TAGS_RESERVES)
|
from app.pe.pe_tabletags import TableTag, TAGS_RESERVES
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
class SemestreTag(TableTag):
|
class SemestreTag(TableTag):
|
||||||
"""Un SemestreTag représente les résultats des étudiants à un semestre, en donnant
|
|
||||||
|
def __init__(self, formsemestre_id: int):
|
||||||
|
"""
|
||||||
|
Un SemestreTag représente les résultats des étudiants à un semestre, en donnant
|
||||||
accès aux moyennes par tag.
|
accès aux moyennes par tag.
|
||||||
Il s'appuie principalement sur FormSemestre et sur ResultatsSemestreBUT.
|
Il s'appuie principalement sur FormSemestre et sur ResultatsSemestreBUT.
|
||||||
"""
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Fonctions d'initialisation
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
def __init__(self, nom: str, formsemestre_id: int):
|
|
||||||
"""
|
|
||||||
Args:
|
Args:
|
||||||
nom: Nom à donner au SemestreTag
|
nom: Nom à donner au SemestreTag
|
||||||
formsemestre_id: Identifiant du FormSemestre sur lequel il se base
|
formsemestre_id: Identifiant du ``FormSemestre`` sur lequel il se base
|
||||||
"""
|
"""
|
||||||
TableTag.__init__(self, nom=nom)
|
# TableTag.__init__(self, nom=nom)
|
||||||
|
|
||||||
"""Le semestre"""
|
# Le semestre
|
||||||
self.formsemestre_id = formsemestre_id
|
self.formsemestre_id = formsemestre_id
|
||||||
self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
"""Les résultats du semestre"""
|
# Le nom du semestre taggué
|
||||||
|
self.nom = self.get_repr()
|
||||||
|
|
||||||
|
# Les résultats du semestre
|
||||||
self.nt = load_formsemestre_results(self.formsemestre)
|
self.nt = load_formsemestre_results(self.formsemestre)
|
||||||
|
|
||||||
"""Les étudiants"""
|
# Les étudiants
|
||||||
self.etuds = self.nt.etuds
|
self.etuds = self.nt.etuds
|
||||||
self.etudiants = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
self.etudiants = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
||||||
|
|
||||||
"""Les notes, les modules implémentés triés, les étudiants, les coeffs,
|
# Les notes, les modules implémentés triés, les étudiants, les coeffs,
|
||||||
récupérés notamment de py:mod:`res_but`
|
# récupérés notamment de py:mod:`res_but`
|
||||||
"""
|
|
||||||
self.sem_cube = self.nt.sem_cube
|
self.sem_cube = self.nt.sem_cube
|
||||||
self.modimpls_sorted = self.nt.formsemestre.modimpls_sorted
|
self.modimpls_sorted = self.nt.formsemestre.modimpls_sorted
|
||||||
self.modimpl_coefs_df = self.nt.modimpl_coefs_df
|
self.modimpl_coefs_df = self.nt.modimpl_coefs_df
|
||||||
|
|
||||||
"""Les inscriptions au module et les dispenses d'UE"""
|
# Les inscriptions au module et les dispenses d'UE
|
||||||
self.modimpl_inscr_df = self.nt.modimpl_inscr_df
|
self.modimpl_inscr_df = self.nt.modimpl_inscr_df
|
||||||
self.ues = self.nt.ues
|
self.ues = self.nt.ues
|
||||||
self.ues_inscr_parcours_df = self.nt.load_ues_inscr_parcours()
|
self.ues_inscr_parcours_df = self.nt.load_ues_inscr_parcours()
|
||||||
self.dispense_ues = self.nt.dispense_ues
|
self.dispense_ues = self.nt.dispense_ues
|
||||||
|
|
||||||
"""Les tags (en supprimant les tags réservés)"""
|
# Les tags (en supprimant les tags réservés)
|
||||||
self.tags = get_synthese_tags_semestre(self.nt.formsemestre)
|
self.tags = get_synthese_tags_semestre(self.nt.formsemestre)
|
||||||
for tag in TAGS_RESERVES:
|
for tag in TAGS_RESERVES:
|
||||||
if tag in self.tags:
|
if tag in self.tags:
|
||||||
del self.tags[tag]
|
del self.tags[tag]
|
||||||
|
|
||||||
"""Calcul des moyennes & les classements de chaque étudiant à chaque tag"""
|
# Calcul des moyennes & les classements de chaque étudiant à chaque tag
|
||||||
self.moyennes_tags = {}
|
self.moyennes_tags = {}
|
||||||
|
|
||||||
for tag in self.tags:
|
for tag in self.tags:
|
||||||
pe_comp.pe_print(f" -> Traitement du tag {tag}")
|
# pe_affichage.pe_print(f" -> Traitement du tag {tag}")
|
||||||
moy_gen_tag = self.compute_moyenne_tag(tag)
|
moy_gen_tag = self.compute_moyenne_tag(tag)
|
||||||
class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int
|
class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int
|
||||||
self.moyennes_tags[tag] = {
|
self.moyennes_tags[tag] = {
|
||||||
@ -111,8 +111,7 @@ class SemestreTag(TableTag):
|
|||||||
"nb_inscrits": len(moy_gen_tag),
|
"nb_inscrits": len(moy_gen_tag),
|
||||||
}
|
}
|
||||||
|
|
||||||
"""Ajoute les moyennes générales de BUT pour le semestre considéré"""
|
# Ajoute les moyennes générales de BUT pour le semestre considéré
|
||||||
pe_comp.pe_print(f" -> Traitement du tag but")
|
|
||||||
moy_gen_but = self.nt.etud_moy_gen
|
moy_gen_but = self.nt.etud_moy_gen
|
||||||
class_gen_but = self.nt.etud_moy_gen_ranks_int
|
class_gen_but = self.nt.etud_moy_gen_ranks_int
|
||||||
self.moyennes_tags["but"] = {
|
self.moyennes_tags["but"] = {
|
||||||
@ -124,16 +123,18 @@ class SemestreTag(TableTag):
|
|||||||
"nb_inscrits": len(moy_gen_but),
|
"nb_inscrits": len(moy_gen_but),
|
||||||
}
|
}
|
||||||
|
|
||||||
"""Synthétise l'ensemble des moyennes dans un dataframe"""
|
# Synthétise l'ensemble des moyennes dans un dataframe
|
||||||
self.tags_sorted = sorted(self.moyennes_tags) # les tags par ordre alphabétique
|
self.tags_sorted = sorted(self.moyennes_tags) # les tags par ordre alphabétique
|
||||||
self.notes = self.df_tagtable() # Le dataframe synthétique des notes (=moyennes par tag)
|
self.notes = (
|
||||||
|
self.df_tagtable()
|
||||||
|
) # Le dataframe synthétique des notes (=moyennes par tag)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
pe_affichage.pe_print(f" => Traitement des tags {', '.join(self.tags_sorted)}")
|
||||||
def get_etudids(self):
|
|
||||||
"""Renvoie la liste des etud_id des étudiants inscrits au semestre"""
|
def get_repr(self):
|
||||||
return [etud["etudid"] for etud in self.inscrlist]
|
"""Nom affiché pour le semestre taggué"""
|
||||||
|
return pe_affichage.nom_semestre_etape(self.formsemestre, avec_fid=True)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
def compute_moyenne_tag(self, tag: str) -> list:
|
def compute_moyenne_tag(self, tag: str) -> list:
|
||||||
"""Calcule la moyenne des étudiants pour le tag indiqué,
|
"""Calcule la moyenne des étudiants pour le tag indiqué,
|
||||||
pour ce SemestreTag.
|
pour ce SemestreTag.
|
||||||
@ -192,14 +193,22 @@ class SemestreTag(TableTag):
|
|||||||
|
|
||||||
return moy_gen_tag
|
return moy_gen_tag
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
||||||
"""Renvoie un couple donnant la note et le coeff normalisé d'un étudiant à un module d'id modimpl_id.
|
"""Renvoie un couple donnant la note et le coeff normalisé d'un étudiant à un module d'id modimpl_id.
|
||||||
La note et le coeff sont extraits :
|
La note et le coeff sont extraits :
|
||||||
1) soit des données du semestre en normalisant le coefficient par rapport à la somme des coefficients des modules du semestre,
|
1) soit des données du semestre en normalisant le coefficient par rapport à la somme des coefficients des modules du semestre,
|
||||||
2) soit des données des UE précédemment capitalisées, en recherchant un module de même CODE que le modimpl_id proposé,
|
2) soit des données des UE précédemment capitalisées, en recherchant un module de même CODE que le modimpl_id proposé,
|
||||||
le coefficient normalisé l'étant alors par rapport au total des coefficients du semestre auquel appartient l'ue capitalisée
|
le coefficient normalisé l'étant alors par rapport au total des coefficients du semestre auquel appartient l'ue capitalisée
|
||||||
|
|
||||||
|
TODO:: A rependre si nécessaire
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def get_ue_capitalisees(etudid) -> list[dict]:
|
||||||
|
"""Renvoie la liste des capitalisation effectivement capitalisées par un étudiant"""
|
||||||
|
if etudid in self.nt.validations.ue_capitalisees.index:
|
||||||
|
return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records")
|
||||||
|
return []
|
||||||
|
|
||||||
(note, coeff_norm) = (None, None)
|
(note, coeff_norm) = (None, None)
|
||||||
|
|
||||||
modimpl = get_moduleimpl(modimpl_id) # Le module considéré
|
modimpl = get_moduleimpl(modimpl_id) # Le module considéré
|
||||||
@ -207,7 +216,7 @@ class SemestreTag(TableTag):
|
|||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
# Y-a-t-il eu capitalisation d'UE ?
|
# Y-a-t-il eu capitalisation d'UE ?
|
||||||
ue_capitalisees = self.get_ue_capitalisees(
|
ue_capitalisees = get_ue_capitalisees(
|
||||||
etudid
|
etudid
|
||||||
) # les ue capitalisées des étudiants
|
) # les ue capitalisées des étudiants
|
||||||
ue_capitalisees_id = {
|
ue_capitalisees_id = {
|
||||||
@ -273,130 +282,18 @@ class SemestreTag(TableTag):
|
|||||||
# Sinon - pas de notes à prendre en compte
|
# Sinon - pas de notes à prendre en compte
|
||||||
return (note, coeff_norm)
|
return (note, coeff_norm)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
def df_semtag(self):
|
||||||
def get_ue_capitalisees(self, etudid) -> list[dict]:
|
"""Renvoie un dataframe listant toutes les moyennes,
|
||||||
"""Renvoie la liste des capitalisation effectivement capitalisées par un étudiant"""
|
les rangs des étudiants pour tous les tags dans le semestre taggué"""
|
||||||
if etudid in self.nt.validations.ue_capitalisees.index:
|
|
||||||
return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records")
|
|
||||||
return []
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
etudiants = self.etudiants
|
||||||
# Fonctions d'affichage (et d'export csv) des données du semestre en mode debug
|
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom"])
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
def str_detail_resultat_d_un_tag(self, tag, etudid=None, delim=";"):
|
|
||||||
"""Renvoie une chaine de caractère décrivant les résultats d'étudiants à un tag :
|
|
||||||
rappelle les notes obtenues dans les modules à prendre en compte, les moyennes et les rangs calculés.
|
|
||||||
Si etudid=None, tous les étudiants inscrits dans le semestre sont pris en compte. Sinon seuls les étudiants indiqués sont affichés.
|
|
||||||
"""
|
|
||||||
# Entete
|
|
||||||
chaine = delim.join(["%15s" % "nom", "etudid"]) + delim
|
|
||||||
taglist = self.get_all_tags()
|
|
||||||
if tag in taglist:
|
|
||||||
for mod in self.tagdict[tag].values():
|
|
||||||
chaine += mod["module_code"] + delim
|
|
||||||
chaine += ("%1.1f" % mod["ponderation"]) + delim
|
|
||||||
chaine += "coeff" + delim
|
|
||||||
chaine += delim.join(
|
|
||||||
["moyenne", "rang", "nbinscrit", "somme_coeff", "somme_coeff"]
|
|
||||||
) # ligne 1
|
|
||||||
chaine += "\n"
|
|
||||||
|
|
||||||
# Différents cas de boucles sur les étudiants (de 1 à plusieurs)
|
for tag in self.get_all_tags():
|
||||||
if etudid == None:
|
df = df.join(self.moyennes_tags[tag]["notes"].rename(f"Moy {tag}"))
|
||||||
lesEtuds = self.get_etudids()
|
df = df.join(self.moyennes_tags[tag]["classements"].rename(f"Class {tag}"))
|
||||||
elif isinstance(etudid, str) and etudid in self.get_etudids():
|
|
||||||
lesEtuds = [etudid]
|
|
||||||
elif isinstance(etudid, list):
|
|
||||||
lesEtuds = [eid for eid in self.get_etudids() if eid in etudid]
|
|
||||||
else:
|
|
||||||
lesEtuds = []
|
|
||||||
|
|
||||||
for etudid in lesEtuds:
|
|
||||||
descr = (
|
|
||||||
"%15s" % self.nt.get_nom_short(etudid)[:15]
|
|
||||||
+ delim
|
|
||||||
+ str(etudid)
|
|
||||||
+ delim
|
|
||||||
)
|
|
||||||
if tag in taglist:
|
|
||||||
for modimpl_id in self.tagdict[tag]:
|
|
||||||
(note, coeff) = self.get_noteEtCoeff_modimpl(modimpl_id, etudid)
|
|
||||||
descr += (
|
|
||||||
(
|
|
||||||
"%2.2f" % note
|
|
||||||
if note != None and isinstance(note, float)
|
|
||||||
else str(note)
|
|
||||||
)
|
|
||||||
+ delim
|
|
||||||
+ (
|
|
||||||
"%1.5f" % coeff
|
|
||||||
if coeff != None and isinstance(coeff, float)
|
|
||||||
else str(coeff)
|
|
||||||
)
|
|
||||||
+ delim
|
|
||||||
+ (
|
|
||||||
"%1.5f" % (coeff * self.somme_coeffs)
|
|
||||||
if coeff != None and isinstance(coeff, float)
|
|
||||||
else "???" # str(coeff * self._sum_coeff_semestre) # voir avec Cléo
|
|
||||||
)
|
|
||||||
+ delim
|
|
||||||
)
|
|
||||||
moy = self.get_moy_from_resultats(tag, etudid)
|
|
||||||
rang = self.get_rang_from_resultats(tag, etudid)
|
|
||||||
coeff = self.get_coeff_from_resultats(tag, etudid)
|
|
||||||
tot = (
|
|
||||||
coeff * self.somme_coeffs
|
|
||||||
if coeff != None
|
|
||||||
and self.somme_coeffs != None
|
|
||||||
and isinstance(coeff, float)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
descr += (
|
|
||||||
pe_tagtable.TableTag.str_moytag(
|
|
||||||
moy, rang, len(self.get_etudids()), delim=delim
|
|
||||||
)
|
|
||||||
+ delim
|
|
||||||
)
|
|
||||||
descr += (
|
|
||||||
(
|
|
||||||
"%1.5f" % coeff
|
|
||||||
if coeff != None and isinstance(coeff, float)
|
|
||||||
else str(coeff)
|
|
||||||
)
|
|
||||||
+ delim
|
|
||||||
+ (
|
|
||||||
"%.2f" % (tot)
|
|
||||||
if tot != None
|
|
||||||
else str(coeff) + "*" + str(self.somme_coeffs)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
chaine += descr
|
|
||||||
chaine += "\n"
|
|
||||||
return chaine
|
|
||||||
|
|
||||||
def str_tagsModulesEtCoeffs(self):
|
|
||||||
"""Renvoie une chaine affichant la liste des tags associés au semestre,
|
|
||||||
les modules qui les concernent et les coeffs de pondération.
|
|
||||||
Plus concrètement permet d'afficher le contenu de self._tagdict"""
|
|
||||||
chaine = "Semestre %s d'id %d" % (self.nom, id(self)) + "\n"
|
|
||||||
chaine += " -> somme de coeffs: " + str(self.somme_coeffs) + "\n"
|
|
||||||
taglist = self.get_all_tags()
|
|
||||||
for tag in taglist:
|
|
||||||
chaine += " > " + tag + ": "
|
|
||||||
for modid, mod in self.tagdict[tag].items():
|
|
||||||
chaine += (
|
|
||||||
mod["module_code"]
|
|
||||||
+ " ("
|
|
||||||
+ str(mod["coeff"])
|
|
||||||
+ "*"
|
|
||||||
+ str(mod["ponderation"])
|
|
||||||
+ ") "
|
|
||||||
+ str(modid)
|
|
||||||
+ ", "
|
|
||||||
)
|
|
||||||
chaine += "\n"
|
|
||||||
return chaine
|
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
# Fonctions diverses
|
# Fonctions diverses
|
||||||
@ -437,8 +334,8 @@ def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float:
|
|||||||
def get_synthese_tags_semestre(formsemestre: FormSemestre):
|
def get_synthese_tags_semestre(formsemestre: FormSemestre):
|
||||||
"""Etant données les implémentations des modules du semestre (modimpls),
|
"""Etant données les implémentations des modules du semestre (modimpls),
|
||||||
synthétise les tags les concernant (tags saisis dans le programme pédagogique)
|
synthétise les tags les concernant (tags saisis dans le programme pédagogique)
|
||||||
en les associant aux modimpls qui les concernent (modimpl_id, module_id,
|
en les associant aux modimpls qui les concernent (modimpl_id) et
|
||||||
le code du module, coeff et pondération fournie avec le tag (par défaut 1 si non indiquée)).
|
aucoeff et pondération fournie avec le tag (par défaut 1 si non indiquée)).
|
||||||
|
|
||||||
{ tagname1: { modimpl_id1: { 'module_id': ...,
|
{ tagname1: { modimpl_id1: { 'module_id': ...,
|
||||||
'coeff': ...,
|
'coeff': ...,
|
||||||
@ -451,6 +348,9 @@ def get_synthese_tags_semestre(formsemestre: FormSemestre):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
formsemestre: Le formsemestre à la base de la recherche des tags
|
formsemestre: Le formsemestre à la base de la recherche des tags
|
||||||
|
|
||||||
|
Return:
|
||||||
|
Un dictionnaire de tags
|
||||||
"""
|
"""
|
||||||
synthese_tags = {}
|
synthese_tags = {}
|
||||||
|
|
||||||
|
@ -91,188 +91,6 @@ class TableTag(object):
|
|||||||
return sorted(self.moyennes_tags.keys())
|
return sorted(self.moyennes_tags.keys())
|
||||||
|
|
||||||
|
|
||||||
# *****************************************************************************************************************
|
|
||||||
# Accesseurs
|
|
||||||
# *****************************************************************************************************************
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
def get_moy_from_resultats(self, tag, etudid):
|
|
||||||
"""Renvoie la moyenne obtenue par un étudiant à un tag donné au regard du format de self.resultats"""
|
|
||||||
return (
|
|
||||||
self.moyennes_tags[tag][etudid][0]
|
|
||||||
if tag in self.moyennes_tags and etudid in self.moyennes_tags[tag]
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
def get_rang_from_resultats(self, tag, etudid):
|
|
||||||
"""Renvoie le rang à un tag d'un étudiant au regard du format de self.resultats"""
|
|
||||||
return (
|
|
||||||
self.rangs[tag][etudid]
|
|
||||||
if tag in self.moyennes_tags and etudid in self.moyennes_tags[tag]
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
def get_coeff_from_resultats(self, tag, etudid):
|
|
||||||
"""Renvoie la somme des coeffs de pondération normalisée utilisés dans le calcul de la moyenne à un tag d'un étudiant
|
|
||||||
au regard du format de self.resultats.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
self.moyennes_tags[tag][etudid][1]
|
|
||||||
if tag in self.moyennes_tags and etudid in self.moyennes_tags[tag]
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
def get_nbinscrits(self):
|
|
||||||
"""Renvoie le nombre d'inscrits"""
|
|
||||||
return len(self.inscrlist)
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
def get_moy_from_stats(self, tag):
|
|
||||||
"""Renvoie la moyenne des notes calculées pour d'un tag donné"""
|
|
||||||
return self.statistiques[tag][0] if tag in self.statistiques else None
|
|
||||||
|
|
||||||
def get_min_from_stats(self, tag):
|
|
||||||
"""Renvoie la plus basse des notes calculées pour d'un tag donné"""
|
|
||||||
return self.statistiques[tag][1] if tag in self.statistiques else None
|
|
||||||
|
|
||||||
def get_max_from_stats(self, tag):
|
|
||||||
"""Renvoie la plus haute des notes calculées pour d'un tag donné"""
|
|
||||||
return self.statistiques[tag][2] if tag in self.statistiques else None
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
# La structure des données mémorisées pour chaque tag dans le dictionnaire de synthèse
|
|
||||||
# d'un jury PE
|
|
||||||
FORMAT_DONNEES_ETUDIANTS = (
|
|
||||||
"note",
|
|
||||||
"coeff",
|
|
||||||
"rang",
|
|
||||||
"nbinscrits",
|
|
||||||
"moy",
|
|
||||||
"max",
|
|
||||||
"min",
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_resultatsEtud(self, tag, etudid):
|
|
||||||
"""Renvoie un tuple (note, coeff, rang, nb_inscrit, moy, min, max) synthétisant les résultats d'un étudiant
|
|
||||||
à un tag donné. None sinon"""
|
|
||||||
return (
|
|
||||||
self.get_moy_from_resultats(tag, etudid),
|
|
||||||
self.get_coeff_from_resultats(tag, etudid),
|
|
||||||
self.get_rang_from_resultats(tag, etudid),
|
|
||||||
self.get_nbinscrits(),
|
|
||||||
self.get_moy_from_stats(tag),
|
|
||||||
self.get_min_from_stats(tag),
|
|
||||||
self.get_max_from_stats(tag),
|
|
||||||
)
|
|
||||||
|
|
||||||
# return self.tag_stats[tag]
|
|
||||||
# else :
|
|
||||||
# return self.pe_stats
|
|
||||||
|
|
||||||
# *****************************************************************************************************************
|
|
||||||
# Ajout des notes
|
|
||||||
# *****************************************************************************************************************
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
|
||||||
def add_moyennesTag(self, tag, listMoyEtCoeff) -> bool:
|
|
||||||
"""
|
|
||||||
Mémorise les moyennes, les coeffs de pondération et les etudid dans resultats
|
|
||||||
avec calcul du rang
|
|
||||||
:param tag: Un tag
|
|
||||||
:param listMoyEtCoeff: Une liste donnant [ (moy, coeff, etudid) ]
|
|
||||||
|
|
||||||
TODO:: Inutile maintenant ?
|
|
||||||
"""
|
|
||||||
# ajout des moyennes au dictionnaire résultat
|
|
||||||
if listMoyEtCoeff:
|
|
||||||
self.moyennes_tags[tag] = {
|
|
||||||
etudid: (moyenne, somme_coeffs)
|
|
||||||
for (moyenne, somme_coeffs, etudid) in listMoyEtCoeff
|
|
||||||
}
|
|
||||||
|
|
||||||
# Calcule les rangs
|
|
||||||
lesMoyennesTriees = sorted(
|
|
||||||
listMoyEtCoeff,
|
|
||||||
reverse=True,
|
|
||||||
key=lambda col: col[0]
|
|
||||||
if isinstance(col[0], float)
|
|
||||||
else 0, # remplace les None et autres chaines par des zéros
|
|
||||||
) # triées
|
|
||||||
self.rangs[tag] = scu.comp_ranks(lesMoyennesTriees) # les rangs
|
|
||||||
|
|
||||||
# calcul des stats
|
|
||||||
self.comp_stats_d_un_tag(tag)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
# *****************************************************************************************************************
|
|
||||||
# Méthodes dévolues aux calculs de statistiques (min, max, moy) sur chaque moyenne taguée
|
|
||||||
# *****************************************************************************************************************
|
|
||||||
|
|
||||||
def comp_stats_d_un_tag(self, tag):
|
|
||||||
"""
|
|
||||||
Calcule la moyenne generale, le min, le max pour un tag donné,
|
|
||||||
en ne prenant en compte que les moyennes significatives. Mémorise le resultat dans
|
|
||||||
self.statistiques
|
|
||||||
"""
|
|
||||||
stats = ("-NA-", "-", "-")
|
|
||||||
if tag not in self.moyennes_tags:
|
|
||||||
return stats
|
|
||||||
|
|
||||||
notes = [
|
|
||||||
self.get_moy_from_resultats(tag, etudid)
|
|
||||||
for etudid in self.moyennes_tags[tag]
|
|
||||||
] # les notes du tag
|
|
||||||
notes_valides = [
|
|
||||||
note for note in notes if isinstance(note, float) and note != None
|
|
||||||
]
|
|
||||||
nb_notes_valides = len(notes_valides)
|
|
||||||
if nb_notes_valides > 0:
|
|
||||||
(moy, _) = moyenne_ponderee_terme_a_terme(notes_valides, force=True)
|
|
||||||
self.statistiques[tag] = (moy, max(notes_valides), min(notes_valides))
|
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# Méthodes dévolues aux affichages -> a revoir
|
|
||||||
# ************************************************************************
|
|
||||||
def str_resTag_d_un_etudiant(self, tag, etudid, delim=";"):
|
|
||||||
"""Renvoie une chaine de caractères (valable pour un csv)
|
|
||||||
décrivant la moyenne et le rang d'un étudiant, pour un tag donné ;
|
|
||||||
"""
|
|
||||||
if tag not in self.get_all_tags() or etudid not in self.moyennes_tags[tag]:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
moystr = TableTag.str_moytag(
|
|
||||||
self.get_moy_from_resultats(tag, etudid),
|
|
||||||
self.get_rang_from_resultats(tag, etudid),
|
|
||||||
self.get_nbinscrits(),
|
|
||||||
delim=delim,
|
|
||||||
)
|
|
||||||
return moystr
|
|
||||||
|
|
||||||
def str_res_d_un_etudiant(self, etudid, delim=";"):
|
|
||||||
"""Renvoie sur une ligne les résultats d'un étudiant à tous les tags (par ordre alphabétique)."""
|
|
||||||
return delim.join(
|
|
||||||
[self.str_resTag_d_un_etudiant(tag, etudid) for tag in self.get_all_tags()]
|
|
||||||
)
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
def str_moytag(cls, moyenne, rang, nbinscrit, delim=";"):
|
|
||||||
"""Renvoie une chaine de caractères représentant une moyenne (float ou string) et un rang
|
|
||||||
pour différents formats d'affichage : HTML, debug ligne de commande, csv"""
|
|
||||||
moystr = (
|
|
||||||
"%2.2f%s%s%s%d" % (moyenne, delim, rang, delim, nbinscrit)
|
|
||||||
if isinstance(moyenne, float)
|
|
||||||
else str(moyenne) + delim + str(rang) + delim + str(nbinscrit)
|
|
||||||
)
|
|
||||||
return moystr
|
|
||||||
|
|
||||||
str_moytag = classmethod(str_moytag)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
def df_tagtable(self):
|
def df_tagtable(self):
|
||||||
"""Renvoie un dataframe (etudid x tag) listant toutes les moyennes par tags
|
"""Renvoie un dataframe (etudid x tag) listant toutes les moyennes par tags
|
||||||
|
|
||||||
@ -300,68 +118,3 @@ class TableTag(object):
|
|||||||
|
|
||||||
return df.to_csv(sep=";")
|
return df.to_csv(sep=";")
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# Fonctions diverses
|
|
||||||
# ************************************************************************
|
|
||||||
|
|
||||||
|
|
||||||
# *********************************************
|
|
||||||
def moyenne_ponderee_terme_a_terme(notes, coefs=None, force=False):
|
|
||||||
"""
|
|
||||||
Calcule la moyenne pondérée d'une liste de notes avec d'éventuels coeffs de pondération.
|
|
||||||
Renvoie le résultat sous forme d'un tuple (moy, somme_coeff)
|
|
||||||
|
|
||||||
La liste de notes contient soit :
|
|
||||||
1) des valeurs numériques
|
|
||||||
2) des strings "-NA-" (pas de notes) ou "-NI-" (pas inscrit) ou "-c-" ue capitalisée,
|
|
||||||
3) None.
|
|
||||||
|
|
||||||
Le paramètre force indique si le calcul de la moyenne doit être forcée ou non, c'est à
|
|
||||||
dire s'il y a ou non omission des notes non numériques (auquel cas la moyenne est
|
|
||||||
calculée sur les notes disponibles) ; sinon renvoie (None, None).
|
|
||||||
"""
|
|
||||||
# Vérification des paramètres d'entrée
|
|
||||||
if not isinstance(notes, list) or (
|
|
||||||
coefs != None and not isinstance(coefs, list) and len(coefs) != len(notes)
|
|
||||||
):
|
|
||||||
raise ValueError("Erreur de paramètres dans moyenne_ponderee_terme_a_terme")
|
|
||||||
|
|
||||||
# Récupération des valeurs des paramètres d'entrée
|
|
||||||
coefs = [1] * len(notes) if coefs is None else coefs
|
|
||||||
|
|
||||||
# S'il n'y a pas de notes
|
|
||||||
if not notes: # Si notes = []
|
|
||||||
return (None, None)
|
|
||||||
|
|
||||||
# Liste indiquant les notes valides
|
|
||||||
notes_valides = [
|
|
||||||
(isinstance(note, float) and not np.isnan(note)) or isinstance(note, int)
|
|
||||||
for note in notes
|
|
||||||
]
|
|
||||||
# Si on force le calcul de la moyenne ou qu'on ne le force pas
|
|
||||||
# et qu'on a le bon nombre de notes
|
|
||||||
if force or sum(notes_valides) == len(notes):
|
|
||||||
moyenne, ponderation = 0.0, 0.0
|
|
||||||
for i in range(len(notes)):
|
|
||||||
if notes_valides[i]:
|
|
||||||
moyenne += coefs[i] * notes[i]
|
|
||||||
ponderation += coefs[i]
|
|
||||||
return (
|
|
||||||
(moyenne / (ponderation * 1.0), ponderation)
|
|
||||||
if ponderation != 0
|
|
||||||
else (None, 0)
|
|
||||||
)
|
|
||||||
# Si on ne force pas le calcul de la moyenne
|
|
||||||
return (None, None)
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------------------------
|
|
||||||
def conversionDate_StrToDate(date_fin):
|
|
||||||
"""Conversion d'une date fournie sous la forme d'une chaine de caractère de
|
|
||||||
type 'jj/mm/aaaa' en un objet date du package datetime.
|
|
||||||
Fonction servant au tri des semestres par date
|
|
||||||
"""
|
|
||||||
(d, m, y) = [int(x) for x in date_fin.split("/")]
|
|
||||||
date_fin_dst = datetime.date(y, m, d)
|
|
||||||
return date_fin_dst
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import app.pe.pe_comp as pe_comp
|
import app.pe.pe_comp as pe_comp
|
||||||
|
import app.pe.pe_affichage as pe_affichage
|
||||||
|
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre
|
||||||
from app.pe.pe_etudiant import EtudiantsJuryPE, get_dernier_semestre_en_date
|
from app.pe.pe_etudiant import EtudiantsJuryPE, get_dernier_semestre_en_date
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ def get_trajectoires_etudid(trajectoires, etudid):
|
|||||||
trajectoires suivies par un étudiant
|
trajectoires suivies par un étudiant
|
||||||
"""
|
"""
|
||||||
if etudid not in trajectoires.suivi:
|
if etudid not in trajectoires.suivi:
|
||||||
pe_comp.pe_print(f"{etudid} fait-il bien partie du jury ?")
|
pe_affichage.pe_print(f"{etudid} fait-il bien partie du jury ?")
|
||||||
|
|
||||||
liste = []
|
liste = []
|
||||||
for aggregat in pe_comp.TOUS_LES_PARCOURS:
|
for aggregat in pe_comp.TOUS_LES_PARCOURS:
|
||||||
|
@ -39,12 +39,10 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
from app.comp import moy_sem
|
from app.comp import moy_sem
|
||||||
from app.comp.res_sem import load_formsemestre_results
|
from app.comp.res_sem import load_formsemestre_results
|
||||||
from app.pe.pe_semtag import SemestreTag
|
from app.pe.pe_semtag import SemestreTag
|
||||||
from app.pe import pe_tabletags
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from app.pe.pe_trajectoire import Trajectoire
|
from app.pe.pe_trajectoire import Trajectoire
|
||||||
|
|
||||||
from app.pe.pe_etudiant import EtudiantsJuryPE
|
|
||||||
from app.pe.pe_tabletags import TableTag
|
from app.pe.pe_tabletags import TableTag
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user