The Best Python Dashboard Tools: A Comparative Analysis With Examples
A tutorial and comparison of five data viz frameworks using Python Plotly charts
Working with global and regional datasets often means building maps and time-series charts with filters (e.g. country or region selectors).
But where the heck do you begin? Well, Python is a great starting point, but how do you know which libraries in Python will work best for the data that you are trying to present?
Let me show you around five Python dashboard frameworks — Streamlit, Dash, Shiny for Python, Voila, and Panel — with some practical examples focusing on ease of use, interactivity for data exploration, layout flexibility, typical use cases, and Plotly integration.
Streamlit
Streamlit is extremely easy to learn for Python users and it is well-suited for exploratory analysis (e.g. filtering GPI data by year or region via sliders and dropdowns).
Widgets (sliders, dropdowns) are generated with functions like st.slider
without boilerplate code, and interactive charts (maps, line charts) display immediately with st.plotly_chart
.
Its reactive loop updates charts instantly as you add code, making it great for quick prototyping.
Additionally, Streamlit syntax is very close to Python, and no HTML/CSS knowledge is needed.
For our examples, let’s download a useful UN dataset called the Global Peace Index (GPI). The dataset can be downloaded from my Github HERE.
The original dataset looks like this:
With this dataset, we can look at the overall global trend for peace by creating a line chart that shows the global average across the range of years in the dataset (2008–2022).
Now let’s access the dataset using Python and display this chart using Streamlit!
Example Streamlit GPI Chart:
import streamlit as st
import pandas as pd
import plotly.express as px
df = pd.read_csv('global_peace_index.csv')
gpi_cols = [str(y) for y in range(2008, 2023)]
df_world = df[gpi_cols].mean().reset_index()
df_world.columns = ['Year', 'GPI']
df_world['Year'] = df_world['Year'].astype(int)
fig = px.line(df_world, x='Year', y='GPI', title='Global Peace Index Trend (2008–2022)', markers=True)
st.plotly_chart(fig, use_container_width=True)
To run this code, you need to have the streamlit framework installed. Then you can run it from a Terminal (command) prompt:
The resulting Streamlit data visualization:
Perfect — super easy, super quick, super efficient code (less than 10 lines).
What we are looking at is the default layout with a single column (with an optional sidebar for widgets)
Streamlit recently added support for columns, tabs, and containers. These give some flexibility, but customization remains limited compared to other frameworks.
On the downside for Streamlit, inter-component reactivity is limited: only widgets (not charts) can serve as inputs to control code, and charts cannot natively send data to other components.
Streamlit has added chart event support (e.g. you can capture click or lasso selections via st.plotly_chart(..., on_select="rerun")
), but this is less seamless than Dash’s callbacks.
You cannot freely embed custom CSS or HTML — theming is handled by Streamlit’s config or the new theming options. Customization can quickly become cumbersome and frustrating.
Dash (By Plotly)
Dash provides the most comprehensive Plotly integration and flexible control of layout and interactivity. This is because the Dash framework was written by the Plotly development team — go figure, right?
Dash allows every component (e.g. graphs, sliders, inputs) to be input/output in Python callbacks. This allows highly dynamic dashboards — like clicking a country in a choropleth map to update time series plots.
Here’s the same line chart example created with Dash:
import dash
from dash import dcc, html
import pandas as pd
import plotly.express as px
app = dash.Dash(__name__)
df = pd.read_csv('global_peace_index.csv')
df_avg = df[[str(y) for y in range(2008, 2023)]].mean().reset_index()
df_avg.columns = ['Year', 'GPI']
df_avg['Year'] = df_avg['Year'].astype(int)
app.layout = html.Div([
dcc.Graph(
figure=px.line(df_avg, x='Year', y='GPI', title='Global GPI Trend')
)
])
if __name__ == '__main__':
app.run_server(debug=True)
As you can see in the code, Dash apps use HTML-style components (html.Div
, dcc.Graph
) allowing full control. You can build responsive layouts and link UI components with CSS or Bootstrap.
We can run the Dash application from the terminal prompt, or also within our CGI editor (in my case, I am using PyCharm):
And the resulting chart is displayed in our default browser at the default port of 8050:
Awesome! We again have our chart displaying in our default browser.
Now as I mentioned above, the issue with Dash is that you need to build up the HTML using the built-in custom controls in Dash. This takes a bit more planning and work than the Streamlit framework, BUT it gives you more control of the layout and display.
This is why Dash is a good choice for production-grade dashboards.
Shiny for Python
Shiny offers reactive programming using decorators and reactive values. The reactive decorators in Shiny automatically update charts when input values change.
Our line chart example created with Shiny:
from shiny import App, ui, render
import pandas as pd
from shinywidgets import output_widget, render_widget
import plotly.express as px
# Load data
df = pd.read_csv("global_peace_index.csv")
# Compute average GPI per year
df_avg = df[[str(y) for y in range(2008, 2023)]].mean().reset_index()
df_avg.columns = ['Year', 'GPI']
df_avg['Year'] = df_avg['Year'].astype(int)
# Define UI
app_ui = ui.page_fluid(
ui.h2("GPI Time Series"),
output_widget("gpi_plot") # for Plotly chart
)
# Define server logic
def server(input, output, session):
@output()
@render_widget
def gpi_plot():
fig = px.line(df_avg, x='Year', y='GPI', title='GPI Trend (2008–2022)')
return fig
# App
app = App(app_ui, server)
Shiny provides fluid layouts and theming through helper functions and using the shinywidgets library. As with the Dash framework, a cursory knowledge of HTML is needed in order to create the layout that supports your dashboard (ie. Heading tags like <H2>).
Now as with Streamlit, once we have the Shiny framework installed, we can run our application from a Terminal (or Command) prompt. I am running my application from within the Pycharm Terminal environment:
You can see from the screenshot that the application loads into the default browser at the first available port at or above 8000. And the “shiny” result:
Very similar to the Dash visualization we saw earlier.
Recent statistics show that Shiny is growing in popularity — and is ideal for users familiar with reactive concepts.
Voila
Voila is a dashboarding framework that converts Jupyter notebooks directly into interactive web applications — very cool.
Unlike Streamlit, Dash, Panel, or Shiny, which require writing dedicated scripts or applications, Voila uses existing .ipynb
notebooks as the app source. This makes it perfect for data scientists who are already comfortable exploring and building in Jupyter.
Here is the code for our line chart, loaded in Jupyter Notebook:
The actual code:
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import ipywidgets as widgets
from IPython.display import display
# Load and prepare the data
df = pd.read_csv('global_peace_index.csv')
gpi_cols = [str(y) for y in range(2008, 2023)]
df_world = df[gpi_cols].mean().reset_index()
df_world.columns = ['Year', 'GPI']
df_world['Year'] = df_world['Year'].astype(int)
# Create the Plotly line chart
fig = px.line(df_world, x='Year', y='GPI',
title='Global Peace Index Trend (2008–2022)', markers=True)
# Display the chart using an Output widget (required for Voila layout control)
output = widgets.Output()
with output:
fig.show()
# Optional title header using ipywidgets
header = widgets.HTML(value="<h2>Global Peace Index Trend (2008–2022)</h2>")
# Display all elements
display(widgets.VBox([header, output]))
Voila follows the notebook layout, and it can be styled with templates.
The resulting data visualization (displayed within our Jupyter Notebook environment):
Great! It loads and displays this chart seamlessly as well.
As mentioned above, if you are familiar with Jupyter notebooks (as I am), then Voila is terrific for sharing existing notebooks as apps — you can even do this through GitHub and myBinder.org.
If you want more detailed information on how to publicly implement a dashboard using Viola, give it a read!
Panel
Our last example here, Panel, provides powerful and flexible dashboarding. It is particularly good for combining multiple interactive widgets with reactive plots, and supports varying layout structures.
Our line chart example created with Panel:
import panel as pn
import pandas as pd
import plotly.express as px
pn.extension('plotly')
df = pd.read_csv('global_peace_index.csv')
df_avg = df[[str(y) for y in range(2008, 2023)]].mean().reset_index()
df_avg.columns = ['Year', 'GPI']
df_avg['Year'] = df_avg['Year'].astype(int)
plot = px.line(df_avg, x='Year', y='GPI', title='GPI Trend')
pn.pane.Plotly(plot).servable()
With Panel, widgets like pn.widgets.Select
can bind to Plotly charts using pn.bind
or reactive Param classes.
Panel also supports tabs, templates, multi-page views, and responsive design.
As with the Streamlit and Shiny framework, we can run our Panel application from the Terminal (or Command) prompt. I ran my code from the built-in PyCharm Terminal prompt:
And the resulting Panel application is displayed in the default browser at port 5006:
Terrific, super easy.
And folks, that’s 5 common Python Dashboard frameworks and libraries in a nutshell. All 5 are able to seamlessly integrate these charts using Python Plotly — which is great as Plotly gives us additional interactivity options (above what traditional libraries like matplotlib can do).
Give each one of them a go to see what they can do!
In Summary…
To give you a bit more direction on where you would best use each framework:
Streamlit is best for fast internal dashboards with minimal setup. Great for beginners and exploratory apps.
Dash offers a high level of interactivity (through callback functions) and layout flexibility. Ideal for polished, multi-page dashboards.
Shiny gives you reactive logic in a clean decorator style. Useful if you prefer a declarative model.
Voila works best when working in Jupyter Notebooks and you need a quick, shareable dashboard. Can be used with GitHub and myBinder.org to provide publicly accessible dashboards.
Panel bridges notebook and script workflows with a Pythonic reactive model. Goodfor scalable exploratory tools (perhaps better than Streamlit).
Each framework integrates well with Plotly — from simple rendering to full interactivity.
Thanks John. The direct comparison using the same dataset across all five frameworks really helps. Seeing how each one handles the exact same line chart makes it easy to spot differences in syntax, layout control, and overall ease of use. It’s a practical way to show strengths without needing to dig through docs.
The quick breakdown of each tool's pros and cons is also handy. Knowing, for instance, that Streamlit is good for fast prototyping but falls short on deeper interactivity, or that Dash gives more control but takes more setup, saves a lot of trial and error.
Showing how each framework integrates with Plotly is another highlight. That level of interactivity often matters more than people realise, especially when building charts that need to respond to user input.
Would’ve been good to also see a brief comparison on how each one performs with bigger datasets or heavier interactions. Something like responsiveness or memory usage under load would add more context, especially for dashboards meant to be shared or deployed. A great post, anyway.