Skip to content

Change styling of slider widgets #19265

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

Merged
merged 8 commits into from
Jul 7, 2021

Conversation

ianhi
Copy link
Contributor

@ianhi ianhi commented Jan 9, 2021

PR Summary

Closes: #19256

Updates the styling of the slider widgets to look like this:
Peek 2021-01-12 17-59

  1. Made the poly patch smaller
  2. Added a circle handle to indicate that the sliders can be grabbed with the mouse
    • will change color when grabbed
  3. removed the black border of the Axes and indicate the length of the slider with rectangle patch.
    • This is skinnier than previously.

PR Checklist

  • [NA?] Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • [I guess?] New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

@QuLogic
Copy link
Member

QuLogic commented Jan 9, 2021

Is _above_rect for the grey part? Why not set a default Axes facecolor instead? This would be more directly overriddable, I think.

@ianhi
Copy link
Contributor Author

ianhi commented Jan 9, 2021

I did it that way for two reasons:

  1. If you make the blue polygon have an alpha != 1 then setting the facecolor of the axis looks bad.
  2. I think it looks better when the line the slider is on is smaller and this way the existing slider axis size from the example (and thus probably most peoples code) will not need to be modified for that visual change

I suppose those probably don't fully justify the added complexity though

@ianhi
Copy link
Contributor Author

ianhi commented Jan 9, 2021

Just tried out with using the facecolor approach. I found that it doesn't look good with the default scaling (first slider), but that if I made the Axes used to make the slider smaller in order to look nicer it was significantly more difficult to click on due to the axis being so small. That's compounded by the fact that clicking on the handle when it clips outside doesn't register as moving the slider unfortunately as the events are all tied to the axis.

image

@ianhi
Copy link
Contributor Author

ianhi commented Jan 9, 2021

I guess it would make sense to simplify by just having a single static background rect

@WeatherGod
Copy link
Member

WeatherGod commented Jan 9, 2021 via email

@ianhi
Copy link
Contributor Author

ianhi commented Jan 9, 2021

can we have a bigger difference in brightness for the right and left
rectangles? They are too close to easily distinguish.

Fine by me. Any specific suggestions for colors? The left rectangle is currently just whatever is first in the users color cycle as it is generated by ax.axvspan.

@ianhi
Copy link
Contributor Author

ianhi commented Jan 9, 2021

How about lightgrey? The bottom slider here:
image

@@ -404,11 +424,31 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
self.val = valinit
self.valinit = valinit
if orientation == 'vertical':
self.poly = ax.axhspan(valmin, valinit, 0, 1, **kwargs)
self.hline = ax.axhline(valinit, 0, 1, color=initcolor, lw=1)
self.bkd = Rectangle((.25, 0), .5, 1, transform=ax.transAxes, facecolor=bkd_color)
Copy link
Member

Choose a reason for hiding this comment

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

Can we have a more telling name?

Suggested change
self.bkd = Rectangle((.25, 0), .5, 1, transform=ax.transAxes, facecolor=bkd_color)
self.track = Rectangle((.25, 0), .5, 1, transform=ax.transAxes, facecolor=bkd_color)

seems to be the technical term.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah that's a much better name thanks. I was struggling to find the correct term.

Comment on lines 519 to 521
if event.name == 'button_press_event':
self._handle.set_markeredgecolor(self._handle_color_grabbed)
self._handle.set_markerfacecolor(self._handle_color_grabbed)
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if this action helpful. If sliders have GUI feedback, it's usually already done on hovering to indicate that you have an control element under the cursor. IMHO changing the color after clicking is too late and serves no purpose.

For simplicity, I'd refrain from changing the color at all.

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 did this because I was copying the behavior of ipywidgets sliders without much critical thought 😬.

I have a slight preference for them changing color after selection vs not but I'll happily remove it when I next push here. Reducing the number of new configuration kwargs seems like a good thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That said changing as you mouse over the axes could be nice. I imagine this could be accomplished by using axes_enter_event and axes_leave_event

Copy link
Member

@timhoffm timhoffm Jan 10, 2021

Choose a reason for hiding this comment

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

ipywidgets use color to indicate focus (e.g. which control reacts to the keyboard). I don't think our widgets have a concept of focus.

If you want an effect, see also Button for a mouse-over effect. Though here you might want to additionally check if the cursor is on the knob.

We could also say that the "active" color is the same color as the bar (C0). That would still save us the extra argument. One can always add more configurability later when the need arises.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ipywidgets use color to indicate focus (e.g. which control reacts to the keyboard). I don't think our widgets have a concept of focus.

