|
46 | 46 | import sys |
47 | 47 | import time |
48 | 48 | import warnings |
| 49 | +from weakref import WeakKeyDictionary |
49 | 50 |
|
50 | 51 | import numpy as np |
51 | 52 | import matplotlib.cbook as cbook |
@@ -2799,15 +2800,11 @@ def __init__(self, canvas): |
2799 | 2800 | @partial(canvas.mpl_connect, 'draw_event') |
2800 | 2801 | def update_stack(event): |
2801 | 2802 | nav_info = self._nav_stack() |
2802 | | - if nav_info is None: |
2803 | | - # Define the true initial navigation info. |
2804 | | - self.push_current() |
2805 | | - else: |
2806 | | - axes, views, positions = nav_info |
2807 | | - if axes != self.canvas.figure.axes: |
| 2803 | + if (nav_info is None # True initial navigation info. |
2808 | 2804 | # An axes has been added or removed, so update the |
2809 | 2805 | # navigation info too. |
2810 | | - self.push_current() |
| 2806 | + or set(nav_info) != set(self.canvas.figure.axes)): |
| 2807 | + self.push_current() |
2811 | 2808 |
|
2812 | 2809 | def set_message(self, s): |
2813 | 2810 | """Display a message on toolbar or in status bar.""" |
@@ -3016,13 +3013,13 @@ def _switch_off_zoom_mode(self, event): |
3016 | 3013 |
|
3017 | 3014 | def push_current(self): |
3018 | 3015 | """Push the current view limits and position onto the stack.""" |
3019 | | - axs = self.canvas.figure.axes |
3020 | | - views = [ax._get_view() for ax in axs] |
3021 | | - # Store both the original and modified positions. |
3022 | | - positions = [ |
3023 | | - (ax.get_position(True).frozen(), ax.get_position().frozen()) |
3024 | | - for ax in axs] |
3025 | | - self._nav_stack.push((axs, views, positions)) |
| 3016 | + self._nav_stack.push( |
| 3017 | + WeakKeyDictionary( |
| 3018 | + {ax: (ax._get_view(), |
| 3019 | + # Store both the original and modified positions. |
| 3020 | + (ax.get_position(True).frozen(), |
| 3021 | + ax.get_position().frozen())) |
| 3022 | + for ax in self.canvas.figure.axes})) |
3026 | 3023 | self.set_history_buttons() |
3027 | 3024 |
|
3028 | 3025 | def release(self, event): |
@@ -3143,16 +3140,17 @@ def _update_view(self): |
3143 | 3140 | """Update the viewlim and position from the view and |
3144 | 3141 | position stack for each axes. |
3145 | 3142 | """ |
3146 | | - |
3147 | 3143 | nav_info = self._nav_stack() |
3148 | 3144 | if nav_info is None: |
3149 | 3145 | return |
3150 | | - axs, views, pos = nav_info |
3151 | | - for i, a in enumerate(self.canvas.figure.get_axes()): |
3152 | | - a._set_view(views[i]) |
| 3146 | + # Retrieve all items at once to avoid any risk of GC deleting an Axes |
| 3147 | + # while in the middle of the loop below. |
| 3148 | + items = list(nav_info.items()) |
| 3149 | + for ax, (view, (pos_orig, pos_active)) in items: |
| 3150 | + ax._set_view(view) |
3153 | 3151 | # Restore both the original and modified positions |
3154 | | - a.set_position(pos[i][0], 'original') |
3155 | | - a.set_position(pos[i][1], 'active') |
| 3152 | + ax.set_position(pos_orig, 'original') |
| 3153 | + ax.set_position(pos_active, 'active') |
3156 | 3154 | self.canvas.draw_idle() |
3157 | 3155 |
|
3158 | 3156 | def save_figure(self, *args): |
|
0 commit comments