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

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
| Method | When 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

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()

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()

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()

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