Thanks to visit codestin.com
Credit goes to github.com

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
16 changes: 16 additions & 0 deletions lib/matplotlib/tests/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -1331,3 +1331,19 @@ def test_draw_text_as_path_fallback(monkeypatch):
_test_complex_shaping(subfig[0])
_test_text_features(subfig[1])
_test_text_language(subfig[2])


def test_annotation_patchA_not_overridden():
# Test that manually setting patchA on annotation arrow is not
# overridden by update_positions. See GitHub issue #28316.
fig, ax = plt.subplots()
ann = ax.annotate(
'',
xy=(0.5, 0.6),
xytext=(0.2, 0.5),
arrowprops=dict(arrowstyle="->")
)
text = ax.text(0.2, 0.5, 'Text', ha='center', va='center')
ann.arrow_patch.set_patchA(text)
fig.draw_without_rendering()
assert ann.arrow_patch.patchA is text
5 changes: 4 additions & 1 deletion lib/matplotlib/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -2199,7 +2199,10 @@ def update_positions(self, renderer):
xy=(bbox.x0 - pad / 2, bbox.y0 - pad / 2),
width=bbox.width + pad, height=bbox.height + pad,
transform=IdentityTransform(), clip_on=False)
self.arrow_patch.set_patchA(patchA)
if self.arrow_patch.patchA is getattr(
self, '_internal_patchA', None):
self.arrow_patch.set_patchA(patchA)
self._internal_patchA = patchA

@artist.allow_rasterization
def draw(self, renderer):
Expand Down
61 changes: 61 additions & 0 deletions lib/matplotlib/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2662,6 +2662,67 @@ def get_matrix(self):
return self._mtx


class IndirectTransform(Transform):
"""
A transform that wraps a callable and resolves it lazily at draw time.

This is useful when the actual transform depends on something not
known until draw time, like another artist's bounding box.

Parameters
----------
func : callable
A callable that takes no arguments and returns a `.Transform`
or `.BboxBase`.

Examples
--------
::

tr = IndirectTransform(
lambda: BboxTransformTo(some_artist.get_window_extent())
)
"""

input_dims = 2
output_dims = 2

def __init__(self, func, **kwargs):
if not callable(func):
raise TypeError(
f"func must be callable, not {type(func).__name__!r}"
)
super().__init__(**kwargs)
self._func = func

def _resolve(self):
"""Call the wrapped function and return a proper Transform."""
result = self._func()
if isinstance(result, BboxBase):
return BboxTransformTo(result)
elif isinstance(result, Transform):
return result
raise TypeError(
f"func must return a Transform or BboxBase, "
f"not {type(result).__name__!r}"
)

def get_affine(self):
return self._resolve().get_affine()

def frozen(self):
return self._resolve().frozen()

def inverted(self):
return self._resolve().inverted()

def transform_affine(self, points):
return self._resolve().transform_affine(points)

def transform_non_affine(self, points):
return self._resolve().transform_non_affine(points)


class BboxTransformFrom(Affine2DBase):
"""
`BboxTransformFrom` linearly transforms points from a given `Bbox` to the
Expand Down
8 changes: 7 additions & 1 deletion lib/matplotlib/transforms.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ from .patches import Patch
from .figure import Figure
import numpy as np
from numpy.typing import ArrayLike
from collections.abc import Iterable, Sequence
from collections.abc import Callable, Iterable, Sequence
from typing import Literal

DEBUG: bool
Expand Down Expand Up @@ -346,3 +346,9 @@ def offset_copy(
class _ScaledRotation(Affine2DBase):
def __init__(self, theta: float, trans_shift: Transform) -> None: ...
def get_matrix(self) -> np.ndarray: ...


class IndirectTransform(Transform):
def __init__(self, func: Callable[..., Transform], **kwargs) -> None: ...
def transform_non_affine(self, points) -> np.ndarray: ...
def transform_affine(self, points) -> np.ndarray: ...
Loading