8000 Fix clipping of markers in PDF backend. · QuLogic/matplotlib@ab0e232 · GitHub
[go: up one dir, main page]

Skip to content

Commit ab0e232

Browse files
committed
Fix clipping of markers in PDF backend.
The bbox only contains the points of the marker, but the line will extend outside by half the line width. This was handled before, except when the line is at an angle to the edge, as the edge is then wider than half a line width. The maximum is at 45°, or √2. This fixes corners on 'v', '^', '<', '>', 'p', 'h', 'H', 'D', 'd', 'X'. Fixes matplotlib#9829.
1 parent 52e04f5 commit ab0e232

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,11 @@ def markerObject(self, path, trans, fill, stroke, lw, joinstyle,
15461546
def writeMarkers(self):
15471547
for ((pathops, fill, stroke, joinstyle, capstyle),
15481548
(name, ob, bbox, lw)) in self.markers.items():
1549-
bbox = bbox.padded(lw * 0.5)
1549+
# bbox wraps the exact limits of the control points, so half a line
1550+
# will appear outside it. If the line is not parallel to the edge,
1551+
# then the line will extend even further to make a corner. The
1552+
# maximum is at 45°, or √2/2, ≈ 0.7071...
1553+
bbox = bbox.padded(lw * 0.71)
15501554
self.beginStream(
15511555
ob.id, None,
15521556
{'Type': Name('XObject'), 'Subtype': Name('Form'),

lib/matplotlib/tests/test_marker.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,44 @@ def draw_ref_marker(y, style, size):
133133

134134
ax_test.set(xlim=(-0.5, 1.5), ylim=(-0.5, 1.5))
135135
ax_ref.set(xlim=(-0.5, 1.5), ylim=(-0.5, 1.5))
136+
137+
138+
@check_figures_equal()
139+
def test_marker_clipping(fig_ref, fig_test):
140+
# Plotting multiple markers can trigger different optimized paths in
141+
# backends, so compare single markers vs multiple to ensure they are
142+
# clipped correctly.
143+
marker_count = len(markers.MarkerStyle.markers)
144+
marker_size = 50
145+
ncol = 7
146+
nrow = marker_count // ncol + 1
147+
148+
width = 2 * marker_size * ncol
149+
height = 2 * marker_size * nrow * 2
150+
fig_ref.set_size_inches((width / fig_ref.dpi, height / fig_ref.dpi))
151+
ax_ref = fig_ref.add_axes([0, 0, 1, 1])
152+
fig_test.set_size_inches((width / fig_test.dpi, height / fig_ref.dpi))
153+
ax_test = fig_test.add_axes([0, 0, 1, 1])
154+
155+
for i, marker in enumerate(markers.MarkerStyle.markers):
156+
x = i % ncol
157+
y = i // ncol * 2
158+
159+
# Singular markers per call.
160+
ax_ref.plot([x, x], [y, y + 1], c='k', linestyle='-', lw=3)
161+
ax_ref.plot(x, y, c='k',
162+
marker=marker, markersize=marker_size, markeredgewidth=10,
163+
fillstyle='full', markerfacecolor='white')
164+
ax_ref.plot(x, y + 1, c='k',
165+
marker=marker, markersize=marker_size, markeredgewidth=10,
166+
fillstyle='full', markerfacecolor='white')
167+
168+
# Multiple markers in a single call.
169+
ax_test.plot([x, x], [y, y + 1], c='k', linestyle='-', lw=3,
170+
marker=marker, markersize=marker_size, markeredgewidth=10,
171+
fillstyle='full', markerfacecolor='white')
172+
173+
ax_ref.set(xlim=(-0.5, ncol), ylim=(-0.5, 2 * nrow))
174+
ax_test.set(xlim=(-0.5, ncol), ylim=(-0.5, 2 * nrow))
175+
ax_ref.axis('off')
176+
ax_test.axis('off')
Binary file not shown.

0 commit comments

Comments
 (0)
0