
Plotly
- 24 installs
- 5 repo stars
- Updated June 18, 2026
- drshailesh88/integrated_content_os
Creates interactive charts with Plotly: scatter, line, bar, heatmaps, 3D, maps, and statistical plots via Plotly Express or graph objects, exporting HTML or images.
About
Plotly is a Python graphing library for interactive, publication-quality visualizations with 40+ chart types. A developer uses Plotly Express for quick charts or graph objects for fine-grained control, outputting interactive HTML or static images.
- Plotly Express for quick charts, graph objects for customization
- 40+ chart types including 3D, maps, and financial charts
Plotly by the numbers
- 24 all-time installs (skills.sh)
- Ranked #1,168 of 2,065 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/drshailesh88/integrated_content_os --skill plotlyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 24 |
|---|---|
| repo stars | ★ 5 |
| Last updated | June 18, 2026 |
| Repository | drshailesh88/integrated_content_os ↗ |
What it does
Creates interactive charts with Plotly: scatter, line, bar, heatmaps, 3D, maps, and statistical plots via Plotly Express or graph objects, exporting HTML or images.
Files
Plotly
Python graphing library for creating interactive, publication-quality visualizations with 40+ chart types.
Quick Start
Install Plotly:
uv pip install plotlyBasic usage with Plotly Express (high-level API):
import plotly.express as px
import pandas as pd
df = pd.DataFrame({
'x': [1, 2, 3, 4],
'y': [10, 11, 12, 13]
})
fig = px.scatter(df, x='x', y='y', title='My First Plot')
fig.show()Choosing Between APIs
Use Plotly Express (px)
For quick, standard visualizations with sensible defaults:
- Working with pandas DataFrames
- Creating common chart types (scatter, line, bar, histogram, etc.)
- Need automatic color encoding and legends
- Want minimal code (1-5 lines)
See reference/plotly-express.md for complete guide.
Use Graph Objects (go)
For fine-grained control and custom visualizations:
- Chart types not in Plotly Express (3D mesh, isosurface, complex financial charts)
- Building complex multi-trace figures from scratch
- Need precise control over individual components
- Creating specialized visualizations with custom shapes and annotations
See reference/graph-objects.md for complete guide.
Note: Plotly Express returns graph objects Figure, so you can combine approaches:
fig = px.scatter(df, x='x', y='y')
fig.update_layout(title='Custom Title') # Use go methods on px figure
fig.add_hline(y=10) # Add shapesCore Capabilities
1. Chart Types
Plotly supports 40+ chart types organized into categories:
Basic Charts: scatter, line, bar, pie, area, bubble
Statistical Charts: histogram, box plot, violin, distribution, error bars
Scientific Charts: heatmap, contour, ternary, image display
Financial Charts: candlestick, OHLC, waterfall, funnel, time series
Maps: scatter maps, choropleth, density maps (geographic visualization)
3D Charts: scatter3d, surface, mesh, cone, volume
Specialized: sunburst, treemap, sankey, parallel coordinates, gauge
For detailed examples and usage of all chart types, see reference/chart-types.md.
2. Layouts and Styling
Subplots: Create multi-plot figures with shared axes:
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(rows=2, cols=2, subplot_titles=('A', 'B', 'C', 'D'))
fig.add_trace(go.Scatter(x=[1, 2], y=[3, 4]), row=1, col=1)Templates: Apply coordinated styling:
fig = px.scatter(df, x='x', y='y', template='plotly_dark')
# Built-in: plotly_white, plotly_dark, ggplot2, seaborn, simple_whiteCustomization: Control every aspect of appearance:
- Colors (discrete sequences, continuous scales)
- Fonts and text
- Axes (ranges, ticks, grids)
- Legends
- Margins and sizing
- Annotations and shapes
For complete layout and styling options, see reference/layouts-styling.md.
3. Interactivity
Built-in interactive features:
- Hover tooltips with customizable data
- Pan and zoom
- Legend toggling
- Box/lasso selection
- Rangesliders for time series
- Buttons and dropdowns
- Animations
# Custom hover template
fig.update_traces(
hovertemplate='<b>%{x}</b><br>Value: %{y:.2f}<extra></extra>'
)
# Add rangeslider
fig.update_xaxes(rangeslider_visible=True)
# Animations
fig = px.scatter(df, x='x', y='y', animation_frame='year')For complete interactivity guide, see reference/export-interactivity.md.
4. Export Options
Interactive HTML:
fig.write_html('chart.html') # Full standalone
fig.write_html('chart.html', include_plotlyjs='cdn') # Smaller fileStatic Images (requires kaleido):
uv pip install kaleidofig.write_image('chart.png') # PNG
fig.write_image('chart.pdf') # PDF
fig.write_image('chart.svg') # SVGFor complete export options, see reference/export-interactivity.md.
Common Workflows
Scientific Data Visualization
import plotly.express as px
# Scatter plot with trendline
fig = px.scatter(df, x='temperature', y='yield', trendline='ols')
# Heatmap from matrix
fig = px.imshow(correlation_matrix, text_auto=True, color_continuous_scale='RdBu')
# 3D surface plot
import plotly.graph_objects as go
fig = go.Figure(data=[go.Surface(z=z_data, x=x_data, y=y_data)])Statistical Analysis
# Distribution comparison
fig = px.histogram(df, x='values', color='group', marginal='box', nbins=30)
# Box plot with all points
fig = px.box(df, x='category', y='value', points='all')
# Violin plot
fig = px.violin(df, x='group', y='measurement', box=True)Time Series and Financial
# Time series with rangeslider
fig = px.line(df, x='date', y='price')
fig.update_xaxes(rangeslider_visible=True)
# Candlestick chart
import plotly.graph_objects as go
fig = go.Figure(data=[go.Candlestick(
x=df['date'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close']
)])Multi-Plot Dashboards
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(
rows=2, cols=2,
subplot_titles=('Scatter', 'Bar', 'Histogram', 'Box'),
specs=[[{'type': 'scatter'}, {'type': 'bar'}],
[{'type': 'histogram'}, {'type': 'box'}]]
)
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]), row=1, col=1)
fig.add_trace(go.Bar(x=['A', 'B'], y=[1, 2]), row=1, col=2)
fig.add_trace(go.Histogram(x=data), row=2, col=1)
fig.add_trace(go.Box(y=data), row=2, col=2)
fig.update_layout(height=800, showlegend=False)Integration with Dash
For interactive web applications, use Dash (Plotly's web app framework):
uv pip install dashimport dash
from dash import dcc, html
import plotly.express as px
app = dash.Dash(__name__)
fig = px.scatter(df, x='x', y='y')
app.layout = html.Div([
html.H1('Dashboard'),
dcc.Graph(figure=fig)
])
app.run_server(debug=True)Reference Files
- [plotly-express.md](reference/plotly-express.md) - High-level API for quick visualizations
- [graph-objects.md](reference/graph-objects.md) - Low-level API for fine-grained control
- [chart-types.md](reference/chart-types.md) - Complete catalog of 40+ chart types with examples
- [layouts-styling.md](reference/layouts-styling.md) - Subplots, templates, colors, customization
- [export-interactivity.md](reference/export-interactivity.md) - Export options and interactive features
Additional Resources
- Official documentation: https://plotly.com/python/
- API reference: https://plotly.com/python-api-reference/
- Community forum: https://community.plotly.com/
Plotly Chart Types
Comprehensive guide to chart types organized by category.
Basic Charts
Scatter Plots
import plotly.express as px
fig = px.scatter(df, x='x', y='y', color='category', size='size')
# With trendlines
fig = px.scatter(df, x='x', y='y', trendline='ols')Line Charts
fig = px.line(df, x='date', y='value', color='group')
# Multiple lines from wide-form data
fig = px.line(df, x='date', y=['metric1', 'metric2', 'metric3'])Bar Charts
# Vertical bars
fig = px.bar(df, x='category', y='value', color='group')
# Horizontal bars
fig = px.bar(df, x='value', y='category', orientation='h')
# Stacked bars
fig = px.bar(df, x='category', y='value', color='group', barmode='stack')
# Grouped bars
fig = px.bar(df, x='category', y='value', color='group', barmode='group')Pie Charts
fig = px.pie(df, names='category', values='count')
# Donut chart
fig = px.pie(df, names='category', values='count', hole=0.4)Area Charts
fig = px.area(df, x='date', y='value', color='category')Statistical Charts
Histograms
# Basic histogram
fig = px.histogram(df, x='values', nbins=30)
# With marginal plot
fig = px.histogram(df, x='values', marginal='box') # or 'violin', 'rug'
# 2D histogram
fig = px.density_heatmap(df, x='x', y='y', nbinsx=20, nbinsy=20)Box Plots
fig = px.box(df, x='category', y='value', color='group')
# Notched box plot
fig = px.box(df, x='category', y='value', notched=True)
# Show all points
fig = px.box(df, x='category', y='value', points='all')Violin Plots
fig = px.violin(df, x='category', y='value', color='group', box=True, points='all')Strip/Dot Plots
fig = px.strip(df, x='category', y='value', color='group')Distribution Plots
# Empirical cumulative distribution
fig = px.ecdf(df, x='value', color='group')
# Marginal distribution
fig = px.scatter(df, x='x', y='y', marginal_x='histogram', marginal_y='box')Error Bars
fig = px.scatter(df, x='x', y='y', error_y='error', error_x='x_error')
# Using graph_objects for custom error bars
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[1, 2, 3],
y=[5, 10, 15],
error_y=dict(
type='data',
array=[1, 2, 3],
visible=True
)
))Scientific Charts
Heatmaps
# From matrix data
fig = px.imshow(z_matrix, color_continuous_scale='Viridis')
# With graph_objects
fig = go.Figure(data=go.Heatmap(
z=z_matrix,
x=x_labels,
y=y_labels,
colorscale='RdBu'
))Contour Plots
# 2D contour
fig = px.density_contour(df, x='x', y='y')
# Filled contour
fig = go.Figure(data=go.Contour(
z=z_matrix,
contours=dict(
coloring='heatmap',
showlabels=True
)
))Ternary Plots
fig = px.scatter_ternary(df, a='component_a', b='component_b', c='component_c')Log Scales
fig = px.scatter(df, x='x', y='y', log_x=True, log_y=True)Image Display
import plotly.express as px
fig = px.imshow(img_array) # img_array from PIL, numpy, etc.Financial Charts
Candlestick Charts
import plotly.graph_objects as go
fig = go.Figure(data=[go.Candlestick(
x=df['date'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close']
)])OHLC Charts
fig = go.Figure(data=[go.Ohlc(
x=df['date'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close']
)])Waterfall Charts
fig = go.Figure(go.Waterfall(
x=categories,
y=values,
measure=['relative', 'relative', 'total', 'relative', 'total']
))Funnel Charts
fig = px.funnel(df, x='count', y='stage')
# Or with graph_objects
fig = go.Figure(go.Funnel(
y=['Stage 1', 'Stage 2', 'Stage 3'],
x=[100, 60, 40]
))Time Series
fig = px.line(df, x='date', y='price')
# With rangeslider
fig.update_xaxes(rangeslider_visible=True)
# With range selector buttons
fig.update_xaxes(
rangeselector=dict(
buttons=list([
dict(count=1, label='1m', step='month', stepmode='backward'),
dict(count=6, label='6m', step='month', stepmode='backward'),
dict(count=1, label='YTD', step='year', stepmode='todate'),
dict(count=1, label='1y', step='year', stepmode='backward'),
dict(step='all')
])
)
)Maps and Geographic
Scatter Maps
# Geographic projection
fig = px.scatter_geo(df, lat='lat', lon='lon', color='value', size='size')
# Mapbox (requires token for some styles)
fig = px.scatter_mapbox(
df, lat='lat', lon='lon',
color='value',
zoom=10,
mapbox_style='open-street-map' # or 'carto-positron', 'carto-darkmatter'
)Choropleth Maps
# Country-level
fig = px.choropleth(
df,
locations='iso_alpha',
color='value',
hover_name='country',
color_continuous_scale='Viridis'
)
# US States
fig = px.choropleth(
df,
locations='state_code',
locationmode='USA-states',
color='value',
scope='usa'
)Density Maps
fig = px.density_mapbox(
df, lat='lat', lon='lon', z='value',
radius=10,
zoom=10,
mapbox_style='open-street-map'
)3D Charts
3D Scatter
fig = px.scatter_3d(df, x='x', y='y', z='z', color='category', size='size')3D Line
fig = px.line_3d(df, x='x', y='y', z='z', color='group')3D Surface
import plotly.graph_objects as go
fig = go.Figure(data=[go.Surface(z=z_matrix, x=x_array, y=y_array)])
fig.update_layout(scene=dict(
xaxis_title='X',
yaxis_title='Y',
zaxis_title='Z'
))3D Mesh
fig = go.Figure(data=[go.Mesh3d(
x=x_coords,
y=y_coords,
z=z_coords,
i=i_indices,
j=j_indices,
k=k_indices,
intensity=intensity_values,
colorscale='Viridis'
)]3D Cone (Vector Field)
fig = go.Figure(data=go.Cone(
x=x, y=y, z=z,
u=u, v=v, w=w,
colorscale='Blues',
sizemode='absolute',
sizeref=0.5
))Hierarchical Charts
Sunburst
fig = px.sunburst(
df,
path=['continent', 'country', 'city'],
values='population',
color='value'
)Treemap
fig = px.treemap(
df,
path=['category', 'subcategory', 'item'],
values='count',
color='value',
color_continuous_scale='RdBu'
)Sankey Diagram
fig = go.Figure(data=[go.Sankey(
node=dict(
pad=15,
thickness=20,
line=dict(color='black', width=0.5),
label=['A', 'B', 'C', 'D', 'E'],
color='blue'
),
link=dict(
source=[0, 1, 0, 2, 3],
target=[2, 3, 3, 4, 4],
value=[8, 4, 2, 8, 4]
)
)])Specialized Charts
Parallel Coordinates
fig = px.parallel_coordinates(
df,
dimensions=['dim1', 'dim2', 'dim3', 'dim4'],
color='target',
color_continuous_scale='Viridis'
)Parallel Categories
fig = px.parallel_categories(
df,
dimensions=['cat1', 'cat2', 'cat3'],
color='value'
)Scatter Matrix (SPLOM)
fig = px.scatter_matrix(
df,
dimensions=['col1', 'col2', 'col3', 'col4'],
color='category'
)Indicator/Gauge
fig = go.Figure(go.Indicator(
mode='gauge+number+delta',
value=75,
delta={'reference': 60},
gauge={'axis': {'range': [None, 100]},
'bar': {'color': 'darkblue'},
'steps': [
{'range': [0, 50], 'color': 'lightgray'},
{'range': [50, 100], 'color': 'gray'}
],
'threshold': {'line': {'color': 'red', 'width': 4},
'thickness': 0.75,
'value': 90}
}
))Table
fig = go.Figure(data=[go.Table(
header=dict(values=['A', 'B', 'C']),
cells=dict(values=[col_a, col_b, col_c])
)])Bioinformatics
Dendrogram
from plotly.figure_factory import create_dendrogram
fig = create_dendrogram(data_matrix)Annotated Heatmap
from plotly.figure_factory import create_annotated_heatmap
fig = create_annotated_heatmap(z_matrix, x=x_labels, y=y_labels)Volcano Plot
# Typically built with scatter plot
fig = px.scatter(
df,
x='log2_fold_change',
y='neg_log10_pvalue',
color='significant',
hover_data=['gene_name']
)
fig.add_hline(y=-np.log10(0.05), line_dash='dash')
fig.add_vline(x=-1, line_dash='dash')
fig.add_vline(x=1, line_dash='dash')Export and Interactivity
Static Image Export
Installation
Static image export requires Kaleido:
uv pip install kaleidoKaleido v1+ requires Chrome/Chromium on your system.
Supported Formats
- Raster: PNG, JPEG, WebP
- Vector: SVG, PDF
Writing to File
import plotly.express as px
fig = px.scatter(df, x='x', y='y')
# Format inferred from extension
fig.write_image('chart.png')
fig.write_image('chart.pdf')
fig.write_image('chart.svg')
# Explicit format
fig.write_image('chart', format='png')Converting to Bytes
# Get image as bytes
img_bytes = fig.to_image(format='png')
# Display in Jupyter
from IPython.display import Image
Image(img_bytes)
# Save to file manually
with open('chart.png', 'wb') as f:
f.write(img_bytes)Customizing Export
fig.write_image(
'chart.png',
format='png',
width=1200,
height=800,
scale=2 # Higher resolution
)Setting Export Defaults
import plotly.io as pio
pio.kaleido.scope.default_format = 'png'
pio.kaleido.scope.default_width = 800
pio.kaleido.scope.default_height = 600
pio.kaleido.scope.default_scale = 2Exporting Multiple Figures
import plotly.io as pio
# Kaleido v1+ only
pio.write_images(
fig=[fig1, fig2, fig3],
file=['chart1.png', 'chart2.png', 'chart3.png']
)Interactive HTML Export
Basic Export
# Full standalone HTML
fig.write_html('interactive_chart.html')
# Open in browser
fig.show()File Size Control
# Full library embedded (~5MB file)
fig.write_html('chart.html', include_plotlyjs=True)
# CDN reference (~2KB file, requires internet)
fig.write_html('chart.html', include_plotlyjs='cdn')
# Local reference (requires plotly.min.js in same directory)
fig.write_html('chart.html', include_plotlyjs='directory')
# No library (for embedding in existing HTML with Plotly.js)
fig.write_html('chart.html', include_plotlyjs=False)HTML Configuration
fig.write_html(
'chart.html',
config={
'displayModeBar': True,
'displaylogo': False,
'toImageButtonOptions': {
'format': 'png',
'filename': 'custom_image',
'height': 800,
'width': 1200,
'scale': 2
}
}
)Embedding in Templates
# Get only the div (no full HTML structure)
html_div = fig.to_html(
full_html=False,
include_plotlyjs='cdn',
div_id='my-plot'
)
# Use in Jinja2 template
template = """
<html>
<body>
<h1>My Dashboard</h1>
{{ plot_div | safe }}
</body>
</html>
"""Interactivity Features
Built-in Interactions
Plotly figures automatically support:
- Hover tooltips - Display data on hover
- Pan and zoom - Click and drag to pan, scroll to zoom
- Box/lasso select - Select multiple points
- Legend toggling - Click to hide/show traces
- Double-click - Reset axes
Hover Customization
# Hover mode
fig.update_layout(
hovermode='closest' # 'x', 'y', 'closest', 'x unified', False
)
# Custom hover template
fig.update_traces(
hovertemplate='<b>%{x}</b><br>' +
'Value: %{y:.2f}<br>' +
'Extra: %{customdata[0]}<br>' +
'<extra></extra>'
)
# Hover data in Plotly Express
fig = px.scatter(
df, x='x', y='y',
hover_data={
'extra_col': True, # Show column
'x': ':.2f', # Format column
'hidden': False # Hide column
},
hover_name='name_column' # Bold title
)Click Events (Dash/FigureWidget)
For web applications, use Dash or FigureWidget for click handling:
# With FigureWidget in Jupyter
import plotly.graph_objects as go
fig = go.FigureWidget(data=[go.Scatter(x=[1, 2, 3], y=[4, 5, 6])])
def on_click(trace, points, selector):
print(f'Clicked on points: {points.point_inds}')
fig.data[0].on_click(on_click)
figZoom and Pan
# Disable zoom/pan
fig.update_xaxes(fixedrange=True)
fig.update_yaxes(fixedrange=True)
# Set initial zoom
fig.update_xaxes(range=[0, 10])
fig.update_yaxes(range=[0, 100])
# Constrain zoom
fig.update_xaxes(
range=[0, 10],
constrain='domain'
)Rangeslider (Time Series)
fig = px.line(df, x='date', y='value')
# Add rangeslider
fig.update_xaxes(rangeslider_visible=True)
# Customize rangeslider
fig.update_xaxes(
rangeslider=dict(
visible=True,
thickness=0.05,
bgcolor='lightgray'
)
)Range Selector Buttons
fig.update_xaxes(
rangeselector=dict(
buttons=list([
dict(count=1, label='1m', step='month', stepmode='backward'),
dict(count=6, label='6m', step='month', stepmode='backward'),
dict(count=1, label='YTD', step='year', stepmode='todate'),
dict(count=1, label='1y', step='year', stepmode='backward'),
dict(step='all', label='All')
]),
x=0.0,
y=1.0,
xanchor='left',
yanchor='top'
)
)Buttons and Dropdowns
fig.update_layout(
updatemenus=[
dict(
type='buttons',
direction='left',
buttons=list([
dict(
args=[{'type': 'scatter'}],
label='Scatter',
method='restyle'
),
dict(
args=[{'type': 'bar'}],
label='Bar',
method='restyle'
)
]),
x=0.1,
y=1.15
)
]
)Sliders
fig.update_layout(
sliders=[
dict(
active=0,
steps=[
dict(
method='update',
args=[{'visible': [True, False]},
{'title': 'Dataset 1'}],
label='Dataset 1'
),
dict(
method='update',
args=[{'visible': [False, True]},
{'title': 'Dataset 2'}],
label='Dataset 2'
)
],
x=0.1,
y=0,
len=0.9
)
]
)Animations
Using Plotly Express
fig = px.scatter(
df, x='gdp', y='life_exp',
animation_frame='year', # Animate over this column
animation_group='country', # Group animated elements
size='population',
color='continent',
hover_name='country',
log_x=True,
range_x=[100, 100000],
range_y=[25, 90]
)
# Customize animation speed
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 1000
fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 500Using Graph Objects
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Scatter(x=[1, 2], y=[1, 2])],
layout=go.Layout(
updatemenus=[dict(
type='buttons',
buttons=[dict(label='Play',
method='animate',
args=[None])]
)]
),
frames=[
go.Frame(data=[go.Scatter(x=[1, 2], y=[1, 2])]),
go.Frame(data=[go.Scatter(x=[1, 2], y=[2, 3])]),
go.Frame(data=[go.Scatter(x=[1, 2], y=[3, 4])])
]
)Displaying Figures
In Jupyter
# Default renderer
fig.show()
# Specific renderer
fig.show(renderer='notebook') # or 'jupyterlab', 'colab', 'kaggle'In Web Browser
fig.show() # Opens in default browserIn Dash Applications
import dash
from dash import dcc, html
import plotly.express as px
app = dash.Dash(__name__)
fig = px.scatter(df, x='x', y='y')
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server(debug=True)Saving and Loading
# Save as JSON
fig.write_json('figure.json')
# Load from JSON
import plotly.io as pio
fig = pio.read_json('figure.json')
# Save as HTML
fig.write_html('figure.html')Configuration Options
Display Config
config = {
'displayModeBar': True, # Show toolbar
'displaylogo': False, # Hide Plotly logo
'modeBarButtonsToRemove': ['pan2d', 'lasso2d'], # Remove buttons
'toImageButtonOptions': {
'format': 'png',
'filename': 'custom_image',
'height': 500,
'width': 700,
'scale': 1
},
'scrollZoom': True, # Enable scroll zoom
'editable': True, # Enable editing
'responsive': True # Responsive sizing
}
fig.show(config=config)
fig.write_html('chart.html', config=config)Available Config Options
displayModeBar: Show/hide toolbar ('hover', True, False)displaylogo: Show Plotly logomodeBarButtonsToRemove: List of buttons to hidemodeBarButtonsToAdd: Custom buttonsscrollZoom: Enable scroll to zoomdoubleClick: Double-click behavior ('reset', 'autosize', 'reset+autosize', False)showAxisDragHandles: Show axis drag handleseditable: Allow editingresponsive: Responsive sizing
Graph Objects - Low-Level API
The plotly.graph_objects module provides fine-grained control over figure construction through Python classes representing Plotly components.
Core Classes
- `go.Figure` - Main figure container
- `go.FigureWidget` - Jupyter-compatible interactive widget
- Trace types - 40+ chart types (Scatter, Bar, Heatmap, etc.)
- Layout components - Axes, annotations, shapes, etc.
Key Advantages
1. Data validation - Helpful error messages for invalid properties 2. Built-in documentation - Accessible via docstrings 3. Flexible syntax - Dictionary or attribute access 4. Convenience methods - .add_trace(), .update_layout(), etc. 5. Magic underscore notation - Compact nested property access 6. Integrated I/O - .show(), .write_html(), .write_image()
Basic Figure Construction
Creating Empty Figure
import plotly.graph_objects as go
fig = go.Figure()Adding Traces
# Method 1: Add traces one at a time
fig = go.Figure()
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6], name='Line 1'))
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[2, 3, 4], name='Line 2'))
# Method 2: Pass data to constructor
fig = go.Figure(data=[
go.Scatter(x=[1, 2, 3], y=[4, 5, 6], name='Line 1'),
go.Scatter(x=[1, 2, 3], y=[2, 3, 4], name='Line 2')
])Common Trace Types
Scatter (Lines and Markers)
fig.add_trace(go.Scatter(
x=[1, 2, 3, 4],
y=[10, 11, 12, 13],
mode='lines+markers', # 'lines', 'markers', 'lines+markers', 'text'
name='Trace 1',
line=dict(color='red', width=2, dash='dash'),
marker=dict(size=10, color='blue', symbol='circle')
))Bar
fig.add_trace(go.Bar(
x=['A', 'B', 'C'],
y=[1, 3, 2],
name='Bar Chart',
marker=dict(color='lightblue'),
text=[1, 3, 2],
textposition='auto'
))Heatmap
fig.add_trace(go.Heatmap(
z=[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
x=['A', 'B', 'C'],
y=['X', 'Y', 'Z'],
colorscale='Viridis'
))3D Scatter
fig.add_trace(go.Scatter3d(
x=[1, 2, 3],
y=[4, 5, 6],
z=[7, 8, 9],
mode='markers',
marker=dict(size=5, color='red')
))Layout Configuration
Update Layout
fig.update_layout(
title='Figure Title',
title_font_size=20,
xaxis_title='X Axis',
yaxis_title='Y Axis',
width=800,
height=600,
template='plotly_white',
showlegend=True,
hovermode='closest' # 'x', 'y', 'closest', 'x unified', False
)Magic Underscore Notation
Compact way to set nested properties:
# Instead of:
fig.update_layout(title=dict(text='Title', font=dict(size=20)))
# Use underscores:
fig.update_layout(
title_text='Title',
title_font_size=20
)Axis Configuration
fig.update_xaxes(
title='X Axis',
range=[0, 10],
showgrid=True,
gridwidth=1,
gridcolor='lightgray',
type='log', # 'linear', 'log', 'date', 'category'
tickformat='.2f',
dtick=1 # Tick spacing
)
fig.update_yaxes(
title='Y Axis',
zeroline=True,
zerolinewidth=2,
zerolinecolor='black'
)Updating Traces
# Update all traces
fig.update_traces(
marker=dict(size=10, opacity=0.7)
)
# Update specific trace
fig.update_traces(
marker=dict(color='red'),
selector=dict(name='Line 1')
)
# Update by position
fig.data[0].marker.size = 15Adding Annotations
fig.add_annotation(
x=2, y=5,
text='Important Point',
showarrow=True,
arrowhead=2,
arrowsize=1,
arrowwidth=2,
arrowcolor='red',
ax=40, # Arrow x offset
ay=-40 # Arrow y offset
)Adding Shapes
# Rectangle
fig.add_shape(
type='rect',
x0=1, y0=2, x1=3, y1=4,
line=dict(color='red', width=2),
fillcolor='lightblue',
opacity=0.3
)
# Line
fig.add_shape(
type='line',
x0=0, y0=0, x1=5, y1=5,
line=dict(color='green', width=2, dash='dash')
)
# Convenience methods for horizontal/vertical lines
fig.add_hline(y=5, line_dash='dash', line_color='red')
fig.add_vline(x=3, line_dash='dot', line_color='blue')Figure Structure
Figures follow a tree hierarchy:
fig = go.Figure(data=[trace1, trace2], layout=go.Layout(...))
# Access via dictionary syntax
fig['layout']['title'] = 'New Title'
fig['data'][0]['marker']['color'] = 'red'
# Or attribute syntax
fig.layout.title = 'New Title'
fig.data[0].marker.color = 'red'Complex Chart Types
Candlestick
fig.add_trace(go.Candlestick(
x=df['date'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name='Stock Price'
))Sankey Diagram
fig = go.Figure(data=[go.Sankey(
node=dict(
label=['A', 'B', 'C', 'D'],
color='blue'
),
link=dict(
source=[0, 1, 0, 2],
target=[2, 3, 3, 3],
value=[8, 4, 2, 8]
)
)])Surface (3D)
fig = go.Figure(data=[go.Surface(
z=z_data, # 2D array
x=x_data,
y=y_data,
colorscale='Viridis'
)])Working with DataFrames
Build traces from pandas DataFrames:
import pandas as pd
df = pd.DataFrame({
'x': [1, 2, 3, 4],
'y': [10, 11, 12, 13]
})
fig = go.Figure()
for group_name, group_df in df.groupby('category'):
fig.add_trace(go.Scatter(
x=group_df['x'],
y=group_df['y'],
name=group_name,
mode='lines+markers'
))When to Use Graph Objects
Use graph_objects when:
- Creating chart types not available in Plotly Express
- Building complex multi-trace figures from scratch
- Need precise control over individual components
- Creating specialized visualizations (3D mesh, isosurface, custom shapes)
- Building subplots with mixed chart types
Use Plotly Express when:
- Creating standard charts quickly
- Working with tidy DataFrame data
- Want automatic styling and legends
Layouts, Styling, and Customization
Subplots
Creating Subplots
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# Basic grid
fig = make_subplots(rows=2, cols=2)
# Add traces to specific positions
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]), row=1, col=1)
fig.add_trace(go.Bar(x=['A', 'B', 'C'], y=[1, 3, 2]), row=1, col=2)
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[2, 3, 4]), row=2, col=1)Subplot Options
fig = make_subplots(
rows=2, cols=2,
# Titles
subplot_titles=('Plot 1', 'Plot 2', 'Plot 3', 'Plot 4'),
# Custom dimensions
column_widths=[0.7, 0.3],
row_heights=[0.4, 0.6],
# Spacing
horizontal_spacing=0.1,
vertical_spacing=0.15,
# Shared axes
shared_xaxes=True, # or 'columns', 'rows', 'all'
shared_yaxes=False,
# Trace types (optional, for mixed types)
specs=[[{'type': 'scatter'}, {'type': 'bar'}],
[{'type': 'surface'}, {'type': 'table'}]]
)Mixed Subplot Types
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# 2D and 3D subplots
fig = make_subplots(
rows=1, cols=2,
specs=[[{'type': 'scatter'}, {'type': 'scatter3d'}]]
)
fig.add_trace(go.Scatter(x=[1, 2], y=[3, 4]), row=1, col=1)
fig.add_trace(go.Scatter3d(x=[1, 2], y=[3, 4], z=[5, 6]), row=1, col=2)Customizing Subplot Axes
# Update specific subplot axes
fig.update_xaxes(title_text='X Label', row=1, col=1)
fig.update_yaxes(title_text='Y Label', range=[0, 100], row=2, col=1)
# Update all x-axes
fig.update_xaxes(showgrid=True, gridcolor='lightgray')Shared Colorscale
fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Bar(x=['A', 'B'], y=[1, 2],
marker=dict(color=[1, 2], coloraxis='coloraxis')),
row=1, col=1)
fig.add_trace(go.Bar(x=['C', 'D'], y=[3, 4],
marker=dict(color=[3, 4], coloraxis='coloraxis')),
row=1, col=2)
fig.update_layout(coloraxis=dict(colorscale='Viridis'))Templates and Themes
Built-in Templates
import plotly.express as px
import plotly.io as pio
# Available templates
templates = [
'plotly', # Default
'plotly_white', # White background
'plotly_dark', # Dark theme
'ggplot2', # ggplot2 style
'seaborn', # Seaborn style
'simple_white', # Minimal white
'presentation', # For presentations
'xgridoff', # No x grid
'ygridoff', # No y grid
'gridon', # Grid on
'none' # No styling
]
# Use in Plotly Express
fig = px.scatter(df, x='x', y='y', template='plotly_dark')
# Use in graph_objects
fig.update_layout(template='seaborn')
# Set default template for session
pio.templates.default = 'plotly_white'Custom Templates
import plotly.graph_objects as go
import plotly.io as pio
# Create custom template
custom_template = go.layout.Template(
layout=go.Layout(
font=dict(family='Arial', size=14),
plot_bgcolor='#f0f0f0',
paper_bgcolor='white',
colorway=['#1f77b4', '#ff7f0e', '#2ca02c'],
title_font_size=20
)
)
# Register template
pio.templates['custom'] = custom_template
# Use it
fig = px.scatter(df, x='x', y='y', template='custom')Styling with Plotly Express
Built-in Arguments
fig = px.scatter(
df, x='x', y='y',
# Dimensions
width=800,
height=600,
# Title
title='Figure Title',
# Labels
labels={'x': 'X Axis Label', 'y': 'Y Axis Label'},
# Colors
color='category',
color_discrete_sequence=px.colors.qualitative.Set2,
color_discrete_map={'A': 'red', 'B': 'blue'},
color_continuous_scale='Viridis',
# Ordering
category_orders={'category': ['A', 'B', 'C']},
# Template
template='plotly_white'
)Setting Defaults
import plotly.express as px
# Session-wide defaults
px.defaults.template = 'plotly_white'
px.defaults.width = 800
px.defaults.height = 600
px.defaults.color_continuous_scale = 'Viridis'Color Scales
Discrete Colors
import plotly.express as px
# Named color sequences
color_sequences = [
px.colors.qualitative.Plotly,
px.colors.qualitative.D3,
px.colors.qualitative.G10,
px.colors.qualitative.Set1,
px.colors.qualitative.Pastel,
px.colors.qualitative.Dark2,
]
fig = px.scatter(df, x='x', y='y', color='category',
color_discrete_sequence=px.colors.qualitative.Set2)Continuous Colors
# Named continuous scales
continuous_scales = [
'Viridis', 'Plasma', 'Inferno', 'Magma', 'Cividis', # Perceptually uniform
'Blues', 'Greens', 'Reds', 'YlOrRd', 'YlGnBu', # Sequential
'RdBu', 'RdYlGn', 'Spectral', 'Picnic', # Diverging
]
fig = px.scatter(df, x='x', y='y', color='value',
color_continuous_scale='Viridis')
# Reverse scale
fig = px.scatter(df, x='x', y='y', color='value',
color_continuous_scale='Viridis_r')
# Custom scale
fig = px.scatter(df, x='x', y='y', color='value',
color_continuous_scale=['blue', 'white', 'red'])Colorbar Customization
fig.update_coloraxes(
colorbar=dict(
title='Value',
tickmode='linear',
tick0=0,
dtick=10,
len=0.7, # Length relative to plot
thickness=20,
x=1.02 # Position
)
)Layout Customization
Title and Fonts
fig.update_layout(
title=dict(
text='Main Title',
font=dict(size=24, family='Arial', color='darkblue'),
x=0.5, # Center title
xanchor='center'
),
font=dict(
family='Arial',
size=14,
color='black'
)
)Margins and Size
fig.update_layout(
width=1000,
height=600,
margin=dict(
l=50, # left
r=50, # right
t=100, # top
b=50, # bottom
pad=10 # padding
),
autosize=True # Auto-resize to container
)Background Colors
fig.update_layout(
plot_bgcolor='#f0f0f0', # Plot area
paper_bgcolor='white' # Figure background
)Legend
fig.update_layout(
showlegend=True,
legend=dict(
title='Legend Title',
orientation='h', # 'h' or 'v'
x=0.5, # Position
y=-0.2,
xanchor='center',
yanchor='top',
bgcolor='rgba(255, 255, 255, 0.8)',
bordercolor='black',
borderwidth=1,
font=dict(size=12)
)
)Axes
fig.update_xaxes(
title='X Axis Title',
title_font=dict(size=16, family='Arial'),
# Range
range=[0, 10],
autorange=True, # Auto range
# Grid
showgrid=True,
gridwidth=1,
gridcolor='lightgray',
# Ticks
showticklabels=True,
tickmode='linear',
tick0=0,
dtick=1,
tickformat='.2f',
tickangle=-45,
# Zero line
zeroline=True,
zerolinewidth=2,
zerolinecolor='black',
# Scale
type='linear', # 'linear', 'log', 'date', 'category'
)
fig.update_yaxes(
title='Y Axis Title',
# ... same options as xaxes
)Hover Behavior
fig.update_layout(
hovermode='closest', # 'x', 'y', 'closest', 'x unified', False
)
# Customize hover template
fig.update_traces(
hovertemplate='<b>%{x}</b><br>Value: %{y:.2f}<extra></extra>'
)Annotations
fig.add_annotation(
text='Important Note',
x=2,
y=5,
showarrow=True,
arrowhead=2,
arrowsize=1,
arrowwidth=2,
arrowcolor='red',
ax=40, # Arrow x offset
ay=-40, # Arrow y offset
font=dict(size=14, color='black'),
bgcolor='yellow',
opacity=0.8
)Shapes
# Rectangle
fig.add_shape(
type='rect',
x0=1, y0=2, x1=3, y1=4,
line=dict(color='red', width=2),
fillcolor='lightblue',
opacity=0.3
)
# Circle
fig.add_shape(
type='circle',
x0=0, y0=0, x1=1, y1=1,
line_color='purple'
)
# Convenience methods
fig.add_hline(y=5, line_dash='dash', line_color='red',
annotation_text='Threshold')
fig.add_vline(x=3, line_dash='dot')
fig.add_vrect(x0=1, x1=2, fillcolor='green', opacity=0.2)
fig.add_hrect(y0=4, y1=6, fillcolor='red', opacity=0.2)Update Methods
Update Layout
fig.update_layout(
title='New Title',
xaxis_title='X',
yaxis_title='Y'
)Update Traces
# Update all traces
fig.update_traces(marker=dict(size=10, opacity=0.7))
# Update with selector
fig.update_traces(
marker=dict(color='red'),
selector=dict(mode='markers', name='Series 1')
)Update Axes
fig.update_xaxes(showgrid=True, gridcolor='lightgray')
fig.update_yaxes(type='log')Responsive Design
# Auto-resize to container
fig.update_layout(autosize=True)
# Responsive in HTML
fig.write_html('plot.html', config={'responsive': True})Plotly Express - High-Level API
Plotly Express (px) is a high-level interface for creating data visualizations with minimal code (typically 1-5 lines).
Installation
uv pip install plotlyKey Advantages
- Concise syntax for common chart types
- Automatic color encoding and legends
- Works seamlessly with pandas DataFrames
- Smart defaults for layout and styling
- Returns graph_objects.Figure for further customization
Basic Usage Pattern
import plotly.express as px
import pandas as pd
# Most functions follow this pattern
fig = px.chart_type(
data_frame=df,
x="column_x",
y="column_y",
color="category_column", # Auto-color by category
size="size_column", # Size by values
title="Chart Title"
)
fig.show()40+ Chart Types
Basic Charts
px.scatter()- Scatter plots with optional trendlinespx.line()- Line charts for time seriespx.bar()- Bar charts (vertical/horizontal)px.area()- Area chartspx.pie()- Pie charts
Statistical Charts
px.histogram()- Histograms with automatic binningpx.box()- Box plots for distributionspx.violin()- Violin plotspx.strip()- Strip plotspx.ecdf()- Empirical cumulative distribution
Maps
px.scatter_geo()- Geographic scatter plotspx.choropleth()- Choropleth mapspx.scatter_mapbox()- Mapbox scatter plotspx.density_mapbox()- Density heatmaps on maps
Specialized
px.sunburst()- Hierarchical sunburst chartspx.treemap()- Treemap visualizationspx.funnel()- Funnel chartspx.parallel_coordinates()- Parallel coordinatespx.scatter_matrix()- Scatter matrix (SPLOM)px.density_heatmap()- 2D density heatmapspx.density_contour()- Density contours
3D Charts
px.scatter_3d()- 3D scatter plotspx.line_3d()- 3D line plots
Common Parameters
All Plotly Express functions support these styling parameters:
fig = px.scatter(
df, x="x", y="y",
# Dimensions
width=800,
height=600,
# Labels
title="Figure Title",
labels={"x": "X Axis", "y": "Y Axis"},
# Colors
color="category",
color_discrete_map={"A": "red", "B": "blue"},
color_continuous_scale="Viridis",
# Ordering
category_orders={"category": ["A", "B", "C"]},
# Theming
template="plotly_dark" # or "simple_white", "seaborn", "ggplot2"
)Data Format
Plotly Express works with:
- Long-form data (tidy): One row per observation
- Wide-form data: Multiple columns as separate traces
# Long-form (preferred)
df_long = pd.DataFrame({
'fruit': ['apple', 'orange', 'apple', 'orange'],
'contestant': ['A', 'A', 'B', 'B'],
'count': [1, 3, 2, 4]
})
fig = px.bar(df_long, x='fruit', y='count', color='contestant')
# Wide-form
df_wide = pd.DataFrame({
'fruit': ['apple', 'orange'],
'A': [1, 3],
'B': [2, 4]
})
fig = px.bar(df_wide, x='fruit', y=['A', 'B'])Trendlines
Add statistical trendlines to scatter plots:
fig = px.scatter(
df, x="x", y="y",
trendline="ols", # "ols", "lowess", "rolling", "ewm", "expanding"
trendline_options=dict(log_x=True) # Additional options
)Faceting (Subplots)
Create faceted plots automatically:
fig = px.scatter(
df, x="x", y="y",
facet_row="category_1", # Separate rows
facet_col="category_2", # Separate columns
facet_col_wrap=3 # Wrap columns
)Animation
Create animated visualizations:
fig = px.scatter(
df, x="gdp", y="life_exp",
animation_frame="year", # Animate over this column
animation_group="country", # Group animated elements
size="population",
color="continent",
hover_name="country"
)Hover Data
Customize hover tooltips:
fig = px.scatter(
df, x="x", y="y",
hover_data={
"extra_col": True, # Add column
"x": ":.2f", # Format existing
"hidden_col": False # Hide column
},
hover_name="name_column" # Bold title in hover
)Further Customization
Plotly Express returns a graph_objects.Figure that can be further customized:
fig = px.scatter(df, x="x", y="y")
# Use graph_objects methods
fig.update_layout(
title="Custom Title",
xaxis_title="X Axis",
font=dict(size=14)
)
fig.update_traces(
marker=dict(size=10, opacity=0.7)
)
fig.add_hline(y=0, line_dash="dash")When to Use Plotly Express
Use Plotly Express when:
- Creating standard chart types quickly
- Working with pandas DataFrames
- Need automatic color/size encoding
- Want sensible defaults with minimal code
Use graph_objects when:
- Building custom chart types not in px
- Need fine-grained control over every element
- Creating complex multi-trace figures
- Building specialized visualizations