Secondary axes in Matplotlib show the same plotted values in a second unit or coordinate scale without drawing another data series. They fit figures that need the native measurement and a converted scale, such as temperatures in Celsius on the left and Fahrenheit on the right.

The secondary_yaxis() and secondary_xaxis() methods attach a converted axis to an existing Axes object. Each method needs a location and a forward/inverse function pair so Matplotlib can convert primary-axis tick values to the secondary scale and map secondary ticks back to the primary scale.

Plot the data on the original Axes and use the secondary axis for converted ticks and labels only. Matplotlib still marks the secondary-axis API as experimental, so keep the conversion functions small and check the exported figure after library upgrades.

Steps to add a secondary axis in Matplotlib:

  1. Save the secondary-axis script as secondary_axis_temperature.py.
    secondary_axis_temperature.py
    from pathlib import Path
     
    import matplotlib
    import matplotlib.pyplot as plt
    import numpy as np
     
     
    def celsius_to_fahrenheit(celsius):
        return celsius * 9 / 5 + 32
     
     
    def fahrenheit_to_celsius(fahrenheit):
        return (fahrenheit - 32) * 5 / 9
     
     
    months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
    temperature_c = np.array([4, 7, 12, 17, 22, 26])
     
    fig, ax = plt.subplots(figsize=(6, 4), layout="constrained")
    ax.plot(months, temperature_c, marker="o", linewidth=2)
    ax.set_title("Average monthly temperature")
    ax.set_xlabel("Month")
    ax.set_ylabel("Temperature (deg C)")
    ax.set_ylim(0, 30)
    ax.grid(True, axis="y", alpha=0.3)
     
    secondary = ax.secondary_yaxis(
        "right", functions=(celsius_to_fahrenheit, fahrenheit_to_celsius)
    )
    secondary.set_ylabel("Temperature (deg F)")
     
    output = Path("temperature-secondary-axis.png")
    fig.savefig(output, dpi=160)
    fig.canvas.draw()
     
    check_c = np.array([0, 20, 30])
    check_f = celsius_to_fahrenheit(check_c)
    round_trip_c = fahrenheit_to_celsius(check_f)
     
    print(f"matplotlib: {matplotlib.__version__} ({matplotlib.get_backend()} backend)")
    print(f"primary y label: {ax.get_ylabel()}")
    print(f"secondary y label: {secondary.get_ylabel()}")
    print(f"conversion check: {check_c.tolist()} deg C -> {check_f.tolist()} deg F")
    print(f"round trip: {round_trip_c.tolist()} deg C")
    print(f"saved: {output}")
    print(f"bytes: {output.stat().st_size}")
     
    plt.close(fig)

    The forward function converts from the primary axis to the secondary axis. The inverse function converts back, and both functions should accept NumPy arrays because Matplotlib passes tick values as arrays.

  2. Run the script from the directory where the output image should be written.
    $ python secondary_axis_temperature.py
    matplotlib: 3.11.0 (Agg backend)
    primary y label: Temperature (deg C)
    secondary y label: Temperature (deg F)
    conversion check: [0, 20, 30] deg C -> [32.0, 68.0, 86.0] deg F
    round trip: [0.0, 20.0, 30.0] deg C
    saved: temperature-secondary-axis.png
    bytes: 50407

    The byte count can vary by backend, font, Matplotlib version, and DPI. Confirm the primary label, secondary label, reversible conversion, and saved filename.

  3. Open temperature-secondary-axis.png and check the converted scale.

    The left axis should read Temperature (deg C) and the right axis should read Temperature (deg F). Use ax.secondary_xaxis(“top”, functions=(forward, inverse)) instead when the converted scale belongs on the x-axis.

  4. Remove the temporary files when they were created only to test the secondary axis.
    $ rm secondary_axis_temperature.py temperature-secondary-axis.png