Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ci/mypy-stubtest-allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ matplotlib\.animation\.EventSourceProtocol
# Avoid a regression in NewType handling for stubtest
# https://github.com/python/mypy/issues/19877
matplotlib\.ft2font\.GlyphIndexType\.__init__

# 3.12 deprecation
matplotlib\.axes\._base\._AxesBase\.ArtistList
10 changes: 10 additions & 0 deletions doc/api/artist_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,14 @@ Functions
getp
setp
kwdoc

Helper classes
==============

.. autosummary::
:template: autosummary.rst
:toctree: _as_gen
:nosignatures:

ArtistInspector
ArtistList
12 changes: 12 additions & 0 deletions doc/api/axes__base_api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
*************************
``matplotlib.axes._base``
*************************

.. This is a stub which is only included to make inheritance links work. It
deliberately does not include any docstrings, so the class-doc-from directive
specifies a non-existent docstring.

.. autoclass:: matplotlib.axes._base._AxesBase
:no-members:
:class-doc-from: class
:show-inheritance:
2 changes: 0 additions & 2 deletions doc/api/axes_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -632,5 +632,3 @@ Other
Axes.get_figure
Axes.figure
Axes.remove

.. autoclass:: matplotlib.axes.Axes.ArtistList
4 changes: 4 additions & 0 deletions doc/api/image_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@
:members:
:undoc-members:
:show-inheritance:

.. autoclass:: _ImageBase
:class-doc-from: class
:show-inheritance:
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ Alphabetical list of modules:
_type1font.rst
_tight_bbox_api.rst
_tight_layout_api.rst
axes__base_api.rst
toolkits/mplot3d.rst
toolkits/axes_grid1.rst
toolkits/axisartist.rst
Expand Down
3 changes: 3 additions & 0 deletions doc/api/next_api_changes/deprecations/31794-REC.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The ``Axes.AxesList`` attribute
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
... is deprecated. Use `.artist.ArtistList` instead.
3 changes: 3 additions & 0 deletions doc/api/text_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
:undoc-members:
:show-inheritance:

.. autoclass:: matplotlib.text._AnnotationBase
:class-doc-from: class

.. autoclass:: matplotlib.text.Annotation
:members:
:undoc-members:
Expand Down
12 changes: 6 additions & 6 deletions galleries/tutorials/artists.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,13 +562,13 @@ class in the Matplotlib API, and the one you will be working with most
# ============== =========================================
# Axes attribute Description
# ============== =========================================
# artists An `.ArtistList` of `.Artist` instances
# artists An `~.artist.ArtistList` of `.Artist` instances
# patch `.Rectangle` instance for Axes background
# collections An `.ArtistList` of `.Collection` instances
# images An `.ArtistList` of `.AxesImage`
# lines An `.ArtistList` of `.Line2D` instances
# patches An `.ArtistList` of `.Patch` instances
# texts An `.ArtistList` of `.Text` instances
# collections An `~.artist.ArtistList` of `.Collection` instances
# images An `~.artist.ArtistList` of `.AxesImage`
# lines An `~.artist.ArtistList` of `.Line2D` instances
# patches An `~.artist.ArtistList` of `.Patch` instances
# texts An `~.artist.ArtistList` of `.Text` instances
# xaxis A `matplotlib.axis.XAxis` instance
# yaxis A `matplotlib.axis.YAxis` instance
# ============== =========================================
Expand Down
70 changes: 70 additions & 0 deletions lib/matplotlib/artist.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import namedtuple
from collections.abc import Sequence
import contextlib
from functools import cache, reduce, wraps
import inspect
Expand Down Expand Up @@ -1789,6 +1790,75 @@ def pprint_getters(self):
return lines


class ArtistList(Sequence):
"""
A sublist of Axes children based on their type.

The type-specific children sublists were made immutable in Matplotlib
3.7. In the future these artist lists may be replaced by tuples. Use
as if this is a tuple already.
"""
def __init__(self, axes, prop_name, valid_types=None, invalid_types=None):
"""
Parameters
----------
axes : `~matplotlib.axes.Axes`
The Axes from which this sublist will pull the children
Artists.
prop_name : str
The property name used to access this sublist from the Axes;
used to generate deprecation warnings.
valid_types : list of type, optional
A list of types that determine which children will be returned
by this sublist. If specified, then the Artists in the sublist
must be instances of any of these types. If unspecified, then
any type of Artist is valid (unless limited by
*invalid_types*.)
invalid_types : tuple, optional
A list of types that determine which children will *not* be
returned by this sublist. If specified, then Artists in the
sublist will never be an instance of these types. Otherwise, no
types will be excluded.
"""
self._axes = axes
self._prop_name = prop_name
self._type_check = lambda artist: (
(not valid_types or isinstance(artist, valid_types)) and
(not invalid_types or not isinstance(artist, invalid_types))
)

def __repr__(self):
return f'<Axes.ArtistList of {len(self)} {self._prop_name}>'

def __len__(self):
return sum(self._type_check(artist)
for artist in self._axes._children)

def __iter__(self):
for artist in list(self._axes._children):
if self._type_check(artist):
yield artist

def __getitem__(self, key):
return [artist
for artist in self._axes._children
if self._type_check(artist)][key]

def __add__(self, other):
if isinstance(other, (list, ArtistList)):
return [*self, *other]
if isinstance(other, (tuple, ArtistList)):
return (*self, *other)
return NotImplemented

def __radd__(self, other):
if isinstance(other, list):
return other + list(self)
if isinstance(other, tuple):
return other + tuple(self)
return NotImplemented


