Im ersten Teil unserer Blogserie haben wir uns mit der Erstellung interaktiver Grafiken unter Verwendung des Open-Source Visualisierungstools Plotly befasst. Diese Grafiken bieten bereits einige Funktionalitäten wie z. B. Mouse-Over oder Zoom, jedoch fehlt die Möglichkeit, die angezeigten Daten durch User-Input anzupassen.
In diesem Beitrag gehen wir den nächsten Schritt und zeigen, wie man diese Grafiken mit Plotly Dash in interaktiven Dashboards nutzen kann. Nach einer Einführung in den Aufbau und die Gestaltung einer Dash App werden wir einen kurzen Vergleich zum Arbeiten mit Tableau ziehen und einen Ausblick zum effektiveren Arbeiten mit Dash durch das Nutzen von KI geben.
Doch warum überhaupt Plotly Dash?
- Dash ist wie die Visualisierungsbibliotheken von Plotly auch ein Open-Source Framework und damit grundsätzlich kostenlos nutzbar.
- Es ermöglicht die Entwicklung von interaktiven Dashboards Apps nativ in Python, ohne dass Kenntnisse in anderen Programmiersprachen für Front-End Gestaltung nötig sind. Für tiefergehende Anpassungen können aber CSS oder JavaScript Bestandteile eingebunden werden.
- Dash nutzt Plotly Grafiken und erweitert diese um Input Möglichkeiten wie z.B. Dropdown Filter, Schieberegler oder andere reaktive Elemente.
- Dash Code kann seit Version 2.11 direkt in Jupyter Notebooks ausgeführt werden und ermöglicht so schnelle und aussagekräftige Visualisierungen mit Dashboards in Data Science Kontexten.
Implementieren einer Dash App
Wir stellen im Folgenden den Aufbau einer Dash-App vor.
App Layout
Es folgt ein Beispiel für eine Basis Dash App (siehe Abbildung 1), die eine einzige Plotly Grafik anzeigt, ohne eine Möglichkeit für User-Input. Nach dem Importieren der benötigten Bibliotheken und dem Initialisieren einer leeren App wird ein Sub-Dataframe erstellt. Dieser basiert auf dem Superstore Sample Dataset. Dann wird ein statischer Barplot erstellt und das App Layout definiert. In einem div HTML-Element wird die erstellte Grafik referenziert und für spätere Anpassungen HTML Klassen definiert.
from dash import Dash, html, dcc, Input, Output
import plotly.express as px
#app init app = Dash(__name__) #sub dataframe df_bar_plot = df.groupby(['Category', 'Sub-Category']).agg({'Sales': 'sum', 'Profit': 'sum'}).reset_index() # create a static plot fig = px.bar(df_bar_plot, x='Category', y='Sales', color='Sub-Category', barmode='stack', text='Sub-Category') fig.update_traces(textposition='auto', textfont_size=10, width=0.8) fig.update_xaxes(tickangle=45) #define app layout app.layout = html.Div([ dcc.Graph(id='bar-plot', figure=fig, className='full-width-graph') ], className='main-container') #run app if __name__ == '__main__': app.run_server(debug=True, port=8081)

