-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Kaleido v1 in Plotly.py #5062
base: main
Are you sure you want to change the base?
Changes from 16 commits
f0a78a6
a681c84
a7a6f24
2e9c8af
60bb748
b87f752
e203623
8054331
1a195a7
577d3ca
89209ad
96bf9a0
350dd48
08c1d4e
8b47a0a
249cc9f
ad9dbd9
e75a5df
a2b4f3c
2549299
ab3b700
de473e1
71696fe
100b955
5541a79
95a05db
0a73d0e
4d3dd56
d871e74
b3e8d36
ef5f520
611e2e4
c92a1ee
b56d5ec
c01cb8a
bcd40f3
54985b8
b4af0d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,43 @@ | ||
import os | ||
import json | ||
from pathlib import Path | ||
import importlib.metadata as importlib_metadata | ||
from packaging.version import Version | ||
import warnings | ||
|
||
import plotly | ||
from plotly.io._utils import validate_coerce_fig_to_dict | ||
|
||
try: | ||
from kaleido.scopes.plotly import PlotlyScope | ||
|
||
scope = PlotlyScope() | ||
ENGINE_SUPPORT_TIMELINE = "September 2025" | ||
|
||
# Compute absolute path to the 'plotly/package_data/' directory | ||
root_dir = os.path.dirname(os.path.abspath(plotly.__file__)) | ||
package_dir = os.path.join(root_dir, "package_data") | ||
scope.plotlyjs = os.path.join(package_dir, "plotly.min.js") | ||
if scope.mathjax is None: | ||
scope.mathjax = ( | ||
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js" | ||
) | ||
except ImportError: | ||
try: | ||
import kaleido | ||
|
||
kaleido_available = True | ||
kaleido_major = Version(importlib_metadata.version("kaleido")).major | ||
|
||
if kaleido_major < 1: | ||
# Kaleido v0 | ||
from kaleido.scopes.plotly import PlotlyScope | ||
|
||
scope = PlotlyScope() | ||
# Compute absolute path to the 'plotly/package_data/' directory | ||
root_dir = os.path.dirname(os.path.abspath(plotly.__file__)) | ||
package_dir = os.path.join(root_dir, "package_data") | ||
scope.plotlyjs = os.path.join(package_dir, "plotly.min.js") | ||
if scope.mathjax is None: | ||
scope.mathjax = ( | ||
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js" | ||
) | ||
except ImportError as e: | ||
kaleido_available = False | ||
kaleido_major = -1 | ||
PlotlyScope = None | ||
scope = None | ||
|
||
|
||
def to_image( | ||
fig, format=None, width=None, height=None, scale=None, validate=True, engine="auto" | ||
fig, format=None, width=None, height=None, scale=None, validate=True, engine=None | ||
): | ||
""" | ||
Convert a figure to a static image bytes string | ||
|
@@ -35,65 +49,61 @@ def to_image( | |
|
||
format: str or None | ||
The desired image format. One of | ||
- 'png' | ||
- 'jpg' or 'jpeg' | ||
- 'webp' | ||
- 'svg' | ||
- 'pdf' | ||
- 'eps' (Requires the poppler library to be installed and on the PATH) | ||
- 'png' | ||
- 'jpg' or 'jpeg' | ||
- 'webp' | ||
- 'svg' | ||
- 'pdf' | ||
- 'eps' (Requires the poppler library to be installed and on the PATH) | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_format` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_format` if engine is "orca" | ||
If not specified, will default to `plotly.io.kaleido.scope.default_format` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do these references to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, those docstrings should be changed -- I need to research where those defaults are defined in Kaleido v1. (@ayjayt do you know off the top of your head?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The order is png default overridden by user-specified output path w/ extension overriden by user-specified format in opts |
||
|
||
width: int or None | ||
The width of the exported image in layout pixels. If the `scale` | ||
property is 1.0, this will also be the width of the exported image | ||
in physical pixels. | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_width` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_width` if engine is "orca" | ||
If not specified, will default to `plotly.io.kaleido.scope.default_width` | ||
|
||
height: int or None | ||
The height of the exported image in layout pixels. If the `scale` | ||
property is 1.0, this will also be the height of the exported image | ||
in physical pixels. | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_height` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_height` if engine is "orca" | ||
If not specified, will default to `plotly.io.kaleido.scope.default_height` | ||
|
||
scale: int or float or None | ||
The scale factor to use when exporting the figure. A scale factor | ||
larger than 1.0 will increase the image resolution with respect | ||
to the figure's layout pixel dimensions. Whereas as scale factor of | ||
less than 1.0 will decrease the image resolution. | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_scale` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_scale` if engine is "orca" | ||
|
||
If not specified, will default to `plotly.io.kaleido.scope.default_scale` | ||
|
||
validate: bool | ||
True if the figure should be validated before being converted to | ||
an image, False otherwise. | ||
|
||
engine: str | ||
Image export engine to use: | ||
- "kaleido": Use Kaleido for image export | ||
- "orca": Use Orca for image export | ||
- "auto" (default): Use Kaleido if installed, otherwise use orca | ||
engine (deprecated): str | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we print a deprecation warning if this argument is used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not yet, assuming we are in agreement about removing this argument, I'll add one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm in agreement that we should remove this argument |
||
No longer used. Kaleido is the only supported engine. | ||
|
||
Returns | ||
------- | ||
bytes | ||
The image data | ||
""" | ||
|
||
# Handle engine | ||
# ------------- | ||
if engine is not None: | ||
warnings.warn( | ||
f"DeprecationWarning: The 'engine' argument is deprecated. Kaleido will be the only supported engine after {ENGINE_SUPPORT_TIMELINE}.", | ||
DeprecationWarning, | ||
) | ||
engine = "auto" | ||
|
||
LiamConnors marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if engine == "auto": | ||
if scope is not None: | ||
if kaleido_available: | ||
# Default to kaleido if available | ||
engine = "kaleido" | ||
else: | ||
|
@@ -109,6 +119,11 @@ def to_image( | |
engine = "kaleido" | ||
|
||
if engine == "orca": | ||
warnings.warn( | ||
f"Support for the orca engine is deprecated and will be removed after {ENGINE_SUPPORT_TIMELINE}. " | ||
+ "Please install Kaleido (`pip install kaleido`) to use the Kaleido engine.", | ||
DeprecationWarning, | ||
) | ||
# Fall back to legacy orca image export path | ||
from ._orca import to_image as to_image_orca | ||
|
||
|
@@ -128,7 +143,7 @@ def to_image( | |
) | ||
|
||
# Raise informative error message if Kaleido is not installed | ||
if scope is None: | ||
if not kaleido_available: | ||
raise ValueError( | ||
""" | ||
Image export using the "kaleido" engine requires the kaleido package, | ||
|
@@ -137,12 +152,40 @@ def to_image( | |
""" | ||
) | ||
|
||
# Validate figure | ||
# --------------- | ||
# Convert figure to dict (and validate if requested) | ||
fig_dict = validate_coerce_fig_to_dict(fig, validate) | ||
img_bytes = scope.transform( | ||
fig_dict, format=format, width=width, height=height, scale=scale | ||
) | ||
|
||
# Request image bytes | ||
if kaleido_major > 0: | ||
# Kaleido v1 | ||
# Check if trying to export to EPS format, which is not supported in Kaleido v1 | ||
if format == "eps": | ||
raise ValueError( | ||
""" | ||
EPS export is not supported with Kaleido v1. | ||
Please downgrade to Kaleido v0 to use EPS export: | ||
$ pip install kaleido==0.2.1 | ||
""" | ||
) | ||
img_bytes = kaleido.calc_fig_sync( | ||
fig_dict, | ||
path=None, | ||
opts=dict( | ||
format=format, | ||
width=width, | ||
height=height, | ||
scale=scale, | ||
), | ||
) | ||
else: | ||
# Kaleido v0 | ||
warnings.warn( | ||
f"Support for Kaleido versions less than 1.0.0 is deprecated and will be removed after {ENGINE_SUPPORT_TIMELINE}. Please upgrade Kaleido to version 1.0.0 or greater (`pip install --upgrade kaleido`).", | ||
DeprecationWarning, | ||
) | ||
img_bytes = scope.transform( | ||
fig_dict, format=format, width=width, height=height, scale=scale | ||
) | ||
|
||
return img_bytes | ||
|
||
|
@@ -190,38 +233,29 @@ def write_image( | |
property is 1.0, this will also be the width of the exported image | ||
in physical pixels. | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_width` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_width` if engine is "orca" | ||
If not specified, will default to`plotly.io.kaleido.scope.default_width` | ||
|
||
height: int or None | ||
The height of the exported image in layout pixels. If the `scale` | ||
property is 1.0, this will also be the height of the exported image | ||
in physical pixels. | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_height` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_height` if engine is "orca" | ||
If not specified, will default to `plotly.io.kaleido.scope.default_height` | ||
|
||
scale: int or float or None | ||
The scale factor to use when exporting the figure. A scale factor | ||
larger than 1.0 will increase the image resolution with respect | ||
to the figure's layout pixel dimensions. Whereas as scale factor of | ||
less than 1.0 will decrease the image resolution. | ||
|
||
If not specified, will default to: | ||
- `plotly.io.kaleido.scope.default_scale` if engine is "kaleido" | ||
- `plotly.io.orca.config.default_scale` if engine is "orca" | ||
If not specified, will default to `plotly.io.kaleido.scope.default_scale` | ||
|
||
validate: bool | ||
True if the figure should be validated before being converted to | ||
an image, False otherwise. | ||
|
||
engine: str | ||
Image export engine to use: | ||
- "kaleido": Use Kaleido for image export | ||
- "orca": Use Orca for image export | ||
- "auto" (default): Use Kaleido if installed, otherwise use orca | ||
engine (deprecated): str | ||
No longer used. Kaleido is the only supported engine. | ||
|
||
Returns | ||
------- | ||
|
@@ -323,7 +357,7 @@ def full_figure_for_development(fig, warn=True, as_dict=False): | |
""" | ||
|
||
# Raise informative error message if Kaleido is not installed | ||
if scope is None: | ||
if not kaleido_available: | ||
raise ValueError( | ||
""" | ||
Full figure generation requires the kaleido package, | ||
|
@@ -341,7 +375,21 @@ def full_figure_for_development(fig, warn=True, as_dict=False): | |
"To suppress this warning, set warn=False" | ||
) | ||
|
||
fig = json.loads(scope.transform(fig, format="json").decode("utf-8")) | ||
if kaleido_major > 0: | ||
# Kaleido v1 | ||
bytes = kaleido.calc_fig_sync( | ||
fig, | ||
opts=dict(format="json"), | ||
) | ||
fig = json.loads(bytes.decode("utf-8")) | ||
else: | ||
# Kaleido v0 | ||
warnings.warn( | ||
f"Support for Kaleido versions less than 1.0.0 is deprecated and will be removed after {ENGINE_SUPPORT_TIMELINE}. Please upgrade Kaleido to version 1.0.0 or greater (`pip install --upgrade kaleido`).", | ||
DeprecationWarning, | ||
) | ||
fig = json.loads(scope.transform(fig, format="json").decode("utf-8")) | ||
|
||
if as_dict: | ||
return fig | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
from ._kaleido import to_image, write_image, scope | ||
from ._kaleido import write_image, to_image |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,9 +17,11 @@ pyshp | |
matplotlib | ||
scikit-image | ||
psutil | ||
kaleido | ||
# kaleido>=1.0.0 # Uncomment and delete line below once Kaleido v1 is released | ||
git+https://github.com/plotly/[email protected]#subdirectory=src/py | ||
orjson | ||
polars[timezone] | ||
pyarrow | ||
plotly-geo | ||
vaex;python_version<="3.9" | ||
pdfrw |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we still handle EPS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gvwilson Following up on this — Kaleido v1 does not support EPS yet. So either we drop support for EPS entirely, or document that EPS is only available with Kaleido v0 and add an informative error message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please do the latter - thanks