noteneingabetool/stats_ui.py
2025-07-25 18:54:33 +02:00

59 lines
2.7 KiB
Python

import streamlit as st
import pandas as pd
import altair as alt
from backend.db import Session
def stats_ui(session: Session, grades_table: pd.DataFrame, grades: list):
with st.expander('Statistiken'):
number_students = len(session.points_df)
number_participants = len(session.points_df[session.points_df['Punkte'].notna()])
if number_participants > 0:
# Convert from categorical strings to numerical values
points_table = session.points_df.reset_index()[['Punkte', 'Note']].copy().dropna()
points_table['Note'] = points_table['Note'].apply(lambda x: float(f'{x}'.replace(',', '.')))
grades_tab = grades_table['Note'].apply(lambda x: float(f'{x}'.replace(',', '.')))
score_hist = pd.DataFrame({'Anzahl': [0] * len(grades_tab)}, index=grades_tab)
counts = pd.DataFrame(points_table['Note'].value_counts().rename('Anzahl'))
score_hist.update(counts)
score_hist.reset_index(inplace=True)
hist = alt.Chart(score_hist).mark_bar().encode(
x=alt.X('Anzahl:Q', axis=alt.Axis(title='Anzahl', tickCount=score_hist['Anzahl'].max()+1, grid=True)),
y=alt.Y('Note:O', bin=alt.Bin(binned=True), axis=alt.Axis(title='Note', grid=True))
)
median = alt.Chart(points_table).mark_rule(color='blue', opacity=0.5).encode(
y = 'median(Note):O',
size=alt.value(5),
)
mean = alt.Chart(points_table).mark_rule(color='orange', opacity=0.5, strokeDash=[5,5]).encode(
y = 'mean(Note):O',
size=alt.value(5),
)
chart = (hist + median + mean)
st.altair_chart(chart, use_container_width=True)
passed = 1-score_hist.iloc[-1]["Anzahl"]/number_participants
1-score_hist.iloc[-1]["Anzahl"]/number_participants
left, mid, right, rightmost = st.columns(4)
with left:
st.write(f'Anzahl Anmeldungen: {number_students}')
st.write(f'Anzahl Teilnehmer: {number_participants}')
with mid:
st.write(f'Bestanden: :green[{passed*100:.2f} %]')
st.write(f'Durchgefallen: :red[{100-passed*100:.2f}%]')
with right:
st.write(f'Punkteuntergrenzen: :gray[(1,0)] {session.grade_1_0:.2f}% / :gray[(4,0)] {session.grade_4_0:.2f}%')
st.write(f'Maximalpunktzahl: {session.max_points}')
with rightmost:
st.write(f':orange[Durchschnitt:] {points_table["Note"].mean():.2f}')
st.write(f':blue[Median:] {points_table["Note"].median():.2f}')
else:
st.write(':orange[Keine Teilnehmer]')