Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -2903,6 +2903,7 @@ class NavigationToolbar2:
('Home', 'Reset original view', 'home', 'home'),
('Back', 'Back to previous view', 'back', 'back'),
('Forward', 'Forward to next view', 'forward', 'forward'),
('Views', 'Snapping to views', 'matplotlib', 'view_snap'),
(None, None, None, None),
('Pan',
'Left button pans, Right button zooms\n'
Expand Down Expand Up @@ -3366,6 +3367,9 @@ def save_figure(self, *args):
"""
raise NotImplementedError

def view_snap(self):
pass

def update(self):
"""Reset the Axes stack."""
self._nav_stack.clear()
Expand Down
17 changes: 17 additions & 0 deletions lib/matplotlib/backends/_backend_tk.py
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,23 @@ def save_figure(self, *args):
except Exception as e:
tkinter.messagebox.showerror("Error saving file", str(e))

def view_snap(self, *args):
btn = self._buttons['Views']
self._view_menu = tk.Menu(self, tearoff=0)
def set_view(elev, azim):
ax = self.canvas.figure.gca()
if hasattr(ax, 'view_init'):
ax.view_init(elev=elev, azim=azim)
self.canvas.draw_idle()
self._view_menu.add_command(label="XY Plane", command=lambda: set_view(90, -90))
self._view_menu.add_command(label="XZ Plane", command=lambda: set_view(0, -90))
self._view_menu.add_command(label="YZ Plane", command=lambda: set_view(0, 0))
Comment on lines +958 to +960
Copy link
Owner

Choose a reason for hiding this comment

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

This is wrong. As we had discussed, backends should not have any reference to the view_init function.

Reasoning: As you can see, this needs defining the draw lambda and using them for all backends. But ideally this should be done in a backend independent way. If in the future, someone wants to add another action to the hamburger menu, all backends need a change. That is not acceptable.

Similar to how we defined context_menu to be used for any labels and actions, I think it would be better if a similar thing is implemented here.

self._view_menu.update_idletasks()
x = btn.winfo_rootx()
y = btn.winfo_rooty() - self._view_menu.winfo_reqheight()
self._view_menu.tk_popup(x, y)
self._view_menu.grab_release()

def set_history_buttons(self):
state_map = {True: tk.NORMAL, False: tk.DISABLED}
can_back = self._nav_stack._pos > 0
Expand Down
16 changes: 16 additions & 0 deletions lib/matplotlib/backends/backend_gtk3.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,22 @@ def on_notify_filter(*args):
dialog.run()
dialog.destroy()

def view_snap(self, *args):
widget = args[0]
self._view_menu = Gtk.Menu()
def draw_lambda(elev, azim):
ax = self.canvas.figure.gca()
ax.view_init(elev=elev, azim=azim)
self.canvas.draw()
views = [("XY Plane", 90, -90), ("XZ Plane", 0, -90), ("YZ Plane", 0, 0)]
for name, el, az in views:
item = Gtk.MenuItem(label=name)
item.connect("activate", lambda x, e=el, a=az: draw_lambda(e, a))
self._view_menu.append(item)
self._view_menu.show_all()
self._view_menu.popup_at_widget(widget, Gdk.Gravity.NORTH,
Gdk.Gravity.SOUTH, None)


class ToolbarGTK3(ToolContainerBase, Gtk.Box):
_icon_extension = '-symbolic.svg'
Expand Down
21 changes: 21 additions & 0 deletions lib/matplotlib/backends/backend_gtk4.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,27 @@ def on_response(dialog, response):
dialog.show()
return self.UNKNOWN_SAVED_STATUS

def view_snap(self, *args):
widget = args[0]
self._view_menu = Gtk.Popover()
menu_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
self._view_menu.set_has_arrow(False)
self._view_menu.set_position(Gtk.PositionType.TOP)
self._view_menu.set_child(menu_box)
def draw_lambda(elev, azim):
ax = self.canvas.figure.gca()
ax.view_init(elev=elev, azim=azim)
self.canvas.draw()
self._view_menu.popdown()
views = [("XY Plane", 90, -90), ("XZ Plane", 0, -90), ("YZ Plane", 0, 0)]
for name, el, az in views:
item = Gtk.Button(label=name)
item.set_has_frame(False)
item.connect("clicked", lambda x, e=el, a=az: draw_lambda(e, a))
menu_box.append(item)
self._view_menu.set_parent(widget)
self._view_menu.popup()


class ToolbarGTK4(ToolContainerBase, Gtk.Box):
_icon_extension = '-symbolic.svg'
Expand Down
14 changes: 14 additions & 0 deletions lib/matplotlib/backends/backend_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,20 @@ def save_figure(self, *args):
QtWidgets.QMessageBox.StandardButton.NoButton)
return fname

def view_snap(self, *args):
action = self._actions.get('view_snap')
btn = self.widgetForAction(action)
self._view_menu = QtWidgets.QMenu(self)
def draw_lambda(elev, azim):
ax = self.canvas.figure.gca()
ax.view_init(elev=elev, azim=azim)
self.canvas.draw()
self._view_menu.addAction("XY Plane", lambda: draw_lambda(90, -90))
self._view_menu.addAction("XZ Plane", lambda: draw_lambda(0, -90))
self._view_menu.addAction("YZ Plane", lambda: draw_lambda(0, 0))
point = btn.mapToGlobal(QtCore.QPoint(0, btn.height()))
self._view_menu.exec(point)

def set_history_buttons(self):
can_backward = self._nav_stack._pos > 0
can_forward = self._nav_stack._pos < len(self._nav_stack) - 1
Expand Down
10 changes: 5 additions & 5 deletions lib/mpl_toolkits/mplot3d/axes3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -1546,11 +1546,6 @@ def _on_move(self, event):
if not self.button_pressed:
return

if self.get_navigate_mode() is not None:
# we don't want to rotate if we are zooming/panning
# from the toolbar
return

if self.M is None:
return

Expand All @@ -1563,6 +1558,11 @@ def _on_move(self, event):
w = self._pseudo_w
h = self._pseudo_h

if self.get_navigate_mode() is not None:
# we don't want to rotate if we are zooming/panning
# from the toolbar
return

Comment on lines +1561 to +1565
Copy link
Owner

Choose a reason for hiding this comment

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

This change seems unnecessary?

# Rotation
if self.button_pressed in self._rotate_btn:
# rotate viewing point
Expand Down
Loading