1from __future__ import (absolute_import, division, print_function, 2 unicode_literals) 3 4import os 5 6from matplotlib._pylab_helpers import Gcf 7from matplotlib.backend_bases import ( 8 _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, 9 TimerBase) 10 11from matplotlib.figure import Figure 12from matplotlib import rcParams 13 14from matplotlib.widgets import SubplotTool 15 16import matplotlib 17from matplotlib.backends import _macosx 18 19from .backend_agg import FigureCanvasAgg 20 21 22######################################################################## 23# 24# The following functions and classes are for pylab and implement 25# window/figure managers, etc... 26# 27######################################################################## 28 29 30class TimerMac(_macosx.Timer, TimerBase): 31 ''' 32 Subclass of :class:`backend_bases.TimerBase` that uses CoreFoundation 33 run loops for timer events. 34 35 Attributes 36 ---------- 37 interval : int 38 The time between timer events in milliseconds. Default is 1000 ms. 39 single_shot : bool 40 Boolean flag indicating whether this timer should operate as single 41 shot (run once and then stop). Defaults to False. 42 callbacks : list 43 Stores list of (func, args) tuples that will be called upon timer 44 events. This list can be manipulated directly, or the functions 45 `add_callback` and `remove_callback` can be used. 46 47 ''' 48 # completely implemented at the C-level (in _macosx.Timer) 49 50 51class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasAgg): 52 """ 53 The canvas the figure renders into. Calls the draw and print fig 54 methods, creates the renderers, etc... 55 56 Events such as button presses, mouse movements, and key presses 57 are handled in the C code and the base class methods 58 button_press_event, button_release_event, motion_notify_event, 59 key_press_event, and key_release_event are called from there. 60 61 Attributes 62 ---------- 63 figure : `matplotlib.figure.Figure` 64 A high-level Figure instance 65 66 """ 67 68 def __init__(self, figure): 69 FigureCanvasBase.__init__(self, figure) 70 width, height = self.get_width_height() 71 _macosx.FigureCanvas.__init__(self, width, height) 72 self._device_scale = 1.0 73 74 def _set_device_scale(self, value): 75 if self._device_scale != value: 76 self.figure.dpi = self.figure.dpi / self._device_scale * value 77 self._device_scale = value 78 79 def _draw(self): 80 renderer = self.get_renderer(cleared=self.figure.stale) 81 82 if self.figure.stale: 83 self.figure.draw(renderer) 84 85 return renderer 86 87 def draw(self): 88 self.invalidate() 89 self.flush_events() 90 91 def draw_idle(self, *args, **kwargs): 92 self.invalidate() 93 94 def blit(self, bbox): 95 self.invalidate() 96 97 def resize(self, width, height): 98 dpi = self.figure.dpi 99 width /= dpi 100 height /= dpi 101 self.figure.set_size_inches(width * self._device_scale, 102 height * self._device_scale, 103 forward=False) 104 FigureCanvasBase.resize_event(self) 105 self.draw_idle() 106 107 def new_timer(self, *args, **kwargs): 108 """ 109 Creates a new backend-specific subclass of `backend_bases.Timer`. 110 This is useful for getting periodic events through the backend's native 111 event loop. Implemented only for backends with GUIs. 112 113 Other Parameters 114 ---------------- 115 interval : scalar 116 Timer interval in milliseconds 117 callbacks : list 118 Sequence of (func, args, kwargs) where ``func(*args, **kwargs)`` 119 will be executed by the timer every *interval*. 120 """ 121 return TimerMac(*args, **kwargs) 122 123 124class FigureManagerMac(_macosx.FigureManager, FigureManagerBase): 125 """ 126 Wrap everything up into a window for the pylab interface 127 """ 128 def __init__(self, canvas, num): 129 FigureManagerBase.__init__(self, canvas, num) 130 title = "Figure %d" % num 131 _macosx.FigureManager.__init__(self, canvas, title) 132 if rcParams['toolbar']=='toolbar2': 133 self.toolbar = NavigationToolbar2Mac(canvas) 134 else: 135 self.toolbar = None 136 if self.toolbar is not None: 137 self.toolbar.update() 138 139 def notify_axes_change(fig): 140 'this will be called whenever the current axes is changed' 141 if self.toolbar != None: self.toolbar.update() 142 self.canvas.figure.add_axobserver(notify_axes_change) 143 144 if matplotlib.is_interactive(): 145 self.show() 146 self.canvas.draw_idle() 147 148 def close(self): 149 Gcf.destroy(self.num) 150 151 152class NavigationToolbar2Mac(_macosx.NavigationToolbar2, NavigationToolbar2): 153 154 def __init__(self, canvas): 155 NavigationToolbar2.__init__(self, canvas) 156 157 def _init_toolbar(self): 158 basedir = os.path.join(rcParams['datapath'], "images") 159 _macosx.NavigationToolbar2.__init__(self, basedir) 160 161 def draw_rubberband(self, event, x0, y0, x1, y1): 162 self.canvas.set_rubberband(int(x0), int(y0), int(x1), int(y1)) 163 164 def release(self, event): 165 self.canvas.remove_rubberband() 166 167 def set_cursor(self, cursor): 168 _macosx.set_cursor(cursor) 169 170 def save_figure(self, *args): 171 filename = _macosx.choose_save_file('Save the figure', 172 self.canvas.get_default_filename()) 173 if filename is None: # Cancel 174 return 175 self.canvas.figure.savefig(filename) 176 177 def prepare_configure_subplots(self): 178 toolfig = Figure(figsize=(6,3)) 179 canvas = FigureCanvasMac(toolfig) 180 toolfig.subplots_adjust(top=0.9) 181 tool = SubplotTool(self.canvas.figure, toolfig) 182 return canvas 183 184 def set_message(self, message): 185 _macosx.NavigationToolbar2.set_message(self, message.encode('utf-8')) 186 187 188######################################################################## 189# 190# Now just provide the standard names that backend.__init__ is expecting 191# 192######################################################################## 193 194@_Backend.export 195class _BackendMac(_Backend): 196 FigureCanvas = FigureCanvasMac 197 FigureManager = FigureManagerMac 198 199 @staticmethod 200 def trigger_manager_draw(manager): 201 # For performance reasons, we don't want to redraw the figure after 202 # each draw command. Instead, we mark the figure as invalid, so that it 203 # will be redrawn as soon as the event loop resumes via PyOS_InputHook. 204 # This function should be called after each draw event, even if 205 # matplotlib is not running interactively. 206 manager.canvas.invalidate() 207 208 @staticmethod 209 def mainloop(): 210 _macosx.show() 211