How to Create a Plot with Two Y-Axes Using Matplotlib ?

Published: December 13, 2024

Tags: Matplotlib;

DMCA.com Protection Status

Introduction

Creating a plot with two y-axes can be a useful way to visualize data that share the same x-axis but have different scales or units. Matplotlib, a powerful plotting library in Python, provides straightforward methods to achieve this. Here’s a step-by-step guide.

Add a Secondary Y-Axis using twinx method

Import Required Libraries

Start by importing Matplotlib and other necessary libraries.

1
2
import matplotlib.pyplot as plt
import numpy as np

Generate Sample Data

For demonstration, create two datasets that you want to visualize on the same plot.

1
2
3
x = np.linspace(0, 10, 100)  # Common x-axis
y1 = np.sin(x)  # First dataset
y2 = np.exp(x / 3)  # Second dataset

Create the Primary Plot

Use the subplots method to create a figure and axis for the primary y-axis.

1
2
3
4
5
6
7
fig, ax1 = plt.subplots()

# Plot the first dataset
ax1.plot(x, y1, 'b-', label='Sine Wave')
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Sine', color='b')
ax1.tick_params(axis='y', labelcolor='b')

Add a Secondary Y-Axis

Use the twinx method to add a second y-axis that shares the same x-axis.

1
2
3
4
5
6
ax2 = ax1.twinx()  # Create a second axes that shares the same x-axis

# Plot the second dataset
ax2.plot(x, y2, 'r-', label='Exponential Growth')
ax2.set_ylabel('Exponential', color='r')
ax2.tick_params(axis='y', labelcolor='r')

Add a Title and Legend

Customize the plot with titles and legends.

1
2
3
4
5
fig.suptitle('Plot with Two Y-Axes')

# Optional: Add legends
ax1.legend(loc='upper left')
ax2.legend(loc='upper right')

Display the Plot

Finally, show the plot using the show method.

1
plt.show()

Full Example Code

Here is the complete script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import matplotlib.pyplot as plt
import numpy as np

# Generate data
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.exp(x / 3)

# Create primary y-axis plot
fig, ax1 = plt.subplots()
ax1.plot(x, y1, 'b-', label='Sine Wave')
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Sine', color='b')
ax1.tick_params(axis='y', labelcolor='b')

# Create secondary y-axis
ax2 = ax1.twinx()
ax2.plot(x, y2, 'r-', label='Exponential Growth')
ax2.set_ylabel('Exponential', color='r')
ax2.tick_params(axis='y', labelcolor='r')

# Add title and legends
fig.suptitle('Plot with Two Y-Axes')
ax1.legend(loc='upper left')
ax2.legend(loc='upper right')

# Display the plot
plt.show()

Output

The resulting plot will have:
- A shared x-axis.
- The sine wave (y1) on the left y-axis with blue labels and a blue line.
- The exponential growth (y2) on the right y-axis with red labels and a red line.

How to Create a Plot with Two Y-Axes Using Matplotlib ?
How to Create a Plot with Two Y-Axes Using Matplotlib ?

Key Notes

  • Use different colors for each axis to improve readability.
  • Ensure that the datasets have a logical relationship or justification for being visualized together.
  • If additional customization is needed, Matplotlib’s extensive documentation can be a helpful resource.

Another example

Code to create a dual y-axis time series plot visualizing atmospheric CO₂ concentrations and global temperature anomalies. The plot combines a line plot for CO₂ and a bar plot for temperature anomalies.

Import Libraries

1
2
3
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
  • pandas: Used for loading and processing time series data.
  • matplotlib.pyplot: Used for plotting.
  • numpy: Provides numerical utilities.

Load and Prepare CO₂ Data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Load CO₂ data
co2_data = pd.read_csv(
    "./inputs/co2_mm_mlo.csv",  # Replace with your file path
    skiprows=40,               # Skip header rows specific to the dataset
    na_values=["-99.99"]       # Handle missing values
)
co2_data = co2_data.dropna()  # Remove rows with missing data

# Create a datetime column from year and month
co2_data['date'] = pd.to_datetime(co2_data[['year', 'month']].assign(day=1))
  • Loads monthly CO₂ data from Mauna Loa Observatory.
  • Cleans the dataset and combines year and month into a datetime object for plotting.

Load and Prepare Temperature Anomaly Data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Load temperature anomaly data
temp_data = pd.read_csv(
    "./inputs/GLB.Ts+dSST.csv",  # Replace with your file path
    skiprows=1                   # Skip header row
)

# Rename and select relevant columns
temp_data = temp_data.rename(columns={"Year": "year", "J-D": "anomaly"})
temp_data = temp_data[['year', 'anomaly']]

# Add a datetime column (mid-year for annual data)
temp_data['date'] = pd.to_datetime(temp_data['year'].astype(str) + '-07-01')
  • Loads global temperature anomaly data and cleans it by renaming and selecting necessary columns.
  • Converts the year column into a datetime object for alignment with CO₂ data.

Align and Filter Data

1
2
3
4
5
6
7
8
9
# Filter data to shared date range
start_date = max(co2_data['date'].min(), temp_data['date'].min())
end_date = min(co2_data['date'].max(), temp_data['date'].max())
co2_filtered = co2_data[(co2_data['date'] >= start_date) & (co2_data['date'] <= end_date)]
temp_filtered = temp_data[(temp_data['date'] >= start_date) & (temp_data['date'] <= end_date)]

# Ensure 'anomaly' column is numeric and drop invalid rows
temp_filtered['anomaly'] = pd.to_numeric(temp_filtered['anomaly'], errors='coerce')
temp_filtered = temp_filtered.dropna(subset=['anomaly'])
  • Aligns CO₂ and temperature data by filtering to the overlapping date range.
  • Converts the anomaly column to numeric and removes invalid rows.

