Move logx, logy, logc, color-autoscale buttons from toolbar to axes#572
Conversation
…g-buttons-per-axis
| xlabel: str | None = None, | ||
| ylabel: str | None = None, | ||
| norm: Literal['linear', 'log'] | None = None, | ||
| autoscale_axes: Callable | None = None, |
There was a problem hiding this comment.
The View is the one who knows how to properly autoscale the axes because it holds the references to the plotted artists. But the canvas need to call autoscale when the log buttons are clicked. So we pass the callback to the canvas here.
Not the most elegant design but it was the least invasive I could come up with.
|
|
||
| # fontsize = 9 |
There was a problem hiding this comment.
| # fontsize = 9 |
| self.widget = ipw.HTML() | ||
| self.widget = HoverButtonWidget() | ||
| self._update_colorbar_widget() | ||
| # TODO: this doesn't seem to work on widget creation |
| # TODO: When the widget is created, if logc=True as passed in the arguments, | ||
| # we need to set the button state according to the value of logc. | ||
| # For some reason, setting `log_toggle_value` here does not seem to work. | ||
| self.widget.log_toggle_value = self._logc |
There was a problem hiding this comment.
TODO now or later? I don't understand if this comment implies that this new feature does not work at all when passing logc=True?
There was a problem hiding this comment.
Sorry I should have been more clear. I'm still figuring out the last details in this PR.
I marked as ready for review to get early feedback and so people could try it out from the branch, to see if this was the direction we wanted to go in.
Don't worry about the small details here, I am trying to fix it and I added a todo for myself. If I don't manage to fix, I will make the comment clearer and leave it for later. It is only a minor issue of appearance but doesn't break any functionality.
There was a problem hiding this comment.
I now managed to fix the issue by manually calling a style update in the button javascript initialization because trait syncing only happens automatically after the button is displayed.
| if ylabel is not None: | ||
| self.ylabel = ylabel | ||
|
|
||
| def _on_mouse_move(self, event: MouseEvent): |
There was a problem hiding this comment.
We have to use the event when the mouse moves instead of the axes enter/leave event because we want to place the buttons outside of the plotting area so as to not appear over and hide some important data in the plot.
| ) | ||
| out.update(get_repr_maker(npoints=npoints)(self.fig)) | ||
| return out | ||
| return self.figures.ravel()[0]._repr_mimebundle_(*args, **kwargs) |
There was a problem hiding this comment.
Showing the repr from any figure will show the entire figure because the matplotlib axes are part of the same mpl canvas. We just pick the first one.
| CASES1DINTERACTIVE.values(), | ||
| ids=CASES1DINTERACTIVE.keys(), | ||
| ) | ||
| class TestCanvasInteractive1d: |
There was a problem hiding this comment.
These tests were moved to mpl_canvas_test.py.
| CASESINTERACTIVE.values(), | ||
| ids=CASESINTERACTIVE.keys(), | ||
| ) | ||
| class TestColormapperInteractiveCases: |
There was a problem hiding this comment.
The tests for the 2d case were moved to mpl_canvas_test.py.
|
@SimonHeybrock this is now ready for another look as I'm done ironing out all the details. Thanks! |
|
I had no comments myself anymore, but here is what Claude suggests: Solid, well-motivated change: putting per-axes controls on the axes resolves the genuine ambiguity with subplots/tiled/user-supplied axes. Below, ordered by significance. Architecture / design1. Cross-object attribute injection (canvas ⇄ colormapper). self._canvas._toggle_color_norm = self.toggle_norm
self._canvas._autoscale_colors = self.autoscaleand 2. 3. Two parallel button implementations. 2D uses matplotlib Correctness / robustness4. 5. 6. Magic-number hover hit-areas ( Minor / nits
Question on Tiled: |
1.
I do not see how I can pass a method from a colorbar as an argument when the colorbar has not yet been created (at the time of canvas creation)...
I declared them as 2.
The matplotlib figure is the only object that can know how many axes it has. So this was the only place that seemed possible to add.
Fair point, but without an alternative suggestion, the only thing I could think of is to change the list for dicts which would replace the callback in case the same axes were used twice. 3.No other way I could see. You don't want to artificially activate the Once the interactive backend has been activated in a notebook, it is buggy to go back to the static one. 4.
Never happens so I will leave it as is. 5.
Toggling a scale can only work properly if the view's autoscale method is called (otherwise you get garbage from matplotlib). I don't see any use case where a Canvas would be used directly apart from unit tests, where we can control the environment anyway, and make sure errors don't happen. 6.I added explanations for the magic numbers. Minor / nitsAddressed most of those. Question on Tiled:Behaviour verified manually. |
|
Finally: I tested that the new buttons also work in VScode; they do 🙂 |
|
👍 Last thing, should we add a test like this: |
The logx, logy, log and color-autoscale buttons in the toolbar are designed to act on one axes.
The Home, Pan, Zoom, and Save buttons act on all axes in a subplot.
It was ambiguous what to do with the toolbar buttons when subplots/user-supplied axes/tiled were used.
We now move them to being on the axes themselves, appearing upon hover.
1d plot:

2d plot:


3d plot:

Note: for 3d plots we replaced the
ipywidgets.Imagewidget with a customAnywidgetbecause the former does not handle hover or click events.Needs #571