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

Horizontal radio buttons #13374

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mromanie
Copy link
Contributor

@mromanie mromanie commented Feb 6, 2019

PR Summary

Add the option to have horizontal RadioButtons. A new optional keyword argument 'direction' is introduced to control it. The new parameter defaults to 'vertical' for backwards compatibility.

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

lib/matplotlib/widgets.py Outdated Show resolved Hide resolved
@jklymak
Copy link
Member

jklymak commented Feb 6, 2019

flake8 needs to pass 😉 https://travis-ci.org/matplotlib/matplotlib/jobs/489577517

Copy link
Member

@NelleV NelleV left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @mromanie !
Here are a couple of comments. I'll do a more thorough review once these are addressed.

Can you in addition add a what's new entry? See doc/users/next_whats_new/README.rst

"""
if orientation not in ['vertical', 'horizontal']:
raise ValueError("Invalid RadioButton orientation: %s" % orientation)
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 add what are the possible values here?
Can you also add a mock test to make sure it runs, as well as a test to make sure this exception is raised properly.

I also think we need to update the examples to show case this (examples/widgets/radio_buttons.py)

Copy link
Member

Choose a reason for hiding this comment

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

We have a shortcut function to check options like this and raise an appropriate error now, cbook._check_in_list

@@ -1007,7 +1007,12 @@ def __init__(self, ax, labels, active=0, activecolor='blue'):
The index of the initially selected button.
activecolor : color
The color of the selected button.
orientation : str
The orientation of the buttons: 'vertical' (default), or 'horizontal'.
Copy link
Member

Choose a reason for hiding this comment

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

The keyword being a bit confusing here, I think it's worth detailing a bit more what orientation means (which is the set of radio buttons are on the same horizontal axis or vertical axis).

@NelleV
Copy link
Member

NelleV commented Feb 6, 2019

For the failing flake8 test, I would suggest adding the check directly to your text editor.

@timhoffm timhoffm added this to the v3.2.0 milestone Feb 16, 2019
@timhoffm
Copy link
Member

Milestoning 3.2 as there has not been activity recently. @mromanie are you still interested to work on this?

@mromanie
Copy link
Contributor Author

@timhoffm Apologies for my inactivity. I am indeed still very much interested in working on this. In fact, I think I managed to do it properly by using patches.Ellipse instead of patches.Circle and stretching them to look circular using the aspects of the axes and figure. In this way, the entire surface of the buttons is sensitive, unlike the current implementation with patches.Circle.

I still need to clean up the auto-scaling of the size of the symbols, which at the moment still results in the symbols to overlap under certain circumstances, and I'll submit the whole lot for review. Shall I use the same PR for this?

@ImportanceOfBeingErnest
Copy link
Member

What about using a PathCollection with a circle marker, such that cicles always stay circles independent on the figure- or axes- dimension or aspect?

@mromanie
Copy link
Contributor Author

mromanie commented Feb 17, 2019

@ImportanceOfBeingErnest I'm not familiar with PathCollection, so I don't know what are the advantages/disadvantages. The gist of what I have implemented is as follows, which seems to do a reasonable job:

fig = ax.get_figure()
fh, fw = fig.get_figheight(), fig.get_figwidth()
rpos = ax.get_position().get_points()
rscale = (rpos[:,0].ptp() / rpos[:,1].ptp()) * (fw / fh)
circle_radius = 0.25
p = Ellipse(xy=(0.15, y), width=circle_radius, height=circle_radius*rscale, edgecolor='black', facecolor=facecolor, transform=ax.transAxes)

Plus a couple more things to make it backwards compatible. Like I said earlier, setting circle_radius to a fixed value is not always satisfactory and I' fine-tuning it.

@mromanie
Copy link
Contributor Author

...forgot to say, the condition to activate the Ellipse button is:

((xy[0] - p.get_center()[0])/p.width)**2 + ((xy[1] - p.get_center()[1])/p.height)**2 <= 1

@ImportanceOfBeingErnest
Copy link
Member

If you plot a scatter plot with circular markers (marker="o") you may have noticed that those markers will stay circles even if you resize the figure, change the aspect or zoom into the plot. This is achieved inside the PathCollection by defining the circle path in display coordinates and using an offset transform to shift those circles at the respective positions in data coordinates. I would think the same can be done here. The advantage compared to the strategy above would be that the bullets will keep their size when resizing the figure after it has first appeared on screen.
In addition, checking the clicks on the bullets could be simplified by using a pick_event.

@mromanie
Copy link
Contributor Author

OK, thanks!

All things considered, I would stick to the solution with Ellipse because:

  • Zooming is disabled for the axes containing the RadioButtons.
  • It is true that the Ellipse looses its circular shape when the entire window is resized, but I'm not sure that this is a problem.
  • The solution entails minimal changes wrt the current implementation.
  • It is straightforward to make it backwards-compatible by mimicking the current behaviour.

@ImportanceOfBeingErnest
Copy link
Member

Not sure what the status is here. Since someone asked a question about horizontal buttons on stackoverflow, I thought it might be worth showing a solution over there: https://stackoverflow.com/questions/55095111/displaying-radio-buttons-horizontally-in-matplotlib/55102639#55102639

Of course this could also be used for this update.

@tacaswell tacaswell modified the milestones: v3.2.0, v3.3.0 Sep 5, 2019
@QuLogic QuLogic modified the milestones: v3.3.0, v3.4.0 Apr 30, 2020
@QuLogic
Copy link
Member

QuLogic commented Oct 3, 2020

This looks mostly done, but needs a rebase and a small tweak to the checks. The squashing is something that affects vertical buttons too, so could be a separate PR.

@QuLogic QuLogic modified the milestones: v3.4.0, v3.5.0 Jan 27, 2021
@jklymak jklymak marked this pull request as draft May 8, 2021 17:07
@QuLogic QuLogic modified the milestones: v3.5.0, v3.6.0 Aug 18, 2021
@timhoffm timhoffm modified the milestones: v3.6.0, unassigned Apr 30, 2022
@story645 story645 removed this from the unassigned milestone Oct 6, 2022
@QuLogic
Copy link
Member

QuLogic commented Mar 19, 2024

Selecting by closest button is now merged as #13268. Using a scatter plot to ensure circular buttons is merged as #24474.

I pushed a rebase, dropping the old changes, fixed the review comments and adding a test/what's new entry. I also modified the implementation a bit so that it modifies the placement of the buttons instead of reversing the labels (as the latter has ramifications for the active index.)

I'm also working on implementing the same change for CheckButtons.

@QuLogic
Copy link
Member

QuLogic commented Mar 19, 2024

@QuLogic QuLogic marked this pull request as ready for review March 19, 2024 03:22
A new optional keyword argument 'orientation' is introduced to control
it. The new parameter defaults to 'vertical' for backwards
compatibility.
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.

None yet

10 participants