matplotlib/matplotlib · error · ValueError

position[0] should be one of 'outward', 'axes', or 'data'

Error message

position[0] should be one of 'outward', 'axes', or 'data' 

What it means

After checking the tuple length, Spine.set_position requires position[0] to be one of 'outward', 'axes', 'data'. This second ValueError fires when the first element is misspelled or wrongly cased ('Data', 'axis'), or when the tuple order is swapped, e.g. (0, 'data').

Source

Thrown at lib/matplotlib/spines.py:354

        * 'axes': place the spine at the specified Axes coordinate (0 to 1).
        * 'data': place the spine at the specified data coordinate.

        Additionally, shorthand notations define a special positions:

        * 'center' -> ``('axes', 0.5)``
        * 'zero' -> ``('data', 0.0)``

        Examples
        --------
        :doc:`/gallery/spines/spine_placement_demo`
        """
        if position in ('center', 'zero'):  # special positions
            pass
        else:
            if len(position) != 2:
                raise ValueError("position should be 'center' or 2-tuple")
            if position[0] not in ['outward', 'axes', 'data']:
                raise ValueError("position[0] should be one of 'outward', "
                                 "'axes', or 'data' ")
        self._position = position
        self.set_transform(self.get_spine_transform())
        if self.axis is not None:
            self.axis.reset_ticks()
        self.stale = True

    def get_position(self):
        """Return the spine position."""
        self._ensure_position_is_set()
        return self._position

    def get_spine_transform(self):
        """Return the spine transform."""
        self._ensure_position_is_set()

        position = self._position
        if isinstance(position, str):

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Use exactly 'outward', 'axes', or 'data' as the first element and the numeric amount as the second
  2. Validate the first element against the allowed set before calling set_position
  3. Prefer the 'center'/'zero' shorthands when applicable, which bypass this check

Example fix

# before
ax.spines['bottom'].set_position(('Data', 0))  # wrong case
ax.spines['bottom'].set_position((0, 'data'))   # swapped order

# after
ax.spines['bottom'].set_position(('data', 0))
Defensive patterns

Strategy: type-guard

Validate before calling

POSITION_TYPES = {'outward', 'axes', 'data'}

if isinstance(pos, tuple) and len(pos) == 2:
    pos = (pos[0].lower() if isinstance(pos[0], str) else pos[0], pos[1])
assert pos[0] in POSITION_TYPES, f'bad position type: {pos[0]!r}'

Type guard

def has_valid_position_type(pos) -> bool:
    return isinstance(pos, tuple) and len(pos) == 2 and pos[0] in ('outward', 'axes', 'data')

Prevention

When it happens

Trigger: set_position(('Data', 0)); set_position((0.5, 'axes')); set_position(('outwards', 5)).

Common situations: Case typos in hand-written theme dicts; tuples built by unpacking in the wrong order; position vocabularies ported from plotting libraries that use different type names.

Related errors


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