matplotlib/matplotlib · error · ValueError

unknown spine spine_type: {self.spine_type!r}

Error message

unknown spine spine_type: {self.spine_type!r}

What it means

Spine.get_spine_transform selects the spine's base transform from spine_type: get_yaxis_transform(which='grid') for 'left'/'right' and get_xaxis_transform(which='grid') for 'top'/'bottom'. No other type has a branch, so a ValueError is raised. set_position() always calls get_spine_transform, and even get_position() triggers it lazily through _ensure_position_is_set, so any position operation on a custom-typed spine raises this error.

Source

Thrown at lib/matplotlib/spines.py:386

        """Return the spine transform."""
        self._ensure_position_is_set()

        position = self._position
        if isinstance(position, str):
            if position == 'center':
                position = ('axes', 0.5)
            elif position == 'zero':
                position = ('data', 0)
        assert len(position) == 2, 'position should be 2-tuple'
        position_type, amount = position
        _api.check_in_list(['axes', 'outward', 'data'],
                           position_type=position_type)
        if self.spine_type in ['left', 'right']:
            base_transform = self.axes.get_yaxis_transform(which='grid')
        elif self.spine_type in ['top', 'bottom']:
            base_transform = self.axes.get_xaxis_transform(which='grid')
        else:
            raise ValueError(f'unknown spine spine_type: {self.spine_type!r}')

        if position_type == 'outward':
            if amount == 0:  # short circuit commonest case
                return base_transform
            else:
                offset_vec = {'left': (-1, 0), 'right': (1, 0),
                              'bottom': (0, -1), 'top': (0, 1),
                              }[self.spine_type]
                # calculate x and y offset in dots
                offset_dots = amount * np.array(offset_vec) / 72
                return (base_transform
                        + mtransforms.ScaledTranslation(
                            *offset_dots, self.get_figure(root=False).dpi_scale_trans))
        elif position_type == 'axes':
            if self.spine_type in ['left', 'right']:
                # keep y unchanged, fix x at amount
                return (mtransforms.Affine2D.from_values(0, 0, 0, 1, amount, 0)
                        + base_transform)

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Guard by spine_type: only call set_position/get_position on 'left', 'right', 'top', 'bottom' spines
  2. Override set_position, get_position, and get_spine_transform together in the Spine subclass (cartopy raises NotImplementedError from set_position)
  3. Register the spine under a standard type if it genuinely should support Cartesian positioning

Example fix

# before
spine = Spine(ax, 'geo', path)
spine.set_position(('outward', 5))  # ValueError: unknown spine spine_type: 'geo'

# after
class GeoSpine(Spine):
    def set_position(self, position):
        raise NotImplementedError('projection spine cannot be repositioned')
    def get_spine_transform(self):
        return self.axes.transAxes
spine = GeoSpine(ax, 'geo', path)
Defensive patterns

Strategy: type-guard

Validate before calling

CARTESIAN = ('left', 'right', 'top', 'bottom')

# guard generic styling loops
for spine in ax.spines.values():
    if getattr(spine, 'spine_type', '') in CARTESIAN:
        spine.set_position(('outward', 5))

Type guard

def can_position_spine(spine) -> bool:
    return getattr(spine, 'spine_type', None) in ('left', 'right', 'top', 'bottom')

Try / catch

try:
    spine.set_position(pos)
except ValueError as err:
    if 'unknown spine spine_type' in str(err):
        pass  # projection/custom spine: positioning not supported, skip
    else:
        raise

Prevention

When it happens

Trigger: spine.set_position(pos) or spine.get_position() on a Spine whose spine_type is a custom name such as 'geo'; generic code that applies the position machinery to every spine including projection spines.

Common situations: Cartopy-style GeoSpine and other projection spines carry custom spine_types; matplotlib core deliberately never calls the position machinery on non-Cartesian spines (see _ensure_transform_is_set), but user styling helpers that do hit this error.

Related errors


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