Skip to content

Add Kaleido image export support #2613

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

Merged
merged 31 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1c18fe4
Add kaleido image export option behind the kaleido_export future flag
jonmmease Jul 3, 2020
7467329
Add CHANGELOG entry
jonmmease Jul 3, 2020
b546fcc
Add eps/emf formats
jonmmease Jul 7, 2020
7f65f5f
Replace future flag with engine kwarg
jonmmease Jul 7, 2020
556ef96
emf only available with kaleido
jonmmease Jul 7, 2020
ed71d6a
import kaleido submodule when plotly.io is imported
jonmmease Jul 8, 2020
da4cb83
Update Image renderers with engine parameter
jonmmease Jul 8, 2020
3e1cbd4
Added kaleido engine tests
jonmmease Jul 8, 2020
299165d
Merge remote-tracking branch 'origin/master' into kaleido
jonmmease Jul 8, 2020
411ffb4
Python 2.7 mock compatibility
jonmmease Jul 8, 2020
de44623
Python 2.7 mock compatibility
jonmmease Jul 8, 2020
c5f4e48
Update CHANGELOG.md
jonmmease Jul 8, 2020
4c5fe76
Add kaleido test that actually calls Kaleido and checks that the
jonmmease Jul 8, 2020
011ec72
Remove broken EMF format as option
jonmmease Jul 8, 2020
b5fc3db
Merge remote-tracking branch 'origin/master' into kaleido
jonmmease Jul 8, 2020
f8bff56
Remove broken EMF format as option
jonmmease Jul 8, 2020
827af91
Update image export documentation to recommend and describe Kaleido
jonmmease Jul 9, 2020
ef6e68d
Add engine docstring to figure image export methods
jonmmease Jul 9, 2020
fc7d856
Change kaleido conda channel to plotly since it most likely won't be …
jonmmease Jul 10, 2020
aee0e0d
Conda package renamed from kaleido -> python-kaleido
jonmmease Jul 12, 2020
32f6e7f
Merge remote-tracking branch 'origin/master' into kaleido
jonmmease Jul 13, 2020
00987c0
in README: indicate that Keleido is new and improved and orca is legacy
jonmmease Jul 14, 2020
a25f5b2
Add Kaleido note to orca-management section
jonmmease Jul 14, 2020
a033df0
JPEG typo
jonmmease Jul 14, 2020
d1fc9a8
Merge "Install Dependency" sections and better explain that Kaleido i…
jonmmease Jul 14, 2020
2bdcfe2
Replace Orca with plotly.py when discussing supported image export fo…
jonmmease Jul 14, 2020
70c11ac
varying type
jonmmease Jul 14, 2020
e350025
factor typo [ci skip]
jonmmease Jul 14, 2020
967b728
Update CHANGELOG.md
jonmmease Jul 14, 2020
81a0bc7
Update doc/python/static-image-export.md
jonmmease Jul 14, 2020
74c4274
Update doc/python/orca-management.md
jonmmease Jul 14, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [4.9.0] - ???

