Skip to content

19195 rotated markers #20914

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e487b1c
Add user supplied transforms and join/cap styles
deep-jkl Jul 23, 2021
37859ea
Avoid reinstanting MarkerStyle in lines.py
deep-jkl Aug 26, 2021
8153632
Update dosctring.
deep-jkl Sep 5, 2021
4469006
Add marker.transformed + test
deep-jkl Sep 6, 2021
4ea2b91
Add affine transform primitives to markers
deep-jkl Sep 10, 2021
7f6d1be
Tweaking docstrings in MarkerStyle.
deep-jkl Sep 11, 2021
2729fe4
Update MarkerStyle module documentation
deep-jkl Sep 12, 2021
4357995
Update marker Reference documentation
deep-jkl Sep 12, 2021
b1bbdff
Add whats new for MarkerStyle features
deep-jkl Sep 12, 2021
9ac3ad2
Add new example with advanced MarkerStyle mapping
deep-jkl Sep 12, 2021
4180843
Fix errors discovered by CI
deep-jkl Sep 12, 2021
905eba4
Fix typo in markers api documentation.
deep-jkl Sep 13, 2021
3fc6140
Improve test for invalid rotated inputs
deep-jkl Sep 14, 2021
04a3e70
Add tests for MarkerStyle scaled and translated
deep-jkl Sep 14, 2021
af6b89a
Add function for optimized None+transform
deep-jkl Sep 15, 2021
c01e8f1
Remove ambiguous translated primitive for MarkerStyle
deep-jkl Sep 15, 2021
95d93d2
Add missing test for MarkerStyle.get_alt_transform
deep-jkl Sep 15, 2021
75a92d8
Improve documentation outputs.
deep-jkl Sep 16, 2021
e4f8456
Update docstrings according to jklymak
deep-jkl Sep 28, 2021
5aa5bbd
Make MarkerStyle.rotated more concise
deep-jkl Sep 28, 2021
214ea3f
Refactor code, linting.
deep-jkl Sep 28, 2021
7101e3c
Rework get_cap(join)style, add tests
deep-jkl Sep 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions doc/users/next_whats_new/extending_MarkerStyle.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
New customization of MarkerStyle
--------------------------------

New MarkerStyle parameters allow control of join style and cap style, and for
the user to supply a transformation to be applied to the marker (e.g. a rotation).

.. plot::
:include-source: true

