@@ -140,6 +140,44 @@ def __setattr__(self, name, value):
140
140
scope = None
141
141
142
142
143
+ def as_path_object (file : str | Path ) -> Path | None :
144
+ """
145
+ Cast the `file` argument, which may be either a string or a Path object,
146
+ to a Path object.
147
+ If `file` is neither a string nor a Path object, None will be returned.
148
+ """
149
+ if isinstance (file , str ):
150
+ # Use the standard Path constructor to make a pathlib object.
151
+ path = Path (file )
152
+ elif isinstance (file , Path ):
153
+ # `file` is already a Path object.
154
+ path = file
155
+ else :
156
+ # We could not make a Path object out of file. Either `file` is an open file
157
+ # descriptor with a `write()` method or it's an invalid object.
158
+ path = None
159
+ return path
160
+
161
+ def infer_format (path : Path | None , format : str | None ) -> str | None :
162
+ if path is not None and format is None :
163
+ ext = path .suffix
164
+ if ext :
165
+ format = ext .lstrip ("." )
166
+ else :
167
+ raise ValueError (
168
+ f"""
169
+ Cannot infer image type from output path '{ path } '.
170
+ Please specify the type using the format parameter, or add a file extension.
171
+ For example:
172
+
173
+ >>> import plotly.io as pio
174
+ >>> pio.write_image(fig, file_path, format='png')
175
+ """
176
+ )
177
+ return format
178
+
179
+
180
+
143
181
def to_image (
144
182
fig ,
145
183
format = None ,
@@ -216,7 +254,6 @@ def to_image(
216
254
"""
217
255
218
256
# Handle engine
219
- # -------------
220
257
if engine is not None :
221
258
warnings .warn (ENGINE_PARAM_DEPRECATION_MSG , DeprecationWarning , stacklevel = 2 )
222
259
else :
@@ -394,7 +431,6 @@ def write_image(
394
431
None
395
432
"""
396
433
# Show Kaleido deprecation warning if needed
397
- # ------------------------------------------
398
434
if (
399
435
engine in {None , "auto" , "kaleido" }
400
436
and kaleido_available ()
@@ -407,38 +443,12 @@ def write_image(
407
443
warnings .warn (ENGINE_PARAM_DEPRECATION_MSG , DeprecationWarning , stacklevel = 2 )
408
444
409
445
# Try to cast `file` as a pathlib object `path`.
410
- # ----------------------------------------------
411
- if isinstance (file , str ):
412
- # Use the standard Path constructor to make a pathlib object.
413
- path = Path (file )
414
- elif isinstance (file , Path ):
415
- # `file` is already a Path object.
416
- path = file
417
- else :
418
- # We could not make a Path object out of file. Either `file` is an open file
419
- # descriptor with a `write()` method or it's an invalid object.
420
- path = None
446
+ path = as_path_object (file )
421
447
422
- # Infer format if not specified
423
- # -----------------------------
424
- if path is not None and format is None :
425
- ext = path .suffix
426
- if ext :
427
- format = ext .lstrip ("." )
428
- else :
429
- raise ValueError (
430
- f"""
431
- Cannot infer image type from output path '{ file } '.
432
- Please add a file extension or specify the type using the format parameter.
433
- For example:
434
-
435
- >>> import plotly.io as pio
436
- >>> pio.write_image(fig, file_path, format='png')
437
- """
438
- )
448
+ # Infer image format if not specified
449
+ format = infer_format (path , format )
439
450
440
451
# Request image
441
- # -------------
442
452
# Do this first so we don't create a file if image conversion fails
443
453
img_data = to_image (
444
454
fig ,
@@ -451,7 +461,6 @@ def write_image(
451
461
)
452
462
453
463
# Open file
454
- # ---------
455
464
if path is None :
456
465
# We previously failed to make sense of `file` as a pathlib object.
457
466
# Attempt to write to `file` as an open file descriptor.
@@ -471,34 +480,121 @@ def write_image(
471
480
path .write_bytes (img_data )
472
481
473
482
474
- def write_images (* args , ** kwargs ):
483
+ def write_images (
484
+ figs ,
485
+ file ,
486
+ format = None ,
487
+ scale = None ,
488
+ width = None ,
489
+ height = None ,
490
+ validate = True ,
491
+ ):
475
492
"""
476
493
Write multiple images to files or writeable objects. This is much faster than
477
- calling write_image() multiple times.
494
+ calling write_image() multiple times. This function can only be used with the Kaleido
495
+ engine, v1.0.0 or greater.
478
496
479
497
Parameters
480
498
----------
481
- Accepts the same parameters as pio.write_image(), but any parameter may be either
482
- a single value or a list of values. If more than one parameter is a list,
483
- all must be the same length.
499
+ figs:
500
+ Iterable of figure objects or dicts representing a figure
501
+
502
+ directory: str or writeable
503
+ A string or pathlib.Path object representing a local directory path.
504
+
505
+ format: str or None
506
+ The desired image format. One of
507
+ - 'png'
508
+ - 'jpg' or 'jpeg'
509
+ - 'webp'
510
+ - 'svg'
511
+ - 'pdf'
512
+
513
+ If not specified, this will default to `plotly.io.defaults.default_format`.
514
+
515
+ width: int or None
516
+ The width of the exported image in layout pixels. If the `scale`
517
+ property is 1.0, this will also be the width of the exported image
518
+ in physical pixels.
519
+
520
+ If not specified, will default to `plotly.io.defaults.default_width`.
521
+
522
+ height: int or None
523
+ The height of the exported image in layout pixels. If the `scale`
524
+ property is 1.0, this will also be the height of the exported image
525
+ in physical pixels.
526
+
527
+ If not specified, will default to `plotly.io.defaults.default_height`.
528
+
529
+ scale: int or float or None
530
+ The scale factor to use when exporting the figure. A scale factor
531
+ larger than 1.0 will increase the image resolution with respect
532
+ to the figure's layout pixel dimensions. Whereas as scale factor of
533
+ less than 1.0 will decrease the image resolution.
534
+
535
+ If not specified, will default to `plotly.io.defaults.default_scale`.
536
+
537
+ validate: bool
538
+ True if the figure should be validated before being converted to
539
+ an image, False otherwise.
484
540
485
541
Returns
486
542
-------
487
543
None
488
544
"""
489
545
490
- # Get individual arguments
491
- individual_args , individual_kwargs = as_individual_args (* args , ** kwargs )
546
+ # Raise informative error message if Kaleido v1 is not installed
547
+ if not kaleido_available ():
548
+ raise ValueError (
549
+ """
550
+ The `write_images()` function requires the kaleido package,
551
+ which can be installed using pip:
552
+ $ pip install -U kaleido
553
+ """
554
+ )
555
+ elif kaleido_major () < 1 :
556
+ raise ValueError (
557
+ f"""
558
+ You have Kaleido version { Version (importlib_metadata .version ("kaleido" ))} installed.
559
+ The `write_images()` function requires the kaleido package version 1 or greater,
560
+ which can be installed using pip:
561
+ $ pip install -U 'kaleido>=1.0.0'
562
+ """
563
+ )
492
564
493
- if kaleido_available () and kaleido_major () > 0 :
494
- # Kaleido v1
495
- # TODO: Use a single shared kaleido instance for all images
496
- for a , kw in zip (individual_args , individual_kwargs ):
497
- write_image (* a , ** kw )
498
- else :
499
- # Kaleido v0, or orca
500
- for a , kw in zip (individual_args , individual_kwargs ):
501
- write_image (* a , ** kw )
565
+ # Try to cast `file` as a pathlib object `path`.
566
+ path = as_path_object (file )
567
+
568
+ # Infer image format if not specified
569
+ format = infer_format (path , format )
570
+
571
+ # Convert figures to dicts (and validate if requested)
572
+ # TODO: Keep same iterable type
573
+ fig_dicts = [validate_coerce_fig_to_dict (fig , validate ) for fig in figs ]
574
+
575
+ kaleido .write_fig_sync (
576
+ fig_dicts ,
577
+ directory = path ,
578
+ opts = dict (
579
+ format = format or defaults .default_format ,
580
+ width = width or defaults .default_width ,
581
+ height = height or defaults .default_height ,
582
+ scale = scale or defaults .default_scale ,
583
+ ),
584
+ )
585
+
586
+ # # Get individual arguments
587
+ # individual_args, individual_kwargs = as_individual_args(*args, **kwargs)
588
+
589
+ # if kaleido_available() and kaleido_major() > 0:
590
+ # # Kaleido v1
591
+ # # TODO: Use a single shared kaleido instance for all images
592
+ # for a, kw in zip(individual_args, individual_kwargs):
593
+ # write_image(*a, **kw)
594
+ # else:
595
+ # # Kaleido v0, or orca
596
+ # for a, kw in zip(individual_args, individual_kwargs):
597
+ # write_image(*a, **kw)
502
598
503
599
504
600
def full_figure_for_development (fig , warn = True , as_dict = False ):
0 commit comments