To set the axis range in Matplotlib, use plt.ylim(bottom, top) and plt.xlim(left, right), or ax.set_ylim() and ax.set_xlim() when you work with an Axes object. ax.axis([xmin, xmax, ymin, ymax]) sets both at once. This guide shows each method with its output, plus how to set only one limit, keep subplots on the same range, and set ranges for dates, log scales, imshow() images, secondary y-axes and pandas plots.
Every example was run with Python 3.12.5, Matplotlib 3.11.2, NumPy 2.5.3 and pandas 3.0.6; the printed output and the charts come from those runs.
Set the y-axis range
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
score = [71, 74, 73, 77, 79, 78]
fig, (auto, fixed) = plt.subplots(1, 2, figsize=(9, 3.5))
auto.plot(months, score, marker="o")
auto.set_title("Automatic y-axis range")
fixed.plot(months, score, marker="o", color="tab:green")
fixed.set_ylim(0, 100) # <- set the y-axis range
fixed.set_title("After set_ylim(0, 100)")
print("automatic:", *auto.get_ylim())
print("fixed: ", *fixed.get_ylim())
plt.tight_layout()
plt.show()
Output:
automatic: 70.6 79.4
fixed: 0.0 100.0
set_ylim(0, 100).A fixed range is useful when you compare several charts, or when an automatic range exaggerates small changes (71 to 79 looks huge on the left). All parameters are in the Matplotlib reference for Axes.set_ylim.
Set the x-axis and y-axis range with pyplot
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [10, 25, 18, 30])
plt.ylim(0, 40) # y-axis from 0 to 40
plt.xlim(0, 5) # x-axis from 0 to 5
print("ylim:", *plt.ylim(), "| xlim:", *plt.xlim())
Output:
ylim: 0.0 40.0 | xlim: 0.0 5.0
Called without arguments, plt.ylim() and plt.xlim() return the current range. More x-axis examples: Matplotlib xlim.
Set both axes at once with axis()
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 25, 18, 30])
ax.axis([0, 5, 0, 40]) # [xmin, xmax, ymin, ymax] in one call
print("axis():", *ax.axis())
print("get_xlim():", *ax.get_xlim(), "| get_ylim():", *ax.get_ylim())
Output:
axis(): 0.0 5.0 0.0 40.0
get_xlim(): 0.0 5.0 | get_ylim(): 0.0 40.0
| Function | Sets | Reads |
|---|---|---|
plt.ylim(b, t) / ax.set_ylim(b, t) | y range | plt.ylim() / ax.get_ylim() |
plt.xlim(l, r) / ax.set_xlim(l, r) | x range | plt.xlim() / ax.get_xlim() |
plt.axis([l, r, b, t]) / ax.axis(...) | both | ax.axis() |
ax.set(xlim=..., ylim=...) | both (with other properties) | – |
Set only the lower (or upper) limit
Pass only bottom or top (left or right for x) and Matplotlib keeps the other side as it was:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [12, 25, 18, 30])
print("automatic: ", *ax.get_ylim())
ax.set_ylim(bottom=0) # only the lower limit
print("set_ylim(bottom=0):", *ax.get_ylim())
ax.set_ylim(top=50) # only the upper limit
print("set_ylim(top=50): ", *ax.get_ylim())
ax.set_xlim(left=0) # same idea for x: left / right
print("set_xlim(left=0): ", *ax.get_xlim())
Output:
automatic: 11.1 30.9
set_ylim(bottom=0): 0.0 30.9
set_ylim(top=50): 0.0 50.0
set_xlim(left=0): 0.0 4.15
set_ylim(bottom=0) is the usual way to make a bar or line chart start at zero.
Fixed range vs. autoscaling
Setting a range switches autoscaling off for that axis, so data you add later can fall outside the visible range:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 1, 2], [0, 5, 10])
ax.set_ylim(0, 12)
print("autoscale on?", ax.get_autoscaley_on())
ax.plot([0, 1, 2], [0, 20, 40]) # new data goes above the limit
print("after new data:", *ax.get_ylim()) # the range stays fixed
ax.autoscale(axis="y") # let Matplotlib fit the data again
print("after autoscale():", *ax.get_ylim())
Output:
autoscale on? False
after new data: 0.0 12.0
after autoscale(): -2.0 42.0
If you only want some space around the data rather than exact numbers, use margins():
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 10], [0, 100])
print("default margins:", *ax.get_ylim())
ax.margins(y=0.2) # 20% padding instead of fixed numbers
print("margins(y=0.2): ", *ax.get_ylim())
ax.margins(y=0) # no padding: the line touches the edges
print("margins(y=0): ", *ax.get_ylim())
Output:
default margins: -5.0 105.0
margins(y=0.2): -20.0 120.0
margins(y=0): 0.0 100.0
Same axis range for all subplots
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, axes = plt.subplots(1, 3, figsize=(11, 3), sharey=True) # one shared y-range
for ax, k in zip(axes, [1, 2, 3]):
ax.plot(x, k * np.sin(x))
ax.set_title(f"{k} * sin(x)")
axes[0].set_ylim(-4, 4) # setting one sets all (sharey=True)
for ax in axes:
print(ax.get_title(), *ax.get_ylim())
plt.tight_layout()
plt.show()
Output:
1 * sin(x) -4.0 4.0
2 * sin(x) -4.0 4.0
3 * sin(x) -4.0 4.0
sharey=True, one set_ylim() call applies to every subplot.For a different range per subplot, loop over the axes:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 2)
ranges = [(0, 10), (0, 100), (-1, 1), (50, 60)]
for ax, (low, high) in zip(axes.flat, ranges):
ax.plot([0, 1], [low, high])
ax.set_ylim(low, high)
for ax in axes.flat:
print(*ax.get_ylim())
Output:
0.0 10.0
0.0 100.0
-1.0 1.0
50.0 60.0
Axis range with dates
Pass datetime or date objects directly to set_xlim():
from datetime import date
import matplotlib.pyplot as plt
days = [date(2026, 9, d) for d in range(1, 31)]
visits = [100 + (d * 7) % 45 for d in range(1, 31)]
fig, ax = plt.subplots()
ax.plot(days, visits)
ax.set_xlim(date(2026, 9, 10), date(2026, 9, 20)) # zoom to 10-20 September
low, high = ax.get_xlim() # numbers: days since 1970-01-01
import matplotlib.dates as mdates
print(mdates.num2date(low).date(), "to", mdates.num2date(high).date())
Output:
2026-09-10 to 2026-09-20
Axis range on a log scale
import warnings
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 10, 100, 1000], [1, 50, 2500, 90000])
ax.set_yscale("log")
ax.set_ylim(1, 1e6)
print("log range:", *ax.get_ylim())
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
ax.set_ylim(0, 1e6) # 0 is impossible on a log axis
print("after set_ylim(0, 1e6):", *ax.get_ylim())
print("warning:", caught[0].message)
Output:
log range: 1.0 1000000.0
after set_ylim(0, 1e6): 1.0 1000000.0
warning: Attempt to set non-positive ylim on a log-scaled axis will be ignored.
On a log axis, both limits must be positive; Matplotlib ignores a limit of 0 and warns.
Set the axis range of an imshow() image
By default imshow() uses pixel coordinates. extent=[left, right, bottom, top] maps the image to data coordinates, and set_xlim() / set_ylim() then zoom in on part of it:
import matplotlib.pyplot as plt
import numpy as np
y, x = np.mgrid[0:100, 0:150]
image = np.sin(x / 12) * np.cos(y / 9)
fig, axes = plt.subplots(1, 3, figsize=(12, 3.2))
axes[0].imshow(image)
axes[0].set_title("pixel coordinates")
axes[1].imshow(image, extent=[0, 15, 0, 10]) # data coordinates: x 0-15, y 0-10
axes[1].set_title("extent=[0, 15, 0, 10]")
axes[2].imshow(image, extent=[0, 15, 0, 10])
axes[2].set_xlim(5, 10) # zoom in on part of the image
axes[2].set_ylim(2, 6)
axes[2].set_title("extent + set_xlim/set_ylim (zoom)")
for ax in axes:
print(f"{ax.get_title():36} x:", *ax.get_xlim(), " y:", *ax.get_ylim())
plt.tight_layout()
plt.show()
Output:
pixel coordinates x: -0.5 149.5 y: 99.5 -0.5
extent=[0, 15, 0, 10] x: 0.0 15.0 y: 0.0 10.0
extent + set_xlim/set_ylim (zoom) x: 5.0 10.0 y: 2.0 6.0
extent. Right: extent plus set_xlim(5, 10) and set_ylim(2, 6).Note the y-range of the first image: imshow() draws row 0 at the top, so its y-axis is inverted. See invert the y-axis in Matplotlib for origin="lower".
Set the range of a secondary y-axis
An axis created with twinx() has its own range:
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
revenue = [120, 135, 150, 160, 172, 190] # thousand $
margin = [8.5, 9.1, 9.8, 10.2, 10.1, 11.0] # percent
fig, ax1 = plt.subplots(figsize=(7, 4))
ax1.bar(months, revenue, color="tab:blue", alpha=0.7)
ax1.set_ylabel("Revenue (k$)", color="tab:blue")
ax1.set_ylim(0, 250) # left axis range
ax2 = ax1.twinx() # secondary y-axis
ax2.plot(months, margin, "o-", color="tab:red")
ax2.set_ylabel("Margin (%)", color="tab:red")
ax2.set_ylim(0, 15) # right axis range, independent
print("left:", *ax1.get_ylim(), "| right:", *ax2.get_ylim())
plt.tight_layout()
plt.show()
Output:
left: 0.0 250.0 | right: 0.0 15.0
A secondary_yaxis() is a converted view of the main axis. You don’t set its range; it follows the main axis through the conversion functions:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 1, 2, 3], [0, 20, 30, 40]) # degrees Celsius
ax.set_ylim(0, 50)
fahrenheit = ax.secondary_yaxis("right", functions=(lambda c: c * 9 / 5 + 32, lambda f: (f - 32) * 5 / 9))
fig.canvas.draw()
print("Celsius range: ", *ax.get_ylim())
print("Fahrenheit range:", *[round(v, 1) for v in fahrenheit.get_ylim()])
Output:
Celsius range: 0.0 50.0
Fahrenheit range: 32.0 122.0
Set the axis range in a pandas plot
import matplotlib
matplotlib.use("Agg")
import pandas as pd
df = pd.DataFrame({"temp": [18, 21, 24, 23, 19]}, index=["Mon", "Tue", "Wed", "Thu", "Fri"])
ax = df.plot(ylim=(0, 30)) # pandas passes ylim to Matplotlib
print(*ax.get_ylim())
ax = df.plot()
ax.set_ylim(10, 30) # or set it on the returned Axes
print(*ax.get_ylim())
Output:
0.0 30.0
10.0 30.0
Common mistakes
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 10], [0, 100])
ax.set_ylim(40) # one number = the bottom limit only
print("set_ylim(40): ", *ax.get_ylim())
ax.set_ylim(100, 0) # top first flips the axis
print("set_ylim(100, 0):", *ax.get_ylim(), "inverted:", ax.yaxis_inverted())
fig, ax = plt.subplots()
ax.set_ylim(0, 5) # limits set BEFORE plotting...
ax.plot([0, 10], [0, 100])
print("set before plot:", *ax.get_ylim()) # ...are kept, even if data is outside
Output:
set_ylim(40): 40.0 105.0
set_ylim(100, 0): 100.0 0.0 inverted: True
set before plot: 0.0 5.0
A single number sets only the bottom limit. Passing the larger number first flips the axis. Limits set before plotting stay fixed, so the data can be cut off.
More Matplotlib axis tutorials:
- Matplotlib xlim: set the x-axis range
- Set the axis range in a 3D plot
- Set xlim on a heatmap
- Invert the y-axis in Matplotlib
Frequently asked questions
How do I set the y-axis range in Matplotlib?
plt.ylim(bottom, top) with pyplot, or ax.set_ylim(bottom, top) on an Axes, for example ax.set_ylim(0, 100).
How do I set the x-axis and y-axis range together?
plt.axis([xmin, xmax, ymin, ymax]), or ax.set(xlim=(xmin, xmax), ylim=(ymin, ymax)).
How do I set only the lower limit of an axis?
ax.set_ylim(bottom=0) (or left= for the x-axis). The other limit stays automatic.
How do I get the current axis range?
ax.get_ylim() and ax.get_xlim(), or plt.ylim() / plt.xlim() without arguments.
Why doesn’t my axis range change when I add more data?
Setting limits turns autoscaling off. Call ax.autoscale() to fit the data again, or set the limits after plotting everything.
How do I give all subplots the same y-axis range?
Create them with plt.subplots(..., sharey=True) and call set_ylim() once, or loop over axes.flat.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn