Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Add hatchcolor parameter for Collections#29044
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
d7da1fc
2fd17a0
f5978ce
5377127
6f18c49
8a7cd65
e3b03fc
7668535
9d0ec23
7e46707
c5e9583
d2b6268
fee895b
b9ac0fb
2e4784b
3b43bc6
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -57,3 +57,39 @@ Previously, hatch colors were the same as edge colors, with a fallback to | ||
xy=(.5, 1.03), xycoords=patch4, ha='center', va='bottom') | ||
plt.show() | ||
For collections, a sequence of colors can be passed to the *hatchcolor* parameter | ||
which will be cycled through for each hatch, similar to *facecolor* and *edgecolor*. | ||
Previously, if *edgecolor* was not specified, the hatch color would fall back to | ||
:rc:`patch.edgecolor`, but the alpha value would default to **1.0**, regardless of the | ||
alpha value of the collection. This behavior has been changed such that, if both | ||
*hatchcolor* and *edgecolor* are not specified, the hatch color will fall back | ||
to 'patch.edgecolor' with the alpha value of the collection. | ||
.. plot:: | ||
:include-source: true | ||
:alt: A random scatter plot with hatches on the markers. The hatches are colored in blue, orange, and green, respectively. After the first three markers, the colors are cycled through again. | ||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
np.random.seed(19680801) | ||
fig, ax = plt.subplots() | ||
x = [29, 36, 41, 25, 32, 70, 62, 58, 66, 80, 58, 68, 62, 37, 48] | ||
y = [82, 76, 48, 53, 62, 70, 84, 68, 55, 75, 29, 25, 12, 17, 20] | ||
colors = ['tab:blue'] * 5 + ['tab:orange'] * 5 + ['tab:green'] * 5 | ||
ax.scatter( | ||
Impaler343 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
x, | ||
y, | ||
s=800, | ||
hatch="xxxx", | ||
hatchcolor=colors, | ||
facecolor="none", | ||
edgecolor="black", | ||
) | ||
plt.show() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,27 @@ | ||
""" | ||
=============== | ||
Hatchcolor Demo | ||
=============== | ||
The color of the hatch can be set using the *hatchcolor* parameter. The following | ||
examples show how to use the *hatchcolor* parameter to set the color of the hatch | ||
in `~.patches.Patch` and `~.collections.Collection`. | ||
See also :doc:`/gallery/shapes_and_collections/hatch_demo` for more usage examples | ||
of hatching. | ||
Patch Hatchcolor | ||
timhoffm marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
---------------- | ||
This example shows how to use the *hatchcolor* parameter to set the color of | ||
the hatch in a rectangle and a bar plot. The *hatchcolor* parameter is available for | ||
`~.patches.Patch`,child classes of Patch, and methods that pass through to Patch. | ||
""" | ||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
import matplotlib.cm as cm | ||
from matplotlib.patches import Rectangle | ||
fig, (ax1, ax2) = plt.subplots(1, 2) | ||
@@ -28,6 +39,43 @@ | ||
ax2.set_xlim(0, 5) | ||
ax2.set_ylim(0, 5) | ||
# %% | ||
# Collection Hatchcolor | ||
# --------------------- | ||
# | ||
# The following example shows how to use the *hatchcolor* parameter to set the color of | ||
# the hatch in a scatter plot. The *hatchcolor* parameter can also be passed to | ||
# `~.collections.Collection`, child classes of Collection, and methods that pass | ||
# through to Collection. | ||
fig, ax = plt.subplots() | ||
num_points_x = 10 | ||
num_points_y = 9 | ||
x = np.linspace(0, 1, num_points_x) | ||
y = np.linspace(0, 1, num_points_y) | ||
X, Y = np.meshgrid(x, y) | ||
X[1::2, :] += (x[1] - x[0]) / 2 # stagger every alternate row | ||
# As ax.scatter (PathCollection) is drawn row by row, setting hatchcolors to the | ||
# first row is enough, as the colors will be cycled through for the next rows. | ||
colors = [cm.rainbow(val) for val in x] | ||
ax.scatter( | ||
X.ravel(), | ||
Y.ravel(), | ||
s=1700, | ||
facecolor="none", | ||
edgecolor="gray", | ||
linewidth=2, | ||
marker="h", # Use hexagon as marker | ||
dstansby marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
hatch="xxx", | ||
hatchcolor=colors, | ||
) | ||
ax.set_xlim(0, 1) | ||
ax.set_ylim(0, 1) | ||
plt.show() | ||
# %% | ||
@@ -41,3 +89,5 @@ | ||
# - `matplotlib.patches.Polygon` | ||
# - `matplotlib.axes.Axes.add_patch` | ||
# - `matplotlib.axes.Axes.bar` / `matplotlib.pyplot.bar` | ||
# - `matplotlib.collections` | ||
# - `matplotlib.axes.Axes.scatter` / `matplotlib.pyplot.scatter` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -208,7 +208,7 @@ | ||
def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, *, hatchcolors=None): | ||
""" | ||
Draw a collection of *paths*. | ||
@@ -217,8 +217,11 @@ | ||
*master_transform*. They are then translated by the corresponding | ||
entry in *offsets*, which has been first transformed by *offset_trans*. | ||
*facecolors*, *edgecolors*, *linewidths*, *linestyles*, *antialiased* | ||
and *hatchcolors* are lists that set the corresponding properties. | ||
timhoffm marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
.. versionadded:: 3.11 | ||
Allow *hatchcolors* to be specified. | ||
*offset_position* is unused now, but the argument is kept for | ||
backwards compatibility. | ||
@@ -235,10 +238,13 @@ | ||
path_ids = self._iter_collection_raw_paths(master_transform, | ||
paths, all_transforms) | ||
if hatchcolors is None: | ||
hatchcolors = [] | ||
Impaler343 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
for xo, yo, path_id, gc0, rgbFace in self._iter_collection( | ||
gc, list(path_ids), offsets, offset_trans, | ||
facecolors, edgecolors, linewidths, linestyles, | ||
antialiaseds, urls, offset_position, hatchcolors=hatchcolors): | ||
path, transform = path_id | ||
# Only apply another translation if we have an offset, else we | ||
# reuse the initial transform. | ||
@@ -252,7 +258,7 @@ | ||
def draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, | ||
coordinates, offsets, offsetTrans, facecolors, | ||
antialiased, edgecolors, *, hatchcolors=None): | ||
""" | ||
Draw a quadmesh. | ||
@@ -265,11 +271,14 @@ | ||
if edgecolors is None: | ||
edgecolors = facecolors | ||
if hatchcolors is None: | ||
hatchcolors = [] | ||
Impaler343 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
linewidths = np.array([gc.get_linewidth()], float) | ||
return self.draw_path_collection( | ||
gc, master_transform, paths, [], offsets, offsetTrans, facecolors, | ||
edgecolors, linewidths, [], [antialiased], [None], 'screen', | ||
hatchcolors=hatchcolors) | ||
def draw_gouraud_triangles(self, gc, triangles_array, colors_array, | ||
transform): | ||
@@ -337,7 +346,7 @@ | ||
def _iter_collection(self, gc, path_ids, offsets, offset_trans, facecolors, | ||
edgecolors, linewidths, linestyles, | ||
antialiaseds, urls, offset_position, *, hatchcolors): | ||
""" | ||
Helper method (along with `_iter_collection_raw_paths`) to implement | ||
`draw_path_collection` in a memory-efficient manner. | ||
@@ -365,11 +374,12 @@ | ||
N = max(Npaths, Noffsets) | ||
Nfacecolors = len(facecolors) | ||
Nedgecolors = len(edgecolors) | ||
Nhatchcolors = len(hatchcolors) | ||
Nlinewidths = len(linewidths) | ||
Nlinestyles = len(linestyles) | ||
Nurls = len(urls) | ||
if (Nfacecolors == 0 and Nedgecolors == 0 and Nhatchcolors == 0) or Npaths == 0: | ||
return | ||
gc0 = self.new_gc() | ||
@@ -384,6 +394,7 @@ | ||
toffsets = cycle_or_default(offset_trans.transform(offsets), (0, 0)) | ||
fcs = cycle_or_default(facecolors) | ||
ecs = cycle_or_default(edgecolors) | ||
hcs = cycle_or_default(hatchcolors) | ||
lws = cycle_or_default(linewidths) | ||
lss = cycle_or_default(linestyles) | ||
aas = cycle_or_default(antialiaseds) | ||
@@ -392,8 +403,8 @@ | ||
if Nedgecolors == 0: | ||
gc0.set_linewidth(0.0) | ||
for pathid, (xo, yo), fc, ec,hc,lw, ls, aa, url in itertools.islice( | ||
zip(pathids, toffsets, fcs, ecs,hcs,lws, lss, aas, urls), N): | ||
if not (np.isfinite(xo) and np.isfinite(yo)): | ||
continue | ||
if Nedgecolors: | ||
@@ -405,6 +416,8 @@ | ||
gc0.set_linewidth(0) | ||
else: | ||
gc0.set_foreground(ec) | ||
if Nhatchcolors: | ||
gc0.set_hatch_color(hc) | ||
if fc is not None and len(fc) == 4 and fc[3] == 0: | ||
fc = None | ||
gc0.set_antialiased(aa) | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -63,6 +63,8 @@ class RendererBase: | ||
antialiaseds: bool | Sequence[bool], | ||
urls: str | Sequence[str], | ||
offset_position: Any, | ||
*, | ||
hatchcolors: ColorType | Sequence[ColorType] | None = None, | ||
timhoffm marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
) -> None: ... | ||
def draw_quad_mesh( | ||
self, | ||
@@ -76,6 +78,8 @@ class RendererBase: | ||
facecolors: Sequence[ColorType], | ||
antialiased: bool, | ||
edgecolors: Sequence[ColorType] | ColorType | None, | ||
*, | ||
hatchcolors: Sequence[ColorType] | ColorType | None = None, | ||
) -> None: ... | ||
def draw_gouraud_triangles( | ||
self, | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -2030,14 +2030,17 @@ def draw_path(self, gc, path, transform, rgbFace=None): | ||
def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, *, hatchcolors=None): | ||
# We can only reuse the objects if the presence of fill and | ||
# stroke (and the amount of alpha for each) is the same for | ||
# all of them | ||
can_do_optimization = True | ||
facecolors = np.asarray(facecolors) | ||
edgecolors = np.asarray(edgecolors) | ||
if hatchcolors is None: | ||
hatchcolors = [] | ||
Impaler343 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
if not len(facecolors): | ||
filled = False | ||
can_do_optimization = not gc.get_hatch() | ||
@@ -2072,7 +2075,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
self, gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, hatchcolors=hatchcolors) | ||
padding = np.max(linewidths) | ||
path_codes = [] | ||
@@ -2088,7 +2091,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
for xo, yo, path_id, gc0, rgbFace in self._iter_collection( | ||
gc, path_codes, offsets, offset_trans, | ||
facecolors, edgecolors, linewidths, linestyles, | ||
antialiaseds, urls, offset_position, hatchcolors=hatchcolors): | ||
self.check_gc(gc0, rgbFace) | ||
dx, dy = xo - lastx, yo - lasty | ||
@@ -2603,7 +2606,10 @@ def delta(self, other): | ||
different = ours is not theirs | ||
else: | ||
different = bool(ours != theirs) | ||
except (ValueError, DeprecationWarning): | ||
# numpy version < 1.25 raises DeprecationWarning when array shapes | ||
# mismatch, unlike numpy >= 1.25 which raises ValueError. | ||
# This should be removed when numpy < 1.25 is no longer supported. | ||
ours = np.asarray(ours) | ||
theirs = np.asarray(theirs) | ||
different = (ours.shape != theirs.shape or | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -674,7 +674,9 @@ def draw_markers( | ||
def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, *, hatchcolors=None): | ||
if hatchcolors is None: | ||
hatchcolors = [] | ||
Impaler343 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
# Is the optimization worth it? Rough calculation: | ||
# cost of emitting a path in-line is | ||
# (len_path + 2) * uses_per_path | ||
@@ -690,7 +692,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
self, gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, hatchcolors=hatchcolors) | ||
path_codes = [] | ||
for i, (path, transform) in enumerate(self._iter_collection_raw_paths( | ||
@@ -709,7 +711,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
for xo, yo, path_id, gc0, rgbFace in self._iter_collection( | ||
gc, path_codes, offsets, offset_trans, | ||
facecolors, edgecolors, linewidths, linestyles, | ||
antialiaseds, urls, offset_position, hatchcolors=hatchcolors): | ||
ps = f"{xo:g} {yo:g} {path_id}" | ||
self._draw_ps(ps, gc0, rgbFace) | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -736,7 +736,9 @@ def draw_markers( | ||
def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, *, hatchcolors=None): | ||
if hatchcolors is None: | ||
hatchcolors = [] | ||
Impaler343 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
# Is the optimization worth it? Rough calculation: | ||
# cost of emitting a path in-line is | ||
# (len_path + 5) * uses_per_path | ||
@@ -752,7 +754,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
gc, master_transform, paths, all_transforms, | ||
offsets, offset_trans, facecolors, edgecolors, | ||
linewidths, linestyles, antialiaseds, urls, | ||
offset_position, hatchcolors=hatchcolors) | ||
writer = self.writer | ||
path_codes = [] | ||
@@ -770,7 +772,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, | ||
for xo, yo, path_id, gc0, rgbFace in self._iter_collection( | ||
gc, path_codes, offsets, offset_trans, | ||
facecolors, edgecolors, linewidths, linestyles, | ||
antialiaseds, urls, offset_position, hatchcolors=hatchcolors): | ||
url = gc0.get_url() | ||
if url is not None: | ||
writer.start('a', attrib={'xlink:href': url}) | ||
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.