Hi, I'm Keita from Squadbase, working as a frontend engineer primarily with React and TypeScript. As a Python beginner, I recently had to build a data visualization dashboard with Streamlit and faced the classic question: "Which chart library should I use?"
I tested 4 major libraries with the same dataset and discovered some surprising performance bottlenecks and usability quirks. Here's what I learned from a frontend developer's perspective.
What You'll Learn
- Practical comparison of 4 Streamlit chart libraries
- Performance limitations you'll actually encounter
- Decision framework for choosing the right library
- Code examples you can copy-paste
Test Setup
I used this environment for testing:
# requirements.txt
streamlit==1.28.0
plotly==5.17.0
altair==5.1.2
matplotlib==3.8.1
seaborn==0.12.2
pandas==2.1.3
numpy==1.25.2
Sample data simulates e-commerce monthly sales:
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# Generate sample data
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
sales_data = pd.DataFrame({
'date': dates,
'sales': np.random.normal(100000, 20000, len(dates)).astype(int),
'category': np.random.choice(['Electronics', 'Clothing', 'Books'], len(dates))
})
# Monthly aggregation
monthly_sales = sales_data.groupby(sales_data['date'].dt.to_period('M'))['sales'].sum().reset_index()
monthly_sales['date'] = monthly_sales['date'].dt.to_timestamp()
I evaluated each library on:
- Code simplicity (learning curve)
- Visual appeal (design quality)
- Performance (data volume constraints)
Streamlit Native Charts: 3 Lines of Glory
Let's start with the built-in option:
import streamlit as st
# Beautiful chart in 3 lines
st.line_chart(monthly_sales.set_index('date')['sales'])
Coming from Chart.js configuration hell, this simplicity is refreshing.
Pros
- Zero learning curve
- Pass DataFrame directly
- Auto-matches Streamlit theme
Cons
- Limited customization options
- Multi-series display gets tricky
# Attempted multi-series visualization
category_sales = sales_data.groupby(['date', 'category'])['sales'].sum().unstack()
st.line_chart(category_sales)
# Result: Not quite what I expected...
The lack of fine-grained control feels limiting after years of frontend chart customization.
Best for: Rapid prototyping where simplicity beats customization
Plotly: Interactive Powerhouse with Gotchas
Plotly brings D3.js-level interactivity to Python:
import plotly.express as px
import plotly.graph_objects as go
# Interactive line chart
fig = px.line(monthly_sales, x='date', y='sales', title='Monthly Sales Trend')
st.plotly_chart(fig, use_container_width=True)
Zoom, pan, and hover interactions work beautifully.
Pros
- Rich interactivity
-
use_container_width=True
for responsive design - Professional appearance
Cons
- WebGL context limits
- Complex API
Here's the WebGL gotcha that bit me:
# Displaying multiple charts
for i in range(20):
fig = px.bar(sample_data, x='category', y='sales', title=f'Chart {i+1}')
st.plotly_chart(fig)
# Only first 16 charts render in Chrome/Edge!
Browser WebGL context limits mean only ~16 charts per page. Fix with:
fig = px.line(plot_df, render_mode='svg')
Best for: Interactive dashboards with moderate chart counts
Altair: Elegant Grammar of Graphics
Altair uses Grammar of Graphics principles:
import altair as alt
# Declarative syntax
chart = alt.Chart(monthly_sales).mark_line().encode(
x='date:T',
y='sales:Q',
tooltip=['date:T', 'sales:Q']
).interactive()
st.altair_chart(chart, use_container_width=True)
The declarative approach feels natural—like JSX for data visualization.
Pros
- Readable declarative syntax
- Excellent performance
- Lightweight JSON output
Cons
- 5000-row data limit
The row limit surprised me:
# Large dataset test
large_data = pd.DataFrame({
'x': range(6000),
'y': np.random.randn(6000)
})
chart = alt.Chart(large_data).mark_point().encode(x='x', y='y')
st.altair_chart(chart)
# MaxRowsError: Dataset exceeds 5000 rows
Override with:
alt.data_transformers.enable('json')
Best for: Medium datasets where performance and clean syntax matter
Matplotlib: Static with Limitations
Matplotlib is Python's visualization standard:
import matplotlib.pyplot as plt
import seaborn as sns
# Classic matplotlib
plt.figure(figsize=(10, 6))
plt.plot(monthly_sales['date'], monthly_sales['sales'], marker='o')
plt.title('Monthly Sales Trend')
plt.xticks(rotation=45)
plt.tight_layout()
st.pyplot(plt)
Looks familiar, but performance issues emerged.
Pros
- Extensive documentation
- Fine-grained control
- Static image output
Cons
- Poor interactive performance
- No built-in interactivity
The killer issue:
# Slider interaction test
year = st.slider('Year', 2020, 2023, 2023)
filtered_data = data[data['year'] == year]
plt.figure(figsize=(10, 6))
plt.plot(filtered_data['month'], filtered_data['sales'])
st.pyplot(plt)
# Slider movement triggers heavy re-rendering
Best for: Static reports requiring precise customization
Decision Framework
After testing all four, here's my recommendation hierarchy:
Learning Path
- Streamlit Native → Get comfortable with basic charting
- Plotly → Add interactivity
- Altair → Learn declarative patterns
- Matplotlib → Handle edge cases
Selection Matrix
Library | Rating | Learning Curve | Best Use Case |
---|---|---|---|
Plotly | ⭐⭐⭐⭐⭐ | Medium | Interactive dashboards |
Altair | ⭐⭐⭐⭐☆ | Medium | Clean, performant charts |
Streamlit Native | ⭐⭐⭐☆☆ | Low | Rapid prototypes |
Matplotlib | ⭐⭐☆☆☆ | Medium | Static reports |
Key Takeaways
Streamlit charting has hidden constraints. WebGL limits (Plotly) and row limits (Altair) only surface with real usage.
Start simple, evolve gradually. Begin with Native Charts, then migrate to Plotly or Altair as requirements grow.
Context matters more than features. Choose based on data volume, interactivity needs, and performance requirements.
Next Steps
Each library shines in different scenarios. Start with one that matches your current needs, then expand your toolkit as projects demand different capabilities.
For complex dashboards, you might even use multiple libraries—Native Charts for simple KPIs, Plotly for interactive exploration, and Altair for performance-critical visualizations.
Building internal tools with data visualization? Squadbase shares practical development insights for modern teams. Let's connect and swap stories about dashboard development!
Top comments (0)