DEV Community

RoyserVillanueva
RoyserVillanueva

Posted on

Beyond the Basics: Streamlit, Dash, and Bokeh for Interactive Dashboards

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))
Enter fullscreen mode Exit fullscreen mode

Run locally:

pip install streamlit pandas numpy altair
streamlit run streamlit_app.py
Enter fullscreen mode Exit fullscreen mode

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)))
Enter fullscreen mode Exit fullscreen mode

Run locally:

pip install dash pandas plotly
python app.py
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Run locally:

pip install bokeh numpy
bokeh serve --show main.py
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

requirements.txt

dash==2.14.0
pandas==2.2.0
plotly==5.18.0
gunicorn==21.2.0
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 Procfile configuration
  • 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)