4646import sys
4747import time
4848import warnings
49+ from weakref import WeakKeyDictionary
4950
5051import numpy as np
5152import 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 ):
0 commit comments