aaah. I'm fully convinced by this, I'll remove it as it's bad to indicate something that is isn't there.

@WeatherGod
Copy link
Member

WeatherGod commented Jan 10, 2021 via email

@ianhi
Copy link
Contributor Author

ianhi commented Jan 10, 2021

I haven't looked at the changes yet. but how easy is it going to be
to tweak these colors?

The track color has a kwarg dedicated to it + the underlying rect is accesible as a public attribute of the slider, and the blue color has always configurable as **kwargs has always been passed on to axvspan.

@ianhi ianhi mentioned this pull request Jan 10, 2021
3 tasks
@ianhi
Copy link
Contributor Author

ianhi commented Jan 10, 2021

Also: heads up to @t-makaro you may be interested in this on account of animatplot.

@ianhi ianhi force-pushed the style-slider-for-real branch from cc44f7d to b335716 Compare January 12, 2021 22:53
Notes
-----
Additional kwargs are passed on to ``self.poly`` which is the
`~matplotlib.patches.Rectangle` that draws the slider knob. See the
`.Rectangle` documentation for valid property names (``facecolor``,
`~matplotlib.patches.Polygon` that draws the slider knob. See the
Copy link
Contributor Author

Choose a reason for hiding this comment

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

https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.axvspan.html

ax{h,v}span returns a Polygon not a Rectangle patch.

@ianhi
Copy link
Contributor Author

ianhi commented Jan 12, 2021

rebased + squashed and updated the GIF on the first post.
I also added a change the notes of the slider docstring as the self.poly is a Polygon not a Rectangle

@ianhi
Copy link
Contributor Author

ianhi commented Jan 12, 2021

I've also reworked the slider_snap_demo to be an example of many sliders that demonstrates how to style them. (see it here: https://github.com/ianhi/matplotlib/blob/slider-styling-example/examples/widgets/slider_styling.py)
image

Should I include that here or add that as a followup PR?

)
ax.add_patch(self.track)
self.poly = ax.axhspan(valmin, valinit, .25, .75, **kwargs)
self.hline = ax.axhline(valinit, .25, .75, color=initcolor, lw=1)
Copy link
Member

@timhoffm timhoffm Jan 17, 2021

Choose a reason for hiding this comment

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

Suggested change
self.hline = ax.axhline(valinit, .25, .75, color=initcolor, lw=1)
self.hline = ax.axhline(valinit, .15, .85, color=initcolor, lw=1)

The init line extends one pixel more to the right (or bottom for horizontal sliders), which looks a bit awkward.

grafik

I suspect that the effect comes from different to-pixel mappings of lines and rectangles (lines render including both end points; i.e. two lines ending in the same point would draw on top of each other. But rectangles are designed to not overlap if they are side-by-side). - This is just speculation, but I've checked and excluded some other possible reasons (capstyle and snapping).

The cheap solution to get away with a reasonably looking init marker is to let it extend slightly on both sides. The pixel difference is still there, but 2 vs. 3 is less noticeable than 0 vs. 1.

grafik

Same for horizontal slider.

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 agree that this simple solution is the way to go. Though I actually feel it is more noticeable in the horizontal slider in your second screenshot. Maybe this is due to your screenshot program but it looks as though on the vertical slider it is 2 vs 3 (or even the same):
image

whereas on the horizontal slider:
image

@timhoffm
Copy link
Member

Should I include that here or add that as a followup PR?

I recommend a separate PR, because that makes reviewing simpler. (The longer a PR is, the less likely somebody takes the time to review. And the relation is non-linear. 😝 )

Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

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

There are more warnings causing the doc build to fail due to #19415.

Please rebase so that that fix is picked up.

edgecolor color '.75' The edgecolor of the slider handles.
size int 10 The size of the slider handles in points.
========= ===== ======= =========================================
Other values will be transformed as marker{foo} and passed to the
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
Other values will be transformed as marker{foo} and passed to the
Other values will be transformed as marker{foo} and passed to the

@ianhi ianhi force-pushed the style-slider-for-real branch from 1d555c0 to 24ff1a9 Compare February 17, 2021 22:25
@ianhi
Copy link
Contributor Author

ianhi commented Feb 17, 2021

Please rebase so that that fix is picked up.

rebased - thanks for the heads up

@ianhi
Copy link
Contributor Author

ianhi commented Mar 7, 2021

Hi,

I think I've addressed all of the requested revisions. Is it ok to remove the needs revision tag?

Well, perhaps with the exception of the issue of the red line offset #19265 (comment) though I don't think that that is waiting on me

