Plotly Viz

Data & APIs

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.

Install

openclaw skills install plotly-viz

Plotly Visualization

Create interactive, publication-quality visualizations with plotly.py - Python's leading interactive graphing library.

Quick Start

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 TypeChartFunction
DistributionHistogrampx.histogram()
DistributionBox plotpx.box()
DistributionViolinpx.violin()
ComparisonBarpx.bar()
ComparisonGrouped barpx.bar(barmode='group')
RelationshipScatterpx.scatter()
RelationshipLinepx.line()
RelationshipHeatmappx.density_heatmap()
Part-to-wholePiepx.pie()
Part-to-wholeTreemappx.treemap()
Part-to-wholeSunburstpx.sunburst()
HierarchicalTreemappx.treemap(path=[...])
HierarchicalSunburstpx.sunburst(path=[...])
GeographicChoroplethpx.choropleth()
GeographicScatter mappx.scatter_geo()
3D3D Scatterpx.scatter_3d()
3D3D Linepx.line_3d()
Time SeriesLine + range sliderfig.update_layout(xaxis_rangeslider_visible=True)
AnimationAnimated scatterpx.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:

    # 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:

    fig.update_layout(title="Title", xaxis_title="X", yaxis_title="Y")
    fig.update_traces(marker=dict(size=10, opacity=0.8))
    
  4. Export:

    fig.write_html("interactive.html")
    fig.write_image("static.png", width=800, height=600, scale=2)
    

Templates

Built-in templates for consistent styling:

# 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)

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)

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

# 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

# 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

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

data = {'Category': ['A', 'B', 'C'], 'Value': [10, 20, 15]}
fig = px.bar(data, x='Category', y='Value')

Time Series with Range Slider

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

# 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

# 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

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

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

# 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)

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

pip install plotly pandas kaleido

Dependencies:

  • plotly - Core library
  • pandas - Data manipulation (recommended)
  • kaleido - Static image export (optional)