Skip to content
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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

Impaler343
Copy link
Contributor

@Impaler343 Impaler343 commented Apr 13, 2024

PR summary

Closes #26718 Distributes keyword args passed to each Patch using a cycler. Probably not the best way to do this?

PR checklist

@jklymak
Copy link
Member

jklymak commented Apr 13, 2024

I'd suggest showing what this does with an example either in the GitHub pr description, or ideally in the gallery

@github-actions github-actions bot added the Documentation: examples files in galleries/examples label Apr 14, 2024
@Impaler343
Copy link
Contributor Author

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

@oscargus
Copy link
Contributor

I guess there are two things here:

  1. Add/modify an example in the gallery to illustrate how it is used. (Will be easier for the reviewers to get an idea of how it is used etc.)
  2. Add a test to get the code coverage up and make sure no one breaks it later. Maybe there is some old example that one can "hi-jack", but otherwise create a new test with all the bells and whistles turned on.

@Impaler343
Copy link
Contributor Author

pinging @story645 for review. The failing tests are unrelated

Copy link
Member

@story645 story645 left a 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?)

Comment on lines 7190 to 7195
if 'hatch' in kwargs:
kwargs['hatch'] = next(hatches)
if 'edgecolor' in kwargs:
kwargs['edgecolor'] = next(edgecolors)
if 'linewidth' in kwargs:
kwargs['linewidth'] = next(linewidths)
Copy link
Member

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

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, makes sense

Copy link
Contributor Author

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

Copy link
Member

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?

Copy link
Contributor Author

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

Copy link
Member

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?

Copy link
Contributor Author

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

lib/matplotlib/axes/_axes.py Outdated Show resolved Hide resolved
galleries/examples/statistics/histogram_multihist.py Outdated Show resolved Hide resolved
@timhoffm
Copy link
Member

timhoffm commented May 19, 2024

also needs updated documentation that the patch properties are now vectorized (@timhoffm any concerns here?)

What should we be concerned about? We already have vectorized label and color. It's only fair to vectorize these inside hist() as well. This should be documented with **kwargs (can't immediately suggest, because that part has not been touched in the PR). Something like:

        **kwargs
            `~matplotlib.patches.Patch` properties. The following properties additionally
            accept lists of property values, one element for each dataset:
            *edgecolors*, *linewidths*, *linestyles*, *hatches*.

This should also get a what's new entry.

@story645
Copy link
Member

What should we be concerned about? We already have vectorized label and color.

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!

@timhoffm
Copy link
Member

I don't see any drawbacks for hist()

@Impaler343
Copy link
Contributor Author

So we are planning to vectorize all parameters of Patches? Like joinstyle, capstyle etc.

@story645
Copy link
Member

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
@Impaler343
Copy link
Contributor Author

Codecov is acting fishy, it passed once and failed again after squashing. Anything else to add/change?

Comment on lines +7224 to +7225
if 'edgecolor' in kwargs:
kwargs['edgecolor'] = next(edgecolors)
Copy link
Member

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?

Comment on lines +4608 to +4622
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=["-", "--", ":"])

Copy link
Member

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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Comment on lines +6 to +7
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.

Copy link
Member

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
: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.

Comment on lines +63 to +67
hatches = ["-", "o", "x"]
linewidths = [1, 2, 3]
edgecolors = ["green", "red", "blue"]
linestyles = ["-", ":", "--"]

Copy link
Member

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.

Comment on lines +59 to +61
# 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.
Copy link
Member

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})
Copy link
Member

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?

Comment on lines +52 to +57
# Plotting a bar chart with sample sets differentiated using:
#
# * edgecolors
# * hatches
# * linewidths
# * linestyles
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation: examples files in galleries/examples New feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: stacked histogram does not properly handle edgecolor and hatches
6 participants