@@ -75,7 +75,6 @@ class BaseFigureWidget(BaseFigure, widgets.DOMWidget):
75
75
** custom_serializers )
76
76
_py2js_removeTraceProps = Dict (allow_none = True ).tag (sync = True ,
77
77
** custom_serializers )
78
- _py2js_svgRequest = Dict (allow_none = True ).tag (sync = True )
79
78
80
79
# ### JS -> Python message properties ###
81
80
# These properties are used to receive messages from the frontend.
@@ -99,8 +98,6 @@ class BaseFigureWidget(BaseFigure, widgets.DOMWidget):
99
98
** custom_serializers )
100
99
_js2py_pointsCallback = Dict (allow_none = True ).tag (sync = True ,
101
100
** custom_serializers )
102
- _js2py_svgResponse = Dict (allow_none = True ).tag (sync = True ,
103
- ** custom_serializers )
104
101
105
102
# ### Message tracking properties ###
106
103
# The _last_layout_edit_id and _last_trace_edit_id properties are used
@@ -168,186 +165,6 @@ def __init__(self,
168
165
# views of this widget
169
166
self ._view_count = 0
170
167
171
- # SVG
172
- # ---
173
- # Dict of pending SVG requests that have been sent to the frontend
174
- self ._svg_requests = {}
175
-
176
- def save_image (self , filename , image_type = None , scale_factor = 2 ):
177
- """
178
- Save figure to a static image file
179
-
180
- Parameters
181
- ----------
182
- filename : str
183
- Image output file name
184
- image_type : str
185
- Image file type. One of: 'svg', 'png', 'pdf', or 'ps'. If not
186
- set, file type is inferred from the filename extension
187
- scale_factor : number
188
- (For png image type) Factor by which to increase the number of
189
- pixels in each dimension. A scale factor of 1 will result in a
190
- image with pixel dimensions (layout.width, layout.height). A
191
- scale factor of 2 will result in an image with dimensions
192
- (2*layout.width, 2*layout.height),
193
- doubling image's DPI. (Default 2)
194
- """
195
-
196
- # Validate / infer image_type
197
- # ---------------------------
198
- supported_image_types = ['svg' , 'png' , 'pdf' , 'ps' ]
199
- cairo_image_types = ['png' , 'pdf' , 'ps' ]
200
- supported_types_csv = ', ' .join (supported_image_types )
201
-
202
- # ### Image type found ###
203
- if not image_type :
204
- # Infer image type from extension
205
- _ , extension = os .path .splitext (filename )
206
-
207
- if not extension :
208
- raise ValueError ('No image_type specified and file extension has no extension '
209
- 'from which to infer an image type '
210
- 'Supported image types are: {image_types}'
211
- .format (image_types = supported_types_csv ))
212
-
213
- image_type = extension [1 :]
214
-
215
- # ### Image type supported ###
216
- image_type = image_type .lower ()
217
- if image_type not in supported_image_types :
218
- raise ValueError ("Unsupported image type '{image_type}'\n "
219
- "Supported image types are: {image_types}"
220
- .format (image_type = image_type ,
221
- image_types = supported_types_csv ))
222
-
223
- # ### Dependencies available for image type ###
224
- # Validate cairo dependency
225
- if image_type in cairo_image_types :
226
- # Check whether we have cairosvg available
227
- try :
228
- import_module ('cairosvg' )
229
- except ImportError :
230
- raise ImportError ('Exporting to {image_type} requires cairosvg'
231
- .format (image_type = image_type ))
232
-
233
- # ### Validate scale_factor ###
234
- if not isinstance (scale_factor , numbers .Number ) or scale_factor <= 0 :
235
- raise ValueError (
236
- 'scale_factor must be a positive number.\n '
237
- ' Received: {scale_factor}' .format (
238
- scale_factor = scale_factor
239
- )
240
- )
241
-
242
- # Build image request
243
- # -------------------
244
- # ### Create UID for request ###
245
- req_id = str (uuid .uuid1 ())
246
-
247
- # ### Register request ###
248
- self ._svg_requests [req_id ] = {'filename' : filename ,
249
- 'image_type' : image_type ,
250
- 'scale_factor' : scale_factor }
251
-
252
- # ### Send request to the frontend###
253
- self ._py2js_svgRequest = {'request_id' : req_id }
254
- self ._py2js_svgRequest = None
255
-
256
- @observe ('_js2py_svgResponse' )
257
- def _handler_js2py_svgResponse (self , change ):
258
- """
259
- Handle _js2py_svgResponse message from the frontend
260
-
261
- Parameters
262
- ----------
263
- change : dict
264
- Message dict containing the following keys:
265
- - request_id: str
266
- The UID of the image request that triggered this message
267
- - svg_uri: str
268
- The SVG image encoded as a data uri
269
- (e.g. 'data:image/svg+xml,...')
270
- """
271
-
272
- # Receive message
273
- # ---------------
274
- response_data = change ['new' ]
275
- self ._js2py_svgResponse = None
276
-
277
- if not response_data :
278
- return
279
-
280
- # Extract message fields
281
- # ----------------------
282
- req_id = response_data ['request_id' ]
283
- svg_uri = response_data ['svg_uri' ]
284
-
285
- # Save image
286
- # ----------
287
- self ._do_save_image (req_id , svg_uri )
288
-
289
- def _do_save_image (self , req_id , svg_uri ):
290
- """
291
- Save requested image to a file
292
-
293
- Parameters
294
- ----------
295
- req_id : str
296
- The UID of the image request that triggered this message
297
- svg_uri :
298
- The SVG image encoded as a data uri
299
- (e.g. 'data:image/svg+xml,...')
300
- """
301
-
302
- # Get request info
303
- # ----------------
304
- # Lack of request info means that widget has multiple frontend views
305
- # and that the request was already processed.
306
- req_info = self ._svg_requests .pop (req_id , None )
307
- if not req_info :
308
- return
309
- filename = req_info ['filename' ]
310
- image_type = req_info ['image_type' ]
311
- scale_factor = req_info ['scale_factor' ]
312
-
313
- # Convert URI string to svg bytes
314
- # -------------------------------
315
-
316
- # ### Remove URI prefix###
317
- if not svg_uri .startswith ('data:image/svg+xml,' ):
318
- raise ValueError ('Invalid svg data URI: ' + svg_uri [:20 ])
319
-
320
- svg = svg_uri .replace ('data:image/svg+xml,' , '' )
321
-
322
- # ### Unquote special characters ###
323
- # (e.g. '%3Csvg%20' -> '<svg ')
324
- svg_bytes = parse .unquote (svg ).encode ('utf-8' )
325
-
326
- # Save as svg
327
- # -----------
328
- # This requires no external dependencies
329
- if image_type == 'svg' :
330
- with open (filename , 'wb' ) as f :
331
- f .write (svg_bytes )
332
-
333
- # Save as cairo image type
334
- # ------------------------
335
- else :
336
- # We already made sure cairosvg is available in save_image
337
- cairosvg = import_module ('cairosvg' )
338
-
339
- if image_type == 'png' :
340
- cairosvg .svg2png (
341
- bytestring = svg_bytes ,
342
- write_to = filename ,
343
- scale = scale_factor )
344
- elif image_type == 'pdf' :
345
- cairosvg .svg2pdf (
346
- bytestring = svg_bytes , write_to = filename )
347
- elif image_type == 'ps' :
348
- cairosvg .svg2ps (
349
- bytestring = svg_bytes , write_to = filename )
350
-
351
168
# Python -> JavaScript Messages
352
169
# -----------------------------
353
170
def _send_relayout_msg (self , layout_data , source_view_id = None ):
0 commit comments