-
-
Notifications
You must be signed in to change notification settings - Fork 7.4k
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
Add support for multiple hatches, edgecolors and linewidths in histograms #28073
base: main
Are you sure you want to change the base?
Conversation
I'd suggest showing what this does with an example either in the GitHub pr description, or ideally in the gallery |
I'm not really sure if I need to add a new test or just modify an exisiting one(test_hist_stacked_bar) in test_axes.py |
I guess there are two things here:
|
pinging @story645 for review. The failing tests are unrelated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also needs updated documentation that the patch properties are now vectorized (@timhoffm any concerns here?)
lib/matplotlib/axes/_axes.py
Outdated
if 'hatch' in kwargs: | ||
kwargs['hatch'] = next(hatches) | ||
if 'edgecolor' in kwargs: | ||
kwargs['edgecolor'] = next(edgecolors) | ||
if 'linewidth' in kwargs: | ||
kwargs['linewidth'] = next(linewidths) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the kwarg names directly instead of this if chain? kinda like how it's implemented in pie
matplotlib/lib/matplotlib/axes/_axes.py
Lines 3339 to 3344 in 80b08bd
w = mpatches.Wedge((x, y), radius, 360. * min(theta1, theta2), | |
360. * max(theta1, theta2), | |
facecolor=get_next_color(), | |
hatch=next(hatch_cycle), | |
clip_on=False, | |
label=label) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some deliberation, it doesn't seem like I can remove the if statements for edgecolor
. The behavior of the edgecolor
attribute is different when it is specified but None, from when it is not specified. Also, to specify kwarg names directly, I need to access the type of the object as it is sometimes BarContainer
, sometimes list
and sometimes Rectangle
. Probably best to handle it via kwargs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the complications in edgecolor go away if #28104 was finished?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, this isn't related to the hatchcolor, but is related to different fallbacks of the edgecolor to either black or blue. Probably an entirely new issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it doing those fallbacks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so it appears that the edgecolor is being explicitly set to black which is the rcParam of patch.edgecolor, regardless of the edgecolor set previously. The setting of edgecolor is different when the histogram type is bar, step, stepfilled, stacked and becomes hard to handle
What should we be concerned about? We already have vectorized
This should also get a what's new entry. |
My bias is vectorize everything so I don't have concerns, but in the past for some vectorization discussions there have been concerns about the tradeoffs. But if there isn't opposition, awesome! |
I don't see any drawbacks for |
So we are planning to vectorize all parameters of Patches? Like joinstyle, capstyle etc. |
Not at this time w/ the current architecture, especially because nobody has asked for those. |
Specify extensions for test Added modified baseline images Modified test for histogram with single parameters Fixed test Add modified baseline images
Added baseline images
Fix test Added baseline images
Codecov is acting fishy, it passed once and failed again after squashing. Anything else to add/change? |
if 'edgecolor' in kwargs: | ||
kwargs['edgecolor'] = next(edgecolors) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, you may have told me before but why does edgecolor need to be special cased here? does edge color behave differently if it's passed in as none vs if it's not set?
def test_hist_vectorized_params(): | ||
fig, ((ax0, ax1), (ax2, ax3)) = plt.subplots(nrows=2, ncols=2) | ||
|
||
np.random.seed(19680801) | ||
x = [np.random.randn(n) for n in [2000, 5000, 10000]] | ||
|
||
ax0.hist(x, bins=10, histtype="barstacked", edgecolor=["red", "black", "blue"], | ||
linewidth=[1, 1.2, 1.5], hatch=["/", "\\", "."]) | ||
ax1.hist(x, bins=10, histtype="barstacked", linewidth=[1, 1.2, 1.5], | ||
hatch=["/", "\\", "."], linestyle=["-", "--", ":"]) | ||
ax2.hist(x, bins=10, histtype="barstacked", edgecolor=["red", "black", "blue"], | ||
hatch=["/", "\\", "."], linestyle=["-", "--", ":"]) | ||
ax3.hist(x, bins=10, histtype="barstacked", edgecolor=["red", "black", "blue"], | ||
linewidth=[1, 1.2, 1.5], linestyle=["-", "--", ":"]) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I'm a little unclear what the benefit of having these 4 panels is/what distinct thing each section is testing. Also, since all these images can already be made the long way, this might be better as a test figures equal: https://matplotlib.org/devdocs/devel/testing.html#compare-two-methods-of-creating-an-image
Mostly in terms of being able to isolate what went wrong, but also cause then you can maybe parametrize each keyword/parametrize the tests and use that to better identify what's being tested.
@@ -6937,7 +6937,9 @@ def hist(self, x, bins=None, range=None, density=False, weights=None, | |||
DATA_PARAMETER_PLACEHOLDER | |||
|
|||
**kwargs | |||
`~matplotlib.patches.Patch` properties | |||
`~matplotlib.patches.Patch` properties. The following properties | |||
additionally accept lists of property values, one element for each dataset: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
additionally accept lists of property values, one element for each dataset: | |
additionally accepts a sequence of properties values corresponding to the datasets in *x*: |
changed to sequence b/c that's the language we use through out, removed element b/c element and values are here being used to refer to the same thing
--------------------------------------------------------------------------------------- | ||
|
||
The parameters ``hatch``, ``edgecolor``, ``linewidth`` and ``linestyle`` of the `~matplotlib.axes.Axes.hist` method are now vectorized. | ||
This means that you can pass a list of values to these parameters, and the values will be applied to each dataset in the histogram. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that you can pass a list of values to these parameters, and the values will be applied to each dataset in the histogram. | |
This means that you can pass in unique parameters for each histogram that is generated when the input *x* has multiple datasets. |
Not sure if it's a nit, but just trying to be super explicit that these are aesthetic parameters rather than computational.
Note that the ``facecolor`` parameter is not vectorized, but the required behavior can be achieved by passing a list of colors to the ``color`` parameter. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we parametrize facecolor? Specifically the use case where I want face and edge to be different colors?
|
||
.. plot:: | ||
:include-source: true | ||
:alt: Three charts, identified as ax1, ax2 and ax3, include plots of three random datasets. The first, second and third plots have datasets differentiated by linewidths, hatches and linestyles, respectively. Edgecolors are used in all of the plots to accentuate the differences. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:alt: Three charts, identified as ax1, ax2 and ax3, include plots of three random datasets. The first, second and third plots have datasets differentiated by linewidths, hatches and linestyles, respectively. Edgecolors are used in all of the plots to accentuate the differences. | |
:alt: Three charts, identified as ax1, ax2 and ax3, show a stacking of three histograms. The histograms in ax1, ax2, and ax3 are differentiated by linewidths, hatches and linestyles, respectively. In ax1, ax2, and ax3, each histogram is bordered by a different color. |
Since you've named the access, cleaner to just refer to it I think, and may as well be specific about the plot type being shown here.
hatches = ["-", "o", "x"] | ||
linewidths = [1, 2, 3] | ||
edgecolors = ["green", "red", "blue"] | ||
linestyles = ["-", ":", "--"] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this separated from where it's used in this exact case where you're trying to teach usage.
# Also, these parameters can be specified for all types of | ||
# histograms (stacked, step, etc.) and not just for the *bar* | ||
# type histogram as shown in the example. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just show this I think
x, n_bins, density=True, fill=False, histtype="bar", | ||
edgecolor=edgecolors, label=edgecolors | ||
) | ||
ax0.legend(prop={"size": 10}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason for setting the legend prop size?
# Plotting a bar chart with sample sets differentiated using: | ||
# | ||
# * edgecolors | ||
# * hatches | ||
# * linewidths | ||
# * linestyles |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So especially in this case where I don't think things need to be interconnected, I think this may work better as subsections.
PR summary
Closes #26718 Distributes keyword args passed to each Patch using a cycler. Probably not the best way to do this?
PR checklist