def getp(obj, property=None):
"""
Return the value of an `.Artist`'s *property*, or print all of them.
Expand Down
32 changes: 31 additions & 1 deletion lib/matplotlib/artist.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ from .transforms import (

import numpy as np

from collections.abc import Callable, Iterable
from collections.abc import Callable, Iterable, Iterator, Sequence
from typing import Any, Literal, NamedTuple, TextIO, overload, TypeVar
from numpy.typing import ArrayLike

Expand Down Expand Up @@ -189,6 +189,36 @@ class ArtistInspector:
def properties(self) -> dict[str, Any]: ...
def pprint_getters(self) -> list[str]: ...


class ArtistList(Sequence[_T_Artist]):
def __init__(
self,
axes: _AxesBase,
prop_name: str,
valid_types: type | Iterable[type] | None = ...,
invalid_types: type | Iterable[type] | None = ...,
) -> None: ...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[_T_Artist]: ...
@overload
def __getitem__(self, key: int) -> _T_Artist: ...
@overload
def __getitem__(self, key: slice) -> list[_T_Artist]: ...

@overload
def __add__(self, other: ArtistList[_T_Artist]) -> list[_T_Artist]: ...
@overload
def __add__(self, other: list[Any]) -> list[Any]: ...
@overload
def __add__(self, other: tuple[Any]) -> tuple[Any]: ...

@overload
def __radd__(self, other: ArtistList[_T_Artist]) -> list[_T_Artist]: ...
@overload
def __radd__(self, other: list[Any]) -> list[Any]: ...
@overload
def __radd__(self, other: tuple[Any]) -> tuple[Any]: ...

def getp(obj: Artist, property: str | None = ...) -> Any: ...

get = getp
Expand Down
89 changes: 12 additions & 77 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from collections.abc import Iterable, Sequence
from collections.abc import Iterable
from contextlib import ExitStack
import functools
import inspect
Expand Down Expand Up @@ -1481,105 +1481,40 @@ def cla(self):
else:
self.clear()

class ArtistList(Sequence):
"""
A sublist of Axes children based on their type.

The type-specific children sublists were made immutable in Matplotlib
3.7. In the future these artist lists may be replaced by tuples. Use
as if this is a tuple already.
"""
def __init__(self, axes, prop_name,
valid_types=None, invalid_types=None):
"""
Parameters
----------
axes : `~matplotlib.axes.Axes`
The Axes from which this sublist will pull the children
Artists.
prop_name : str
The property name used to access this sublist from the Axes;
used to generate deprecation warnings.
valid_types : list of type, optional
A list of types that determine which children will be returned
by this sublist. If specified, then the Artists in the sublist
must be instances of any of these types. If unspecified, then
any type of Artist is valid (unless limited by
*invalid_types*.)
invalid_types : tuple, optional
A list of types that determine which children will *not* be
returned by this sublist. If specified, then Artists in the
sublist will never be an instance of these types. Otherwise, no
types will be excluded.
"""
self._axes = axes
self._prop_name = prop_name
self._type_check = lambda artist: (
(not valid_types or isinstance(artist, valid_types)) and
(not invalid_types or not isinstance(artist, invalid_types))
)

def __repr__(self):
return f'<Axes.ArtistList of {len(self)} {self._prop_name}>'

def __len__(self):
return sum(self._type_check(artist)
for artist in self._axes._children)

def __iter__(self):
for artist in list(self._axes._children):
if self._type_check(artist):
yield artist

def __getitem__(self, key):
return [artist
for artist in self._axes._children
if self._type_check(artist)][key]

def __add__(self, other):
if isinstance(other, (list, _AxesBase.ArtistList)):
return [*self, *other]
if isinstance(other, (tuple, _AxesBase.ArtistList)):
return (*self, *other)
return NotImplemented

def __radd__(self, other):
if isinstance(other, list):
return other + list(self)
if isinstance(other, tuple):
return other + tuple(self)
return NotImplemented
@_api.deprecated('3.12', alternative='matplotlib.artist.ArtistList')
@property
def ArtistList(self):
return martist.ArtistList

@property
def artists(self):
return self.ArtistList(self, 'artists', invalid_types=(
return martist.ArtistList(self, 'artists', invalid_types=(
mcoll.Collection, mimage.AxesImage, mlines.Line2D, mpatches.Patch,
mtable.Table, mtext.Text))

@property
def collections(self):
return self.ArtistList(self, 'collections',
valid_types=mcoll.Collection)
return martist.ArtistList(self, 'collections', valid_types=mcoll.Collection)

@property
def images(self):
return self.ArtistList(self, 'images', valid_types=mimage.AxesImage)
return martist.ArtistList(self, 'images', valid_types=mimage.AxesImage)

@property
def lines(self):
return self.ArtistList(self, 'lines', valid_types=mlines.Line2D)
return martist.ArtistList(self, 'lines', valid_types=mlines.Line2D)

@property
def patches(self):
return self.ArtistList(self, 'patches', valid_types=mpatches.Patch)
return martist.ArtistList(self, 'patches', valid_types=mpatches.Patch)

@property
def tables(self):
return self.ArtistList(self, 'tables', valid_types=mtable.Table)
return martist.ArtistList(self, 'tables', valid_types=mtable.Table)

@property
def texts(self):
return self.ArtistList(self, 'texts', valid_types=mtext.Text)
return martist.ArtistList(self, 'texts', valid_types=mtext.Text)

def get_facecolor(self):
"""Get the facecolor of the Axes."""
Expand Down
Loading
Loading