66import warnings
77
88import plotly
9- from plotly .io ._utils import validate_coerce_fig_to_dict , as_individual_args
9+ from plotly .io ._utils import validate_coerce_fig_to_dict , broadcast_args_to_dicts
1010from plotly .io import defaults
1111
1212ENGINE_SUPPORT_TIMELINE = "September 2025"
1313
14+ PLOTLY_GET_CHROME_ERROR_MSG = """
15+
16+ Kaleido requires Google Chrome to be installed. Install it by running:
17+ $ plotly_get_chrome
18+ """
19+
1420
1521# TODO: Remove --pre flag once Kaleido v1 full release is available
1622KALEIDO_DEPRECATION_MSG = f"""
@@ -158,6 +164,7 @@ def as_path_object(file: str | Path) -> Path | None:
158164 path = None
159165 return path
160166
167+
161168def infer_format (path : Path | None , format : str | None ) -> str | None :
162169 if path is not None and format is None :
163170 ext = path .suffix
@@ -177,7 +184,6 @@ def infer_format(path: Path | None, format: str | None) -> str | None:
177184 return format
178185
179186
180-
181187def to_image (
182188 fig ,
183189 format = None ,
@@ -331,13 +337,7 @@ def to_image(
331337 ),
332338 )
333339 except choreographer .errors .ChromeNotFoundError :
334- raise RuntimeError (
335- """
336-
337- Kaleido requires Google Chrome to be installed. Install it by running:
338- $ plotly_get_chrome
339- """
340- )
340+ raise RuntimeError (PLOTLY_GET_CHROME_ERROR_MSG )
341341
342342 else :
343343 # Kaleido v0
@@ -481,7 +481,7 @@ def write_image(
481481
482482
483483def write_images (
484- figs ,
484+ fig ,
485485 file ,
486486 format = None ,
487487 scale = None ,
@@ -494,13 +494,17 @@ def write_images(
494494 calling write_image() multiple times. This function can only be used with the Kaleido
495495 engine, v1.0.0 or greater.
496496
497+ This function accepts the same arguments as write_image() (minus the `engine` argument),
498+ except that any of the arguments may be either a single value or an iterable of values.
499+ If multiple arguments are iterable, they must all have the same length.
500+
497501 Parameters
498502 ----------
499- figs :
503+ fig :
500504 Iterable of figure objects or dicts representing a figure
501505
502- directory : str or writeable
503- A string or pathlib.Path object representing a local directory path .
506+ file : str or writeable
507+ Iterables of strings or pathlib.Path objects representing local file paths to write to .
504508
505509 format: str or None
506510 The desired image format. One of
@@ -562,39 +566,48 @@ def write_images(
562566"""
563567 )
564568
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- ),
569+ # Broadcast arguments into correct format for passing to Kaleido
570+ arg_dicts = broadcast_args_to_dicts (
571+ fig = fig ,
572+ file = file ,
573+ format = format ,
574+ scale = scale ,
575+ width = width ,
576+ height = height ,
577+ validate = validate ,
584578 )
585579
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)
580+ # For each dict:
581+ # - convert figures to dicts (and validate if requested)
582+ # - try to cast `file` as a Path object
583+ for d in arg_dicts :
584+ d ["fig" ] = validate_coerce_fig_to_dict (d ["fig" ], d ["validate" ])
585+ d ["file" ] = as_path_object (d ["file" ])
586+
587+ # Reshape arg_dicts into correct format for passing to Kaleido
588+ # We call infer_format() here rather than above so that the `file` argument
589+ # has already been cast to a Path object.
590+ # Also insert defaults for any missing arguments as needed
591+ kaleido_specs = [
592+ {
593+ "fig" : d ["fig" ],
594+ "path" : d ["file" ],
595+ "opts" : dict (
596+ format = infer_format (d ["file" ], d ["format" ]) or defaults .default_format ,
597+ width = d ["width" ] or defaults .default_width ,
598+ height = d ["height" ] or defaults .default_height ,
599+ scale = d ["scale" ] or defaults .default_scale ,
600+ ),
601+ }
602+ for d in arg_dicts
603+ ]
604+
605+ import choreographer
606+
607+ try :
608+ kaleido .write_fig_from_object_sync (kaleido_specs )
609+ except choreographer .errors .ChromeNotFoundError :
610+ raise RuntimeError (PLOTLY_GET_CHROME_ERROR_MSG )
598611
599612
600613def full_figure_for_development (fig , warn = True , as_dict = False ):
0 commit comments