### Added
- Added preview image export support using Kaleido. Kaleido support is enabled by installing the `kaleido` package from PyPI and setting the `kaleido_export` future flag before importing `plotly` ([#2613](https://github.com/plotly/plotly.py/pull/2613)).

## [4.8.2] - 2020-06-26

### Updated
Expand Down
5 changes: 5 additions & 0 deletions packages/python/plotly/_plotly_future_/kaleido_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from __future__ import absolute_import
from _plotly_future_ import _future_flags, _assert_plotly_not_imported

_assert_plotly_not_imported()
_future_flags.add("kaleido_export")
31 changes: 23 additions & 8 deletions packages/python/plotly/plotly/io/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
from _plotly_utils.importers import relative_import
from _plotly_future_ import _future_flags
import sys

if sys.version_info < (3, 7):
from ._orca import to_image, write_image
from . import orca
if "kaleido_export" in _future_flags:
from .kaleido import to_image, write_image
from . import kaleido

extra_modules = ["kaleido"]
else:
from ._orca import to_image, write_image
from . import orca

extra_modules = ["orca"]

from ._json import to_json, from_json, read_json, write_json
from ._templates import templates, to_templated
from ._html import to_html, write_html
Expand All @@ -13,7 +23,6 @@
__all__ = [
"to_image",
"write_image",
"orca",
"to_json",
"from_json",
"read_json",
Expand All @@ -25,14 +34,19 @@
"renderers",
"show",
"base_renderers",
]
] + extra_modules
else:
if "kaleido_export" in _future_flags:
extra_modules = [".kaleido"]
extra_objects = [".kaleido.to_image", ".kaleido.write_image"]
else:
extra_modules = [".orca"]
extra_objects = ["._orca.to_image", "._orca.write_image"]

__all__, __getattr__, __dir__ = relative_import(
__name__,
[".orca", ".base_renderers"],
[".base_renderers"] + extra_modules,
[
"._orca.to_image",
"._orca.write_image",
"._json.to_json",
"._json.from_json",
"._json.read_json",
Expand All @@ -43,7 +57,8 @@
"._html.write_html",
"._renderers.renderers",
"._renderers.show",
],
]
+ extra_objects,
)

# Set default template (for < 3.7 this is done in ploty/__init__.py)
Expand Down
183 changes: 183 additions & 0 deletions packages/python/plotly/plotly/io/_kaleido.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
from six import string_types
import os
from plotly.io._utils import validate_coerce_fig_to_dict

try:
from kaleido.scopes.plotly import PlotlyScope

scope = PlotlyScope()
except ImportError:
PlotlyScope = None
scope = None


def to_image(fig, format=None, width=None, height=None, scale=None, validate=True):
"""
Convert a figure to a static image bytes string

Parameters
----------
fig:
Figure object or dict representing a figure

format: str or None
The desired image format. One of
- 'png'
- 'jpg' or 'jpeg'
- 'webp'
- 'svg'
- 'pdf'

If not specified, will default to `plotly.io.kaleido.scope.default_format`

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`

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`

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`

validate: bool
True if the figure should be validated before being converted to
an image, False otherwise.

Returns
-------
bytes
The image data
"""
# Raise informative error message if Kaleido is not installed
if scope is None:
raise ValueError(
"""
Image export requires the kaleido package, which can be installed using pip:
$ pip install -U kaleido
"""
)

# Validate figure
# ---------------
fig_dict = validate_coerce_fig_to_dict(fig, validate)
img_bytes = scope.transform(
fig_dict, format=format, width=width, height=height, scale=scale
)

return img_bytes


def write_image(
fig, file, format=None, scale=None, width=None, height=None, validate=True
):
"""
Convert a figure to a static image and write it to a file or writeable
object

Parameters
----------
fig:
Figure object or dict representing a figure

file: str or writeable
A string representing a local file path or a writeable object
(e.g. an open file descriptor)

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)

If not specified and `file` is a string then this will default to the
file extension. If not specified and `file` is not a string then this
will default to `plotly.io.config.default_format`

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.config.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.config.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.config.default_scale`

validate: bool
True if the figure should be validated before being converted to
an image, False otherwise.

Returns
-------
None
"""

# Check if file is a string
# -------------------------
file_is_str = isinstance(file, string_types)

# Infer format if not specified
# -----------------------------
if file_is_str and format is None:
_, ext = os.path.splitext(file)
if ext:
format = ext.lstrip(".")
else:
raise ValueError(
"""
Cannot infer image type from output path '{file}'.
Please add a file extension or specify the type using the format parameter.
For example:

>>> import plotly.io as pio
>>> pio.write_image(fig, file_path, format='png')
""".format(
file=file
)
)

# Request image
# -------------
# Do this first so we don't create a file if image conversion fails
img_data = to_image(
fig, format=format, scale=scale, width=width, height=height, validate=validate
)

# Open file
# ---------
if file_is_str:
with open(file, "wb") as f:
f.write(img_data)
else:
file.write(img_data)


__all__ = ["to_image", "write_image", "scope"]
1 change: 1 addition & 0 deletions packages/python/plotly/plotly/io/kaleido.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._kaleido import to_image, write_image, scope