Dual-Axis Time Series Plot in Matplotlib

Galaxy Glossary

How do I plot a dual-axis time series in Matplotlib?

A dual-axis time series plot overlays two related time-dependent datasets in the same figure, mapping each series to its own y-axis while sharing a common x-axis.

Sign up for the latest in SQL knowledge from the Galaxy Team!
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Description

Overview

A dual-axis (or secondary-axis) time-series chart is a powerful visualization that lets you compare two variables with different value ranges or units across time. In Matplotlib, you create one set of axes, plot the first series, and then call ax.twinx() (or ax.twiny()) to spawn a second axis that shares the same x-axis. Properly labelled, colored, and scaled, the resulting figure communicates relationships that would be hard to see on separate plots.

Why Use a Dual-Axis Plot?

  • Contrast disparate scales: Overlay revenue (millions) with website traffic (thousands).
  • Reveal leading/lagging patterns: Compare temperature and energy consumption across seasons.
  • Save dashboard space: Two insights in one figure instead of two.

Core Steps in Matplotlib

  1. Create a standard Figure and Axes with plt.subplots().
  2. Plot your first time-series on the primary axis.
  3. Generate the secondary axis with ax2 = ax.twinx().
  4. Plot the second series on ax2.
  5. Customize colors, labels, and tick parameters so each axis is visually distinct.
  6. Synchronize x-axis limits and optionally align y-axis zero lines with ax2.set_ylim().
  7. Add legends, gridlines, and annotations for clarity.

Detailed Walkthrough

1. Data Preparation

Time-series require a datetime index. Use pandas to parse dates and handle missing values. Resample if necessary to minimise clutter.

2. Color and Style Cohesion

Users often fail to keep axis colors consistent with their respective line colors. A best practice is to set the y-axis spine, ticks, and label to match the plot color. This minimizes cognitive load.

3. Grid Management

Dual grids can confuse. Enable the primary axis grid only (ax.grid(True)) and disable it on the twin axis to prevent a tangled lattice.

4. Legends

Matplotlib cannot combine legends from separate axes automatically. Combine handles manually:

lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines+lines2, labels+labels2, loc="upper left")

5. Handling Date Formatting

Use matplotlib.dates formatters to avoid overlapping ticks. Rotate labels by 30–45° if needed and set ax.xaxis.set_major_locator for monthly or quarterly intervals.

6. Export Quality

Always call fig.tight_layout() or fig.autofmt_xdate() before saving. For publications, save as SVG or PDF to preserve vector quality.

Best Practices at a Glance

  • Limit to two y-axes—more overwhelms readers.
  • Scale y-axes sensibly; avoid misleading proportional gaps.
  • Use descriptive units in axis labels (e.g., “Temperature (°C)”).
  • Provide a clear legend or annotate lines directly.
  • Color-blind friendly palettes (e.g., matplotlib.cm.tab10) improve accessibility.

Practical Example: Temperature vs. Power Demand

Below we plot daily average temperature (°C) and electricity demand (MWh) for a city over one year:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# Sample dataset
df = pd.read_csv("city_energy_temp.csv", parse_dates=["date"]).set_index("date")

fig, ax = plt.subplots(figsize=(10, 5))
color1 = "tab:blue"
color2 = "tab:red"

# Primary axis: Temperature
a1 = ax.plot(df.index, df["temp_c"], color=color1, label="Temperature (°C)")
ax.set_ylabel("Temperature (°C)", color=color1, fontsize=12)
ax.tick_params(axis="y", labelcolor=color1)

# Secondary axis: Demand
ax2 = ax.twinx()
a2 = ax2.plot(df.index, df["demand_mwh"], color=color2, label="Demand (MWh)")
ax2.set_ylabel("Demand (MWh)", color=color2, fontsize=12)
ax2.tick_params(axis="y", labelcolor=color2)

# Date formatting
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
fig.autofmt_xdate()

# Combined legends
lines = a1 + a2
labels = [l.get_label() for l in lines]
ax.legend(lines, labels, loc="upper left")

ax.set_title("Daily Temperature vs. Power Demand – 2023")
fig.tight_layout()
plt.show()

Common Pitfalls and How to Fix Them

Mistake 1: Unmatched Axis Colors

Problem: Viewers cannot instantly tell which y-axis belongs to which line.
Fix: Match the spine, tick, and label colors to the data line via ax.spines["left"].set_color(color1) and ax2.spines["right"].set_color(color2).

Mistake 2: Misleading Scale Compression

Problem: Default y-limits exaggerate minor fluctuations.
Fix: Set explicit limits or use ax.margins() and ax2.margins() to add proportional padding.

Mistake 3: Cluttered Date Labels

Problem: Overlapping or excessive date ticks.
Fix: Use mdates.AutoDateLocator or manually set monthly/quarterly locators and call fig.autofmt_xdate().

Galaxy Relation

While Galaxy is primarily a modern SQL editor, engineering and analytics teams often export query results to Python for advanced visualizations like dual-axis plots. Galaxy’s AI copilot can write the SQL needed to produce the temperature and demand dataset above. After executing and downloading the CSV inside Galaxy, you can move directly into a Python environment to craft the dual-axis chart with Matplotlib, bridging fast data extraction with insightful visualization.

Conclusion

Dual-axis time-series plots condense two complementary stories into a single, elegant figure. With Matplotlib’s twinx() method, careful styling, and attention to axis alignment, you can deliver persuasive visual narratives without overwhelming your audience.

Why Dual-Axis Time Series Plot in Matplotlib is important

Analysts frequently need to compare two metrics over time, each with different units—think revenue (USD) and web traffic (visits). Plotting them on the same chart with separate y-axes saves space, highlights correlations, and accelerates decision-making. Matplotlib’s twin axis functionality is therefore a staple skill for data engineers and scientists who craft dashboards, reports, and anomaly detections.

Dual-Axis Time Series Plot in Matplotlib Example Usage



Common Mistakes

Frequently Asked Questions (FAQs)

What is ax.twinx() in Matplotlib?

It is a method that creates a new y-axis sharing the same x-axis as the original. This allows you to overlay a second dataset with its own scale on the same time axis.

Can I add more than two y-axes?

Technically yes by repeatedly calling twinx() and adjusting spines, but it is discouraged because it quickly becomes unreadable. Stick to two y-axes for clarity.

How do I align the zero lines of both y-axes?

Manually set y-limits of both axes so that 0 is positioned at the same pixel height. Use the ratio (0 - ymin) / (ymax - ymin) to compute matching limits.

Does Galaxy support dual-axis charts directly?

Galaxy focuses on query editing and collaboration. While it does not render dual-axis plots within the SQL editor today, you can export query results and use Matplotlib (or other Python tools) to build the visualization.

Want to learn about other SQL terms?