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

Skip to content

Commit ca664a1

Browse files
marker-transforms
1 parent b42d6d9 commit ca664a1

File tree

3 files changed

+100
-13
lines changed

3 files changed

+100
-13
lines changed

examples/lines_bars_and_markers/scatter_piecharts.py

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
Scatter plot with pie chart markers
44
===================================
55
6-
This example makes custom 'pie charts' as the markers for a scatter plot.
7-
8-
Thanks to Manuel Metz for the example.
6+
This example shows two methods to make custom 'pie charts' as the markers
7+
for a scatter plot.
98
"""
109

10+
##########################################################################
11+
# Manually creating marker vertices
12+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13+
#
14+
1115
import numpy as np
1216
import matplotlib.pyplot as plt
1317

14-
# first define the ratios
18+
# first define the cumulative ratios
1519
r1 = 0.2 # 20%
1620
r2 = r1 + 0.4 # 40%
1721

@@ -36,10 +40,54 @@
3640
s3 = np.abs(xy3).max()
3741

3842
fig, ax = plt.subplots()
39-
ax.scatter(range(3), range(3), marker=xy1, s=s1**2 * sizes, facecolor='blue')
40-
ax.scatter(range(3), range(3), marker=xy2, s=s2**2 * sizes, facecolor='green')
41-
ax.scatter(range(3), range(3), marker=xy3, s=s3**2 * sizes, facecolor='red')
43+
ax.scatter(range(3), range(3), marker=xy1, s=s1**2 * sizes, facecolor='C0')
44+
ax.scatter(range(3), range(3), marker=xy2, s=s2**2 * sizes, facecolor='C1')
45+
ax.scatter(range(3), range(3), marker=xy3, s=s3**2 * sizes, facecolor='C2')
46+
47+
plt.show()
48+
49+
50+
##########################################################################
51+
# Using wedges as markers
52+
# ~~~~~~~~~~~~~~~~~~~~~~~
53+
#
54+
# An alternative is to create custom markers from the `~.path.Path` of a
55+
# `~.patches.Wedge`, which might be more versatile.
56+
#
57+
58+
import numpy as np
59+
import matplotlib.pyplot as plt
60+
from matplotlib.patches import Wedge
61+
from matplotlib.markers import MarkerStyle
62+
63+
# first define the ratios
64+
r1 = 0.2 # 20%
65+
r2 = r1 + 0.3 # 50%
66+
r3 = 1 - r1 - r2 # 30%
67+
68+
def markers_from_ratios(ratios, width=1):
69+
markers = []
70+
angles = 360*np.concatenate(([0], np.cumsum(ratios)))
71+
for i in range(len(angles)-1):
72+
# create a Wedge within the unit square in between the given angles...
73+
w = Wedge((0, 0), 0.5, angles[i], angles[i+1], width=width/2)
74+
# ... and create a custom Marker from its path.
75+
markers.append(MarkerStyle(w.get_path(), normalize_path=False))
76+
return markers
77+
78+
# define some sizes of the scatter marker
79+
sizes = np.array([100, 200, 400, 800])
80+
# collect the markers and some colors
81+
markers = markers_from_ratios([r1, r2, r3], width=0.6)
82+
colors = plt.cm.tab10.colors[:len(markers)]
83+
84+
fig, ax = plt.subplots()
85+
86+
for marker, color in zip(markers, colors):
87+
ax.scatter(range(len(sizes)), range(len(sizes)), marker=marker, s=sizes,
88+
edgecolor="none", facecolor=color)
4289

90+
ax.margins(0.1)
4391
plt.show()
4492

4593
#############################################################################
@@ -55,3 +103,5 @@
55103
import matplotlib
56104
matplotlib.axes.Axes.scatter
57105
matplotlib.pyplot.scatter
106+
matplotlib.patches.Wedge
107+
matplotlib.markers.MarkerStyle

lib/matplotlib/markers.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ class MarkerStyle:
201201
# TODO: Is this ever used as a non-constant?
202202
_point_size_reduction = 0.5
203203

204-
def __init__(self, marker=None, fillstyle=None):
204+
def __init__(self, marker=None, fillstyle=None, normalize_path=True):
205205
"""
206206
Attributes
207207
----------
@@ -213,12 +213,19 @@ def __init__(self, marker=None, fillstyle=None):
213213
214214
Parameters
215215
----------
216-
marker : str or array-like, optional, default: None
216+
marker : str, array-like, `~.path.Path`, or `~.markers.MarkerStyle`,
217+
default: None
217218
See the descriptions of possible markers in the module docstring.
218219
219220
fillstyle : str, optional, default: 'full'
220221
'full', 'left", 'right', 'bottom', 'top', 'none'
222+
223+
normalize_path : bool, default: True
224+
Whether to normalize a custom paths that are provided as array of
225+
vertices or `~.path.Path`. If True, the marker is normalized to the
226+
unit square.
221227
"""
228+
self._normalize = normalize_path
222229
self._marker_function = None
223230
self.set_fillstyle(fillstyle)
224231
self.set_marker(marker)
@@ -302,6 +309,13 @@ def get_path(self):
302309

303310
def get_transform(self):
304311
return self._transform.frozen()
312+
313+
def set_transform(self, transform):
314+
"""
315+
Sets the transform of the marker. This is the transform by which the
316+
marker path is transformed.
317+
"""
318+
self._transform = transform
305319

306320
def get_alt_path(self):
307321
return self._alt_path
@@ -316,8 +330,9 @@ def _set_nothing(self):
316330
self._filled = False
317331

318332
def _set_custom_marker(self, path):
319-
rescale = np.max(np.abs(path.vertices)) # max of x's and y's.
320-
self._transform = Affine2D().scale(0.5 / rescale)
333+
if self._normalize:
334+
rescale = np.max(np.abs(path.vertices)) # max of x's and y's.
335+
self._transform = Affine2D().scale(0.5 / rescale)
321336
self._path = path
322337

323338
def _set_path_marker(self):
@@ -349,8 +364,6 @@ def _set_tuple_marker(self):
349364
def _set_mathtext_path(self):
350365
"""
351366
Draws mathtext markers '$...$' using TextPath object.
352-
353-
Submitted by tcb
354367
"""
355368
from matplotlib.text import TextPath
356369

lib/matplotlib/tests/test_marker.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import numpy as np
22
from matplotlib import markers
33
from matplotlib.path import Path
4+
from matplotlib.transforms import Affine2D
5+
import matplotlib.pyplot as plt
46

7+
from matplotlib.testing.decorators import check_figures_equal
58
import pytest
69

710

@@ -26,3 +29,24 @@ def test_marker_path():
2629
path = Path([[0, 0], [1, 0]], [Path.MOVETO, Path.LINETO])
2730
# Checking this doesn't fail.
2831
marker_style.set_marker(path)
32+
33+
34+
@check_figures_equal(extensions=["png"])
35+
def test_marker_normalization(fig_test, fig_ref):
36+
plt.style.use("mpl20")
37+
38+
ax = fig_ref.subplots()
39+
ax.margins(0.3)
40+
ax.scatter([0, 1], [0, 0], s=400, marker="s", c="C2")
41+
42+
ax = fig_test.subplots()
43+
ax.margins(0.3)
44+
# test normalize
45+
p = Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]], closed=True)
46+
p1 = p.transformed(Affine2D().translate(-.5, -.5).scale(20))
47+
m1 = markers.MarkerStyle(p1, normalize_path=False)
48+
ax.scatter([0], [0], s=1, marker=m1, c="C2")
49+
# test transform
50+
m2 = markers.MarkerStyle("s")
51+
m2.set_transform(m2.get_transform() + Affine2D().scale(20))
52+
ax.scatter([1], [0], s=1, marker=m2, c="C2")

0 commit comments

Comments
 (0)