Compare Multiple Time Series in Plotly Without Resetting the Zoom
Use Plotly make_subplots to view related charts side by side with linked axes, independent scales, and safe defaults for dense data.
09 Aug 2025, 02:01 UTC

The problem: one chart hides the pattern
You are debugging a production line where two ovens report temperature every second. Plotting both traces on one set of axes makes the lines overlap, and the oven with the wider swing compresses the other into a nearly flat line. You need to compare them side by side, but you also want a zoom in one panel to move the other so you can align events across machines.
Plotly's make_subplots function arranges multiple traces in a grid and lets you link axes across panels. This is useful when the comparison itself is the insight, not just the individual values.
Configure shared axes without forcing identical scales
A subplot grid can share the x-axis, the y-axis, both, or neither. Shared axes mean zooming or panning in one panel updates the linked panels. Independent y-axis ranges let each panel use its own scale, which prevents a high-variance series from flattening the others.
The trade-off is readability. Independent scales make each panel look 'normal' but can mislead viewers into thinking two panels have the same magnitude when they do not. Always label units clearly and consider adding a reference line or annotation if the comparison depends on absolute values.
Version assumption
This article assumes Plotly 5.0 or newer. Arguments for make_subplots changed between 4.x and 5.x. Verify your installed version before copying configuration:
# Run in a Python interpreter or notebook cell
import plotly
print(plotly.__version__)
Expected check: the printed version starts with 5.. If you see 4., consult the Plotly 5.x release notes before using shared-axis arguments shown here.
Worked example: two ovens, one shared timeline
This example creates two rows and one column. The x-axis is shared so a zoom in the top panel moves the bottom panel. Each panel has its own y-axis range. The traces use scattergl, Plotly's WebGL-backed scatter trace, which handles dense time series better than the default SVG-based scatter.
# Run in a Python script or Jupyter notebook
# No special file permissions required; writing an HTML file requires
# permission to create files in the current working directory.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
# Simulated sensor data: 5,000 points per oven
np.random.seed(42)
t = np.arange(5000)
oven_a = 200 + np.cumsum(np.random.randn(5000) * 0.5)
oven_b = 180 + np.cumsum(np.random.randn(5000) * 0.2)
# oven_c omitted for brevity
fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
vertical_spacing=0.03,
subplot_titles=('Oven A', 'Oven B')
)
# Top panel: independent y-axis, WebGL trace
fig.add_trace(
go.Scattergl(x=t, y=oven_a, name='Oven A', line=dict(color='#1f77b4')),
row=1, col=1
)
# Bottom panel: independent y-axis, WebGL trace
fig.add_trace(
go.Scattergl(x=t, y=oven_b, name='Oven B', line=dict(color='#ff7f0e')),
row=2, col=1
)
fig.update_xaxes(title_text='Time (s)', row=2, col=1)
fig.update_yaxes(title_text='Temperature (°C)', row=1, col=1)
fig.update_yaxes(title_text='Temperature (°C)', row=2, col=1)
fig.update_layout(
height=600,
showlegend=False,
title_text='Linked zoom, independent temperature scales'
)
fig.write_html('oven_comparison.html')
fig.show()
Expected check: after running, you should see two panels. Zooming into a spike in the top panel should adjust the visible x-range in the bottom panel. Each panel keeps its own y-axis range, so Oven B's smaller variations remain visible.
Risk: fig.write_html creates a file in the current directory. If the directory is read-only or the application lacks write permission, the command raises an error. Use fig.show() alone if you only need to inspect the figure interactively.
Limitation: dense data and too many panels slow rendering
Even with scattergl, a grid with many subplots and thousands of points per trace can increase page load time and make the browser tab sluggish. If you need more than four or five panels, consider downsampling the data first or loading panels lazily in a web app rather than rendering everything at once.
Practical check: open the browser's developer tools, reload the figure, and watch the Performance or Network panel. If the HTML file is several megabytes or rendering blocks the main thread for more than a second, reduce the point count or split the figure into separate pages.
Closing: verify before you present
Use make_subplots when the relationship between panels matters as much as the data inside them. Lock shared axes for linked navigation, keep y-axes independent when scales differ, and prefer scattergl for dense series. Before sharing the figure, confirm the Plotly version, test that zooming one panel moves the others, and check that no panel's independent scale makes two different magnitudes look equivalent.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.