-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
feat: StepPatch #18275
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
feat: StepPatch #18275
Conversation
Would be real cool if the crowd vocal at the previous iterations @jklymak @timhoffm @tacaswell @ImportanceOfBeingErnest could leave a comment if they're happy with this take before I sink time into tests and docs. |
I haven't looked in super detail but this seems like a cleaner approach to me. |
This definitively goes in the right direction. However, there are a few design decisions to be considered:
|
@timhoffm props, this is exactly the type of discussion I was hoping could happen before more time is put into writing code that might not get used... I think a new class, based on Re 2) The reason that Re 3) Having a default |
I think one of the points of such an artist is to be able to set the x-data and the y-data (or bins and vals) after it is created and have the right thing happen. This is important for animations. So I don't think that returning multiple patches is a good design decision because you can't do that. It might be fine under the hood to have multiple patches, but ideally the user would get one object they could manipulate. |
The current nan handling could be pushed down into the HistLine artist, which could internally be a list of one or more polygons masquerading as one artist for get/set purposes. I don't know if there's another way to implement it and it's definitely a reasonable thing to have. Btw I think |
Alright, so I am not sure I particularly like this solution because it essentially maps a "collection" onto one artist, which seems weird. But in this way, the By the looks of it, this approach can yield the same result, but the code might get uglier. |
It's reasonable to build the class on top of Collections are more made for similar objects, e.g. a set of squares with, possibly different properties like color but maybe also size. I'm coming back on issue 3) (edges vs bins) later. |
I'll stick my oar in on I'm torn about whether edges should be a kwarg or not. I guess it is OK that its second because I'm also not sure about your choice of default. I guess I'd expect, by default, the bins would be centred on an integer (i.e. +/-0.5 of what you chose). |
Parameter namingI agree with @jklymak in that I favor
Default edgesI'm not clear what a good default would be Parameter order+/-0 My interpretation of a step line is more that of a piece-wise constant function, which favors OTOH |
I agree with you that Regarding the param order and presence of a default, you mention the 2 points that I was going to. I just want to add that I am still disappointed at times when I forget that There is an additional value in making this I have to admit I find |
|
Yes, that's too much magic. Even more so: Our discussion shows that there are arguments for both oderings (values-edges and edges-values). People thinking in the convention not chosen by us would surprisingly get the other orientation.
You have to manually define the matplotlib/tools/boilerplate.py Line 187 in 8511771
That's ok. I don't think variable baseline is an important use case. One can still later expand the API by supporting an array as |
I think adding a baseline is actually pretty important. You are going to get complaints about zero as soon as someone does |
I am not sure what you mean. There is a baseline and sticky edges and it seems to work fine with log, the test is there. The question was about having the option of baseline being an array of len(vals). |
# The use of the following functions, methods, classes and modules is shown | ||
# in this example: | ||
|
||
import matplotlib |
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'll need to suppress this flake8 in .flake8
Sorry, I should have read the test more closely - search doesn't work for some reason ;-) And yes, a single value for Just to be clear, |
Hmm interesting, in that case “bin_edges" is also viable option. I've changed the StepPatch kwarg to edges because it makes sense to me, that that object would be decoupled from the histogram meaning. |
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.
StepLine
essentially looks good.
Still have to think about histline()
. Do we want that semantically connotated name or do we want stepline()
? Will get back to you on this.
I think I was thinking about the plotting fcn name, but I think here it should be possible to go more specialized - i.e. have a |
Any hints on what needs to be changed to pass the docs? |
If you click through to the error and then download the full file you can search for "Warning" to finally get:
|
Yeah, I was able to find that. But I'm not entirely sure why it doesn't work. I've modeled the way I referenced stuff from other mpl scripts, apparently missing some bit that actually makes it work. |
Other Parameters | ||
---------------- | ||
**kwargs | ||
`~matplotlib.patches.StepPatch` properties |
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.
`~matplotlib.patches.StepPatch` properties | |
`~.matplotlib.patches.StepPatch` properties |
55daa34
to
4018a62
Compare
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 looks good! Thank's @andrzejnovak for following through with all our requested changes. This is an extremely useful feature, but we had to make sure we get it right. Thanks all for the API discussions!
While there are still some minor things to decide and improve, this PR has seen enough discussion and is generally in good shape. I suggest to merge this as is and incrementally improve via follow-up PRs. These can then be done by anybody and don't necessarily burden @andrzejnovak, who has already done a great job.
For follow-up PRs I consider the following topics:
Comparison ofaddressed in Documentation improvements for stairs() #18543.pyplot.step
and.pyplot.stairs
could use some explanatory text.- I'm not entirely sure why the default StepPatch example renders with fill color and edges. I thought that default patches render without edge lines. To be checked.
Some docstring parameters don't have a description. Even if they state something apparently obvious, they should be explicit.addressed in Documentation improvements for stairs() #18543- From an API perspective: Do we need both
get/set_data()
andget/set_values/edges()
? They are redundant. It might be better to reduce the API and either makeget/set_data()
private or removeget/set_values/edges()
. I'm not sure which way is best.
|
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 suggest clarifying an error message before merging, but won't insist on it. Overall, this is a nice addition.
lib/matplotlib/tests/test_axes.py
Outdated
@pytest.mark.xfail | ||
def test_stairs_invalid_update(): | ||
h = plt.stairs([1, 2], [0, 1]) | ||
h.set_edges(np.arange(5)) |
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.
What are you trying to do w/ these tests? They are failing before the set_edges gets run... I've not seen us use xfail
tests very often in the test base.
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.
Good catch, but yeah the idea is just to make sure stairs fail when the values are invalid.
d264f8e
to
b91b14c
Compare
if orientation == 'vertical': | ||
patch.sticky_edges.y.append(baseline) | ||
else: | ||
patch.sticky_edges.x.append(baseline) |
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.
just looking from the peanut gallery...
- do you actually want a sticky at y=0 if baseline is None?
- adding the sticky could be done as part of the StepPatch implementation (you could even try to keep it in sync in
set_baseline
, although it's not necessarily clear what to do if the user manually changed the value in the meantime, so... perhaps not). I realize other classes don't do that, although for many of them that's because they're too general for the class to really know what stickies to use (e.g. a Rectangle does not know it's being used as part of a 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.
1 is intended. I think the implied consensus was that the naming would be general but some histogram like assumptions could be made in the plotting function. That's why sticky is in stairs and not in StepPatch. I suppose that means the update of StepPatch is not nicely behaved wrt baseline sticky, but then again neither are lims
b91b14c
to
ecc54cb
Compare
In the spirit of @timhoffm #18275 (review), I'm going to merge this. It looks like the subsequent comments have been addressed. |
@timhoffm would you like to make an issue based on your list of possible follow-ups? I think that the API question about whether to retain all of the ways of setting values and edges should be decided before release. |
Will do. Part of that might directly be a PR. |
Can |
@ianhi I think we established that set/get_data needs to be the fundamental method to allow changing number of bins. The discussion seems to be about the auxiliary ones. I've implemented get/set_data, set_values and set_edges, because imo |
@timhoffm Sorry to be late to this discussion, but I think the pyplot method should be "stair" instead of "stairs". Similar to "step" which is also not called "steps". According to https://www.merriam-webster.com/dictionary/stair, a "stair" is already a series of steps. |
From your link:
"stairs" is a weird word in English that is always written in plural, unless you are referring to a single step. |
@HDembinski thanks for your feedback. We've extensively discussed the name in the developer call, in particular also It is acknowledged that most of our plotting function (but not all, c.f. |
This didn't get milestones. Was it 3.4? |
PR Summary
A new
StepPatch
artists based ofPathPatch
facilitation plotting histogram-like data and an associatedpyplot.stairs()
plotting function.Implementation based on @timhoffm and @jklymak suggestions, after drafts and discussions in #15065 and #15019 and the discussion below.
Closes #6669 and possibly #5855.
It is also considerably faster than
ax.hist
for a filled plot, since it draws only one* patch.PR Checklist