How to Invert the Y-Axis in Matplotlib (invert_yaxis, ylim, imshow, twinx)

To invert the y-axis in Matplotlib, call ax.invert_yaxis() on your axes, or plt.gca().invert_yaxis() if you use the pyplot interface. On an inverted y-axis the values grow downward instead of upward, so the smallest value is at the top. That’s what you want for rankings (1 at the top), depth, screen/pixel coordinates and horizontal bar charts that should list the first item on top. This guide covers every way to do it, including imshow() images, the x-axis, subplots and secondary y-axes.

Every example was run with Python 3.12.5, NumPy 2.5.3 and Matplotlib 3.11.2; the printed output and the charts come from those runs.

Invert the y-axis with invert_yaxis()

import matplotlib.pyplot as plt

years = [2020, 2021, 2022, 2023, 2024]
sales = [12, 18, 15, 24, 30]

fig, (normal, inverted) = plt.subplots(1, 2, figsize=(9, 3.5))
normal.plot(years, sales, marker="o")
normal.set_title("Normal y-axis")

inverted.plot(years, sales, marker="o", color="tab:red")
inverted.invert_yaxis()                      # <- flip the y-axis
inverted.set_title("After ax.invert_yaxis()")
for ax in (normal, inverted):
    ax.set_xticks(years)                     # whole years on the x-axis

print("normal:   ylim =", *normal.get_ylim(), "| inverted:", normal.yaxis_inverted())
print("inverted: ylim =", *inverted.get_ylim(), "| inverted:", inverted.yaxis_inverted())
plt.tight_layout()
plt.show()

Output:

normal:   ylim = 11.1 30.9 | inverted: False
inverted: ylim = 30.9 11.1 | inverted: True
Matplotlib invert y axis: the same line plot with a normal y-axis on the left and an inverted y-axis after ax.invert_yaxis() on the right
Left: normal. Right: the same data after ax.invert_yaxis(), with 30 at the bottom.

get_ylim() now returns the limits top-value-first, and yaxis_inverted() tells you whether an axis is flipped. Both methods are listed in the Matplotlib API reference for Axes.invert_yaxis.

With pyplot (plt)

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4], [10, 20, 25, 40])
plt.gca().invert_yaxis()          # gca() = "get current axes"
print(*plt.ylim())                # the larger value comes first now

Output:

41.5 8.5

All the ways to invert or reverse the y-axis

import matplotlib.pyplot as plt

def fresh():
    fig, ax = plt.subplots()
    ax.plot([0, 1, 2], [0, 5, 10])
    return ax

ax = fresh(); ax.invert_yaxis()
print("invert_yaxis()            ", *ax.get_ylim())

ax = fresh(); ax.set_ylim(10.5, -0.5)          # top value first
print("set_ylim(top, bottom)     ", *ax.get_ylim())

ax = fresh(); ax.set_ylim(ax.get_ylim()[::-1])  # reverse whatever the limits are
print("set_ylim(get_ylim()[::-1])", *ax.get_ylim())

ax = fresh(); ax.yaxis.set_inverted(True)      # explicit: safe to call more than once
print("yaxis.set_inverted(True)  ", *ax.get_ylim())

plt.figure(); plt.plot([0, 1, 2], [0, 5, 10]); plt.ylim(10, 0)
print("plt.ylim(10, 0)           ", *plt.ylim())

Output:

invert_yaxis()             10.5 -0.5
set_ylim(top, bottom)      10.5 -0.5
set_ylim(get_ylim()[::-1]) 10.5 -0.5
yaxis.set_inverted(True)   10.5 -0.5
plt.ylim(10, 0)            10.0 0.0
MethodWhen to use it
ax.invert_yaxis()Simplest. Toggles: calling it twice flips back.
ax.yaxis.set_inverted(True)Explicit on/off, safe to call repeatedly.
ax.set_ylim(top, bottom) / plt.ylim(top, bottom)When you also want fixed limits.
ax.set_ylim(ax.get_ylim()[::-1])Reverse whatever the current limits are.

Common gotchas

invert_yaxis() toggles

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 1, 2], [0, 5, 10])

ax.invert_yaxis()
print("after 1st invert_yaxis():", ax.yaxis_inverted())
ax.invert_yaxis()
print("after 2nd invert_yaxis():", ax.yaxis_inverted())   # flipped back!

ax.yaxis.set_inverted(True)
ax.yaxis.set_inverted(True)
print("after set_inverted(True) twice:", ax.yaxis_inverted())

Output:

after 1st invert_yaxis(): True
after 2nd invert_yaxis(): False
after set_inverted(True) twice: True

If a function might be called twice (for example when you redraw a figure), use ax.yaxis.set_inverted(True).

Later set_ylim() calls can undo it

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 1, 2], [0, 5, 10])
ax.invert_yaxis()

ax.plot([0, 1, 2], [2, 12, 20])          # more data after inverting
print("after plotting more data: ylim =", *ax.get_ylim(), "| inverted:", ax.yaxis_inverted())

ax.set_ylim(0, 25)                       # limits given bottom-first
print("after set_ylim(0, 25):    ylim =", *ax.get_ylim(), "| inverted:", ax.yaxis_inverted())

Output:

after plotting more data: ylim = 21.0 -1.0 | inverted: True
after set_ylim(0, 25):    ylim = 0.0 25.0 | inverted: False

Adding data keeps the axis inverted, but set_ylim(0, 25) sets the direction too. Pass the limits top-first (set_ylim(25, 0)) or call set_ylim() first and invert_yaxis() after.

Invert the x-axis (or both axes)

The x-axis works the same way with invert_xaxis(), xaxis.set_inverted(True) or set_xlim(right, left):

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [1, 4, 9, 16, 25]

fig, axes = plt.subplots(1, 3, figsize=(10, 3))
titles = ["invert_xaxis()", "invert_yaxis()", "both"]
for ax, title in zip(axes, titles):
    ax.plot(x, y, marker="o")
    ax.set_title(title)

axes[0].invert_xaxis()
axes[1].invert_yaxis()
axes[2].invert_xaxis()
axes[2].invert_yaxis()

for ax in axes:
    print(f"{ax.get_title():15} x inverted: {ax.xaxis_inverted()!s:5}  y inverted: {ax.yaxis_inverted()}")
plt.tight_layout()
plt.show()

Output:

invert_xaxis()  x inverted: True   y inverted: False
invert_yaxis()  x inverted: False  y inverted: True
both            x inverted: True   y inverted: True
Matplotlib invert x axis, invert y axis and invert both axes shown side by side for the same curve
Left to right: x inverted, y inverted, both inverted.

Practical examples

Rankings: position 1 at the top

import matplotlib.pyplot as plt

weeks = range(1, 9)
song_a = [8, 5, 3, 2, 1, 1, 2, 4]      # chart position: 1 is best
song_b = [2, 1, 1, 3, 4, 6, 7, 9]

fig, ax = plt.subplots(figsize=(7, 3.8))
ax.plot(weeks, song_a, marker="o", label="Song A")
ax.plot(weeks, song_b, marker="s", label="Song B")
ax.invert_yaxis()                       # rank 1 at the top
ax.set_yticks(range(1, 10))
ax.set_xlabel("Week")
ax.set_ylabel("Chart position")
ax.legend()
ax.grid(alpha=0.3)
plt.show()
Matplotlib line chart with inverted y-axis so chart position 1 is at the top, comparing two songs over 8 weeks
Inverting puts rank 1 at the top, where readers expect it.

Depth profile

import matplotlib.pyplot as plt

depth_m = [0, 10, 20, 50, 100, 200, 500, 1000]
temperature_c = [26, 25.5, 24, 20, 15, 11, 7, 4.5]

fig, ax = plt.subplots(figsize=(4.5, 5))
ax.plot(temperature_c, depth_m, marker="o")
ax.invert_yaxis()                       # depth grows downward
ax.set_xlabel("Temperature (°C)")
ax.set_ylabel("Depth (m)")
ax.set_title("Ocean temperature profile")
ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()
Ocean temperature profile in Matplotlib with an inverted y-axis showing depth in metres increasing downward
Depth increases downward, like a real water column.

Horizontal bar chart: first category on top

barh() draws the first category at the bottom. Inverting the y-axis lists the categories in the order you gave them:

import matplotlib.pyplot as plt

languages = ["Python", "JavaScript", "Java", "C#", "Go"]
share = [29.9, 19.1, 16.3, 6.9, 4.1]

fig, (before, after) = plt.subplots(1, 2, figsize=(10, 3.2))
before.barh(languages, share)
before.set_title("barh() default: first item at the bottom")

after.barh(languages, share, color="tab:green")
after.invert_yaxis()                     # first item at the top
after.set_title("After invert_yaxis(): first item on top")
plt.tight_layout()
plt.show()
Matplotlib barh chart before and after invert_yaxis: the first category Python moves from the bottom to the top
Left: default order. Right: after invert_yaxis().

Invert the y-axis in imshow()

imshow() is the exception: it already draws images with an inverted y-axis, because row 0 of an image is the top row. Use origin="lower" (or invert_yaxis()) to put row 0 at the bottom, like a normal graph:

import matplotlib.pyplot as plt
import numpy as np

data = np.arange(12).reshape(3, 4)      # row 0 = [0, 1, 2, 3]

fig, axes = plt.subplots(1, 3, figsize=(11, 3))
axes[0].imshow(data)                         # default origin="upper"
axes[0].set_title('default (origin="upper")')
axes[1].imshow(data, origin="lower")         # row 0 at the bottom
axes[1].set_title('origin="lower"')
axes[2].imshow(data)
axes[2].invert_yaxis()                       # flip the default back
axes[2].set_title("imshow() + invert_yaxis()")

for ax in axes:
    for (r, c), v in np.ndenumerate(data):
        ax.text(c, r, v, ha="center", va="center", color="w")
    print(f"{ax.get_title():27} ylim = {ax.get_ylim()[0]:4}, {ax.get_ylim()[1]:4}   inverted: {ax.yaxis_inverted()}")
plt.tight_layout()
plt.show()

Output:

default (origin="upper")    ylim =  2.5, -0.5   inverted: True
origin="lower"              ylim = -0.5,  2.5   inverted: False
imshow() + invert_yaxis()   ylim = -0.5,  2.5   inverted: False