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

Skip to content

Commit ec937be

Browse files
committed
Simplify axisartist line clipping.
axisartist.clip_path is currently used to clip the paths for curvilinear grid lines and compute the angles at which the ticks are drawn. We don't actually need to clip the lines (because we can just set a clipbox on the gridline instead); actually we just need to find the crossings positions and angles, which is much simpler, and now encapsulated in the `_find_line_box_crossings` function. Therefore, deprecate the whole clip_path module. The baseline images change slightly, mostly because we don't clip the path ourselves anymore, but let the renderer do that; also because floating point slop changes for ticks exactly at the edges.
1 parent dbe3622 commit ec937be

File tree

6 files changed

+81
-15
lines changed

6 files changed

+81
-15
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``mpl_toolkits.axisartist.clip_path`` is deprecated
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
... with no replacement.

lib/mpl_toolkits/axisartist/clip_path.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import math
55

66

7+
_api.warn_deprecated("3.5", name=__name__, obj_type="module")
8+
9+
710
def atan2(dy, dx):
811
if dx == 0 and dy == 0:
912
_api.warn_external("dx and dy are 0")

lib/mpl_toolkits/axisartist/grid_finder.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,49 @@
22

33
from matplotlib import _api, ticker as mticker
44
from matplotlib.transforms import Bbox, Transform
5-
from .clip_path import clip_line_to_rect
5+
6+
7+
def _find_line_box_crossings(xys, bbox):
8+
"""
9+
Find the points where a polyline crosses a bbox, and the crossing angles.
10+
11+
Parameters
12+
----------
13+
xys : (N, 2) array
14+
The polyline coordinates.
15+
bbox : `.Bbox`
16+
The bounding box.
17+
18+
Returns
19+
-------
20+
list of ((float, float), float)
21+
Four separate lists of crossings, for the left, right, bottom, and top
22+
sides of the bbox, respectively. For each list, the entries are the
23+
``((x, y), ccw_angle_in_degrees)`` of the crossing, where an angle of 0
24+
means that the polyline is moving to the right at the crossing point.
25+
26+
The entries are computed by linearly interpolating at each crossing
27+
between the nearest points on either side of the bbox edges.
28+
"""
29+
crossings = []
30+
dxys = xys[1:] - xys[:-1]
31+
for sl in [slice(None), slice(None, None, -1)]:
32+
us, vs = xys.T[sl] # "this" coord, "other" coord
33+
dus, dvs = dxys.T[sl]
34+
umin, vmin = bbox.min[sl]
35+
umax, vmax = bbox.max[sl]
36+
for u0, du0s in [(umin, us - umin), (umax, umax - us)]:
37+
crossings.append([])
38+
# du0 > 0 <=> polyline is on the "in" side of the edge.
39+
idxs, = ((du0s[:-1] > 0) ^ (du0s[1:] > 0)).nonzero()
40+
for idx in idxs:
41+
v = vs[idx] + (u0 - us[idx]) * dvs[idx] / dus[idx]
42+
if not vmin <= v <= vmax:
43+
continue
44+
crossing = (u0, v)[sl]
45+
theta = np.degrees(np.arctan2(*dxys[idx][::-1]))
46+
crossings[-1].append((crossing, theta))
47+
return crossings
648

749

850
class ExtremeFinderSimple:
@@ -161,14 +203,12 @@ def _clip_grid_lines_and_find_ticks(self, lines, values, levs, bb):
161203
tck_levels = gi["tick_levels"]
162204
tck_locs = gi["tick_locs"]
163205
for (lx, ly), v, lev in zip(lines, values, levs):
164-
xy, tcks = clip_line_to_rect(lx, ly, bb)
165-
if not xy:
166-
continue
206+
tcks = _find_line_box_crossings(np.column_stack([lx, ly]), bb)
167207
gi["levels"].append(v)
168-
gi["lines"].append(xy)
208+
gi["lines"].append([(lx, ly)])
169209

