up follow livre
This commit is contained in:
parent
b4b4398bb0
commit
3a7a3849ae
12242 changed files with 2564461 additions and 6914 deletions
269
venv/lib/python3.13/site-packages/matplotlib/inset.py
Normal file
269
venv/lib/python3.13/site-packages/matplotlib/inset.py
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
"""
|
||||
The inset module defines the InsetIndicator class, which draws the rectangle and
|
||||
connectors required for `.Axes.indicate_inset` and `.Axes.indicate_inset_zoom`.
|
||||
"""
|
||||
|
||||
from . import _api, artist, transforms
|
||||
from matplotlib.patches import ConnectionPatch, PathPatch, Rectangle
|
||||
from matplotlib.path import Path
|
||||
|
||||
|
||||
_shared_properties = ('alpha', 'edgecolor', 'linestyle', 'linewidth')
|
||||
|
||||
|
||||
class InsetIndicator(artist.Artist):
|
||||
"""
|
||||
An artist to highlight an area of interest.
|
||||
|
||||
An inset indicator is a rectangle on the plot at the position indicated by
|
||||
*bounds* that optionally has lines that connect the rectangle to an inset
|
||||
Axes (`.Axes.inset_axes`).
|
||||
|
||||
.. versionadded:: 3.10
|
||||
"""
|
||||
zorder = 4.99
|
||||
|
||||
def __init__(self, bounds=None, inset_ax=None, zorder=None, **kwargs):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
bounds : [x0, y0, width, height], optional
|
||||
Lower-left corner of rectangle to be marked, and its width
|
||||
and height. If not set, the bounds will be calculated from the
|
||||
data limits of inset_ax, which must be supplied.
|
||||
|
||||
inset_ax : `~.axes.Axes`, optional
|
||||
An optional inset Axes to draw connecting lines to. Two lines are
|
||||
drawn connecting the indicator box to the inset Axes on corners
|
||||
chosen so as to not overlap with the indicator box.
|
||||
|
||||
zorder : float, default: 4.99
|
||||
Drawing order of the rectangle and connector lines. The default,
|
||||
4.99, is just below the default level of inset Axes.
|
||||
|
||||
**kwargs
|
||||
Other keyword arguments are passed on to the `.Rectangle` patch.
|
||||
"""
|
||||
if bounds is None and inset_ax is None:
|
||||
raise ValueError("At least one of bounds or inset_ax must be supplied")
|
||||
|
||||
self._inset_ax = inset_ax
|
||||
|
||||
if bounds is None:
|
||||
# Work out bounds from inset_ax
|
||||
self._auto_update_bounds = True
|
||||
bounds = self._bounds_from_inset_ax()
|
||||
else:
|
||||
self._auto_update_bounds = False
|
||||
|
||||
x, y, width, height = bounds
|
||||
|
||||
self._rectangle = Rectangle((x, y), width, height, clip_on=False, **kwargs)
|
||||
|
||||
# Connector positions cannot be calculated till the artist has been added
|
||||
# to an axes, so just make an empty list for now.
|
||||
self._connectors = []
|
||||
|
||||
super().__init__()
|
||||
self.set_zorder(zorder)
|
||||
|
||||
# Initial style properties for the artist should match the rectangle.
|
||||
for prop in _shared_properties:
|
||||
setattr(self, f'_{prop}', artist.getp(self._rectangle, prop))
|
||||
|
||||
def _shared_setter(self, prop, val):
|
||||
"""
|
||||
Helper function to set the same style property on the artist and its children.
|
||||
"""
|
||||
setattr(self, f'_{prop}', val)
|
||||
|
||||
artist.setp([self._rectangle, *self._connectors], prop, val)
|
||||
|
||||
def set_alpha(self, alpha):
|
||||
# docstring inherited
|
||||
self._shared_setter('alpha', alpha)
|
||||
|
||||
def set_edgecolor(self, color):
|
||||
"""
|
||||
Set the edge color of the rectangle and the connectors.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
color : :mpltype:`color` or None
|
||||
"""
|
||||
self._shared_setter('edgecolor', color)
|
||||
|
||||
def set_color(self, c):
|
||||
"""
|
||||
Set the edgecolor of the rectangle and the connectors, and the
|
||||
facecolor for the rectangle.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
c : :mpltype:`color`
|
||||
"""
|
||||
self._shared_setter('edgecolor', c)
|
||||
self._shared_setter('facecolor', c)
|
||||
|
||||
def set_linewidth(self, w):
|
||||
"""
|
||||
Set the linewidth in points of the rectangle and the connectors.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
w : float or None
|
||||
"""
|
||||
self._shared_setter('linewidth', w)
|
||||
|
||||
def set_linestyle(self, ls):
|
||||
"""
|
||||
Set the linestyle of the rectangle and the connectors.
|
||||
|
||||
========================================== =================
|
||||
linestyle description
|
||||
========================================== =================
|
||||
``'-'`` or ``'solid'`` solid line
|
||||
``'--'`` or ``'dashed'`` dashed line
|
||||
``'-.'`` or ``'dashdot'`` dash-dotted line
|
||||
``':'`` or ``'dotted'`` dotted line
|
||||
``'none'``, ``'None'``, ``' '``, or ``''`` draw nothing
|
||||
========================================== =================
|
||||
|
||||
Alternatively a dash tuple of the following form can be provided::
|
||||
|
||||
(offset, onoffseq)
|
||||
|
||||
where ``onoffseq`` is an even length tuple of on and off ink in points.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
|
||||
The line style.
|
||||
"""
|
||||
self._shared_setter('linestyle', ls)
|
||||
|
||||
def _bounds_from_inset_ax(self):
|
||||
xlim = self._inset_ax.get_xlim()
|
||||
ylim = self._inset_ax.get_ylim()
|
||||
return (xlim[0], ylim[0], xlim[1] - xlim[0], ylim[1] - ylim[0])
|
||||
|
||||
def _update_connectors(self):
|
||||
(x, y) = self._rectangle.get_xy()
|
||||
width = self._rectangle.get_width()
|
||||
height = self._rectangle.get_height()
|
||||
|
||||
existing_connectors = self._connectors or [None] * 4
|
||||
|
||||
# connect the inset_axes to the rectangle
|
||||
for xy_inset_ax, existing in zip([(0, 0), (0, 1), (1, 0), (1, 1)],
|
||||
existing_connectors):
|
||||
# inset_ax positions are in axes coordinates
|
||||
# The 0, 1 values define the four edges if the inset_ax
|
||||
# lower_left, upper_left, lower_right upper_right.
|
||||
ex, ey = xy_inset_ax
|
||||
if self.axes.xaxis.get_inverted():
|
||||
ex = 1 - ex
|
||||
if self.axes.yaxis.get_inverted():
|
||||
ey = 1 - ey
|
||||
xy_data = x + ex * width, y + ey * height
|
||||
if existing is None:
|
||||
# Create new connection patch with styles inherited from the
|
||||
# parent artist.
|
||||
p = ConnectionPatch(
|
||||
xyA=xy_inset_ax, coordsA=self._inset_ax.transAxes,
|
||||
xyB=xy_data, coordsB=self.axes.transData,
|
||||
arrowstyle="-",
|
||||
edgecolor=self._edgecolor, alpha=self.get_alpha(),
|
||||
linestyle=self._linestyle, linewidth=self._linewidth)
|
||||
self._connectors.append(p)
|
||||
else:
|
||||
# Only update positioning of existing connection patch. We
|
||||
# do not want to override any style settings made by the user.
|
||||
existing.xy1 = xy_inset_ax
|
||||
existing.xy2 = xy_data
|
||||
existing.coords1 = self._inset_ax.transAxes
|
||||
existing.coords2 = self.axes.transData
|
||||
|
||||
if existing is None:
|
||||
# decide which two of the lines to keep visible....
|
||||
pos = self._inset_ax.get_position()
|
||||
bboxins = pos.transformed(self.get_figure(root=False).transSubfigure)
|
||||
rectbbox = transforms.Bbox.from_bounds(x, y, width, height).transformed(
|
||||
self._rectangle.get_transform())
|
||||
x0 = rectbbox.x0 < bboxins.x0
|
||||
x1 = rectbbox.x1 < bboxins.x1
|
||||
y0 = rectbbox.y0 < bboxins.y0
|
||||
y1 = rectbbox.y1 < bboxins.y1
|
||||
self._connectors[0].set_visible(x0 ^ y0)
|
||||
self._connectors[1].set_visible(x0 == y1)
|
||||
self._connectors[2].set_visible(x1 == y0)
|
||||
self._connectors[3].set_visible(x1 ^ y1)
|
||||
|
||||
@property
|
||||
def rectangle(self):
|
||||
"""`.Rectangle`: the indicator frame."""
|
||||
return self._rectangle
|
||||
|
||||
@property
|
||||
def connectors(self):
|
||||
"""
|
||||
4-tuple of `.patches.ConnectionPatch` or None
|
||||
The four connector lines connecting to (lower_left, upper_left,
|
||||
lower_right upper_right) corners of *inset_ax*. Two lines are
|
||||
set with visibility to *False*, but the user can set the
|
||||
visibility to True if the automatic choice is not deemed correct.
|
||||
"""
|
||||
if self._inset_ax is None:
|
||||
return
|
||||
|
||||
if self._auto_update_bounds:
|
||||
self._rectangle.set_bounds(self._bounds_from_inset_ax())
|
||||
self._update_connectors()
|
||||
return tuple(self._connectors)
|
||||
|
||||
def draw(self, renderer):
|
||||
# docstring inherited
|
||||
conn_same_style = []
|
||||
|
||||
# Figure out which connectors have the same style as the box, so should
|
||||
# be drawn as a single path.
|
||||
for conn in self.connectors or []:
|
||||
if conn.get_visible():
|
||||
drawn = False
|
||||
for s in _shared_properties:
|
||||
if artist.getp(self._rectangle, s) != artist.getp(conn, s):
|
||||
# Draw this connector by itself
|
||||
conn.draw(renderer)
|
||||
drawn = True
|
||||
break
|
||||
|
||||
if not drawn:
|
||||
# Connector has same style as box.
|
||||
conn_same_style.append(conn)
|
||||
|
||||
if conn_same_style:
|
||||
# Since at least one connector has the same style as the rectangle, draw
|
||||
# them as a compound path.
|
||||
artists = [self._rectangle] + conn_same_style
|
||||
paths = [a.get_transform().transform_path(a.get_path()) for a in artists]
|
||||
path = Path.make_compound_path(*paths)
|
||||
|
||||
# Create a temporary patch to draw the path.
|
||||
p = PathPatch(path)
|
||||
p.update_from(self._rectangle)
|
||||
p.set_transform(transforms.IdentityTransform())
|
||||
p.draw(renderer)
|
||||
|
||||
return
|
||||
|
||||
# Just draw the rectangle
|
||||
self._rectangle.draw(renderer)
|
||||
|
||||
@_api.deprecated(
|
||||
'3.10',
|
||||
message=('Since Matplotlib 3.10 indicate_inset_[zoom] returns a single '
|
||||
'InsetIndicator artist with a rectangle property and a connectors '
|
||||
'property. From 3.12 it will no longer be possible to unpack the '
|
||||
'return value into two elements.'))
|
||||
def __getitem__(self, key):
|
||||
return [self._rectangle, self.connectors][key]
|
||||
Loading…
Add table
Add a link
Reference in a new issue