Separate Positive and Negative Anomalies

1
2
3
# Separate data into positive and negative anomalies
positive_anomalies = temp_filtered[temp_filtered['anomaly'] > 0]
negative_anomalies = temp_filtered[temp_filtered['anomaly'] <= 0]
  • Splits the temperature anomaly data into two subsets for positive (red) and negative (blue) bars.

Create the Plot

1
2
3
4
5
6
7
8
fig, ax1 = plt.subplots(figsize=(10, 6))

# Plot CO₂ data
ax1.plot(co2_filtered['year'], co2_filtered['average'], 'g-', label='CO₂ (ppm)')
ax1.set_xlabel('Year')
ax1.set_ylabel('CO₂ Concentration (ppm)', color='g')
ax1.tick_params(axis='y', colors='g')
ax1.legend(loc='upper left')
  • Creates the primary y-axis for CO₂ data with a green line plot.

Add Secondary Y-Axis for Temperature Anomalies

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Add a second axis for temperature anomalies
ax2 = ax1.twinx()

# Plot bars with different colors for anomalies
ax2.bar(positive_anomalies['year'], positive_anomalies['anomaly'], color='r', alpha=0.7, label='Positive Anomaly')
ax2.bar(negative_anomalies['year'], negative_anomalies['anomaly'], color='b', alpha=0.7, label='Negative Anomaly')

# Set secondary y-axis label and formatting
ax2.set_ylabel('Temperature Anomaly (°C)', color='k')
ax2.tick_params(axis='y', colors='k')
ax2.legend(loc='upper right')
  • Adds a secondary y-axis for temperature anomalies.
  • Uses a bar plot with red bars for positive anomalies and blue bars for negative anomalies.

Add Title and Display the Plot

1
2
3
4
5
# Add title and grid
plt.title('Atmospheric CO₂ and Global Temperature Anomalies')
plt.grid()
plt.tight_layout()
plt.show()
  • Adds a title, grid, and adjusts layout to prevent overlap.

Complete Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# Load CO₂ data
co2_data = pd.read_csv(
    "./inputs/co2_mm_mlo.csv",  # Replace with your file path
    skiprows=40,
    na_values=["-99.99"])

co2_data = co2_data.dropna()
co2_data['date'] = pd.to_datetime(co2_data[['year', 'month']].assign(day=1))

# Load temperature anomaly data
temp_data = pd.read_csv(
    "./inputs/GLB.Ts+dSST.csv",  # Replace with your file path
    skiprows=1
)

temp_data = temp_data.rename(columns={"Year": "year", "J-D": "anomaly"})
temp_data = temp_data[['year', 'anomaly']]
temp_data['date'] = pd.to_datetime(temp_data['year'].astype(str) + '-07-01')  # Mid-year for annual data

start_date = max(co2_data['date'].min(), temp_data['date'].min())
end_date = min(co2_data['date'].max(), temp_data['date'].max())
co2_filtered = co2_data[(co2_data['date'] >= start_date) & (co2_data['date'] <= end_date)]
temp_filtered = temp_data[(temp_data['date'] >= start_date) & (temp_data['date'] <= end_date)]

# Ensure 'anomaly' column is numeric
temp_filtered['anomaly'] = pd.to_numeric(temp_filtered['anomaly'], errors='coerce')

# Drop rows with NaN values in 'anomaly' after conversion
temp_filtered = temp_filtered.dropna(subset=['anomaly'])

# Separate data into positive and negative anomalies
positive_anomalies = temp_filtered[temp_filtered['anomaly'] > 0]
negative_anomalies = temp_filtered[temp_filtered['anomaly'] <= 0]

# Plotting
fig, ax1 = plt.subplots(figsize=(10, 6))

# Plot CO₂ data
ax1.plot(co2_filtered['year'], co2_filtered['average'], 'g-', label='CO₂ (ppm)')
ax1.set_xlabel('Year')
ax1.set_ylabel('CO₂ Concentration (ppm)', color='g')
ax1.tick_params(axis='y', colors='g')
ax1.legend(loc='upper left')

# Add a second axis for temperature anomalies
ax2 = ax1.twinx()

# Plot bars with different colors
ax2.bar(positive_anomalies['year'], positive_anomalies['anomaly'], color='r', alpha=0.7, label='Positive Anomaly')
ax2.bar(negative_anomalies['year'], negative_anomalies['anomaly'], color='b', alpha=0.7, label='Negative Anomaly')

# Set secondary y-axis label and formatting
ax2.set_ylabel('Temperature Anomaly (°C)', color='k')
ax2.tick_params(axis='y', colors='k')
ax2.legend(loc='upper right')

# Add title and grid
plt.title('Atmospheric CO₂ and Global Temperature Anomalies')
plt.grid()
plt.tight_layout()
plt.show()

Output

  • Left Y-Axis: CO₂ concentration (ppm) as a green line plot.
  • Right Y-Axis: Temperature anomalies (°C) as red and blue bars.
  • The plot provides a clear visualization of the relationship between CO₂ levels and global temperature anomalies over time.

How to Create a Plot with Two Y-Axes Using Matplotlib ?
How to Create a Plot with Two Y-Axes Using Matplotlib ?

Key Notes

  • Replace file paths ("./inputs/co2_mm_mlo.csv" and "./inputs/GLB.Ts+dSST.csv") with actual file locations on your system.
  • Ensure data formats match the code expectations, or adjust column names and parsing logic as needed.

References

Image

of