Skip to content

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

@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

The orientation of the buttons: 'vertical' (default), or 'horizontal'.
"""
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

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 QuLogic force-pushed the horizontalRadioButtons branch from f76df0a to b82537a Compare August 21, 2024 22:08
@QuLogic QuLogic modified the milestones: v3.10.0, v3.11.0 Oct 9, 2024
@rbroders
Copy link

Are you guys still working on this? Its been 5 years for what seems like a trivial (but very useful) feature

@doronbehar
Copy link
Contributor

I'm using this patch locally and it has been working fine for me for a while now.

@mromanie
Copy link
Contributor Author

mromanie commented Mar 12, 2025 via email

.. versionadded:: 3.7
layout_direction : {'vertical', 'horizontal'}
The orientation of the buttons: 'vertical' places buttons from top
to bottom, 'horizontal' places buttons from left to right.
Copy link
Member

@timhoffm timhoffm Mar 12, 2025

Choose a reason for hiding this comment

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

Suggested change
to bottom, 'horizontal' places buttons from left to right.
to bottom, 'horizontal' places buttons from left to right, distributing
the buttons across the whole Axes. The Axes is divided into equal-sized
boxes, and each button is left-aligned in the box. There is currently no
size check with the associated labels, so that long labels may overlap
with the next box.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I did not check what this actually does:

grafik

I strongly think we should follow standard conventions that labels are right of the button not above, because I consider the unusual layout a UX issue. See also #27946 (comment).

grafik

The orientation of the buttons: 'vertical' places buttons from top
to bottom, 'horizontal' places buttons from left to right.
.. versionadded:: 3.10
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
.. versionadded:: 3.10
.. versionadded:: 3.11

@github-actions
Copy link

github-actions bot commented Jun 6, 2025

Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you need a review or guidance to move the PR forward! If you do not plan on continuing the work, please let us know so that we can either find someone to take the PR over, or close it.

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Jun 6, 2025
@story645 story645 added keep Items to be ignored by the “Stale” Github Action and removed status: inactive Marked by the “Stale” Github Action labels Jun 6, 2025
@story645
Copy link
Member

story645 commented Jun 6, 2025

It looks like there isn't much left to do here, @mromanie do you have the bandwidth to do so or are you okay w/ someone else closing this out?

@timhoffm
Copy link
Member

timhoffm commented Jun 6, 2025

It looks like there isn't much left to do here

Um, I disagree #13374 (comment)

@mromanie
Copy link
Contributor Author

mromanie commented Jun 6, 2025 via email

@story645
Copy link
Member

story645 commented Jun 6, 2025

It looks like there isn't much left to do here

Um, I disagree #13374 (comment)

To me put labels next to rather than on top reads like a relatively small/clear change if there's agreement that that should be the position.

What am I missing here?

@mromanie
Copy link
Contributor Author

mromanie commented Jun 6, 2025 via email

@timhoffm
Copy link
Member

timhoffm commented Jun 6, 2025

o me put labels next to rather than on top reads like a relatively small/clear change if there's agreement that that should be the position.

What am I missing here?

That depends on your size of small 😆. Putting the buttons above the text a bit simpler because you only calculate the centers and center-align text and button to these coordianates. For horizontal, you have to think a bit more: What is the starting point for each buttom+text group, how much offset does the text need from the button? It's not terribly complicated, but needs a bit more effort.

@marko-pi
Copy link

marko-pi commented Oct 22, 2025

For my purposes, I would prefer the labels to the right of the circles. Horizontal radio buttons are supposed to be used when vertical space is limited. Placing labels above the circles reduces the efficiency of the solution.
It can also be used instead of dropdown menus, which also do not exist.
Is there any chance that this will be implemented soon?

@timhoffm
Copy link
Member

Is there any chance that this will be implemented soon?

This is not a priority of the core developers. So unless somebody steps up to contribute, it won’t be implemented soon.

@story645
Copy link
Member

So unless somebody steps up to contribute, it won’t be implemented soon.

Just to add to this, one way to contribute is to take over this orphaned PR and get it to the finish line by addressing/implementing the feedback in #13374 (comment)

doronbehar added a commit to doronbehar/matplotlib that referenced this pull request Dec 1, 2025
The RadioButtons widget now supports arranging buttons in a 2D grid by
passing a list of lists of strings as the labels parameter. Each inner
list represents a row in the grid.

Key features:
- Active index and index_selected remain as single integers for the
  flattened array (reading left-to-right, top-to-bottom)
- Column positions are automatically calculated based on the maximum
  text width in each column for optimal spacing
- Text offset is now consistent between 1D and 2D layouts (0.10)
- Includes new example: galleries/examples/widgets/radio_buttons_grid.py

Closes matplotlib#13374

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@doronbehar
Copy link
Contributor

I implemented this feature slightly more generally in:

Reviews are welcome :).

doronbehar added a commit to doronbehar/matplotlib that referenced this pull request Dec 1, 2025
The RadioButtons widget now supports arranging buttons in a 2D grid by
passing a list of lists of strings as the labels parameter. Each inner
list represents a row in the grid.

Key features:
- Active index and index_selected remain as single integers for the
  flattened array (reading left-to-right, top-to-bottom)
- Column positions are automatically calculated based on the maximum
  text width in each column for optimal spacing
- Text offset is now consistent between 1D and 2D layouts (0.10)
- Includes new example: galleries/examples/widgets/radio_buttons_grid.py

Closes matplotlib#13374

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
doronbehar added a commit to doronbehar/matplotlib that referenced this pull request Dec 1, 2025
The RadioButtons widget now supports arranging buttons in a 2D grid by
passing a list of lists of strings as the labels parameter. Each inner
list represents a row in the grid.

Key features:
- Active index and index_selected remain as single integers for the
  flattened array (reading left-to-right, top-to-bottom)
- Column positions are automatically calculated based on the maximum
  text width in each column for optimal spacing
- Text offset is now consistent between 1D and 2D layouts (0.10)
- Includes new example: galleries/examples/widgets/radio_buttons_grid.py

Closes matplotlib#13374

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
doronbehar added a commit to doronbehar/matplotlib that referenced this pull request Dec 5, 2025
The RadioButtons widget now supports arranging buttons in a 2D grid by
passing a list of lists of strings as the labels parameter. Each inner
list represents a row in the grid.

Key features:
- Active index and index_selected remain as single integers for the
  flattened array (reading left-to-right, top-to-bottom)
- Column positions are automatically calculated based on the maximum
  text width in each column for optimal spacing
- Text offset is now consistent between 1D and 2D layouts (0.10)
- Includes new example: galleries/examples/widgets/radio_buttons_grid.py

Closes matplotlib#13374

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
doronbehar added a commit to doronbehar/matplotlib that referenced this pull request Dec 7, 2025
The RadioButtons widget now supports arranging buttons in a 2D grid by
passing a list of lists of strings as the labels parameter. Each inner
list represents a row in the grid.

Key features:
- Active index and index_selected remain as single integers for the
  flattened array (reading left-to-right, top-to-bottom)
- Column positions are automatically calculated based on the maximum
  text width in each column for optimal spacing
- Text offset is now consistent between 1D and 2D layouts (0.10)
- Includes new example: galleries/examples/widgets/radio_buttons_grid.py

Closes matplotlib#13374

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
doronbehar added a commit to doronbehar/matplotlib that referenced this pull request Dec 7, 2025
The RadioButtons widget now supports arranging buttons in a 2D grid by
passing a list of lists of strings as the labels parameter. Each inner
list represents a row in the grid.

Key features:
- Active index and index_selected remain as single integers for the
  flattened array (reading left-to-right, top-to-bottom)
- Column positions are automatically calculated based on the maximum
  text width in each column for optimal spacing
- Text offset is now consistent between 1D and 2D layouts (0.10)
- Includes new example: galleries/examples/widgets/radio_buttons_grid.py

Closes matplotlib#13374

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

keep Items to be ignored by the “Stale” Github Action New feature status: orphaned PR topic: widgets/UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.