import matplotlib.pyplot as plt
from matplotlib.markers import MarkerStyle
from matplotlib.transforms import Affine2D
fig, ax = plt.subplots(figsize=(6, 1))
fig.suptitle('New markers', fontsize=14)
for col, (size, rot) in enumerate(zip([2, 5, 10], [0, 45, 90])):
t = Affine2D().rotate_deg(rot).scale(size)
ax.plot(col, 0, marker=MarkerStyle("*", transform=t))
ax.axis("off")
ax.set_xlim(-0.1, 2.4)
95 changes: 95 additions & 0 deletions examples/lines_bars_and_markers/marker_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
.. redirect-from:: /gallery/shapes_and_collections/marker_path
"""

from matplotlib.markers import MarkerStyle
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.transforms import Affine2D


text_style = dict(horizontalalignment='right', verticalalignment='center',
Expand Down Expand Up @@ -159,3 +161,96 @@ def split_list(a_list):
format_axes(ax)

plt.show()

###############################################################################
# Advanced marker modifications with transform
# ============================================
#
# Markers can be modified by passing a transform to the MarkerStyle
# constructor. Following example shows how a supplied rotation is applied to
# several marker shapes.

common_style = {k: v for k, v in filled_marker_style.items() if k != 'marker'}
angles = [0, 10, 20, 30, 45, 60, 90]

fig, ax = plt.subplots()
fig.suptitle('Rotated markers', fontsize=14)

ax.text(-0.5, 0, 'Filled marker', **text_style)
for x, theta in enumerate(angles):
t = Affine2D().rotate_deg(theta)
ax.plot(x, 0, marker=MarkerStyle('o', 'left', t), **common_style)

ax.text(-0.5, 1, 'Un-filled marker', **text_style)
for x, theta in enumerate(angles):
t = Affine2D().rotate_deg(theta)
ax.plot(x, 1, marker=MarkerStyle('1', 'left', t), **common_style)

ax.text(-0.5, 2, 'Equation marker', **text_style)
for x, theta in enumerate(angles):
t = Affine2D().rotate_deg(theta)
eq = r'$\frac{1}{x}$'
ax.plot(x, 2, marker=MarkerStyle(eq, 'left', t), **common_style)

for x, theta in enumerate(angles):
ax.text(x, 2.5, f"{theta}°", horizontalalignment="center")
format_axes(ax)

fig.tight_layout()
plt.show()

###############################################################################
# Setting marker cap style and join style
# =======================================
#
# Markers have default cap and join styles, but these can be
# customized when creating a MarkerStyle.

from matplotlib.markers import JoinStyle, CapStyle

marker_inner = dict(markersize=35,
markerfacecolor='tab:blue',
markerfacecoloralt='lightsteelblue',
markeredgecolor='brown',
markeredgewidth=8,
)

marker_outer = dict(markersize=35,
markerfacecolor='tab:blue',
markerfacecoloralt='lightsteelblue',
markeredgecolor='white',
markeredgewidth=1,
)

fig, ax = plt.subplots()
fig.suptitle('Marker CapStyle', fontsize=14)
fig.subplots_adjust(left=0.1)

for y, cap_style in enumerate(CapStyle):
ax.text(-0.5, y, cap_style.name, **text_style)
for x, theta in enumerate(angles):
t = Affine2D().rotate_deg(theta)
m = MarkerStyle('1', transform=t, capstyle=cap_style)
ax.plot(x, y, marker=m, **marker_inner)
ax.plot(x, y, marker=m, **marker_outer)
ax.text(x, len(CapStyle) - .5, f'{theta}°', ha='center')
format_axes(ax)
plt.show()

###############################################################################
# Modifying the join style:

fig, ax = plt.subplots()
fig.suptitle('Marker JoinStyle', fontsize=14)
fig.subplots_adjust(left=0.05)

for y, join_style in enumerate(JoinStyle):
ax.text(-0.5, y, join_style.name, **text_style)
for x, theta in enumerate(angles):
t = Affine2D().rotate_deg(theta)
m = MarkerStyle('*', transform=t, joinstyle=join_style)
ax.plot(x, y, marker=m, **marker_inner)
ax.text(x, len(JoinStyle) - .5, f'{theta}°', ha='center')
format_axes(ax)

plt.show()
46 changes: 46 additions & 0 deletions examples/lines_bars_and_markers/multivariate_marker_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
==============================================
Mapping marker properties to multivariate data
==============================================

This example shows how to use different properties of markers to plot
multivariate datasets. Here we represent a successful baseball throw as a
smiley face with marker size mapped to the skill of thrower, marker rotation to
the take-off angle, and thrust to the marker color.
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.markers import MarkerStyle
from matplotlib.transforms import Affine2D
from matplotlib.textpath import TextPath
from matplotlib.colors import Normalize

SUCCESS_SYMBOLS = [
TextPath((0, 0), "☹"),
TextPath((0, 0), "😒"),
TextPath((0, 0), "☺"),
]

N = 25
np.random.seed(42)
skills = np.random.uniform(5, 80, size=N) * 0.1 + 5
takeoff_angles = np.random.normal(0, 90, N)
thrusts = np.random.uniform(size=N)
successfull = np.random.randint(0, 3, size=N)
positions = np.random.normal(size=(N, 2)) * 5
data = zip(skills, takeoff_angles, thrusts, successfull, positions)

cmap = plt.cm.get_cmap("plasma")
fig, ax = plt.subplots()
fig.suptitle("Throwing success", size=14)
for skill, takeoff, thrust, mood, pos in data:
t = Affine2D().scale(skill).rotate_deg(takeoff)
m = MarkerStyle(SUCCESS_SYMBOLS[mood], transform=t)
ax.plot(pos[0], pos[1], marker=m, color=cmap(thrust))
fig.colorbar(plt.cm.ScalarMappable(norm=Normalize(0, 1), cmap=cmap),
ax=ax, label="Normalized Thrust [a.u.]")
ax.set_xlabel("X position [m]")
ax.set_ylabel("Y position [m]")

plt.show()
5 changes: 4 additions & 1 deletion lib/matplotlib/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,10 @@ def __init__(self, xdata, ydata,
self.set_color(color)
if marker is None:
marker = 'none' # Default.
self._marker = MarkerStyle(marker, fillstyle)
if not isinstance(marker, MarkerStyle):
self._marker = MarkerStyle(marker, fillstyle)
else:
self._marker = marker

self._markevery = None
self._markersize = None
Expand Down
Loading