Die resultierende App unterscheidet sich auf den ersten Blick nicht von einer einfachen Plotly Grafik. Im unteren Bereich finden sich jedoch 3 Icons, die den Dash Status wiedergeben. Zum einen den Status des Servers, der in diesem Fall der lokale Rechner ist, dann mögliche Fehler und zuletzt vorhandene Callbacks.
Multi-Page Apps
In Dash ist es auch möglich Apps mit mehreren Seiten zu erstellen. Das Navigieren kann über Links und Klickpfade erfolgen. Ein Layout mit einzelnen Tabs pro Seite ist genauso möglich. Der Aufbau einer Multi-Page App kann in drei Layout Elemente unterteilt werden:
- Das Hauptlayout, das den Aufbau der App und Unterseiten beschreibt. In diesem Beispiel werden für die App drei Seiten jeweils als Tab festgesetzt und mit Label versehen.
app.layout = html.Div([
dcc.Tabs(id="tabs", value='tab-1', className='dash-tab-label' ,children=[
dcc.Tab(label='Sales by Category', value='tab-1'),
dcc.Tab(label='Sales by State', value='tab-2'),
dcc.Tab(label='Product Analysis', value='tab-product-analysis')
]),
html.Div(id='tabs-content')
])
2. Den Seitenlayouts die aufgerufen werden, wenn ein Tab oder eine Seite aufgerufen wird.
elif tab == 'tab-1':
return html.Div([
html.Div([
html.Label('Year', className='dropdown-label'),
dcc.Dropdown(
id='year-dropdown',
options=year_options,
value=years[0],
clearable=False,
className='dropdown-quarter-width'
)
], className='dropdown-container'),-content')
])
3. Den Callbacks der einzelnen Seiten, die auch miteinander verknüpft sein können. Wie diese funktionieren wird im nächsten Abschnitt erklärt.
Abschließend zum Thema Multi-Page Apps noch ein Beispiel, wie eine Tab-basierte App aussehen kann. Im oberen Reiter kann auf die einzelnen Seiten zugegriffen werden

