matplotlib/matplotlib · error · TypeError

'markevery' tuple must be pair of ints or of floats

Error message

'markevery' tuple must be pair of ints or of floats

What it means

validate_markevery() runs over the 'markevery' key of axes.prop_cycle (via validate_markeverylist). A tuple markevery must be a pair of exactly two elements and homogeneous: both int (subsample start/stride) or both float (start/stop fraction). A 2-tuple mixing int and float, or any tuple of another length, raises this TypeError.

Source

Thrown at lib/matplotlib/rcsetup.py:596

    Parameters
    ----------
    s : None, int, (int, int), slice, float, (float, float), or list[int]

    Returns
    -------
    None, int, (int, int), slice, float, (float, float), or list[int]
    """
    # Validate s against type slice float int and None
    if isinstance(s, (slice, float, int, type(None))):
        return s
    # Validate s against type tuple
    if isinstance(s, tuple):
        if (len(s) == 2
                and (all(isinstance(e, int) for e in s)
                     or all(isinstance(e, float) for e in s))):
            return s
        else:
            raise TypeError(
                "'markevery' tuple must be pair of ints or of floats")
    # Validate s against type list
    if isinstance(s, list):
        if all(isinstance(e, int) for e in s):
            return s
        else:
            raise TypeError(
                "'markevery' list must have all elements of type int")
    raise TypeError("'markevery' is of an invalid type")


validate_markeverylist = _listify_validator(validate_markevery)


def validate_bbox(s):
    if isinstance(s, str):
        s = s.lower()
        if s == 'tight':

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Use an int pair for index-based subsampling: (0, 10) = every 10th marker starting at index 0
  2. Or a float pair for fractional positions: (0.1, 0.5) = markers between 10%-50% of the line
  3. Normalize mixed pairs before building the cycler: tuple(int(x) for x in pair) or tuple(float(x) for x in pair)

Example fix

# before
from cycler import cycler
import matplotlib.pyplot as plt
plt.rc('axes', prop_cycle=cycler(markevery=[(0, 0.1)]))  # mixed types

# after
plt.rc('axes', prop_cycle=cycler(markevery=[(0.0, 0.1)]))
Defensive patterns

Strategy: type-guard

Validate before calling

def valid_markevery(s):
    if isinstance(s, (slice, float, int, type(None))):
        return True
    if isinstance(s, tuple):
        return (len(s) == 2
                and (all(type(e) is int for e in s)
                     or all(type(e) is float for e in s)))
    if isinstance(s, list):
        return all(type(e) is int for e in s)
    return False

assert valid_markevery((0, 10))
assert not valid_markevery((0, 0.1))

Type guard

def is_markevery_pair(v) -> bool:
    return (isinstance(v, tuple) and len(v) == 2
            and (all(isinstance(e, int) and not isinstance(e, bool) for e in v)
                 or all(isinstance(e, float) for e in v)))

Try / catch

from cycler import cycler
try:
    plt.rc('axes', prop_cycle=cycler(markevery=[me]))
except TypeError as e:
    me = (int(me[0]), int(me[1]))
    plt.rc('axes', prop_cycle=cycler(markevery=[me]))

Prevention

When it happens

Trigger: Building plt.rc('axes', prop_cycle=cycler(markevery=[(0, 10)])) correctly, but [(0, 0.1)], [(0.1, 10)], or [(0, 1, 2)] raise. Note bool counts as int, so (True, 5) slips through.

Common situations: Converting an interval spec from user config into a markevery tuple without normalizing types; mixing a 0-based index with a fraction in one pair after refactoring.

Related errors


AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21). Data as JSON: /api/errors/f359a59177f8b40f. Report an issue: GitHub.