Plotly Essentials¶
Interactive, web-ready charts from pandas DataFrames. Plotly Express (
px) gives you polished figures in one line; hover tooltips, zoom, and pan come free — perfect for exploration and dashboards.
Table of Contents¶
- Installation / Setup
- Core Syntax
- Common Operations
- Practical Examples
- Common Patterns
- Best Practices
- Common Mistakes
- Troubleshooting
- Related Cheat Sheets
- Official Documentation
Installation / Setup¶
In Jupyter/VSCode/Colab figures render automatically; in plain scripts use fig.show() (opens a browser tab).
Core Syntax¶
One-liner charts (Plotly Express)¶
| Goal | One-liner |
|---|---|
| Line | px.line(df, x="date", y="sales", color="region") |
| Bar | px.bar(df, x="day", y="total_bill", color="sex") |
| Histogram | px.histogram(df, x="age", nbins=30, color="churn") |
| Scatter | px.scatter(df, x="bill", y="tip", color="day", size="size") |
| Box | px.box(df, x="species", y="body_mass_g", color="sex") |
| Violin | px.violin(df, x="species", y="flipper_length_mm", box=True) |
| Heatmap | px.imshow(corr_matrix, text_auto=True, color_continuous_scale="RdBu_r") |
| Density heatmap | px.density_heatmap(df, x="bill", y="tip", marginal_x="histogram") |
| Scatter matrix | px.scatter_matrix(df, dimensions=[...], color="species") |
fig = px.scatter(df, x="total_bill", y="tip",
color="day", title="Tips", template="plotly_white")
fig.show()
Low-level control (graph_objects)¶
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode="lines+markers", name="train"))
fig.add_trace(go.Scatter(x=x, y=y2, mode="lines", name="val", line=dict(dash="dash")))
fig.update_layout(title="Loss curves", xaxis_title="epoch", yaxis_title="loss")
Use px for 90% of work; switch to go for multi-trace figures and fine control.
Layout, annotations, axes¶
fig.update_layout(
title="Title",
xaxis_title="x", yaxis_title="y",
legend_title="Groups",
template="plotly_white", # plotly, plotly_dark, seaborn, ggplot2, none
width=800, height=500,
)
fig.update_xaxes(range=[0, 10], title_text="epochs")
fig.update_yaxes(tickformat=".0%") # axis tick formatting
fig.add_annotation(x=5, y=0.9, text="peak", showarrow=True, arrowhead=2)
fig.add_vline(x=7, line_dash="dash", line_color="red") # reference lines
fig.add_hline(y=0.5)
Legends & colors¶
fig.update_layout(legend=dict(title="Model", orientation="h", y=1.05))
fig = px.line(df, x="epoch", y="acc", color="model",
color_discrete_sequence=px.colors.qualitative.Set2)
Subplots¶
from plotly.subplots import make_subplots
fig = make_subplots(rows=2, cols=2, subplot_titles=("hist", "scatter", "box", "line"))
fig.add_trace(go.Histogram(x=df["age"]), row=1, col=1)
fig.add_trace(go.Scatter(x=df["x"], y=df["y"], mode="markers"), row=1, col=2)
fig.add_trace(go.Box(y=df["val"]), row=2, col=1)
fig.add_trace(go.Scatter(x=t, y=y), row=2, col=2)
fig.update_layout(height=700, showlegend=False)
Exporting¶
fig.write_html("chart.html") # standalone interactive file
fig.write_html("chart.html", include_plotlyjs="cdn") # smaller file
fig.write_image("chart.png", scale=2) # needs kaleido
fig.write_image("chart.pdf")
fig.to_html() / fig.to_json() # embed or transfer
Common Operations¶
# Marginal distributions on a scatter
px.scatter(df, x="total_bill", y="tip", marginal_x="histogram", marginal_y="box")
# Faceted by category
px.histogram(df, x="body_mass_g", color="species",
facet_col="island", facet_col_wrap=2)
# Animation over time (great with gapminder-style data)
px.scatter(gap, x="gdpPercap", y="lifeExp", size="pop", color="continent",
log_x=True, animation_frame="year", range_y=[20, 90])
# Update traces after creation
fig = px.scatter(df, x="x", y="y")
fig.update_traces(marker=dict(size=6, opacity=0.7))
Practical Examples¶
1. Explore a DataFrame interactively¶
import plotly.express as px
df = px.data.tips() # built-in tips dataset
fig = px.scatter(df, x="total_bill", y="tip",
color="day", size="size", facet_col="sex",
hover_data=["time", "smoker"], title="Tips exploration")
fig.update_layout(template="plotly_white")
fig.show()
2. Distribution comparisons with a toggle of plot types¶
px.histogram(px.data.penguins(), x="flipper_length_mm", color="species",
nbins=30, marginal="box", barmode="overlay", opacity=0.6)
3. Correlation heatmap with values¶
import pandas as pd
corr = px.data.iris().select_dtypes("number").corr()
px.imshow(corr, text_auto=".2f", aspect="auto",
color_continuous_scale="RdBu_r", zmin=-1, zmax=1)
Common Patterns¶
# Reusable theme
px.defaults.template = "plotly_white"
# Combine px figure with extra go traces
fig = px.line(df, x="date", y="obs")
fig.add_trace(go.Scatter(x=df["date"], y=df["pred"], name="forecast"))
# Range slider for long time series
fig.update_layout(xaxis=dict(rangeslider=dict(visible=True), type="date"))
# Downloadable hover info
fig = px.scatter(df, x="x", y="y", custom_data=["id"])
fig.update_traces(hovertemplate="id=%{customdata[0]}<br>x=%{x:.2f}")
Best Practices¶
- Start with
px, drop togoonly when needed — Express handles aggregation, colors, legends, facets. - Give every figure a
title, axis titles, and a legend title. - Use
templatefor consistent styling; setpx.defaults.templateonce per notebook. - Export
write_htmlfor sharing;write_image(kaleido) for papers/slides. - Downsample before plotting huge data — Plotly renders every point in the DOM.
- Keep animations and 100k+ point scatters lazy: filter, aggregate, or use
scattergl.
Common Mistakes¶
| Mistake | Consequence | Correct approach |
|---|---|---|
fig.show() in a script |
Blocks / opens browser unexpectedly | Use fig.write_html in scripts |
write_image without kaleido |
ValueError: Image export requires kaleido |
pip install kaleido |
| Sorting done by Plotly alphabetically | Wrong categorical order | category_orders={"day": ["Mon", "Tue", ...]} |
Mixing px traces into a go.Figure |
Color/legend weirdness | Use px alone, or add go traces to px.fig via add_trace |
| Hover on huge data | Laggy page | Sample or aggregate first |
Nested layout dicts overwritten |
Confusing updates | Use the kwargs form (xaxis_title= not dict) |
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
| Figure not shown in Jupyter | Missing renderer | fig.show(); check plotly.io.renderers.default |
| Static export fails | kaleido not installed / version mismatch | pip install -U kaleido |
| Dates on x-axis look wrong | Not datetime dtype | pd.to_datetime first |
KeyError for a column |
Typo or column dropped | Verify df.columns |
| Huge HTML file | Full plotly.js embedded | include_plotlyjs="cdn" |
Related Cheat Sheets¶
- matplotlib.md · seaborn.md — static counterparts
- bokeh.md · altair.md — other interactive options
- pandas.md — the DataFrames powering
px - Data Visualization category index · Home · Index
Official Documentation¶
Last Updated¶
2026-09-06 — Initial version.