Interactive data visualization using plotly.py. Create publication-quality interactive charts, dashboards, and animated visualizations. Use when creating int...
---
name: plotly-viz
description: Interactive data visualization using plotly.py. Create publication-quality interactive charts, dashboards, and animated visualizations. Use when creating interactive charts/graphs/plots from data, building dashboards, creating animated visualizations, or when hover/zoom/pan interactivity is needed. Supports HTML (interactive) and PNG/SVG/PDF (static) export. Specialized for plotly.py only - for matplotlib/seaborn use python-dataviz.
---
# Plotly Visualization
Create interactive, publication-quality visualizations with plotly.py - Python's leading interactive graphing library.
## Quick Start
```python
import plotly.express as px
# Simple scatter plot
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species")
fig.show()
# Export
fig.write_html("chart.html") # Interactive
fig.write_image("chart.png", width=800, height=600, scale=2) # Static (requires kaleido)
```
## Chart Type Selection
| Data Type | Chart | Function |
|-----------|-------|----------|
| Distribution | Histogram | `px.histogram()` |
| Distribution | Box plot | `px.box()` |
| Distribution | Violin | `px.violin()` |
| Comparison | Bar | `px.bar()` |
| Comparison | Grouped bar | `px.bar(barmode='group')` |
| Relationship | Scatter | `px.scatter()` |
| Relationship | Line | `px.line()` |
| Relationship | Heatmap | `px.density_heatmap()` |
| Part-to-whole | Pie | `px.pie()` |
| Part-to-whole | Treemap | `px.treemap()` |
| Part-to-whole | Sunburst | `px.sunburst()` |
| Hierarchical | Treemap | `px.treemap(path=[...])` |
| Hierarchical | Sunburst | `px.sunburst(path=[...])` |
| Geographic | Choropleth | `px.choropleth()` |
| Geographic | Scatter map | `px.scatter_geo()` |
| 3D | 3D Scatter | `px.scatter_3d()` |
| 3D | 3D Line | `px.line_3d()` |
| Time Series | Line + range slider | `fig.update_layout(xaxis_rangeslider_visible=True)` |
| Animation | Animated scatter | `px.scatter(animation_frame=...)` |
## Core Workflow
1. **Choose API level**:
- `plotly.express` (px) → Quick, declarative, ~30 chart types
- `plotly.graph_objects` (go) → Fine-grained control, all features
2. **Create figure**:
```python
# Express (recommended for most cases)
fig = px.scatter(df, x="col1", y="col2", color="category")
# Graph Objects (for complex customization)
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode='lines', name='Trace'))
```
3. **Customize**:
```python
fig.update_layout(title="Title", xaxis_title="X", yaxis_title="Y")
fig.update_traces(marker=dict(size=10, opacity=0.8))
```
4. **Export**:
```python
fig.write_html("interactive.html")
fig.write_image("static.png", width=800, height=600, scale=2)
```
## Templates
Built-in templates for consistent styling:
```python
# Available templates: plotly, plotly_white, plotly_dark, ggplot2, seaborn, simple_white, presentation
fig = px.scatter(df, x="x", y="y", template="plotly_white")
# Set default template
import plotly.io as pio
pio.templates.default = "plotly_white"
```
**Template guide**:
- `plotly_white` → Clean, white background (default for publications)
- `plotly_dark` → Dark theme, good for dashboards
- `ggplot2` → R ggplot2 style
- `seaborn` → Seaborn-inspired styling
- `presentation` → Larger fonts for presentations
## Multiple Traces & Subplots
### Multiple Traces (same plot)
```python
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y1, name='Series 1'))
fig.add_trace(go.Bar(x=x, y=y2, name='Series 2'))
fig.show()
```
### Subplots (multiple plots)
```python
from plotly.subplots import make_subplots
fig = make_subplots(rows=2, cols=2, subplot_titles=("Plot 1", "Plot 2", "Plot 3", "Plot 4"))
fig.add_trace(go.Scatter(x=x1, y=y1), row=1, col=1)
fig.add_trace(go.Bar(x=x2, y=y2), row=1, col=2)
fig.add_trace(go.Histogram(x=x3), row=2, col=1)
fig.add_trace(go.Pie(labels=labels, values=values), row=2, col=2)
fig.update_layout(height=600, title_text="Multi-Panel Dashboard")
fig.show()
```
## Animations
```python
# Animated scatter plot
df = px.data.gapminder()
fig = px.scatter(
df, x="gdpPercap", y="lifeExp",
animation_frame="year", animation_group="country",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90]
)
fig.show()
```
**Animation best practices**:
- Always set `range_x` and `range_y` to prevent axis jumping
- Use `animation_group` to link points across frames
- Control speed: `fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 500`
## Hover & Interactivity
```python
# Custom hover template
fig.update_traces(
hovertemplate='<b>%{text}</b><br>X: %{x}<br>Y: %{y}<extra></extra>',
text=df['names']
)
# Unified hover (show all traces at x position)
fig.update_layout(hovermode='x unified')
# Compare hover (show closest point from each trace)
fig.update_layout(hovermode='x')
```
## Common Patterns
### Data from DataFrame
```python
import pandas as pd
import plotly.express as px
df = pd.read_csv("data.csv")
fig = px.scatter(df, x="col1", y="col2", color="category", size="value")
fig.write_html("output.html")
```
### Data from Dictionary
```python
data = {'Category': ['A', 'B', 'C'], 'Value': [10, 20, 15]}
fig = px.bar(data, x='Category', y='Value')
```
### Time Series with Range Slider
```python
df = pd.read_csv("timeseries.csv", parse_dates=['date'])
fig = px.line(df, x='date', y='value')
fig.update_layout(xaxis_rangeslider_visible=True)
```
### Statistical Charts
```python
# Histogram with marginal plots
fig = px.histogram(df, x="value", marginal="box", nbins=30)
# Box with points
fig = px.box(df, x="category", y="value", points="all")
# Violin with box inside
fig = px.violin(df, y="value", x="category", box=True, points="all")
```
## Export Options
```python
# Interactive HTML (standalone)
fig.write_html("chart.html", include_plotlyjs=True)
# Interactive HTML (CDN, smaller file)
fig.write_html("chart.html", include_plotlyjs='cdn')
# Static images (requires kaleido: pip install kaleido)
fig.write_image("chart.png", width=800, height=600, scale=2)
fig.write_image("chart.svg")
fig.write_image("chart.pdf")
# Get HTML string for embedding
html_str = fig.to_html(include_plotlyjs=False, full_html=False)
```
## Advanced Features
### Annotations & Shapes
```python
fig.add_annotation(x=2, y=10, text="Peak", showarrow=True, arrowhead=1)
fig.add_hline(y=5, line_dash="dash", line_color="red")
fig.add_vrect(x0=1, x1=3, fillcolor="gray", opacity=0.2)
```
### Dual Y-Axis
```python
from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(go.Scatter(x=x, y=y1, name="Primary"), secondary_y=False)
fig.add_trace(go.Scatter(x=x, y=y2, name="Secondary"), secondary_y=True)
```
### Custom Color Scales
```python
# Sequential
fig = px.scatter(df, x="x", y="y", color="value", color_continuous_scale="Viridis")
# Diverging
fig = px.scatter(df, x="x", y="y", color="value", color_continuous_scale="RdBu_r")
# Custom discrete
fig = px.bar(df, x="cat", y="val", color="cat",
color_discrete_map={"A": "red", "B": "blue", "C": "green"})
```
## Troubleshooting
**"kaleido not found"** (for static export)
```bash
pip install kaleido
```
**Blank figure / No output**
- Ensure `fig.show()` or export after adding traces
- For scripts, use `fig.write_html()` instead of `fig.show()`
**Large file sizes**
- Use `include_plotlyjs='cdn'` for smaller HTML files
- Use SVG for vector graphics (smaller for simple charts)
**Slow rendering with many points**
- Consider downsampling or aggregation
- Use `px.scatter` with `render_mode='webgl'` for 100K+ points
## Resources
- **Chart examples**: See `scripts/` for ready-to-use chart templates
- **Templates reference**: See `references/templates.md` for template customization
- **Color reference**: See `references/colors.md` for color scales and palettes
- **Advanced charts**: See `references/advanced.md` for specialized visualizations
## Environment Setup
```bash
pip install plotly pandas kaleido
```
Dependencies:
- `plotly` - Core library
- `pandas` - Data manipulation (recommended)
- `kaleido` - Static image export (optional)don't have the plugin yet? install it then click "run inline in claude" again.