Skip to content

Commit dc81103

Browse files
tacaswellmeeseeksmachine
authored andcommitted
Backport PR #16770: Fix tuple markers
1 parent 15b1cb5 commit dc81103

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

lib/matplotlib/markers.py

+1
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ def _set_tuple_marker(self):
347347
self._joinstyle = 'bevel'
348348
else:
349349
raise ValueError(f"Unexpected tuple marker: {marker}")
350+
self._transform = Affine2D().scale(0.5).rotate_deg(rotation)
350351

351352
def _set_mathtext_path(self):
352353
"""

lib/matplotlib/tests/test_marker.py

+107
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import numpy as np
2+
import matplotlib.pyplot as plt
23
from matplotlib import markers
34
from matplotlib.path import Path
5+
from matplotlib.testing.decorators import check_figures_equal
46

57
import pytest
68

@@ -26,3 +28,108 @@ def test_marker_path():
2628
path = Path([[0, 0], [1, 0]], [Path.MOVETO, Path.LINETO])
2729
# Checking this doesn't fail.
2830
marker_style.set_marker(path)
31+
32+
33+
class UnsnappedMarkerStyle(markers.MarkerStyle):
34+
"""
35+
A MarkerStyle where the snap threshold is force-disabled.
36+
37+
This is used to compare to polygon/star/asterisk markers which do not have
38+
any snap threshold set.
39+
"""
40+
def _recache(self):
41+
super()._recache()
42+
self._snap_threshold = None
43+
44+
45+
@check_figures_equal()
46+
def test_poly_marker(fig_test, fig_ref):
47+
ax_test = fig_test.add_subplot()
48+
ax_ref = fig_ref.add_subplot()
49+
50+
# Note, some reference sizes must be different because they have unit
51+
# *length*, while polygon markers are inscribed in a circle of unit
52+
# *radius*. This introduces a factor of np.sqrt(2), but since size is
53+
# squared, that becomes 2.
54+
size = 20**2
55+
56+
# Squares
57+
ax_test.scatter([0], [0], marker=(4, 0, 45), s=size)
58+
ax_ref.scatter([0], [0], marker='s', s=size/2)
59+
60+
# Diamonds, with and without rotation argument
61+
ax_test.scatter([1], [1], marker=(4, 0), s=size)
62+
ax_ref.scatter([1], [1], marker=UnsnappedMarkerStyle('D'), s=size/2)
63+
ax_test.scatter([1], [1.5], marker=(4, 0, 0), s=size)
64+
ax_ref.scatter([1], [1.5], marker=UnsnappedMarkerStyle('D'), s=size/2)
65+
66+
# Pentagon, with and without rotation argument
67+
ax_test.scatter([2], [2], marker=(5, 0), s=size)
68+
ax_ref.scatter([2], [2], marker=UnsnappedMarkerStyle('p'), s=size)
69+
ax_test.scatter([2], [2.5], marker=(5, 0, 0), s=size)
70+
ax_ref.scatter([2], [2.5], marker=UnsnappedMarkerStyle('p'), s=size)
71+
72+
# Hexagon, with and without rotation argument
73+
ax_test.scatter([3], [3], marker=(6, 0), s=size)
74+
ax_ref.scatter([3], [3], marker='h', s=size)
75+
ax_test.scatter([3], [3.5], marker=(6, 0, 0), s=size)
76+
ax_ref.scatter([3], [3.5], marker='h', s=size)
77+
78+
# Rotated hexagon
79+
ax_test.scatter([4], [4], marker=(6, 0, 30), s=size)
80+
ax_ref.scatter([4], [4], marker='H', s=size)
81+
82+
# Octagons
83+
ax_test.scatter([5], [5], marker=(8, 0, 22.5), s=size)
84+
ax_ref.scatter([5], [5], marker=UnsnappedMarkerStyle('8'), s=size)
85+
86+
ax_test.set(xlim=(-0.5, 5.5), ylim=(-0.5, 5.5))
87+
ax_ref.set(xlim=(-0.5, 5.5), ylim=(-0.5, 5.5))
88+
89+
90+
def test_star_marker():
91+
# We don't really have a strict equivalent to this marker, so we'll just do
92+
# a smoke test.
93+
size = 20**2
94+
95+
fig, ax = plt.subplots()
96+
ax.scatter([0], [0], marker=(5, 1), s=size)
97+
ax.scatter([1], [1], marker=(5, 1, 0), s=size)
98+
ax.set(xlim=(-0.5, 0.5), ylim=(-0.5, 1.5))
99+
100+
101+
# The asterisk marker is really a star with 0-size inner circle, so the ends
102+
# are corners and get a slight bevel. The reference markers are just singular
103+
# lines without corners, so they have no bevel, and we need to add a slight
104+
# tolerance.
105+
@check_figures_equal(tol=1.45)
106+
def test_asterisk_marker(fig_test, fig_ref, request):
107+
ax_test = fig_test.add_subplot()
108+
ax_ref = fig_ref.add_subplot()
109+
110+
# Note, some reference sizes must be different because they have unit
111+
# *length*, while asterisk markers are inscribed in a circle of unit
112+
# *radius*. This introduces a factor of np.sqrt(2), but since size is
113+
# squared, that becomes 2.
114+
size = 20**2
115+
116+
def draw_ref_marker(y, style, size):
117+
# As noted above, every line is doubled. Due to antialiasing, these
118+
# doubled lines make a slight difference in the .png results.
119+
ax_ref.scatter([y], [y], marker=UnsnappedMarkerStyle(style), s=size)
120+
if request.getfixturevalue('ext') == 'png':
121+
ax_ref.scatter([y], [y], marker=UnsnappedMarkerStyle(style),
122+
s=size)
123+
124+
# Plus
125+
ax_test.scatter([0], [0], marker=(4, 2), s=size)
126+
draw_ref_marker(0, '+', size)
127+
ax_test.scatter([0.5], [0.5], marker=(4, 2, 0), s=size)
128+
draw_ref_marker(0.5, '+', size)
129+
130+
# Cross
131+
ax_test.scatter([1], [1], marker=(4, 2, 45), s=size)
132+
draw_ref_marker(1, 'x', size/2)
133+
134+
ax_test.set(xlim=(-0.5, 1.5), ylim=(-0.5, 1.5))
135+
ax_ref.set(xlim=(-0.5, 1.5), ylim=(-0.5, 1.5))

0 commit comments

Comments
 (0)