diff --git a/doc/missing-references.json b/doc/missing-references.json index 52ffa65805b1..bc95ad1880c2 100644 --- a/doc/missing-references.json +++ b/doc/missing-references.json @@ -367,6 +367,7 @@ "matplotlib.patches.BoxStyle._Base": [ "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle.Circle:1", "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle.DArrow:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle.Ellipse:1", "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle.LArrow:1", "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle.Round4:1", "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle.Round:1", diff --git a/doc/users/next_whats_new/ellipse_annotation.rst b/doc/users/next_whats_new/ellipse_annotation.rst new file mode 100644 index 000000000000..d6a989e77a5b --- /dev/null +++ b/doc/users/next_whats_new/ellipse_annotation.rst @@ -0,0 +1,15 @@ +``ellipse`` boxstyle option for annotations +------------------------------------------- + +The ``'ellipse'`` option for boxstyle can now be used to create annotations +with an elliptical outline. It can be used as a closed curve shape for +longer texts instead of the ``'circle'`` boxstyle which can get quite big. + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + fig, ax = plt.subplots(figsize=(5, 5)) + t = ax.text(0.5, 0.5, "elliptical box", + ha="center", size=15, + bbox=dict(boxstyle="ellipse,pad=0.3")) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index f127ab20a97b..7b0314bcbfe9 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -9,6 +9,7 @@ import textwrap from types import SimpleNamespace from collections import namedtuple +from matplotlib.transforms import Affine2D import numpy as np @@ -2337,7 +2338,35 @@ def __call__(self, x0, y0, width, height, mutation_size): # boundary of the padded box x0, y0 = x0 - pad, y0 - pad return Path.circle((x0 + width / 2, y0 + height / 2), - max(width, height) / 2) + max(width, height) / 2) + + @_register_style(_style_list) + class Ellipse: + """ + An elliptical box. + + .. versionadded:: 3.7 + """ + + def __init__(self, pad=0.3): + """ + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + """ + self.pad = pad + + def __call__(self, x0, y0, width, height, mutation_size): + pad = mutation_size * self.pad + width, height = width + 2 * pad, height + 2 * pad + # boundary of the padded box + x0, y0 = x0 - pad, y0 - pad + a = width / math.sqrt(2) + b = height / math.sqrt(2) + trans = Affine2D().scale(a, b).translate(x0 + width / 2, + y0 + height / 2) + return trans.transform_path(Path.unit_circle()) @_register_style(_style_list) class LArrow: diff --git a/lib/matplotlib/tests/baseline_images/test_arrow_patches/boxarrow_test_image.png b/lib/matplotlib/tests/baseline_images/test_arrow_patches/boxarrow_test_image.png index 9e613ff40ca9..11ad0b89b4db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_arrow_patches/boxarrow_test_image.png and b/lib/matplotlib/tests/baseline_images/test_arrow_patches/boxarrow_test_image.png differ diff --git a/tutorials/text/annotations.py b/tutorials/text/annotations.py index 6029d1180d08..4889f63d7465 100644 --- a/tutorials/text/annotations.py +++ b/tutorials/text/annotations.py @@ -193,6 +193,7 @@ # ========== ============== ========================== # Circle ``circle`` pad=0.3 # DArrow ``darrow`` pad=0.3 +# Ellipse ``ellipse`` pad=0.3 # LArrow ``larrow`` pad=0.3 # RArrow ``rarrow`` pad=0.3 # Round ``round`` pad=0.3,rounding_size=None