Interaktivität durch Callbacks
Callbacks ermöglichen eine Interaktion des Users mit den angezeigten Daten. Über z.B. das Auswählen von Werten in einem Dropdown Filter oder das Bewegen eines Sliders werden bestimmte Elemente eines Dashboards aktualisiert und die Darstellung angepasst. Der Code im folgenden Block generiert drei Callbacks für das zuvor gezeigte Basis Dashboard.
@app.callback(
Output('bar-plot', 'figure'),
[Input('year-dropdown', 'value'),
Input('sub-category-dropdown', 'value'),
Input('profit-range-slider', 'value')]
)
def update_bar_chart(selected_year, selected_sub_categories, selected_profit_range):
# Filter based on the selected year
filtered_df = df[df['Order Date'].dt.year == selected_year]
# Aggregate data
agg_df = filtered_df.groupby(['Category', 'Sub-Category']).agg({'Sales': 'sum', 'Profit': 'sum'}).reset_index()
# Apply sub-category filter if sub-categories are selected
if selected_sub_categories:
agg_df = agg_df[agg_df['Sub-Category'].isin(selected_sub_categories)]
# Filter sub-categories based on total profit
agg_df = agg_df[(agg_df['Profit'] >= selected_profit_range[0]) &
(agg_df['Profit'] <= selected_profit_range[1])]
# Create the bar plot
fig = px.bar(agg_df, x='Category', y='Sales',
color='Profit',
color_continuous_scale=px.colors.sequential.Viridis,
text='Sub-Category')
fig.update_traces(textposition='auto', textfont_size=10, width=0.8)
fig.update_xaxes(tickangle=45)
fig.update_layout(coloraxis_colorbar=dict(title='Profit'))
return fig
Zu Beginn eines Callbacks wird zunächst der Output (Barplot) und der Input definiert, der hier einer Auswahl von Jahr, Produktkategorie und einem Wertebereich für Profit entspricht. Mit der Auswahl der Inputs wird ein Dataframe gefiltert und mit dieser neuen Datengrundlage eine Grafik erzeugt. Damit der User diese Inputs auch setzen kann, müssen HTML-Elemente zum App-Layout hinzugefügt werden.
html.Div([ html.Label('Subcategory', className='dropdown-label'), dcc.Dropdown( id='sub-category-dropdown', options=sub_category_options, multi=True, className='dropdown-quarter-width' ) ], className='dropdown-container', html.Div([ html.Label('Profit Range', className='slider-label'), dcc.RangeSlider( id='profit-range-slider', min=min_profit, max=max_profit, step=0.01, value=[min_profit, max_profit], marks=profit_marks className='profit-slider', tooltip={"placement": "bottom", "always_visible": True} ) ], className='slider-container')
Dieser Beispielcode fügt der App einen Dropdown-Filter über bestimmte Produktkategorien und einen Slider für den Profit hinzu. Damit Dash weiß, welche möglichen Inputwerte es gibt, müssen Variablen aus dem Input Dataframe definiert werden.
sub_category_options = [{'label': sub_cat, 'value': sub_cat} for sub_cat in sorted(df['Sub-Category'].unique())] min_profit = int(yearly_subcat_profit['Profit'].min()) max_profit = int(yearly_subcat_profit['Profit'].max())
Dieser Workflow ist unumgänglich und bedeutet, dass man sich immer wieder aktiv mit den zu Grunde liegenden Daten beschäftigen muss, um die richtigen Visualisierungen zu erstellen. Als Resultat des hinzugefügten Callbacks ergibt sich eine App, die dem Nutzer das Filtern der Daten erlaubt.

Ein großer Vorteil von Dash Apps und der Gestaltung in Python Code ist, dass der Komplexität der Callbacks eigentlich keine Grenzen gesetzt sind. Wenn man eine Logik in Code abbilden kann, ist es möglich diese als Callback einfließen zu lassen. So können auch neue Objekte erstellt oder mit Daten befüllt werden. Ein Beispiel ist die nachfolgende Grafik, die Verkaufsdaten auf geographischer Ebene mit einer Karte darstellen. Sobald der Nutzer auf einen Staat klickt wird eine Tabelle erstellt, die alle Informationen zu Verkäufen in diesem Staat enthält.

Die Optik von Dash Apps anpassen
Wenn man das Design von App Komponenten anpassen möchte, sind grundsätzlich zwei Wege zu unterscheiden:
- Inline Styles: Dabei werden Anpassungen direkt in den HTML-Elementen des App Layouts vorgenommen. Im Folgenden Beispiel sind dies Optionen wie z.B. backgroundColor, fontWeight, textAlign.
app.layout = html.Div([ dcc.Graph(id='state-sales-map', figure=fig_state_sales), html.Pre(id='click-data', style={'whiteSpace': 'pre-wrap', 'wordBreak': 'break-all'}), dash_table.DataTable(style_cell={'textAlign': 'left', 'padding': '10px'}, style_header={ 'backgroundColor': 'white', 'fontWeight': 'bold', 'border': '1px solid black' }, style_data={ 'backgroundColor': 'lightgrey', 'color': 'black', 'border': '1px solid black' }, style_table={'overflowX': 'auto'}, id='orders-table', columns=[{"name": i, "id": i} for i in df.columns], data=[], page_size=10, # Number of rows per page sort_action='native', # Enables sorting # Display 25 rows per page ) ])
-
CSS-Klassen: Für tiefergreifende Anpassungen und einen konsistenten Look von gleichen Objekten in verschiedenen Apps macht es Sinn CSS-Klassen zu verwenden. Diese Klassen werden in einem CSS-Dokumentiert angelegt und können dann im App Layout aufgerufen werden
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap'); /* Main container */ .main-container { width: 100%; display: flex; flex-direction: column; align-items: center; } .dropdown-container { width: 50%; margin-bottom: 10px; } .dropdown-label { font-family: 'Roboto', sans-serif; display: block; margin-bottom: 5px; }
In diesem Auszug aus der CSS-Datei wird zum Beispiel eine neue Schriftart importiert, die dann für die CSS-Klasse der Dropdown Labels verwendet wird. Die container regeln die Anordnung von Objekten auf einer App Seite. Im App Layout werden die Klassen so aufgerufen:
app.layout = html.Div([ html.Div([ html.Label('Year', className='dropdown-label'), dcc.Dropdown( id='year-dropdown', options=year_options, value=years[0], clearable=False, className='dropdown-quarter-width' ) ], className='dropdown-container'), dcc.Graph(id='bar-plot', className='full-width-graph') ], className='main-container')
Durch das obige Beispiel-CSS-Styling wird sichergestellt, dass die Grafik immer mit einer Weite von 100% dargestellt wird und die Dropdown Felder mit einer bestimmten Schriftart nur die Hälfte der App Seite einnehmen. Mit CSS-Dokumenten können Layout Vorlagen generiert und eine wiederkehrende Designsprache ermöglicht werden.
Dash versus Tableau
Wenn man nur das Endprodukt in Form eines Dashboards vergleicht, so kann man sagen, dass es mit Dash möglich ist, eigentlich alles zu reproduzieren, was in Tableau erstellt werden kann. Hier ein Beispiel Tableau Dashboard, das mit der gleichen Datengrundlage erstellt wurde und dieselben Elemente beinhaltet. Der Weg zu diesem Endprodukt ist jedoch komplett unterschiedlich.

- Arbeiten mit Dash benötigt zwingend Python Programmierkenntnisse, um Visualisierungen zu erstellen. Der Nutzer muss auch in der Lage sein Dataframes so zu bearbeiten, dass die gewünschte Datengrundlage für Grafiken, als auch Input Elemente wie Dropdown-Filter entsteht.
- Anbindungen an Datenbanken und Cloud müssen per Code erstellt werden. Im Bereich Customization bietet Dash jedoch mehr Möglichkeiten als die meisten kommerziellen Tools und die einfache Integration von verschiedenen Python Machine Learning Bibliotheken ist ebenfalls ein Vorteil.
Tableau ist von einem breiteren Nutzerkreis verwendbar. Durch Drag/Drop können schneller Dashboard erstellt werden und interaktive Element sind leichter zu integrieren. Wenn ein Dataset als Input bereitgestellt wird muss ein Nutzer sich nicht tiefergehend mit den Daten beschäftigen, um in der Lage zu sein Visualisierungen zu erstellen. Auch verfügt Tableau nativ über Konnektoren zu allen gängigen Datenbanktypen. Das Deployment von Tableau Apps über einen Tableau Server ist auf Business Use-Cases zugeschnitten und nimmt dem Anwender Arbeit im Bereich Maintenance und Security ab.
- Dash Apps müssen selbstständig auf Servern gehostet werden. Der Zugang zu den Apps, mögliche Updates und Skalierung müssen von den Entwicklern gemanagt werden. Es gibt auch eine Enterprise Version von Plotly Dash, die wie Tableau eine kommerzielle Lösung ist und zusätzliche Features beinhaltet.
Abschließend kann man sagen, dass Dash ein geeignetes Visualisierungstools ist, wenn Anwender Flexibilität schätzen, bereits in Python programmieren und Dash Apps in ihre Data Science/Analytics Workflows integrieren können. Anwender, die eine Möglichkeit suchen schnell Visualisierungen zu erstellen und zu teilen, ohne sich tiefergehend mit der technischen Umsetzung zu beschäftigen sind wahrscheinlich mit stabilen Business Lösungen wie Tableau besser aufgehoben.
Der Zeitfaktor beim Erstellen von Dashboards in Dash sollte auch nicht unterschätzt werden. Das händische Anlegen von Layouts,, Callbacks, CSS-Styles in Code ist aufwändig. Es gibt jedoch Möglichkeiten diese Arbeit effizienter zu gestalten.
KI als Arbeitserleichterung bei der Erstellung von Dash Apps
KI-Tools wie Chat GPT können für verschiedene Programmieraufgaben Vorlagen liefern, die dem Nutzer ein schnelleres Arbeiten ermöglichen. Für das Arbeiten mit Dash kann die KI Dashboard-Bestandteile in Sekunden erstellen, die händisch deutlich mehr Zeit in Anspruch nehmen. Hier ein Beispiel Prompt, aus dem ChatGPT Code für eine lauffähige Dash App generiert.
Create an example dash app using the superstore dataset that is stored locally that features a barplot and dropdown filter.
import dash from dash import html, dcc, Input, Output import plotly.express as px import pandas as pd # Load your dataset (assuming it's a CSV file) df = pd.read_csv('path_to_your_superstore_dataset.csv') # Initialize the Dash app app = dash.Dash(__name__) # Define the layout of the app app.layout = html.Div([ dcc.Dropdown( id='category-dropdown', options=[{'label': i, 'value': i} for i in df['Category'].unique()], value=df['Category'].unique()[0] ), dcc.Graph(id='bar-plot') ]) # Callback to update bar plot based on selected category @app.callback( Output('bar-plot', 'figure'), [Input('category-dropdown', 'value')] ) def update_graph(selected_category): filtered_df = df[df['Category'] == selected_category] fig = px.bar(filtered_df, x='Sub-Category', y='Sales', color='Sub-Category') return fig # Run the app if __name__ == '__main__': app.run_server(debug=True)
Chat GPT kann beim Erstellen von Apps „lästige“ Arbeitsschritte übernehmen und so zum Beispiel auch dafür genutzt werden, neue CSS-Styles auszuprobieren, ohne händisch viele Zeilen Code schreiben zu müssen.
generate a new css style for the basic example app
body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px; } #category-dropdown { width: 300px; margin: 20px auto; } #bar-plot { max-width: 900px; margin: auto; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); } .dash-dropdown { min-height: 38px; border: 1px solid #ddd; border-radius: 4px; background-color: #fff; } .dash-graph { padding: 20px; background-color: #fff; border-radius: 8px; }
Dem Entwickler können repetitive Aufgaben abgenommen werden und er kann seine Zeit in tiefergehende Tätigkeiten investieren. Auch wenn man über eine konzeptionelle Idee zur Erweiterung einer Dash App verfügt, diese jedoch auf Anhieb nicht in Python Code übersetzen kann, ist Chat GPT in der Lage zu helfen. Es kann Code Snippets generieren, die als Ausgangspunkt für weitere Entwicklung dienen können. Für eine effektive Unterstützung bei der Entwicklung von Dash Elementen sollte der Nutzer mit den Grundkonzepten einer Dash App vertraut sein und nicht einfach per Copy/Paste Code einfügen. Die KI bietet auf jeden Fall viele Möglichkeiten die Nachteile eines code-basierten Ansatzes zur Entwicklung von Datenvisualisierungen zu minimieren und so den zeitlichen Vorteil einer Software Lösung mit grafischer Oberfläche zumindest zu verkleinern.
Fazit
Wie in diesem Beitrag gezeigt ist Plotly Dash ist ein gutes Tool um relativ schnell und ohne Kosten schöne Dashboards zu erstellen. Im Vergleich zu kommerziellen Tools bleibt jedoch immer der Nachteil des aufwendigeren Workflows und die zwingend notwendigen Programmierkenntnisse. Nutzer die sich für Dash entscheiden profitieren von den Customization Möglichkeiten des Frameworks und können wie erwähnt von KI profitieren um schneller ihre gewünschten Dashboards zu erstellen. Insgesamt zeigt sich, dass Plotly Dash ein äußerst mächtiges Tool für interaktive Datenvisualisierung ist – insbesondere für Data Scientists und Entwickler, die bevorzugt in Python arbeiten. Durch die nahtlose Integration von Plotly-Grafiken, HTML-Komponenten und reaktiven Callbacks können schnell performante Dashboards gebaut werden, die sich zudem flexibel erweitern lassen.
Ein weiterer Vorteil: Dash-Apps lassen sich sowohl lokal entwickeln als auch problemlos auf Cloud-Plattformen wie Heroku oder Dash Enterprise ausrollen – was sie auch für den produktiven Einsatz in Unternehmen interessant macht.