From e775103616537a0ed61d7bc283bc4e622b2ee8d6 Mon Sep 17 00:00:00 2001 From: DotNaos Date: Thu, 3 Oct 2024 11:45:57 +0200 Subject: [PATCH] Third Prompt --- backend/app.py | 144 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 37 deletions(-) diff --git a/backend/app.py b/backend/app.py index f858164..7a124b1 100644 --- a/backend/app.py +++ b/backend/app.py @@ -3,7 +3,7 @@ import pandas as pd import numpy as np import plotly.express as px -st.title("List Data Visualizer & Analyzer") +st.title("Erweiterter List Data Visualizer & Analyzer") # Seitenleiste für die Dateneingabe st.sidebar.header("Dateneingabe") @@ -11,10 +11,13 @@ st.sidebar.header("Dateneingabe") datenquelle = st.sidebar.radio("Datenquelle auswählen:", ("Manuelle Eingabe", "CSV-Datei hochladen")) if datenquelle == "Manuelle Eingabe": - dateneingabe = st.sidebar.text_area("Gib Zahlen ein, getrennt durch Kommas:", value="1,2,3,4,5") + dateneingabe = st.sidebar.text_area("Gib Zahlen ein, getrennt durch Kommas oder Zeilenumbrüche:", value="1,2,3,4,5") try: - datenliste = [float(x.strip()) for x in dateneingabe.split(",") if x.strip()] - df = pd.DataFrame(datenliste, columns=['Werte']) + # Unterstützung für mehrere Spalten + daten_zeilen = [zeile.strip() for zeile in dateneingabe.strip().split("\n") if zeile.strip()] + datenliste = [list(map(float, zeile.split(','))) for zeile in daten_zeilen] + df = pd.DataFrame(datenliste) + df.columns = [f"Spalte {i+1}" for i in range(df.shape[1])] except ValueError: st.error("Bitte gib eine gültige Liste von Zahlen ein.") st.stop() @@ -22,54 +25,121 @@ elif datenquelle == "CSV-Datei hochladen": hochgeladene_datei = st.sidebar.file_uploader("Wähle eine CSV-Datei aus", type="csv") if hochgeladene_datei is not None: df = pd.read_csv(hochgeladene_datei) - # Annahme: Die Daten stehen in der ersten Spalte - df = df.iloc[:, [0]] - df.columns = ['Werte'] + # Numerische Spalten identifizieren + numerische_spalten = df.select_dtypes(include=[np.number]).columns.tolist() + if not numerische_spalten: + st.error("Die hochgeladene Datei enthält keine numerischen Spalten.") + st.stop() + st.sidebar.subheader("Spaltenauswahl") + ausgewählte_spalten = st.sidebar.multiselect("Wähle die Spalten für die Analyse aus", numerische_spalten, default=numerische_spalten) + if not ausgewählte_spalten: + st.error("Bitte wähle mindestens eine Spalte aus.") + st.stop() + df = df[ausgewählte_spalten] else: st.warning("Bitte lade eine CSV-Datei hoch.") st.stop() +else: + st.error("Ungültige Datenquelle ausgewählt.") + st.stop() # Interaktive Filter st.sidebar.header("Datenfilter") -min_wert = float(df['Werte'].min()) -max_wert = float(df['Werte'].max()) -filterbereich = st.sidebar.slider('Wertebereich auswählen:', min_wert, max_wert, (min_wert, max_wert)) -gefilterter_df = df[(df['Werte'] >= filterbereich[0]) & (df['Werte'] <= filterbereich[1])] +gefilterter_df = df.copy() + +for spalte in df.columns: + # Konvertiere die Spalte in numerische Werte und entferne NaN + gefilterter_df[spalte] = pd.to_numeric(gefilterter_df[spalte], errors='coerce') + gefilterter_df = gefilterter_df.dropna(subset=[spalte]) + + min_wert = float(gefilterter_df[spalte].min()) + max_wert = float(gefilterter_df[spalte].max()) + + # Überprüfen, ob min_wert und max_wert unterschiedlich sind + if min_wert == max_wert: + st.warning(f"Die Spalte '{spalte}' hat konstante Werte. Der Slider wird für diese Spalte deaktiviert.") + continue # Überspringe diese Spalte + + # Slider erstellen + filterbereich = st.sidebar.slider( + f"Wertebereich für '{spalte}' auswählen:", + min_value=min_wert, + max_value=max_wert, + value=(min_wert, max_wert) + ) + + # Daten filtern + gefilterter_df = gefilterter_df[(gefilterter_df[spalte] >= filterbereich[0]) & (gefilterter_df[spalte] <= filterbereich[1])] # Statistische Analyse st.header("Statistische Analyse") -st.write(f"**Anzahl:** {gefilterter_df['Werte'].count()}") -st.write(f"**Mittelwert:** {gefilterter_df['Werte'].mean()}") -st.write(f"**Median:** {gefilterter_df['Werte'].median()}") -st.write(f"**Standardabweichung:** {gefilterter_df['Werte'].std()}") -# Ausreißererkennung (mithilfe der 1.5*IQR-Regel) -Q1 = gefilterter_df['Werte'].quantile(0.25) -Q3 = gefilterter_df['Werte'].quantile(0.75) -IQR = Q3 - Q1 -untere_grenze = Q1 - 1.5 * IQR -obere_grenze = Q3 + 1.5 * IQR -ausreisser = gefilterter_df[(gefilterter_df['Werte'] < untere_grenze) | (gefilterter_df['Werte'] > obere_grenze)] +def berechne_statistiken(daten): + beschreibung = daten.describe().transpose() + beschreibung['Median'] = daten.median() + beschreibung['Varianz'] = daten.var() + return beschreibung[['count', 'mean', 'Median', 'std', 'Varianz', 'min', '25%', '50%', '75%', 'max']] + +statistiken = berechne_statistiken(gefilterter_df) +st.dataframe(statistiken) + +# Ausreißererkennung +st.header("Ausreißererkennung") +ausreisser_df = pd.DataFrame() + +for spalte in gefilterter_df.columns: + Q1 = gefilterter_df[spalte].quantile(0.25) + Q3 = gefilterter_df[spalte].quantile(0.75) + IQR = Q3 - Q1 + untere_grenze = Q1 - 1.5 * IQR + obere_grenze = Q3 + 1.5 * IQR + ausreisser = gefilterter_df[(gefilterter_df[spalte] < untere_grenze) | (gefilterter_df[spalte] > obere_grenze)] + ausreisser_df = pd.concat([ausreisser_df, ausreisser]) + +if not ausreisser_df.empty: + st.subheader("Erkannte Ausreißer") + st.write(ausreisser_df.drop_duplicates()) +else: + st.subheader("Keine Ausreißer erkannt") # Visualisierungen st.header("Datenvisualisierungen") +st.sidebar.header("Visualisierungseinstellungen") -# Histogramm -st.subheader("Histogramm") -fig1 = px.histogram(gefilterter_df, x='Werte', nbins=20, title='Histogramm') -st.plotly_chart(fig1) +diagramm_typ = st.sidebar.selectbox("Diagrammtyp auswählen", ["Histogramm", "Boxplot", "Streudiagramm", "Liniendiagramm", "Korrelationsmatrix"]) -# Boxplot -st.subheader("Boxplot") -fig2 = px.box(gefilterter_df, y='Werte', points="all", title='Boxplot mit Ausreißern') -st.plotly_chart(fig2) - -# Ausreißer anzeigen -if not ausreisser.empty: - st.subheader("Erkannte Ausreißer") - st.write(ausreisser) -else: - st.subheader("Keine Ausreißer erkannt") +if diagramm_typ == "Histogramm": + st.subheader("Histogramm") + ausgewählte_spalten = st.multiselect("Wähle die Spalten für das Histogramm aus", gefilterter_df.columns.tolist(), default=gefilterter_df.columns.tolist()) + for spalte in ausgewählte_spalten: + fig = px.histogram(gefilterter_df, x=spalte, nbins=20, title=f'Histogramm von {spalte}') + st.plotly_chart(fig) +elif diagramm_typ == "Boxplot": + st.subheader("Boxplot") + fig = px.box(gefilterter_df, points="all", title='Boxplot') + st.plotly_chart(fig) +elif diagramm_typ == "Streudiagramm": + if len(gefilterter_df.columns) >= 2: + x_achse = st.sidebar.selectbox("X-Achse", gefilterter_df.columns) + y_achse = st.sidebar.selectbox("Y-Achse", gefilterter_df.columns, index=1) + st.subheader("Streudiagramm") + fig = px.scatter(gefilterter_df, x=x_achse, y=y_achse, title=f'Streudiagramm {x_achse} vs {y_achse}') + st.plotly_chart(fig) + else: + st.warning("Für ein Streudiagramm sind mindestens zwei numerische Spalten erforderlich.") +elif diagramm_typ == "Liniendiagramm": + st.subheader("Liniendiagramm") + ausgewählte_spalten = st.multiselect("Wähle die Spalten für das Liniendiagramm aus", gefilterter_df.columns.tolist(), default=gefilterter_df.columns.tolist()) + fig = px.line(gefilterter_df, y=ausgewählte_spalten, title='Liniendiagramm') + st.plotly_chart(fig) +elif diagramm_typ == "Korrelationsmatrix": + if len(gefilterter_df.columns) >= 2: + st.subheader("Korrelationsmatrix") + korrelation = gefilterter_df.corr() + fig = px.imshow(korrelation, text_auto=True, title='Korrelationsmatrix') + st.plotly_chart(fig) + else: + st.warning("Für eine Korrelationsmatrix sind mindestens zwei numerische Spalten erforderlich.") # Gefilterte Daten anzeigen st.header("Gefilterte Daten")