4
4
from matplotlib .externals import six
5
5
6
6
import os
7
- import numpy
8
7
9
8
from matplotlib ._pylab_helpers import Gcf
10
- from matplotlib .backend_bases import RendererBase , GraphicsContextBase , \
11
- FigureManagerBase , FigureCanvasBase , NavigationToolbar2 , TimerBase
9
+ from matplotlib .backend_bases import FigureManagerBase , FigureCanvasBase , \
10
+ NavigationToolbar2 , TimerBase
12
11
from matplotlib .backend_bases import ShowBase
13
12
14
- from matplotlib .cbook import maxdict
15
13
from matplotlib .figure import Figure
16
- from matplotlib .path import Path
17
- from matplotlib .mathtext import MathTextParser
18
- from matplotlib .colors import colorConverter
19
14
from matplotlib import rcParams
20
15
21
16
from matplotlib .widgets import SubplotTool
22
17
23
18
import matplotlib
24
19
from matplotlib .backends import _macosx
25
20
21
+ from .backend_agg import RendererAgg , FigureCanvasAgg
22
+
26
23
27
24
class Show (ShowBase ):
28
25
def mainloop (self ):
29
26
_macosx .show ()
30
27
show = Show ()
31
28
32
29
33
- class RendererMac (RendererBase ):
34
- """
35
- The renderer handles drawing/rendering operations. Most of the renderer's
36
- methods forward the command to the renderer's graphics context. The
37
- renderer does not wrap a C object and is written in pure Python.
38
- """
39
-
40
- texd = maxdict (50 ) # a cache of tex image rasters
41
-
42
- def __init__ (self , dpi , width , height ):
43
- RendererBase .__init__ (self )
44
- self .dpi = dpi
45
- self .width = width
46
- self .height = height
47
- self .gc = GraphicsContextMac ()
48
- self .gc .set_dpi (self .dpi )
49
- self .mathtext_parser = MathTextParser ('MacOSX' )
50
-
51
- def set_width_height (self , width , height ):
52
- self .width , self .height = width , height
53
-
54
- def draw_path (self , gc , path , transform , rgbFace = None ):
55
- if rgbFace is not None :
56
- rgbFace = tuple (rgbFace )
57
- linewidth = gc .get_linewidth ()
58
- gc .draw_path (path , transform , linewidth , rgbFace )
59
-
60
- def draw_markers (self , gc , marker_path , marker_trans , path , trans , rgbFace = None ):
61
- if rgbFace is not None :
62
- rgbFace = tuple (rgbFace )
63
- linewidth = gc .get_linewidth ()
64
- gc .draw_markers (marker_path , marker_trans , path , trans , linewidth , rgbFace )
65
-
66
- def draw_path_collection (self , gc , master_transform , paths , all_transforms ,
67
- offsets , offsetTrans , facecolors , edgecolors ,
68
- linewidths , linestyles , antialiaseds , urls ,
69
- offset_position ):
70
- if offset_position == 'data' :
71
- offset_position = True
72
- else :
73
- offset_position = False
74
- path_ids = []
75
- for path , transform in self ._iter_collection_raw_paths (
76
- master_transform , paths , all_transforms ):
77
- path_ids .append ((path , transform ))
78
- master_transform = master_transform .get_matrix ()
79
- offsetTrans = offsetTrans .get_matrix ()
80
- gc .draw_path_collection (master_transform , path_ids , all_transforms ,
81
- offsets , offsetTrans , facecolors , edgecolors ,
82
- linewidths , linestyles , antialiaseds ,
83
- offset_position )
84
-
85
- def draw_quad_mesh (self , gc , master_transform , meshWidth , meshHeight ,
86
- coordinates , offsets , offsetTrans , facecolors ,
87
- antialiased , edgecolors ):
88
- gc .draw_quad_mesh (master_transform .get_matrix (),
89
- meshWidth ,
90
- meshHeight ,
91
- coordinates ,
92
- offsets ,
93
- offsetTrans .get_matrix (),
94
- facecolors ,
95
- antialiased ,
96
- edgecolors )
97
-
98
- def new_gc (self ):
99
- self .gc .save ()
100
- self .gc .set_hatch (None )
101
- self .gc ._alpha = 1.0
102
- self .gc ._forced_alpha = False # if True, _alpha overrides A from RGBA
103
- return self .gc
104
-
105
- def draw_gouraud_triangle (self , gc , points , colors , transform ):
106
- points = transform .transform (points )
107
- gc .draw_gouraud_triangle (points , colors )
108
-
109
- def get_image_magnification (self ):
110
- return self .gc .get_image_magnification ()
111
-
112
- def draw_image (self , gc , x , y , im ):
113
- nrows , ncols , data = im .as_rgba_str ()
114
- gc .draw_image (x , y , nrows , ncols , data )
115
-
116
- def draw_tex (self , gc , x , y , s , prop , angle , ismath = 'TeX!' , mtext = None ):
117
- # todo, handle props, angle, origins
118
- scale = self .gc .get_image_magnification ()
119
- size = prop .get_size_in_points ()
120
- texmanager = self .get_texmanager ()
121
- key = s , size , self .dpi , angle , texmanager .get_font_config ()
122
- im = self .texd .get (key ) # Not sure what this does; just copied from backend_agg.py
123
- if im is None :
124
- Z = texmanager .get_grey (s , size , self .dpi * scale )
125
- Z = numpy .array (255.0 - Z * 255.0 , numpy .uint8 )
126
-
127
- gc .draw_mathtext (x , y , angle , Z )
128
-
129
- def _draw_mathtext (self , gc , x , y , s , prop , angle ):
130
- scale = self .gc .get_image_magnification ()
131
- ox , oy , width , height , descent , image , used_characters = \
132
- self .mathtext_parser .parse (s , self .dpi * scale , prop )
133
- descent /= scale
134
- xd = descent * numpy .sin (numpy .deg2rad (angle ))
135
- yd = descent * numpy .cos (numpy .deg2rad (angle ))
136
- x = numpy .round (x + ox + xd )
137
- y = numpy .round (y + oy - yd )
138
- gc .draw_mathtext (x , y , angle , 255 - image .as_array ())
139
-
140
- def draw_text (self , gc , x , y , s , prop , angle , ismath = False , mtext = None ):
141
- if ismath :
142
- self ._draw_mathtext (gc , x , y , s , prop , angle )
143
- else :
144
- family = prop .get_family ()
145
- weight = prop .get_weight ()
146
- # transform weight into string for the native backend
147
- if weight >= 700 :
148
- weight = 'bold'
149
- else :
150
- weight = 'normal'
151
- style = prop .get_style ()
152
- points = prop .get_size_in_points ()
153
- size = self .points_to_pixels (points )
154
- gc .draw_text (x , y , six .text_type (s ), family , size , weight , style , angle )
155
-
156
- def get_text_width_height_descent (self , s , prop , ismath ):
157
- if ismath == 'TeX' :
158
- # todo: handle props
159
- texmanager = self .get_texmanager ()
160
- fontsize = prop .get_size_in_points ()
161
- w , h , d = texmanager .get_text_width_height_descent (s , fontsize ,
162
- renderer = self )
163
- return w , h , d
164
- if ismath :
165
- ox , oy , width , height , descent , fonts , used_characters = \
166
- self .mathtext_parser .parse (s , self .dpi , prop )
167
- return width , height , descent
168
- family = prop .get_family ()
169
- weight = prop .get_weight ()
170
- # transform weight into string for the native backend
171
- if weight >= 700 :
172
- weight = 'bold'
173
- else :
174
- weight = 'normal'
175
- style = prop .get_style ()
176
- points = prop .get_size_in_points ()
177
- size = self .points_to_pixels (points )
178
- width , height , descent = self .gc .get_text_width_height_descent (
179
- six .text_type (s ), family , size , weight , style )
180
- return width , height , descent
181
-
182
- def flipy (self ):
183
- return False
184
-
185
- def points_to_pixels (self , points ):
186
- return points / 72.0 * self .dpi
187
-
188
- def option_image_nocomposite (self ):
189
- return True
190
-
191
-
192
- class GraphicsContextMac (_macosx .GraphicsContext , GraphicsContextBase ):
193
- """
194
- The GraphicsContext wraps a Quartz graphics context. All methods
195
- are implemented at the C-level in macosx.GraphicsContext. These
196
- methods set drawing properties such as the line style, fill color,
197
- etc. The actual drawing is done by the Renderer, which draws into
198
- the GraphicsContext.
199
- """
200
- def __init__ (self ):
201
- GraphicsContextBase .__init__ (self )
202
- _macosx .GraphicsContext .__init__ (self )
203
-
204
- def set_alpha (self , alpha ):
205
- GraphicsContextBase .set_alpha (self , alpha )
206
- _alpha = self .get_alpha ()
207
- _macosx .GraphicsContext .set_alpha (self , _alpha , self .get_forced_alpha ())
208
- rgb = self .get_rgb ()
209
- _macosx .GraphicsContext .set_foreground (self , rgb )
210
-
211
- def set_foreground (self , fg , isRGBA = False ):
212
- GraphicsContextBase .set_foreground (self , fg , isRGBA )
213
- rgb = self .get_rgb ()
214
- _macosx .GraphicsContext .set_foreground (self , rgb )
215
-
216
- def set_graylevel (self , fg ):
217
- GraphicsContextBase .set_graylevel (self , fg )
218
- _macosx .GraphicsContext .set_graylevel (self , fg )
219
-
220
- def set_clip_rectangle (self , box ):
221
- GraphicsContextBase .set_clip_rectangle (self , box )
222
- if not box : return
223
- _macosx .GraphicsContext .set_clip_rectangle (self , box .bounds )
224
-
225
- def set_clip_path (self , path ):
226
- GraphicsContextBase .set_clip_path (self , path )
227
- if not path : return
228
- path = path .get_fully_transformed_path ()
229
- _macosx .GraphicsContext .set_clip_path (self , path )
230
-
231
-
232
30
########################################################################
233
31
#
234
32
# The following functions and classes are for pylab and implement
@@ -285,7 +83,7 @@ class TimerMac(_macosx.Timer, TimerBase):
285
83
# completely implemented at the C-level (in _macosx.Timer)
286
84
287
85
288
- class FigureCanvasMac (_macosx .FigureCanvas , FigureCanvasBase ):
86
+ class FigureCanvasMac (_macosx .FigureCanvas , FigureCanvasAgg ):
289
87
"""
290
88
The canvas the figure renders into. Calls the draw and print fig
291
89
methods, creates the renderers, etc...
@@ -300,61 +98,66 @@ class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasBase):
300
98
key_press_event, and key_release_event are called from there.
301
99
"""
302
100
303
- filetypes = FigureCanvasBase .filetypes .copy ()
304
- filetypes ['bmp' ] = 'Windows bitmap'
305
- filetypes ['jpeg' ] = 'JPEG'
306
- filetypes ['jpg' ] = 'JPEG'
307
- filetypes ['gif' ] = 'Graphics Interchange Format'
308
- filetypes ['tif' ] = 'Tagged Image Format File'
309
- filetypes ['tiff' ] = 'Tagged Image Format File'
310
-
311
101
def __init__ (self , figure ):
312
102
FigureCanvasBase .__init__ (self , figure )
313
103
width , height = self .get_width_height ()
314
- self .renderer = RendererMac (figure .dpi , width , height )
315
104
_macosx .FigureCanvas .__init__ (self , width , height )
105
+ self ._needs_draw = True
106
+ self ._device_scale = 1.0
107
+
108
+ def _set_device_scale (self , value ):
109
+ if self ._device_scale != value :
110
+ self .figure .dpi = self .figure .dpi / self ._device_scale * value
111
+ self ._device_scale = value
112
+
113
+ def get_renderer (self , cleared = False ):
114
+ l , b , w , h = self .figure .bbox .bounds
115
+ key = w , h , self .figure .dpi
116
+ try :
117
+ self ._lastKey , self ._renderer
118
+ except AttributeError :
119
+ need_new_renderer = True
120
+ else :
121
+ need_new_renderer = (self ._lastKey != key )
316
122
317
- def draw_idle (self , * args , ** kwargs ):
318
- self .invalidate ()
123
+ if need_new_renderer :
124
+ self ._renderer = RendererAgg (w , h , self .figure .dpi )
125
+ self ._lastKey = key
126
+ elif cleared :
127
+ self ._renderer .clear ()
319
128
320
- def resize (self , width , height ):
321
- self .renderer .set_width_height (width , height )
322
- dpi = self .figure .dpi
323
- width /= dpi
324
- height /= dpi
325
- self .figure .set_size_inches (width , height , forward = False )
326
- FigureCanvasBase .resize_event (self )
129
+ return self ._renderer
327
130
328
- def _print_bitmap (self , filename , * args , ** kwargs ):
329
- # In backend_bases.py, print_figure changes the dpi of the figure.
330
- # But since we are essentially redrawing the picture, we need the
331
- # original dpi. Pick it up from the renderer.
332
- dpi = kwargs ['dpi' ]
333
- old_dpi = self .figure .dpi
334
- self .figure .dpi = self .renderer .dpi
335
- width , height = self .figure .get_size_inches ()
336
- width , height = width * dpi , height * dpi
337
- filename = six .text_type (filename )
338
- self .write_bitmap (filename , width , height , dpi )
339
- self .figure .dpi = old_dpi
131
+ def _draw (self ):
132
+ renderer = self .get_renderer ()
340
133
341
- def print_bmp ( self , filename , * args , ** kwargs ) :
342
- self . _print_bitmap ( filename , * args , ** kwargs )
134
+ if not self . _needs_draw :
135
+ return renderer
343
136
344
- def print_jpg (self , filename , * args , ** kwargs ):
345
- self ._print_bitmap (filename , * args , ** kwargs )
137
+ self .figure .draw (renderer )
138
+ self ._needs_draw = False
139
+ return renderer
346
140
347
- def print_jpeg (self , filename , * args , ** kwargs ):
348
- self ._print_bitmap (filename , * args , ** kwargs )
141
+ def draw (self ):
142
+ self ._draw ()
143
+ self .invalidate ()
349
144
350
- def print_tif (self , filename , * args , ** kwargs ):
351
- self ._print_bitmap (filename , * args , ** kwargs )
145
+ def draw_idle (self , * args , ** kwargs ):
146
+ self ._needs_draw = True
147
+ self .invalidate ()
352
148
353
- def print_tiff (self , filename , * args , ** kwargs ):
354
- self ._print_bitmap ( filename , * args , ** kwargs )
149
+ def blit (self , bbox ):
150
+ self .invalidate ( )
355
151
356
- def print_gif (self , filename , * args , ** kwargs ):
357
- self ._print_bitmap (filename , * args , ** kwargs )
152
+ def resize (self , width , height ):
153
+ dpi = self .figure .dpi
154
+ width /= dpi
155
+ height /= dpi
156
+ self .figure .set_size_inches (width * self ._device_scale ,
157
+ height * self ._device_scale ,
158
+ forward = False )
159
+ FigureCanvasBase .resize_event (self )
160
+ self .draw_idle ()
358
161
359
162
def new_timer (self , * args , ** kwargs ):
360
163
"""
0 commit comments