-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
More generic value snapping for Slider widgets #18569
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
Conversation
lib/matplotlib/widgets.py
Outdated
@@ -330,6 +334,11 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None, | |||
self.valmin = valmin | |||
self.valmax = valmax | |||
self.valstep = valstep | |||
self.valsnap = valsnap | |||
if self.valsnap is not None: |
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 isn't a great pattern because now if valsnap is None
, we silently drop the user's input for valstep
on the floor. This is the sort of thing that causes the greatest anger at libraries, you change the thing AND NOTHING HAPPENS.
We should find a way to either fold valstep
and valsnap
into one parameter or raise if both are passed.
Folding them into one parameter seems ok (there is a bit of ambiguity else where about plural) and an the code shows, you can generate the snap location from a step. In other cases where we have colliding kwargs we raise (e.g. norm vs density in hist).
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.
Ah indeed. Are you expressing a preference for a single kwarg here? I'm 55/45 towards two kwargs (appropriately ordered) and raising an error if both are passed. I think there is also an opportunity for user anger when they discover that a feature exists but was not very discoverable.
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 just pushed a change so it is two kwargs and raises an error if both are given. If need be I'm happy to move to a single valstep
kwarg
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 do this above, before the assignment, as if valstep is not None and valsnap is not None:...
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 moved the ValueError
up to be with the other ValueError
s
lib/matplotlib/widgets.py
Outdated
@@ -255,7 +255,7 @@ class Slider(AxesWidget): | |||
def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None, | |||
closedmin=True, closedmax=True, slidermin=None, | |||
slidermax=None, dragging=True, valstep=None, | |||
orientation='horizontal', **kwargs): | |||
valsnap=None, orientation='horizontal', **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.
If you are adding a new argument it has to go at the end (or better yet be keyword only!). This in an API break as if there is someone (admittedly making a poor coding choice) of passing in 13 positional arguments, valsnap
would get the string intended for orientation
and likely blow up.
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.
Yikes. But yes ok, I suppose having millions of users nearly guarantees that that is happening somewhere.
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.
👍 in principle, but the API needs some tweaking.
|
7334e31
to
1055bce
Compare
While I'm at it would it be ok to add a kwarg that would allow for eliminating the red line that marks the initial value? Something like The color and whether is is drawn is currently hardcoded here: matplotlib/lib/matplotlib/widgets.py Lines 338 to 343 in 5173cda
|
1055bce
to
51feb94
Compare
I also added another kwarg |
24fdcd4
to
70ff4cd
Compare
ade813e
to
fc4acd6
Compare
👍 I dropped that commit. Otherwise I can't think of anything else to change here. |
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.
Only minor style comments.
fc4acd6
to
41bdc05
Compare
I also added changing the color of the bar for one of the sliders to increase the discoverability of that option. |
41bdc05
to
caa3f42
Compare
Does this need another review from @tacaswell given their prior changes requested? |
Every code PR needs 2 positive reviews. Ideally, @tacaswell would do the second review because he has requested changes. But if he doesn't have time any other reviewer is fine. I take the authority to clear the change request if needed. |
lib/matplotlib/widgets.py
Outdated
initcolor : color or None, default: 'r' | ||
The color of the line at the *valinit* position. If None then | ||
no line will be drawn. |
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.
Usually we use None
to mean default. We also already have 'none'
to mean no colour; do we really need to support None
here?
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 find using None
to mean "don't draw" and colors otherwise to be the most intuitive api. I'd also worry about the discoverability of using 'none'
for example: I'm an advanced user but did not know that you could specify 'none'
as a color.
Usually we use None to mean default
I made the default 'r'
as that's what was hardcoded, but I think it would make more sense for None
to be the default and specifiying a color otherwise. I don't really see the usecase for drawing a line at the starting position, but I guess this edges into personal preference rather than logic and additionally is maybe backwards incompatible. What about switching the default to None
?
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.
None
means "default" unless we really can't help it. I you want the default to be "none"
I guess that could work for you....
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.
Gotcha - thanks. It probably is the least friction to as 'r'
and not accept None
so I'll do that + leave a note in the docstring to use 'none'
if you don't want it to be visible.
caa3f42
to
0baa16b
Compare
I add a reference to the new example - and while doing so added the references to the other widget examples except for |
plus lint snapping example
18b6d1d
to
bafcca9
Compare
PR Summary
Closes: #18562
Adds a
valsnap
argument to the Slider widget to allow specifying the values the slider should snap to. This overrides thevalstep
argument.I also made a new slider demo to show the use of
valstep
andvalsnap
as I think they would get lost in the current slider demo. For a point of context I have read through the existing tutorial multiple times, but never managed to encode thatvalstep
existed until I started working on this PRsearchsorted
instead ofargmin
as it is significantly faster.idx=0
because then the indexing just becomes-1
and we compare the largest and smallest elements of the array.PR Checklist
I have a few questions here:
a. There isn't any narrative docs on widgets to add this to?
b. Does this deserve it's own example (perhaps named
slider valstep and valsnap demo
) it feel weird to cram into the currentvalsnap
because it was consistent with the other kwargs but if there are better ideas I'm happy to change it.whats_new
and anext_api_changes
?next_api_changes
is the best strategy to look through both open and closed PRs right before opening this?pytest
passes).flake8
on changed files to check).flake8-docstrings
andpydocstyle<4
and runflake8 --docstring-convention=all
).doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).