-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add support for multiple hatches, edgecolors and linewidths in histograms #28073
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
Changes from 10 commits
1a6ec0f
0e52daa
34df06a
4fcb709
347ce22
d7ffeaa
9024be4
3bfca5f
6029e32
0349e7d
d1a8079
9a813f4
43ce57d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
Vectorize ``hatch``, ``edgecolor``, ``facecolor``, ``linewidth`` and ``linestyle`` in *hist* methods | ||
---------------------------------------------------------------------------------------------------- | ||
|
||
The parameters ``hatch``, ``edgecolor``, ``facecolor``, ``linewidth`` and ``linestyle`` | ||
Impaler343 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
of the `~matplotlib.axes.Axes.hist` method are now vectorized. | ||
This means that you can pass in unique parameters for each histogram that is generated | ||
Impaler343 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
when the input *x* has multiple datasets. | ||
|
||
|
||
.. plot:: | ||
:include-source: true | ||
:alt: Four charts, each displaying stacked histograms of three Poisson distributions. Each chart differentiates the histograms using various parameters: ax1 uses different linewidths, ax2 uses different hatches, ax3 uses different edgecolors, and ax4 uses different facecolors. Each histogram in ax1 and ax3 also has a different edgecolor. | ||
Impaler343 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
np.random.seed(19680801) | ||
|
||
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(9, 9)) | ||
|
||
data1 = np.random.poisson(5, 1000) | ||
data2 = np.random.poisson(7, 1000) | ||
data3 = np.random.poisson(10, 1000) | ||
|
||
labels = ["Data 1", "Data 2", "Data 3"] | ||
|
||
ax1.hist([data1, data2, data3], bins=range(17), histtype="step", stacked=True, | ||
edgecolor=["red", "green", "blue"], linewidth=[1, 2, 3]) | ||
ax1.set_title("Different linewidths") | ||
ax1.legend(labels) | ||
|
||
ax2.hist([data1, data2, data3], bins=range(17), histtype="barstacked", | ||
hatch=["/", ".", "*"]) | ||
ax2.set_title("Different hatch patterns") | ||
ax2.legend(labels) | ||
|
||
ax3.hist([data1, data2, data3], bins=range(17), histtype="bar", fill=False, | ||
edgecolor=["red", "green", "blue"], linestyle=["--", "-.", ":"]) | ||
ax3.set_title("Different linestyles") | ||
ax3.legend(labels) | ||
|
||
ax4.hist([data1, data2, data3], bins=range(17), histtype="barstacked", | ||
facecolor=["red", "green", "blue"]) | ||
ax4.set_title("Different facecolors") | ||
ax4.legend(labels) | ||
|
||
plt.show() |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4603,6 +4603,64 @@ def test_hist_stacked_bar(): | |||||||||||||||||||||||||||||||
ax.legend(loc='upper right', bbox_to_anchor=(1.0, 1.0), ncols=1) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@pytest.mark.parametrize('kwargs', ({'facecolor': ["b", "g", "r"]}, | ||||||||||||||||||||||||||||||||
{'edgecolor': ["b", "g", "r"]}, | ||||||||||||||||||||||||||||||||
{'hatch': ["/", "\\", "."]}, | ||||||||||||||||||||||||||||||||
{'linestyle': ["-", "--", ":"]}, | ||||||||||||||||||||||||||||||||
{'linewidth': [1, 1.5, 2]}, | ||||||||||||||||||||||||||||||||
{'color': ["b", "g", "r"]})) | ||||||||||||||||||||||||||||||||
@check_figures_equal(extensions=["png"]) | ||||||||||||||||||||||||||||||||
def test_hist_vectorized_params(fig_test, fig_ref, kwargs): | ||||||||||||||||||||||||||||||||
np.random.seed(19680801) | ||||||||||||||||||||||||||||||||
x = [np.random.randn(n) for n in [2000, 5000, 10000]] | ||||||||||||||||||||||||||||||||
Impaler343 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
(axt1, axt2) = fig_test.subplots(2) | ||||||||||||||||||||||||||||||||
(axr1, axr2) = fig_ref.subplots(2) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
for histtype, axt, axr in [("stepfilled", axt1, axr1), ("step", axt2, axr2)]: | ||||||||||||||||||||||||||||||||
_, bins, _ = axt.hist(x, bins=10, histtype=histtype, **kwargs) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
kw, values = next(iter(kwargs.items())) | ||||||||||||||||||||||||||||||||
for i, (xi, value) in enumerate(zip(x, values)): | ||||||||||||||||||||||||||||||||
axr.hist(xi, bins=bins, histtype=histtype, **{kw: value}, | ||||||||||||||||||||||||||||||||
zorder=(len(x)-i)/2) | ||||||||||||||||||||||||||||||||
Impaler343 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@pytest.mark.parametrize('kwargs, patch_face, patch_edge', | ||||||||||||||||||||||||||||||||
[({'histtype': 'stepfilled', 'color': 'r', | ||||||||||||||||||||||||||||||||
'facecolor': 'y', 'edgecolor': 'g'}, 'y', 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'color': 'r', | ||||||||||||||||||||||||||||||||
'facecolor': 'y', 'edgecolor': 'g'}, ('y', 0), 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled', 'color': 'r', | ||||||||||||||||||||||||||||||||
'edgecolor': 'g'}, 'r', 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'color': 'r', | ||||||||||||||||||||||||||||||||
'edgecolor': 'g'}, ('r', 0), 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled', 'color': 'r', | ||||||||||||||||||||||||||||||||
'facecolor': 'y'}, 'y', 'k'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'color': 'r', | ||||||||||||||||||||||||||||||||
'facecolor': 'y'}, ('y', 0), 'r'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled', | ||||||||||||||||||||||||||||||||
'facecolor': 'y', 'edgecolor': 'g'}, 'y', 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'facecolor': 'y', | ||||||||||||||||||||||||||||||||
'edgecolor': 'g'}, ('y', 0), 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled', 'color': 'r'}, 'r', 'k'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'color': 'r'}, ('r', 0), 'r'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled', 'facecolor': 'y'}, 'y', 'k'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'facecolor': 'y'}, ('y', 0), 'C0'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled', 'edgecolor': 'g'}, 'C0', 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step', 'edgecolor': 'g'}, ('C0', 0), 'g'), | ||||||||||||||||||||||||||||||||
({'histtype': 'stepfilled'}, 'C0', 'k'), | ||||||||||||||||||||||||||||||||
({'histtype': 'step'}, ('C0', 0), 'C0')]) | ||||||||||||||||||||||||||||||||
def test_hist_color_semantics(kwargs, patch_face, patch_edge): | ||||||||||||||||||||||||||||||||
_, _, patches = plt.figure().subplots().hist([1, 2, 3], **kwargs) | ||||||||||||||||||||||||||||||||
# 'C0'(blue) stands for the first color of the default color cycle | ||||||||||||||||||||||||||||||||
# as well as the patch.facecolor rcParam | ||||||||||||||||||||||||||||||||
# When the expected edgecolor is 'k'(black), it corresponds to the | ||||||||||||||||||||||||||||||||
# patch.edgecolor rcParam | ||||||||||||||||||||||||||||||||
assert all(mcolors.same_color([p.get_facecolor(), p.get_edgecolor()], | ||||||||||||||||||||||||||||||||
Impaler343 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
[patch_face, patch_edge]) for p in patches) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
def test_hist_barstacked_bottom_unchanged(): | ||||||||||||||||||||||||||||||||
b = np.array([10, 20]) | ||||||||||||||||||||||||||||||||
plt.hist([[0, 1], [0, 1]], 2, histtype="barstacked", bottom=b) | ||||||||||||||||||||||||||||||||
|
@@ -4614,6 +4672,16 @@ def test_hist_emptydata(): | |||||||||||||||||||||||||||||||
ax.hist([[], range(10), range(10)], histtype="step") | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
def test_hist_none_patch(): | ||||||||||||||||||||||||||||||||
# To cover None patches when excess labels are provided | ||||||||||||||||||||||||||||||||
labels = ["First", "Second"] | ||||||||||||||||||||||||||||||||
patches = [[1, 2]] | ||||||||||||||||||||||||||||||||
fig, ax = plt.subplots() | ||||||||||||||||||||||||||||||||
ax.hist(patches, label=labels) | ||||||||||||||||||||||||||||||||
_, lbls = ax.get_legend_handles_labels() | ||||||||||||||||||||||||||||||||
assert (len(lbls) < len(labels) and len(patches) < len(labels)) | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please elaborate what this tests? What are None patches? Does this express what you want to test?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None patches are the ones generated when the number of labels specified are more than the number of patches(Filled in by zip_longest). The suggested test also covers the line and has clearer labels, ill change it up |
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
def test_hist_labels(): | ||||||||||||||||||||||||||||||||
# test singleton labels OK | ||||||||||||||||||||||||||||||||
fig, ax = plt.subplots() | ||||||||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.