@anntzer
Copy link
Contributor

anntzer commented Mar 7, 2021

Is it ok to remove the needs revision tag?

Yes. (Basically whenever you consider you handled the revision requests.)

@timhoffm
Copy link
Member

timhoffm commented Mar 8, 2021

Well, perhaps with the exception of the issue of the red line offset #19265 (comment) though I don't think that that is waiting on me

Actually, I was waiting on a code change here. IMHO uneven extensions are at least better than one side ending exactly on the line and the other going beyond. Since we cannot be pixel-perfect, the default lines should be a bit wider than the bar.

At a closer look, you are right that .15, .85 work for the vertical slider but not very well for the horizontal slider. I'd be ok if you tune the horizontal slider by using .2, .9 and adding a comment on that. Interestingly, this asymmetric axes coordinates result in a symmetric extension of the line. It seems that for some reason, horizontal and vertical coordinate to pixel mapping is different. If somebody is interested, you're welcome to dig in this. But just using the empirical values is good enough for now. In the worst case we accidentially fix the coordinates and the line will move one pixel again, but that would also not be the end of the world.

@ianhi
Copy link
Contributor Author

ianhi commented Mar 8, 2021

Actually, I was waiting on a code change here.

ack! sorry for misinterpreting.

At a closer look, you are right that .15, .85 work for the vertical slider but not very well for the horizontal slider. I'd be ok if you tune the horizontal slider by using .2, .9 and adding a comment on that. Interestingly, this asymmetric axes coordinates result in a symmetric extension of the line. It seems that for some reason, horizontal and vertical coordinate to pixel mapping is different. If somebody is interested, you're welcome to dig in this.

Oh that's wild. Thanks for finding those values! I've gone with the simple solution for now.

@timhoffm timhoffm added this to the v3.5.0 milestone Apr 20, 2021
@timhoffm
Copy link
Member

Milestoning as this is ready modulo the what's new entry, and we should not miss the next minor release.

@ianhi
Copy link
Contributor Author

ianhi commented Apr 20, 2021

@timhoffm sorry I stalled out here. I was asking on gitter awhile ago about how to show the style in the whats new and @tacaswell expressed concern that these changes are somewhat backwards incompatible as there is not easy way to get the old style back.

@timhoffm
Copy link
Member

Hm ok, maybe that's to be discussed on the dev call. OTOH, this is essentially UI element style change, which I consider less invasive than a plot style change (Any OS I'm using is changing its UI under me all the time).

@timhoffm
Copy link
Member

timhoffm commented Apr 29, 2021

Discussed in the dev call today: Widget apperance is not considered stable API. We can change this in minor releases.

This shoud still get a "What's new" entry.

@jklymak jklymak marked this pull request as draft May 10, 2021 16:28
@ianhi ianhi force-pushed the style-slider-for-real branch from 6b4cbc8 to 91c2e4e Compare June 23, 2021 21:22
@ianhi ianhi marked this pull request as ready for review June 23, 2021 21:23
@ianhi ianhi force-pushed the style-slider-for-real branch from 91c2e4e to 56ae7d3 Compare June 23, 2021 23:40
ianhi and others added 8 commits June 24, 2021 13:13
Goal is to add a clear handle for the user to grab and to provide visual feedback via color change of when the slider has been grabbed.

Simplify slider background rectangles

rename bkd -> track + change default color to lightgrey

lint

remove facecolor from snap demo example

Don't change handle color on grab.

correct errors in slider docstrings

Co-Authored-By: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Co-Authored-By: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Co-Authored-By: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
@ianhi ianhi force-pushed the style-slider-for-real branch from 56ae7d3 to f5dcedd Compare June 24, 2021 17:13
@ianhi
Copy link
Contributor Author

ianhi commented Jun 24, 2021

Rebased to pick up fix for failing tests #20488

Rendered What's new Entry here: https://61099-1385122-gh.circle-artifacts.com/0/doc/build/html/users/next_whats_new/slider_styling.html

@jklymak
Copy link
Member

jklymak commented Jul 4, 2021

Any other widget users want to bless this? Please squash commits unless @ianhi thinks they are all meaningful.

@ianhi
Copy link
Contributor Author

ianhi commented Jul 5, 2021

Any other widget users want to bless this?

Maybe @snowtechblog @redeboer @t-makaro

Please squash commits unless @ianhi thinks they are all meaningful.

They are not - I can squash

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

Not an expert on widgets, but I think @timhoffm gave this a through review.

@jklymak jklymak merged commit 2a7d9bf into matplotlib:master Jul 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New Styling for Sliders
6 participants