import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as snsInteraktive Dashboards: Der Einstieg mit Plotly
In diesem Kapitel werden wir uns mit der Erstellung interaktiver Dashboards mit Plotly beschäftigen. Im Bereich Data Analysis wird ein “Dashboard” als eine interaktive Darstellung von Daten verstanden, die es ermöglicht als betrachtende Person verschiedene Aspekte der Daten selbst zu erkunden bzw. zu analysieren. In Unternehmen ist es oft der Fall, dass verschiedene Personen an unterschiedlichen Aspekten der Daten interessiert sind. Ein Dashboard ermöglicht es, die Daten so zu präsentieren, dass alle die für sie relevanten Informationen schnell und einfach finden können. Dies nimmt uns als Data Analysten ggf. die Arbeit ab, individuelle Analysen für jede Person zu erstellen. Es ist aber natürlich auch klar, dass es nicht immer möglich ist ein Dashboard anzubieten. Oft wird weiterhin eine Auswertung als statische Datei (also z.B. als PDF) benötigt, sodass keine Interaktion möglich ist.
Plotly ist eines der gängigen Python-Module, mit denen interaktive Diagramme und Dashboards erstellt werden können. Es ist nicht in der Anaconda-Distribution enthalten und muss somit erst installiert werden:
!pip install plotlyUm uns wie so oft nur auf das Neue zu konzentrieren, nutzen wir wieder die palmer_penguins-Daten.
csv_url='https://raw.githubusercontent.com/SchmidtPaul/ExampleData/main/palmer_penguins/palmer_penguins.csv'
df=pd.read_csv(csv_url)
# Konvertiere alle 'object'-Spalten in 'category'
for col in df.select_dtypes(include='object').columns:
df[col] = df[col].astype('category')Die Grundlagen
Erstaunlicherweise ist die Erstellung eines interaktiven Dashboards mit Plotly nicht viel schwieriger als die Erstellung eines normalen Diagramms. Der folgende Code erstellt denselben Scatterplot wie schon in den vorherigen Kapiteln, aber diesmal interaktiv:
import plotly.express as px
fig = px.scatter(df, x='body_mass_g', y='flipper_length_mm', color='species')
fig.show()Das Ergebnis ist ein interaktives Diagramm, das es ermöglicht, die Daten zu erkunden. Das Diagramm ist also sowohl in euren Jupyter Notebooks, als auch hier auf der Webseite interaktiv. Folgende Dinge funktionieren direkt ohne Weiteres:
- Fahrt ihr mit der Maus über die Abbildung erscheint oben rechts eine Liste mit verschiedenen Auswahlmöglichkeiten.
- Zoomen: Ihr könnt in das Diagramm hineinzoomen, indem ihr mit der Maus einen Bereich auswählt, also mit einem Viereck umschließt. Danach kann mit Doppelklick wieder auf die ursprüngliche Ansicht zurückgekehrt werden.
- Verschieben: Ihr könnt das Diagramm verschieben, indem ihr mit der Maus auf das Diagramm klickt und die Maus bewegt.
- Informationen: Wenn ihr mit der Maus über ein Punkt fahrt, wird euch der Wert des Punktes angezeigt.
- Legende: Ihr könnt die Legende nutzen, um die Punkte nach einer bestimmten Kategorie zu filtern.
- Export: Ihr könnt das Diagramm als Bild speichern.
Beschriftung usw.
Nicht ganz identisch wie bei Seaborn, aber immerhin vergleichbar lassen sich Beschriftung usw. anpassen:
fig = px.scatter(
df,
x='body_mass_g',
y='flipper_length_mm',
color='species',
labels={
'body_mass_g': 'Körpermasse (g)',
'flipper_length_mm': 'Flossenlänge (mm)',
'species': 'Pinguinart'
},
color_discrete_sequence=['#ffcdb2', '#e5989b', '#6d6875'],
title='Körpermasse vs. Flossenlänge bei Pinguinen')
fig.show()Hover Data
Mit hover_data lässt sich außerdem festlegen, welche Informationen angezeigt werden, wenn man mit der Maus über einen Punkt fährt. Der Kasten, der dort erscheint wird als Tooltip bezeichnet. Standardmäßig (siehe oben) werden genau die Informationen angegeben, die auch notwendig sind, um den Punkt zu zeichnen. In folgendem Beispiel könnten wir aber z.B. die Pinguinart nicht als Text im Tooltip anzeigen lassen, da diese ja bereits durch die Füllfarbe des Punktes dargestellt wird - wir setzen also species auf False. Außerdem könnten wir die Insel und das Geschlecht anzeigen lassen - beides sind Informationen, die wir dem eigentlichen Scatterplot nicht entnehmen können, aber so zumindest für einzelne Beobachtungen mittels Tooltip nachvollziehen können. Schließlich kann auch das Zahlenformat der numerischen Werte angepasst werden. Hier erzwingen wir zwei Dezimalstellen für die Körpermasse und keine Dezimalstellen für die Flossenlänge.
fig = px.scatter(
df,
x='body_mass_g',
y='flipper_length_mm',
color='species',
labels={
'body_mass_g': 'Körpermasse (g)',
'flipper_length_mm': 'Flossenlänge (mm)',
'species': 'Pinguinart',
'island': 'Insel',
'sex': 'Geschlecht'
},
color_discrete_sequence=['#ffcdb2', '#e5989b', '#6d6875'],
title='Körpermasse vs. Flossenlänge bei Pinguinen',
hover_data={
'species': False,
'island': True,
'sex': True,
'body_mass_g': ':,.2f',
'flipper_length_mm': ':,.0f'
})
fig.show()Facetten
Facettenplots sind auch in Plotly möglich und zwar mit facet_colund/oder facet_row. Hier erstellen wir eine Facette je Kombination aus Geschlecht und Insel. Als zusätzliche Anpassung entfernen wir die Beschriftung der y-Achse für die erste und dritte Facettenzeile, da diese hier nicht nur redundant sind, sondern sogar überlappen würden.
df = df.dropna(subset=['sex']) # Entferne Fehlwerte in Spalte sex
fig = px.scatter(
df,
x='body_mass_g',
y='flipper_length_mm',
color='species',
facet_col='sex', # <-----
facet_row='island', # <-----
labels={
'body_mass_g': 'Körpermasse (g)',
'flipper_length_mm': 'Flossenlänge (mm)',
'species': 'Pinguinart',
'island': 'Insel',
'sex': 'Geschlecht'
},
color_discrete_sequence=['#ffcdb2', '#e5989b', '#6d6875'],
title='Körpermasse vs. Flossenlänge bei Pinguinen',
hover_data={
'species': False,
'island': False, # <-----
'sex': False # <-----
})
# Entferne y-Achsentitel für erste und dritte Facettenzeile
fig = fig.update_yaxes(matches='y', title_text='', row=1)
fig = fig.update_yaxes(matches='y', title_text='', row=3)
fig.show()Kurzer Ausblick: Dash
Wir haben also mit überschaubarem Aufwand eine interaktive Abbildung erzeugt und Feinheiten wie Beschriftung, Tooltip und Facetten angepasst. Ein richtiges Dashboard ist aber mehr als nur eine interaktive Abbildung. Es besteht aus mehreren interaktiven Elementen, die miteinander verbunden sind.
Plotly bietet dafür das Modul dash an. Mit dash können interaktive Webanwendungen erstellt werden, die auf Plotly basieren. Wie man an diesen Beispieldashboards erkennen kann, sind die Möglichkeiten vielfältig. Allerdings ist die Erstellung eines Dashboards mit dash deutlich aufwändiger als die Erstellung eines interaktiven Diagramms mit Plotly und geht daher auch über den Umfang dieses Kurses hinaus.
Nichtsdestotrotz soll hier zumindest ein Minimalbeispiel gezeigt werden, um einen Eindruck zu vermitteln, wie ein Dashboard mit dash aussehen könnte. Hier zeigen wir, wie man ein Dropdown-Menü erstellt, mit dem man eine Insel auswählen kann, um nur die Daten für diese Insel anzuzeigen. Der folgende Code funktioniert, wenn man ihn z.B. in Jupyter Lab ausführt. Unter dem Code ist ein gif zu sehen, das zeigt, wie das Dashboard in Aktion aussieht.
### MODULE
# Installiere Dash falls noch nicht installiert
# !pip install dash
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.express as px
### DATEN
csv_url='https://raw.githubusercontent.com/SchmidtPaul/ExampleData/main/palmer_penguins/palmer_penguins.csv'
df=pd.read_csv(csv_url)
# Konvertiere alle 'object'-Spalten in 'category'
for col in df.select_dtypes(include='object').columns:
df[col] = df[col].astype('category')
### DASHBOARD
# Erstellen einer Dash-Anwendung
app = dash.Dash(__name__)
# Layout der Dash-Anwendung definieren
app.layout = html.Div([
dcc.Dropdown(
id='island-dropdown',
options=[
{'label': 'Biscoe-Insel', 'value': 'Biscoe'},
{'label': 'Traum-Insel', 'value': 'Dream'},
{'label': 'Torgersen-Insel', 'value': 'Torgersen'}
],
value='Biscoe' # Standardwert
),
dcc.Graph(id='scatter-plot')
])
# Callback-Funktion zur Aktualisierung des Diagramms basierend auf der Auswahl im Dropdown-Menü
@app.callback(
Output('scatter-plot', 'figure'),
[Input('island-dropdown', 'value')]
)
def update_figure(selected_island):
filtered_df = df[df['island'] == selected_island]
fig = px.scatter(
filtered_df,
x='body_mass_g',
y='flipper_length_mm',
color='species',
labels={
'body_mass_g': 'Körpermasse (g)',
'flipper_length_mm': 'Flossenlänge (mm)',
'species': 'Pinguinart',
'island': 'Insel',
'sex': 'Geschlecht'
},
color_discrete_sequence=['#ffcdb2', '#e5989b', '#6d6875'],
title=f'Körpermasse vs. Flossenlänge bei Pinguinen auf {selected_island}-Insel'
)
return fig
# Ausführen der Dash-Anwendung
if __name__ == '__main__':
app.run_server(debug=True)
!Optional weil über Kursinhalt hinaus!