170210
for tck, direction in zip(tcks,
171-
["left", "bottom", "right", "top"]):
211+
["left", "right", "bottom", "top"]):
172212
for t in tck:
173213
tck_levels[direction].append(lev)
174214
tck_locs[direction].append(t)

lib/mpl_toolkits/tests/test_axisartist_clip_path.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import numpy as np
2+
from matplotlib import _api
23
import matplotlib.pyplot as plt
34
from matplotlib.testing.decorators import image_comparison
45
from matplotlib.transforms import Bbox
56

6-
from mpl_toolkits.axisartist.clip_path import clip_line_to_rect
7+
with _api.suppress_matplotlib_deprecation_warning():
8+
from mpl_toolkits.axisartist.clip_path import clip_line_to_rect
79

810

911
@image_comparison(['clip_path.png'], style='default')

lib/mpl_toolkits/tests/test_axisartist_grid_finder.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
1+
from matplotlib.transforms import Bbox
12
from mpl_toolkits.axisartist.grid_finder import (
2-
FormatterPrettyPrint,
3-
MaxNLocator)
3+
_find_line_box_crossings, FormatterPrettyPrint, MaxNLocator)
4+
5+
import numpy as np
6+
import pytest
7+
8+
9+
def test_find_line_box_crossings():
10+
x = np.array([-3, -2, -1, 0., 1, 2, 3, 2, 1, 0, -1, -2, -3, 5])
11+
y = np.arange(len(x))
12+
bbox = Bbox.from_extents(-2, 3, 2, 12.5)
13+
left, right, bottom, top = _find_line_box_crossings(
14+
np.column_stack([x, y]), bbox)
15+
((lx0, ly0), la0), ((lx1, ly1), la1), = left
16+
((rx0, ry0), ra0), ((rx1, ry1), ra1), = right
17+
((bx0, by0), ba0), = bottom
18+
((tx0, ty0), ta0), = top
19+
assert (lx0, ly0, la0) == (-2, 11, 135)
20+
assert (lx1, ly1, la1) == pytest.approx((-2., 12.125, 7.125016))
21+
assert (rx0, ry0, ra0) == (2, 5, 45)
22+
assert (rx1, ry1, ra1) == (2, 7, 135)
23+
assert (bx0, by0, ba0) == (0, 3, 45)
24+
assert (tx0, ty0, ta0) == pytest.approx((1., 12.5, 7.125016))
425

526

627
def test_pretty_print_format():

lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import numpy as np
2-
import platform
32

43
import matplotlib.pyplot as plt
54
from matplotlib.path import Path
@@ -16,8 +15,7 @@
1615
GridHelperCurveLinear
1716

1817

19-
@image_comparison(['custom_transform.png'], style='default',
20-
tol=0.03 if platform.machine() == 'x86_64' else 0.034)
18+
@image_comparison(['custom_transform.png'], style='default', tol=0.2)
2119
def test_custom_transform():
2220
class MyTransform(Transform):
2321
input_dims = output_dims = 2
@@ -79,8 +77,7 @@ def inverted(self):
7977
ax1.grid(True)
8078

8179

82-
@image_comparison(['polar_box.png'], style='default',
83-
tol={'aarch64': 0.04}.get(platform.machine(), 0.03))
80+
@image_comparison(['polar_box.png'], style='default', tol=0.04)
8481
def test_polar_box():
8582
# Remove this line when this test image is regenerated.
8683
plt.rcParams['text.kerning_factor'] = 6
@@ -143,7 +140,7 @@ def test_polar_box():
143140
ax1.grid(True)
144141

145142

146-
@image_comparison(['axis_direction.png'], style='default', tol=0.03)
143+
@image_comparison(['axis_direction.png'], style='default', tol=0.07)
147144
def test_axis_direction():
148145
# Remove this line when this test image is regenerated.
149146
plt.rcParams['text.kerning_factor'] = 6

0 commit comments

Comments
 (0)