#!/usr/bin/env python # encoding: utf-8 import pandas as pd import numpy as np from repytex.tools.marks_plottings import (pie_pivot_table, parallel_on, radar_on, hist_boxplot ) import seaborn as sns class Student(object): """ Informations on a student which can be use inside template. Those informations should not be modify or use for compute analysis otherwise they won't be spread over other POV. """ def __init__(self, quest_df, exo_df, eval_df): """ Description of a student from quest, exo and eval """ name = {*quest_df["Eleve"].unique(), *exo_df["Eleve"].unique(), *eval_df["Eleve"].unique(), } if len(name) != 1: raise ValueError("Can't initiate Student: dfs contains different student names") self.name = name.pop() evalname = {*quest_df["Nom"].unique(), *exo_df["Nom"].unique(), *eval_df["Nom"].unique(), } if len(evalname) != 1: raise ValueError(f"Can't initiate Student: dfs contains different evaluation names ({'-'.join(evalname)})") self.quest_df = quest_df self.exo_df = exo_df self.eval = eval_df.to_dict('records')[0] @property def latex_exo_tabulars(self): """ Return list of latex tabulars. One by exercise of the evaluation """ try: self._latex_exo_tabulars except AttributeError: self._latex_exo_tabulars = self.build_latex_exo_tabulars() return self._latex_exo_tabulars def build_latex_exo_tabulars(self): tabulars = [] for t in self.exo_df["Exercice"]: tabulars.append(self.build_latex_exo_tabular(t)) return tabulars def build_latex_exo_tabular(self, exo_name): exo = self.exo_df[self.exo_df["Exercice"] == exo_name] quest = self.quest_df[self.quest_df["Exercice"] == exo_name] tabular = [r"\begin{tabular}{|p{2cm}|p{1cm}|}"] tabular.append(r"\hline") tabular.append(r"\rowcolor{highlightbg}") if type(exo_name) == int: l = f"Exercice {exo_name} & {exo['Mark_barem'].all()}" tabular.append(l + r" \\") else: l = f"{exo_name} & {exo['Mark_barem'].all()}" tabular.append(l + r" \\") tabular.append(r"\hline") if len(quest) > 1: for _, q in quest.iterrows(): line = "" if not pd.isnull(q["Question"]): line += " "+str(q['Question']) if not pd.isnull(q["Commentaire"]): line += " "+str(q['Commentaire']) line += " & " if q["Niveau"] == 1: line += q['Latex_rep'] else: line += str(q['Mark']) line += r" \\" tabular.append(line) tabular.append(r"\hline") tabular.append(r"\end{tabular}") return '\n'.join(tabular) @property def pies_on_competence(self): """ Pies chart on competences """ return pie_pivot_table(self.quest_df, index = "Level", columns = "Competence", values = "Eleve", aggfunc = len, fill_value = 0, ) @property def pies_on_domaine(self): """ Pies chart on domaines """ return pie_pivot_table(self.quest_df, index = "Level", columns = "Domaine", values = "Eleve", aggfunc = len, fill_value = 0, ) @property def radar_on_competence(self): """ Radar plot on competence """ return radar_on(self.quest_df, "Competence") @property def radar_on_domaine(self): """ Radar plot on domaine """ return radar_on(self.quest_df, "Domaine") @property def heatmap_on_domain(self): """ Heatmap over evals on domains """ comp = pd.pivot_table(self.quest_df, index = "Competence", columns = ["Exercice", "Question"], values = ["Normalized"], aggfunc = np.mean, ) comp.columns = [f"{i['Exercice']} {i['Question']}" for _,i in self.quest_df[["Exercice", "Question"]].drop_duplicates().iterrows()] return sns.heatmap(comp) class Classe(object): """ Informations on a class which can be use inside template. Those informations should not be modify or use for compute analysis otherwise they won't be spread over other POV. """ def __init__(self, quest_df, exo_df, eval_df): """ Init of a class from quest, exo and eval """ names = {*quest_df["Nom"].unique(), *exo_df["Nom"].unique(), *eval_df["Nom"].unique(), } if len(names) != 1: raise ValueError("Can't initiate Classe: dfs contains different evaluation names") self.name = names.pop() self.quest_df = quest_df self.exo_df = exo_df self.eval_df = eval_df @property def marks_tabular(self): """ Latex tabular with marks of students""" try: self._marks_tabular except AttributeError: self._marks_tabular = self.eval_df[["Eleve", "Mark_barem"]] self._marks_tabular.columns = ["Élèves", "Note"] return self._marks_tabular.to_latex() @property def hist_boxplot(self): """ Marks histogram and associed box plot """ return hist_boxplot(self.eval_df) @property def level_heatmap(self): """ Heapmap on acheivement level """ pv = pd.pivot_table(self.quest_df, index = "Eleve", columns = ["Exercice", "Question", "Commentaire"], values = ["Normalized"], aggfunc = "mean", ) def lines_4_heatmap(c): lines = [] ini = '' for k,v in enumerate(c.labels[1][::-1]): if v != ini: lines.append(k) ini = v return lines[1:] exercice_sep = lines_4_heatmap(pv.columns) pv.columns = [f"{i[3]:.15} {i[1]} {i[2]}" for i in pv.columns.get_values()] level_heatmap = sns.heatmap(pv.T) level_heatmap.hlines(exercice_sep, *level_heatmap.get_xlim(), colors = "orange", ) return level_heatmap @property def pies_eff_pts_on_competence(self): """ Pie charts on competence with repartition of evaluated times and attributed points """ return pie_pivot_table(self.quest_df[["Competence", "Bareme", "Exercice", "Question", "Commentaire"]].drop_duplicates(), index = "Competence", #columns = "Level", values = "Bareme", aggfunc=[len,np.sum], fill_value=0) @property def pies_eff_pts_on_domaine(self): """ Pie charts on domaine with repartition of evaluated times and attributed points """ return pie_pivot_table(self.quest_df[["Domaine", "Bareme", "Exercice", "Question", "Commentaire"]].drop_duplicates(), index = "Domaine", #columns = "Level", values = "Bareme", aggfunc=[len,np.sum], fill_value=0) # TODO: à factoriser Il y a la même dans term.py |jeu. mars 23 19:36:28 EAT 2017 def select(quest_df, exo_df, eval_df, index, value): """ Return quest, exo and eval rows which correspond index == value :param quest_df: TODO :param exo_df: TODO :param eval_df: TODO """ qu = quest_df[quest_df[index] == value] exo = exo_df[exo_df[index] == value] ev = eval_df[eval_df[index] == value] return qu, exo, ev def select_contains(quest_df, exo_df, eval_df, index, name_part): """ Return quest, exo and eval rows which contains name_part :param quest_df: TODO :param exo_df: TODO :param eval_df: TODO """ qu = quest_df[quest_df[index].str.contains(name_part)] exo = exo_df[exo_df[index].str.contains(name_part)] ev = eval_df[eval_df[index].str.contains(name_part)] return qu, exo, ev def students_pov(quest_df, exo_df, eval_df): es = [] for e in eval_df["Eleve"].unique(): d = select(quest_df, exo_df, eval_df, "Eleve", e) eleve = Student(*d) es.append(eleve) return es def class_pov(quest_df, exo_df, eval_df): return Classe(quest_df, exo_df, eval_df) # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: # cursor: 16 del