8000 Merge pull request #9359 from anntzer/interactive-nav · matplotlib/matplotlib@39575ed · GitHub
[go: up one dir, main page]

Skip to content

Commit 39575ed

Browse files
authored
Merge pull request #9359 from anntzer/interactive-nav
Keep track of axes in interactive navigation.
2 parents 5c9f49a + cffeef0 commit 39575ed

File tree

2 files changed

+31
-39
lines changed

2 files changed

+31
-39
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import sys
4747
import time
4848
import warnings
49+
from weakref import WeakKeyDictionary
4950

5051
import numpy as np
5152
import matplotlib.cbook as cbook
@@ -2778,9 +2779,7 @@ class NavigationToolbar2(object):
27782779
def __init__(self, canvas):
27792780
self.canvas = canvas
27802781
canvas.toolbar = self
2781-
# a dict from axes index to a list of view limits
2782-
self._views = cbook.Stack()
2783-
self._positions = cbook.Stack() # stack of subplot positions
2782+
self._nav_stack = cbook.Stack()
27842783
self._xypress = None # the location and axis info at the time
27852784
# of the press
27862785
self._idPress = None
@@ -2802,19 +2801,20 @@ def __init__(self, canvas):
28022801
self.set_history_buttons()
28032802

28042803
@partial(canvas.mpl_connect, 'draw_event')
2805-
def define_home(event):
2806-
self.push_current()
2807-
# The decorator sets `define_home` to the callback cid, so we can
2808-
# disconnect it after the first use.
2809-
canvas.mpl_disconnect(define_home)
2804+
def update_stack(event):
2805+
nav_info = self._nav_stack()
2806+
if (nav_info is None # True initial navigation info.
2807+
# An axes has been added or removed, so update the
2808+
# navigation info too.
2809+
or set(nav_info) != set(self.canvas.figure.axes)):
2810+
self.push_current()
28102811

28112812
def set_message(self, s):
28122813
"""Display a message on toolbar or in status bar."""
28132814

28142815
def back(self, *args):
28152816
"""move back up the view lim stack"""
2816-
self._views.back()
2817-
self._positions.back()
2817+
self._nav_stack.back()
28182818
self.set_history_buttons()
28192819
self._update_view()
28202820

@@ -2833,15 +2833,13 @@ def remove_rubberband(self):
28332833

28342834
def forward(self, *args):
28352835
"""Move forward in the view lim stack."""
2836-
self._views.forward()
2837-
self._positions.forward()
2836+
self._nav_stack.forward()
28382837
self.set_history_buttons()
28392838
self._update_view()
28402839

28412840
def home(self, *args):
28422841
"""Restore the original view."""
2843-
self._views.home()
2844-
self._positions.home()
2842+
self._nav_stack.home()
28452843
self.set_history_buttons()
28462844
self._update_view()
28472845

@@ -3018,16 +3016,13 @@ def _switch_off_zoom_mode(self, event):
30183016

30193017
def push_current(self):
30203018
"""Push the current view limits and position onto the stack."""
3021-
views = []
3022-
pos = []
3023-
for a in self.canvas.figure.get_axes():
3024-
views.append(a._get_view())
3025-
# Store both the original and modified positions
3026-
pos.append((
3027-
a.get_position(True).frozen(),
3028-
a.get_position().frozen()))
3029-
self._views.push(views)
3030-
self._positions.push(pos)
3019+
self._nav_stack.push(
3020+
WeakKeyDictionary(
3021+
{ax: (ax._get_view(),
3022+
# Store both the original and modified positions.
3023+
(ax.get_position(True).frozen(),
3024+
ax.get_position().frozen()))
3025+
for ax in self.canvas.figure.axes}))
30313026
self.set_history_buttons()
30323027

30333028
def release(self, event):
@@ -3148,19 +3143,17 @@ def _update_view(self):
31483143
"""Update the viewlim and position from the view and
31493144
position stack for each axes.
31503145
"""
3151-
3152-
views = self._views()
3153-
if views is None:
3154-
return
3155-
pos = self._positions()
3156-
if pos is None:
3146+
nav_info = self._nav_stack()
3147+
if nav_info is None:
31573148
return
3158-
for i, a in enumerate(self.canvas.figure.get_axes()):
3159-
a._set_view(views[i])
3149+
# Retrieve all items at once to avoid any risk of GC deleting an Axes
3150+
# while in the middle of the loop below.
3151+
items = list(nav_info.items())
3152+
for ax, (view, (pos_orig, pos_active)) in items:
3153+
ax._set_view(view)
31603154
# Restore both the original and modified positions
3161-
a.set_position(pos[i][0], 'original')
3162-
a.set_position(pos[i][1], 'active')
3163-
3155+
ax.set_position(pos_orig, 'original')
3156+
ax.set_position(pos_active, 'active')
31643157
self.canvas.draw_idle()
31653158

31663159
def save_figure(self, *args):
@@ -3178,8 +3171,7 @@ def set_cursor(self, cursor):
31783171

31793172
def update(self):
31803173
"""Reset the axes stack."""
3181-
self._views.clear()
3182-
self._positions.clear()
3174+
self._nav_stack.clear()
31833175
self.set_history_buttons()
31843176

31853177
def zoom(self, *args):

lib/matplotlib/backends/backend_wx.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,8 +1703,8 @@ def set_message(self, s):
17031703
self.statbar.set_function(s)
17041704

17051705
def set_history_buttons(self):
1706-
can_backward = (self._views._pos > 0)
1707-
can_forward = (self._views._pos < len(self._views._elements) - 1)
1706+
can_backward = self._nav_stack._pos > 0
1707+
can_forward = self._nav_stack._pos < len(self._nav_stack._elements) - 1
17081708
self.EnableTool(self.wx_ids['Back'], can_backward)
17091709
self.EnableTool(self.wx_ids['Forward'], can_forward)
17101710

0 commit comments

Comments
 (0)
0