matplotlib/matplotlib · error · ValueError
'step' must be positive
Error message
'step' must be positive
What it means
_Edge_integer is the internal helper behind MultipleLocator, MaxNLocator and the matplotlib.dates locators that snaps tick positions to integer multiples of a step. Its constructor requires step > 0 because every operation on it divides by the step (divmod-based largest/smallest multiple); zero or negative steps would divide by zero or reverse the tick ladder, so they are rejected immediately.
Source
Thrown at lib/matplotlib/ticker.py:2089
"""
Helper for `.MaxNLocator`, `.MultipleLocator`, etc.
Take floating-point precision limitations into account when calculating
tick locations as integer multiples of a step.
"""
def __init__(self, step, offset):
"""
Parameters
----------
step : float > 0
Interval between ticks.
offset : float
Offset subtracted from the data limits prior to calculating tick
locations.
"""
if step <= 0:
raise ValueError("'step' must be positive")
self.step = step
self._offset = abs(offset)
def closeto(self, ms, edge):
# Allow more slop when the offset is large compared to the step.
if self._offset > 0:
digits = np.log10(self._offset / self.step)
tol = max(1e-10, 10 ** (digits - 12))
tol = min(0.4999, tol)
else:
tol = 1e-10
return abs(ms - edge) < tol
def le(self, x):
"""Return the largest n: n*step <= x."""
d, m = divmod(x, self.step)
if self.closeto(m / self.step, 1):
return d + 1View on GitHub (pinned to b379c1b69e)
Solutions
- Ensure the value passed to MultipleLocator, or the base/interval of a date locator, is a strictly positive number.
- Guard computed spacings: if step <= 0 or not finite, skip installing the locator or clamp to a tiny positive value.
- For date locators use interval=1 (or leave it out) rather than 0.
Example fix
import numpy as np
from matplotlib import ticker
// before
step = (x.max() - x.min()) / 5 # 0 when x is constant
ax.xaxis.set_major_locator(ticker.MultipleLocator(step))
// after
step = (x.max() - x.min()) / 5
if step > 0:
ax.xaxis.set_major_locator(ticker.MultipleLocator(step))
# else: keep the default AutoLocator Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
from matplotlib import ticker
def safe_tick_step(data, n=5):
span = np.ptp(data) if len(data) else 0.0
return span / n if span > 0 else None
step = safe_tick_step(x)
if step:
ax.xaxis.set_major_locator(ticker.MultipleLocator(step)) Prevention
- Compute tick spacing only after validating the data range is positive.
- Treat non-positive or NaN spacings as 'use the default locator' instead of passing them on.
- Validate config-supplied base/interval values for MultipleLocator and date locators.
When it happens
Trigger: ticker.MultipleLocator(0) or MultipleLocator(base=-5); a date locator built with a non-positive base/interval, e.g. matplotlib.dates.DayLocator(interval=0) (dates.py constructs _Edge_integer(base, 0) with it); rarely, a MaxNLocator whose internal staircase step degenerates to 0 with pathological data ranges.
Common situations: Spacing derived from data, e.g. step = (x.max() - x.min()) / n, which becomes 0 for constant or empty data; passing a negative value intending 'step backwards'; treating interval=0 on date locators as 'use default'.
Related errors
- match must be None, a matplotlib.artist.Artist subclass, or
- The set args must be string, value pairs
- secondary_xaxis location must be either a float or "top"/"bo
- secondary_yaxis location must be either a float or "left"/"r
- 'transform' is not allowed as a keyword argument; axhline ge
AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21).
Data as JSON: /api/errors/8371dad1aa9f8b15.
Report an issue: GitHub.