FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Addresses issue #24618 "Road sign" boxstyle/annotation, alternative to #24697 by Abitamim · Pull Request #24744 · matplotlib/matplotlib · GitHub

Repository navigation

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .png  (1) .py  (3) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
92 changes: 84 additions & 8 deletions lib/matplotlib/patches.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2372,14 +2372,35 @@ def __call__(self, x0, y0, width, height, mutation_size):
class LArrow:
"""A box in the shape of a left-pointing arrow."""

def __init__(self, pad=0.3):
def __init__(self, pad=0.3, head_width=1.5, head_angle=90.0):
"""
Parameters
----------
pad : float, default: 0.3
The amount of padding around the original box.
head_width : float, default: 1.5
The width of the arrow head versus the body. The minimum value
is 0.0 and the maximum value is 10.0. Any value smaller or
greater than this is contrained to the edge values.
head_angle : float, default: 90.0
The inside angle of the tip of the arrow. The minimum value is
10.0 and the maximum value is 179.0. Any value smaller or
greater than this is contrained to the edge values.
"""
self.pad = pad
if head_width > 10:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This can be done as self.head_width = np.clip(head_width, 0, 10)

self.head_width = 10
elif head_width < 0:
self.head_width = 0
else:
self.head_width = head_width

if head_angle >= 180:
self.head_angle = 179
elif head_angle < 10:
self.head_angle = 10
else:
self.head_angle = head_angle

def __call__(self, x0, y0, width, height, mutation_size):
# padding
Expand All @@ -2394,10 +2415,26 @@ def __call__(self, x0, y0, width, height, mutation_size):
dxx = dx / 2
x0 = x0 + pad / 1.4 # adjust by ~sqrt(2)

# The width adjustment is the value that must be added or
# subtracted from y_0 and y_1 for the ends of the head.
# The body width is 2dx.
# Subtracting 1 from the head_width gives what percentage of the
# body width is in the head, and there is .5x of that on each side.
# The .5 cancels out the 2dx for the body width.
width_adjustment = (self.head_width - 1) * dx

# The angle adjustment is the value that must be subtracted/added
# from x_0 or x_1 for the position of the tip.
# each half of the arrow head is a right angle triangle. Therefore,
# each half of the arrow head has the equation tan(head_angle/2)=
# (dx+width_adjustment)/(dxx+angle_adjustment).
angle_adjustment = ((dx + width_adjustment) / math.tan((self.
head_angle/2) * (math.pi/180))) - dxx

return Path._create_closed(
[(x0 + dxx, y0), (x1, y0), (x1, y1), (x0 + dxx, y1),
(x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx),
(x0 + dxx, y0 - dxx), # arrow
(x0 + dxx, y1 + width_adjustment), (x0 - angle_adjustment, y0
+ dx), (x0 + dxx, y0 - width_adjustment), # arrow
(x0 + dxx, y0)])

@_register_style(_style_list)
Expand All @@ -2415,14 +2452,35 @@ class DArrow:
"""A box in the shape of a two-way arrow."""
# Modified from LArrow to add a right arrow to the bbox.

def __init__(self, pad=0.3):
def __init__(self, pad=0.3, head_width=1.5, head_angle=90.0):
"""
Parameters
----------
pad : float, default: 0.3
The amount of padding around the original box.
head_width : float, default: 1.5
The width of the arrow head versus the body. The minimum value
is 0.0 and the maximum value is 10.0. Any value smaller or
greater than this is contrained to the edge values.
head_angle : float, default: 90.0
The inside angle of the tip of the arrow. The minimum value is
10.0 and the maximum value is 179.0. Any value smaller or
greater than this is contrained to the edge values.
"""
self.pad = pad
if head_width > 10:
self.head_width = 10
elif head_width < 0:
self.head_width = 0
else:
self.head_width = head_width

if head_angle >= 180:
self.head_angle = 179
elif head_angle < 10:
self.head_angle = 10
else:
self.head_angle = head_angle

def __call__(self, x0, y0, width, height, mutation_size):
# padding
Expand All @@ -2438,13 +2496,31 @@ def __call__(self, x0, y0, width, height, mutation_size):
dxx = dx / 2
x0 = x0 + pad / 1.4 # adjust by ~sqrt(2)

