@@ -140,6 +140,44 @@ def __setattr__(self, name, value):
140140 scope = None
141141
142142
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+
143181def to_image (
144182 fig ,
145183 format = None ,
@@ -216,7 +254,6 @@ def to_image(
216254 """
217255
218256 # Handle engine
219- # -------------
220257 if engine is not None :
221258 warnings .warn (ENGINE_PARAM_DEPRECATION_MSG , DeprecationWarning , stacklevel = 2 )
222259 else :
@@ -394,7 +431,6 @@ def write_image(
394431 None
395432 """
396433 # Show Kaleido deprecation warning if needed
397- # ------------------------------------------
398434 if (
399435 engine in {None , "auto" , "kaleido" }
400436 and kaleido_available ()
@@ -407,38 +443,12 @@ def write_image(
407443 warnings .warn (ENGINE_PARAM_DEPRECATION_MSG , DeprecationWarning , stacklevel = 2 )
408444
409445 # 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 )
421447
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 )
439450
440451 # Request image
441- # -------------
442452 # Do this first so we don't create a file if image conversion fails
443453 img_data = to_image (
444454 fig ,
@@ -451,7 +461,6 @@ def write_image(
451461 )
452462
453463 # Open file
454- # ---------
455464 if path is None :
456465 # We previously failed to make sense of `file` as a pathlib object.
457466 # Attempt to write to `file` as an open file descriptor.
@@ -471,34 +480,121 @@ def write_image(
471480 path .write_bytes (img_data )
472481
473482
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+ ):
475492 """
476493 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.
478496
479497 Parameters
480498 ----------
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.
484540
485541 Returns
486542 -------
487543 None
488544 """
489545
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+ )
492564
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)
502598
503599
504600def full_figure_for_development (fig , warn = True , as_dict = False ):
0 commit comments