When we talk about data visualization and dashboards, enterprise tools like Tableau or PowerBI usually dominate the conversation. However, for Data Scientists and Developers, these GUI-based tools can feel restrictive. What if you need integration with machine learning models, custom UI logic, or CI/CD deployments?
This is where three powerful Python libraries come into play: Streamlit, Dash, and Bokeh. In this article, we'll explore the differences between these frameworks, build a basic financial dashboard with each one, and automate their deployment to the cloud using Docker and GitHub Actions.
The Contenders: Streamlit vs. Dash vs. Bokeh
1. Streamlit (The Sprinter)
Streamlit turns data scripts into shareable web apps in minutes. Everything in pure Python. No frontend experience required.
- Best for: Rapid prototyping, internal tools, and quick data exploration.
- Strengths: Incredibly low learning curve, completely reactive script execution.
- Weakness: The "re-run everything" model can be inefficient for complex applications.
2. Plotly Dash (The Architect)
Dash is built on Flask, Plotly.js, and React.js. It requires more boilerplate than Streamlit but offers enterprise-grade customization.
- Best for: Production-ready analytical dashboards with complex layouts and advanced interactivity.
- Strengths: Highly customizable UI, callback-based architecture ideal for scaling.
- Weakness: Steeper learning curve and more boilerplate code.
3. Bokeh (The Artist)
Bokeh focuses on creating high-performance interactive visualizations for modern browsers. Its strength lies in granular control over every chart element.
- Best for: Large datasets, streaming data, and highly customized visualizations.
- Strengths: Fine-grained control over visualization, excellent for large volumes of data.
- Weakness: Can be more verbose for building complete dashboard layouts.
Building a Real Example: Stock Market Dashboard
We'll create a stock price explorer with each tool. Let's start with the fastest one.
Streamlit: The Minutes-to-Dashboard Solution
This script downloads historical stock data, visualizes it, and calculates moving averages interactively.
# streamlit_app.py
import streamlit as st
import pandas as pd
import numpy as np
import altair as alt
st.set_page_config(page_title="Financial Dashboard", layout="wide")
st.title("📈 Interactive Financial Explorer")
st.markdown("Built with **Streamlit** for rapid prototyping.")
# Sidebar for user inputs
st.sidebar.header("Parameters")
ticker = st.sidebar.selectbox("Select Asset", ("AAPL", "GOOGL", "MSFT", "BTC-USD"))
days = st.sidebar.slider("Number of days", 10, 365, 100)
ma_window = st.sidebar.number_input("Moving Average Window", 5, 50, 20)
# Simulated data (replace with real API)
@st.cache_data
def get_data(ticker, days):
dates = pd.date_range(end=pd.Timestamp.today(), periods=days)
prices = np.random.normal(loc=150, scale=10, size=days)
df = pd.DataFrame({'Date': dates, 'Price': prices})
df.set_index('Date', inplace=True)
return df
data = get_data(ticker, days)
data['Moving Average'] = data['Price'].rolling(window=ma_window).mean()
# Visualization with Altair
st.subheader(f"Price History for {ticker}")
chart = alt.Chart(data.reset_index()).mark_line().encode(
x='Date',
y='Price'
)
st.altair_chart(chart, use_container_width=True)
# Raw Data
with st.expander("Show Raw Data"):
st.dataframe(data.tail(10))
Run locally:
pip install streamlit pandas numpy altair
streamlit run streamlit_app.py
Dash: The Structured Dashboard
Dash requires a more defined structure with layouts and callbacks.
# app.py
import os
from dash import Dash, html, dcc, Input, Output
import plotly.express as px
import pandas as pd
import numpy as np
# Sample data
df = pd.DataFrame({
'Category': ['A', 'B', 'C', 'A', 'B', 'C'],
'Sales': [10, 15, 7, 12, 9, 20]
})
app = Dash(__name__)
server = app.server # For Gunicorn
app.layout = html.Div([
html.H1('📊 Dash Dashboard'),
html.Label('Select Category:'),
dcc.Dropdown(
id='category-dropdown',
options=[{'label': 'All', 'value': 'All'}] +
[{'label': cat, 'value': cat} for cat in df['Category'].unique()],
value='All'
),
dcc.Graph(id='sales-chart')
])
@app.callback(
Output('sales-chart', 'figure'),
Input('category-dropdown', 'value')
)
def update_chart(selected_category):
filtered_df = df if selected_category == 'All' else df[df['Category'] == selected_category]
fig = px.bar(filtered_df, x='Category', y='Sales', title='Sales by Category')
return fig
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8050)))
Run locally:
pip install dash pandas plotly
python app.py
Bokeh: The Interactive Visualization
Bokeh focuses on generating interactive plots with its own server.
# main.py
from bokeh.plotting import figure
from bokeh.io import curdoc
import numpy as np
# Sample data
x = np.linspace(0, 10, 100)
y = np.sin(x) + np.random.normal(0, 0.1, 100)
p = figure(title='Bokeh - Interactive Visualization',
x_axis_label='X', y_axis_label='Y')
p.line(x, y, legend_label='Without noise', line_width=2)
p.circle(x, y, legend_label='With noise', size=5, color='red', alpha=0.5)
curdoc().add_root(p)
Run locally:
pip install bokeh numpy
bokeh serve --show main.py
Deploying to the Cloud with CI/CD
To take these dashboards to production, we'll containerize them with Docker and automate deployment using GitHub Actions.
Dockerfile (for Dash and Bokeh)
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8050 # Port for Dash
# For Bokeh use EXPOSE 5006
CMD ["gunicorn", "--bind", "0.0.0.0:8050", "--workers", "1", "--threads", "8", "app:server"]
requirements.txt
dash==2.14.0
pandas==2.2.0
plotly==5.18.0
gunicorn==21.2.0
GitHub Actions: CI/CD Pipeline
This workflow automates building and deploying to Google Cloud Run:
# .github/workflows/deploy-cloudrun.yml
name: CI/CD - Cloud Run
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure GCloud
uses: google-github-actions/setup-gcloud@v1
with:
service_account_key: ${{ secrets.GCP_SA_KEY }}
project_id: ${{ secrets.GCP_PROJECT_ID }}
- name: Build and push image
run: |
gcloud builds submit --tag gcr.io/${{ secrets.GCP_PROJECT_ID }}/dash-app:$GITHUB_SHA
- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@v1
with:
service: dash-app
image: gcr.io/${{ secrets.GCP_PROJECT_ID }}/dash-app:$GITHUB_SHA
region: us-central1
Simplified Deployment with Streamlit Cloud
For Streamlit, deployment is even simpler: just connect your GitHub repository at share.streamlit.io and get a public URL in seconds.
Alternative Deployment Options:
- Heroku: Supports all three frameworks with simple
Procfileconfiguration - AWS Elastic Beanstalk: Great for enterprise deployments
- PythonAnywhere: Budget-friendly option for smaller projects
Conclusion: Which One Should You Choose?
- Choose Streamlit if: You're a data scientist who needs to build an interactive tool quickly. Perfect for prototypes, internal tools, and ML demos.
- Choose Dash if: You're building a complex, production-ready application requiring specific layout design, multi-page functionality, and robust state management.
- Choose Bokeh if: Your primary need is highly interactive and performant visualizations, especially with large datasets or streaming data.
All these tools are open-source, Python-based, and can be deployed to the cloud, turning your local experiments into shareable, scalable projects.
Top comments (0)