# The width adjustment is the value that must be added or
# subtracted from y_0 and y_1 for the ends of the head.
# The body width is 2dx.
# Subtracting 1 from the head_width gives what percentage of the
# body width is in the head, and there is .5x of that on each side.
# The .5 cancels out the 2dx for the body width.
width_adjustment = (self.head_width - 1) * dx

# The angle adjustment is the value that must be subtracted/added
# from x_0 or x_1 for the position of the tip.
# each half of the arrow head is a right angle triangle. Therefore,
# each half of the arrow head has the equation tan(head_angle/2)=
# (dx+width_adjustment)/(dxx+angle_adjustment).
angle_adjustment = ((dx + width_adjustment) / math.tan((self.
head_angle/2) * (math.pi/180))) - dxx

return Path._create_closed([
(x0 + dxx, y0), (x1, y0), # bot-segment
(x1, y0 - dxx), (x1 + dx + dxx, y0 + dx),
(x1, y1 + dxx), # right-arrow
(x1, y0 - width_adjustment),
(x1 + angle_adjustment + dxx, y0 + dx),
(x1, y1 + width_adjustment), # right-arrow
(x1, y1), (x0 + dxx, y1), # top-segment
(x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx),
(x0 + dxx, y0 - dxx), # left-arrow
(x0 + dxx, y1 + width_adjustment),
(x0 - angle_adjustment, y0 + dx),
(x0 + dxx, y0 - width_adjustment), # left-arrow
(x0 + dxx, y0)])

@_register_style(_style_list)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Viewer requires iframe.
23 changes: 23 additions & 0 deletions lib/matplotlib/tests/test_arrow_patches.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,29 @@ def test_boxarrow():
bbox=dict(boxstyle=stylename, fc="w", ec="k"))


@image_comparison(['roadsign_test_image.png'])
def temp_test_boxarrow():

styles = mpatches.BoxStyle.get_styles()

n = len(styles)
spacing = 1.2

figheight = (n * spacing + .5)
fig = plt.figure(figsize=(4 / 1.5, figheight / 1.5))

fontsize = 0.3 * 72

for i, stylename in enumerate(sorted(styles)):
if stylename in ("larrow", "rarrow", "darrow"):
fig.text(0.5, ((n - i) * spacing - 0.5)/figheight, stylename,
ha="center",
size=fontsize,
transform=fig.transFigure,
bbox=dict(boxstyle=stylename+",head_width=1", fc="w",
ec="k"))


def __prepare_fancyarrow_dpi_cor_test():
"""
Convenience function that prepares and returns a FancyArrowPatch. It aims
Expand Down
10 changes: 5 additions & 5 deletions tutorials/text/annotations.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@
# Class Name Attrs
# ========== ============== ==========================
# Circle ``circle`` pad=0.3
# DArrow ``darrow`` pad=0.3
# DArrow ``darrow`` pad=0.3,head_width=1.5,head_angle=90
# Ellipse ``ellipse`` pad=0.3
# LArrow ``larrow`` pad=0.3
# RArrow ``rarrow`` pad=0.3
# LArrow ``larrow`` pad=0.3,head_width=1.5,head_angle=90
# RArrow ``rarrow`` pad=0.3,head_width=1.5,head_angle=90
# Round ``round`` pad=0.3,rounding_size=None
# Round4 ``round4`` pad=0.3,rounding_size=None
# Roundtooth ``roundtooth`` pad=0.3,tooth_size=None
Expand Down Expand Up @@ -254,8 +254,8 @@ def custom_box_style(x0, y0, width, height, mutation_size):
x0, y0 = x0 - pad, y0 - pad
x1, y1 = x0 + width, y0 + height
# return the new path
return Path([(x0, y0), (x1, y0), (x1, y1), (x0, y1),
(x0-pad, (y0+y1)/2), (x0, y0), (x0, y0)],
return Path([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y1-pad),
(x0-pad, (y0+y1)/2), (x0, y0+pad), (x0, y0), (x0, y0)],
closed=True)

fig, ax = plt.subplots(figsize=(3, 3))
Expand Down

Back | FazBrowse Home | New Git URL