From 1c18fe406154dc493b73ee231349209b4ecb30c0 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Fri, 3 Jul 2020 14:34:30 -0400 Subject: [PATCH 01/28] Add kaleido image export option behind the kaleido_export future flag --- .../plotly/_plotly_future_/kaleido_export.py | 5 + packages/python/plotly/plotly/io/__init__.py | 31 ++- packages/python/plotly/plotly/io/_kaleido.py | 183 ++++++++++++++++++ packages/python/plotly/plotly/io/kaleido.py | 1 + 4 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 packages/python/plotly/_plotly_future_/kaleido_export.py create mode 100644 packages/python/plotly/plotly/io/_kaleido.py create mode 100644 packages/python/plotly/plotly/io/kaleido.py diff --git a/packages/python/plotly/_plotly_future_/kaleido_export.py b/packages/python/plotly/_plotly_future_/kaleido_export.py new file mode 100644 index 00000000000..3e0450481ba --- /dev/null +++ b/packages/python/plotly/_plotly_future_/kaleido_export.py @@ -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") diff --git a/packages/python/plotly/plotly/io/__init__.py b/packages/python/plotly/plotly/io/__init__.py index ab9f9218c70..c031266e720 100644 --- a/packages/python/plotly/plotly/io/__init__.py +++ b/packages/python/plotly/plotly/io/__init__.py @@ -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 @@ -13,7 +23,6 @@ __all__ = [ "to_image", "write_image", - "orca", "to_json", "from_json", "read_json", @@ -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", @@ -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) diff --git a/packages/python/plotly/plotly/io/_kaleido.py b/packages/python/plotly/plotly/io/_kaleido.py new file mode 100644 index 00000000000..ae19efd23e7 --- /dev/null +++ b/packages/python/plotly/plotly/io/_kaleido.py @@ -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"] diff --git a/packages/python/plotly/plotly/io/kaleido.py b/packages/python/plotly/plotly/io/kaleido.py new file mode 100644 index 00000000000..c14b315047b --- /dev/null +++ b/packages/python/plotly/plotly/io/kaleido.py @@ -0,0 +1 @@ +from ._kaleido import to_image, write_image, scope From 7467329d1aff6a844c00a693505f080ff9063c49 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Fri, 3 Jul 2020 15:53:03 -0400 Subject: [PATCH 02/28] Add CHANGELOG entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e087fcb07d..d1c3f6bdc83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 From b546fcc91a44a954b3b9d17ab5dbccf0c30b6137 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 7 Jul 2020 05:59:23 -0400 Subject: [PATCH 03/28] Add eps/emf formats --- packages/python/plotly/plotly/io/_kaleido.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/python/plotly/plotly/io/_kaleido.py b/packages/python/plotly/plotly/io/_kaleido.py index ae19efd23e7..b95d6d0d5dc 100644 --- a/packages/python/plotly/plotly/io/_kaleido.py +++ b/packages/python/plotly/plotly/io/_kaleido.py @@ -27,6 +27,8 @@ def to_image(fig, format=None, width=None, height=None, scale=None, validate=Tru - 'webp' - 'svg' - 'pdf' + - 'eps' (Requires the poppler library to be installed and on the PATH) + - 'emf' (Requires inkscape application to be installed and on the PATH) If not specified, will default to `plotly.io.kaleido.scope.default_format` @@ -103,7 +105,8 @@ def write_image( - 'webp' - 'svg' - 'pdf' - - 'eps' (Requires the poppler library to be installed) + - 'eps' (Requires the poppler library to be installed and on the PATH) + - 'emf' (Requires inkscape application to be installed and on the PATH) 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 From 7f65f5f586402f0dd2c93a3a211d4a83c3d96b4d Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 7 Jul 2020 05:59:41 -0400 Subject: [PATCH 04/28] Replace future flag with engine kwarg --- .../plotly/_plotly_future_/kaleido_export.py | 5 - packages/python/plotly/plotly/io/__init__.py | 31 ++---- packages/python/plotly/plotly/io/_kaleido.py | 105 +++++++++++++++--- 3 files changed, 100 insertions(+), 41 deletions(-) delete mode 100644 packages/python/plotly/_plotly_future_/kaleido_export.py diff --git a/packages/python/plotly/_plotly_future_/kaleido_export.py b/packages/python/plotly/_plotly_future_/kaleido_export.py deleted file mode 100644 index 3e0450481ba..00000000000 --- a/packages/python/plotly/_plotly_future_/kaleido_export.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import absolute_import -from _plotly_future_ import _future_flags, _assert_plotly_not_imported - -_assert_plotly_not_imported() -_future_flags.add("kaleido_export") diff --git a/packages/python/plotly/plotly/io/__init__.py b/packages/python/plotly/plotly/io/__init__.py index c031266e720..e4239fc8cf1 100644 --- a/packages/python/plotly/plotly/io/__init__.py +++ b/packages/python/plotly/plotly/io/__init__.py @@ -1,19 +1,9 @@ from _plotly_utils.importers import relative_import -from _plotly_future_ import _future_flags import sys if sys.version_info < (3, 7): - 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 ._kaleido import to_image, write_image + from . import 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 @@ -23,6 +13,7 @@ __all__ = [ "to_image", "write_image", + "orca", "to_json", "from_json", "read_json", @@ -34,19 +25,14 @@ "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__, - [".base_renderers"] + extra_modules, + [".orca", ".base_renderers"], [ + "._kaleido.to_image", + "._kaleido.write_image", "._json.to_json", "._json.from_json", "._json.read_json", @@ -57,8 +43,7 @@ "._html.write_html", "._renderers.renderers", "._renderers.show", - ] - + extra_objects, + ], ) # Set default template (for < 3.7 this is done in ploty/__init__.py) diff --git a/packages/python/plotly/plotly/io/_kaleido.py b/packages/python/plotly/plotly/io/_kaleido.py index b95d6d0d5dc..cdcec584c1c 100644 --- a/packages/python/plotly/plotly/io/_kaleido.py +++ b/packages/python/plotly/plotly/io/_kaleido.py @@ -1,17 +1,27 @@ +from __future__ import absolute_import from six import string_types import os +import plotly from plotly.io._utils import validate_coerce_fig_to_dict try: 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") + scope.mathjax = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js" except ImportError: PlotlyScope = None scope = None -def to_image(fig, format=None, width=None, height=None, scale=None, validate=True): +def to_image( + fig, format=None, width=None, height=None, scale=None, validate=True, engine="auto" +): """ Convert a figure to a static image bytes string @@ -30,21 +40,27 @@ def to_image(fig, format=None, width=None, height=None, scale=None, validate=Tru - 'eps' (Requires the poppler library to be installed and on the PATH) - 'emf' (Requires inkscape application to be installed and on the PATH) - If not specified, will default to `plotly.io.kaleido.scope.default_format` + 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" 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 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" 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 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" scale: int or float or None The scale factor to use when exporting the figure. A scale factor @@ -52,22 +68,59 @@ def to_image(fig, format=None, width=None, height=None, scale=None, validate=Tru 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 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" + 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 + Returns ------- bytes The image data """ + # Handle engine + # ------------- + if engine == "auto": + if scope is not None: + engine = "kaleido" + else: + engine = "orca" + + if engine == "orca": + # Fall back to legacy orca image export path + from ._orca import to_image as to_image_orca + + return to_image_orca( + fig, + format=format, + width=width, + height=height, + scale=scale, + validate=validate, + ) + elif engine != "kaleido": + raise ValueError( + "Invalid image export engine specified: {engine}".format( + engine=repr(engine) + ) + ) + # 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: +Image export using the "kaleido" engine requires the kaleido package, +which can be installed using pip: $ pip install -U kaleido """ ) @@ -83,7 +136,14 @@ def to_image(fig, format=None, width=None, height=None, scale=None, validate=Tru def write_image( - fig, file, format=None, scale=None, width=None, height=None, validate=True + fig, + file, + format=None, + scale=None, + width=None, + height=None, + validate=True, + engine="auto", ): """ Convert a figure to a static image and write it to a file or writeable @@ -110,21 +170,27 @@ def write_image( 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` + will default to: + - `plotly.io.kaleido.scope.default_format` if engine is "kaleido" + - `plotly.io.orca.config.default_format` if engine is "orca" 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` + 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" 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` + 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" scale: int or float or None The scale factor to use when exporting the figure. A scale factor @@ -132,17 +198,24 @@ def write_image( 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` + 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" 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 + Returns ------- None """ - # Check if file is a string # ------------------------- file_is_str = isinstance(file, string_types) @@ -171,7 +244,13 @@ def write_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 + fig, + format=format, + scale=scale, + width=width, + height=height, + validate=validate, + engine=engine, ) # Open file From 556ef96e9a745449b42ce7cf621d551383adb147 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 7 Jul 2020 07:32:16 -0400 Subject: [PATCH 05/28] emf only available with kaleido --- packages/python/plotly/plotly/io/_kaleido.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/plotly/plotly/io/_kaleido.py b/packages/python/plotly/plotly/io/_kaleido.py index cdcec584c1c..0f88f9a971a 100644 --- a/packages/python/plotly/plotly/io/_kaleido.py +++ b/packages/python/plotly/plotly/io/_kaleido.py @@ -38,7 +38,7 @@ def to_image( - 'svg' - 'pdf' - 'eps' (Requires the poppler library to be installed and on the PATH) - - 'emf' (Requires inkscape application to be installed and on the PATH) + - 'emf' ("kaleido" engine only, requires inkscape on the PATH) If not specified, will default to: - `plotly.io.kaleido.scope.default_format` if engine is "kaleido" @@ -166,7 +166,7 @@ def write_image( - 'svg' - 'pdf' - 'eps' (Requires the poppler library to be installed and on the PATH) - - 'emf' (Requires inkscape application to be installed and on the PATH) + - 'emf' ("kaleido" engine only, requires inkscape on the PATH) 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 From ed71d6ac4da5f9ad5957bbdda71d9dfce5b7bdee Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 05:35:19 -0400 Subject: [PATCH 06/28] import kaleido submodule when plotly.io is imported --- packages/python/plotly/plotly/io/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/plotly/plotly/io/__init__.py b/packages/python/plotly/plotly/io/__init__.py index e4239fc8cf1..cdbf473d1fd 100644 --- a/packages/python/plotly/plotly/io/__init__.py +++ b/packages/python/plotly/plotly/io/__init__.py @@ -3,7 +3,7 @@ if sys.version_info < (3, 7): from ._kaleido import to_image, write_image - from . import orca + from . import orca, kaleido from ._json import to_json, from_json, read_json, write_json from ._templates import templates, to_templated from ._html import to_html, write_html @@ -29,7 +29,7 @@ else: __all__, __getattr__, __dir__ = relative_import( __name__, - [".orca", ".base_renderers"], + [".orca", ".kaleido", ".base_renderers"], [ "._kaleido.to_image", "._kaleido.write_image", From da4cb83cf7c0ccb239c7dc7f11f3d51223c80875 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 05:37:42 -0400 Subject: [PATCH 07/28] Update Image renderers with engine parameter Don't auto-start orca when image renderer is activated because now we might not end up using orca. --- .../plotly/plotly/io/_base_renderers.py | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/python/plotly/plotly/io/_base_renderers.py b/packages/python/plotly/plotly/io/_base_renderers.py index 9cd7fbfb72b..10226ad71e0 100644 --- a/packages/python/plotly/plotly/io/_base_renderers.py +++ b/packages/python/plotly/plotly/io/_base_renderers.py @@ -112,6 +112,7 @@ def __init__( width=None, height=None, scale=None, + engine="auto", ): self.mime_type = mime_type @@ -120,10 +121,7 @@ def __init__( self.width = width self.height = height self.scale = scale - - def activate(self): - # Start up orca server to reduce the delay on first render - ensure_server() + self.engine = engine def to_mimebundle(self, fig_dict): image_bytes = to_image( @@ -133,6 +131,7 @@ def to_mimebundle(self, fig_dict): height=self.height, scale=self.scale, validate=False, + engine=self.engine, ) if self.b64_encode: @@ -146,14 +145,14 @@ def to_mimebundle(self, fig_dict): class PngRenderer(ImageRenderer): """ Renderer to display figures as static PNG images. This renderer requires - the orca command-line utility and is broadly compatible across IPython - environments (classic Jupyter Notebook, JupyterLab, QtConsole, VSCode, - PyCharm, etc) and nbconvert targets (HTML, PDF, etc.). + either the kaleido package or the orca command-line utility and is broadly + compatible across IPython environments (classic Jupyter Notebook, JupyterLab, + QtConsole, VSCode, PyCharm, etc) and nbconvert targets (HTML, PDF, etc.). mime type: 'image/png' """ - def __init__(self, width=None, height=None, scale=None): + def __init__(self, width=None, height=None, scale=None, engine="auto"): super(PngRenderer, self).__init__( mime_type="image/png", b64_encode=True, @@ -161,20 +160,21 @@ def __init__(self, width=None, height=None, scale=None): width=width, height=height, scale=scale, + engine=engine, ) class SvgRenderer(ImageRenderer): """ Renderer to display figures as static SVG images. This renderer requires - the orca command-line utility and is broadly compatible across IPython - environments (classic Jupyter Notebook, JupyterLab, QtConsole, VSCode, - PyCharm, etc) and nbconvert targets (HTML, PDF, etc.). + either the kaleido package or the orca command-line utility and is broadly + compatible across IPython environments (classic Jupyter Notebook, JupyterLab, + QtConsole, VSCode, PyCharm, etc) and nbconvert targets (HTML, PDF, etc.). mime type: 'image/svg+xml' """ - def __init__(self, width=None, height=None, scale=None): + def __init__(self, width=None, height=None, scale=None, engine="auto"): super(SvgRenderer, self).__init__( mime_type="image/svg+xml", b64_encode=False, @@ -182,20 +182,21 @@ def __init__(self, width=None, height=None, scale=None): width=width, height=height, scale=scale, + engine=engine, ) class JpegRenderer(ImageRenderer): """ Renderer to display figures as static JPEG images. This renderer requires - the orca command-line utility and is broadly compatible across IPython - environments (classic Jupyter Notebook, JupyterLab, QtConsole, VSCode, - PyCharm, etc) and nbconvert targets (HTML, PDF, etc.). + either the kaleido package or the orca command-line utility and is broadly + compatible across IPython environments (classic Jupyter Notebook, JupyterLab, + QtConsole, VSCode, PyCharm, etc) and nbconvert targets (HTML, PDF, etc.). mime type: 'image/jpeg' """ - def __init__(self, width=None, height=None, scale=None): + def __init__(self, width=None, height=None, scale=None, engine="auto"): super(JpegRenderer, self).__init__( mime_type="image/jpeg", b64_encode=True, @@ -203,19 +204,20 @@ def __init__(self, width=None, height=None, scale=None): width=width, height=height, scale=scale, + engine=engine, ) class PdfRenderer(ImageRenderer): """ Renderer to display figures as static PDF images. This renderer requires - the orca command-line utility and is compatible with JupyterLab and the - LaTeX-based nbconvert export to PDF. + either the kaleido package or the orca command-line utility and is compatible + with JupyterLab and the LaTeX-based nbconvert export to PDF. mime type: 'application/pdf' """ - def __init__(self, width=None, height=None, scale=None): + def __init__(self, width=None, height=None, scale=None, engine="auto"): super(PdfRenderer, self).__init__( mime_type="application/pdf", b64_encode=True, @@ -223,6 +225,7 @@ def __init__(self, width=None, height=None, scale=None): width=width, height=height, scale=scale, + engine=engine, ) From 3e1cbd4e295030ff8185b41164dd4ebe187dd548 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 07:08:49 -0400 Subject: [PATCH 08/28] Added kaleido engine tests --- .../test_optional/test_kaleido/__init__.py | 0 .../test_kaleido/test_kaleido.py | 92 +++++++++++++++++++ packages/python/plotly/tox.ini | 1 + 3 files changed, 93 insertions(+) create mode 100644 packages/python/plotly/plotly/tests/test_optional/test_kaleido/__init__.py create mode 100644 packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py diff --git a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/__init__.py b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py new file mode 100644 index 00000000000..b833f029348 --- /dev/null +++ b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py @@ -0,0 +1,92 @@ +import plotly.io as pio +import plotly.io.kaleido +from unittest.mock import Mock +from contextlib import contextmanager + + +fig = {"layout": {"title": {"text": "figure title"}}} + + +@contextmanager +def mocked_scope(): + # Code to acquire resource, e.g.: + scope_mock = Mock() + original_scope = pio._kaleido.scope + pio._kaleido.scope = scope_mock + try: + yield scope_mock + finally: + pio._kaleido.scope = original_scope + + +def test_kaleido_engine_to_image(): + with mocked_scope() as scope: + pio.to_image(fig, engine="kaleido", validate=False) + + scope.transform.assert_called_with( + fig, format=None, width=None, height=None, scale=None + ) + + +def test_kaleido_engine_write_image(): + writeable_mock = Mock() + with mocked_scope() as scope: + pio.write_image(fig, writeable_mock, engine="kaleido", validate=False) + + scope.transform.assert_called_with( + fig, format=None, width=None, height=None, scale=None + ) + + writeable_mock.write.assert_called_once() + + +def test_kaleido_engine_to_image_kwargs(): + with mocked_scope() as scope: + pio.to_image( + fig, + format="pdf", + width=700, + height=600, + scale=2, + engine="kaleido", + validate=False, + ) + + scope.transform.assert_called_with( + fig, format="pdf", width=700, height=600, scale=2 + ) + + +def test_kaleido_engine_write_image_kwargs(): + writeable_mock = Mock() + with mocked_scope() as scope: + pio.write_image( + fig, + writeable_mock, + format="jpg", + width=700, + height=600, + scale=2, + engine="kaleido", + validate=False, + ) + + scope.transform.assert_called_with( + fig, format="jpg", width=700, height=600, scale=2 + ) + + writeable_mock.write.assert_called_once() + + +def test_image_renderer(): + with mocked_scope() as scope: + pio.show(fig, renderer="svg", engine="kaleido", validate=False) + + renderer = pio.renderers["svg"] + scope.transform.assert_called_with( + fig, + format="svg", + width=renderer.width, + height=renderer.height, + scale=renderer.scale, + ) diff --git a/packages/python/plotly/tox.ini b/packages/python/plotly/tox.ini index dddc6e69ec4..8746fcab515 100644 --- a/packages/python/plotly/tox.ini +++ b/packages/python/plotly/tox.ini @@ -74,6 +74,7 @@ deps= optional: pillow==5.2.0 optional: matplotlib==2.2.3 optional: scikit-image==0.14.4 + optional: kaleido ; CORE ENVIRONMENTS [testenv:py27-core] From 411ffb448f24ec72c38256f91c0c1e0c526290c7 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 07:21:42 -0400 Subject: [PATCH 09/28] Python 2.7 mock compatibility --- .../plotly/tests/test_optional/test_kaleido/test_kaleido.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py index b833f029348..c9efb164741 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py @@ -1,8 +1,12 @@ import plotly.io as pio import plotly.io.kaleido -from unittest.mock import Mock +import sys from contextlib import contextmanager +if sys.version_info >= (3, 3): + from unittest.mock import Mock +else: + from mock import Mock fig = {"layout": {"title": {"text": "figure title"}}} From de44623db9c4ee0eb9ea42bc853b40cd5bb1e4da Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 07:29:44 -0400 Subject: [PATCH 10/28] Python 2.7 mock compatibility --- .../plotly/tests/test_optional/test_kaleido/test_kaleido.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py index c9efb164741..7c35ba09f5a 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py @@ -41,7 +41,7 @@ def test_kaleido_engine_write_image(): fig, format=None, width=None, height=None, scale=None ) - writeable_mock.write.assert_called_once() + assert writeable_mock.write.call_count == 1 def test_kaleido_engine_to_image_kwargs(): @@ -79,7 +79,7 @@ def test_kaleido_engine_write_image_kwargs(): fig, format="jpg", width=700, height=600, scale=2 ) - writeable_mock.write.assert_called_once() + assert writeable_mock.write.call_count == 1 def test_image_renderer(): From c5f4e4854ee034f6030f14022a3340651ee7c6dd Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 07:29:56 -0400 Subject: [PATCH 11/28] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c3f6bdc83..a6c93020596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ 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)). + - Added image export support using Kaleido. The image export backend can be configured using the new `engine` argument to `plotly.io.to_image` and `plotly.io.write_image`. The `engine` argument may be set to `"kaleido"`, `"orca"`, or `"auto"`. The default is `engine="auto"`, in which case the Kaleido backend is enabled if the `kaleido` package from PyPI is installed, otherwise Orca is used. ([#2613](https://github.com/plotly/plotly.py/pull/2613)). ## [4.8.2] - 2020-06-26 From 4c5fe767adb6cb0dc40c8bc5c1223bbf85b641fc Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 07:32:30 -0400 Subject: [PATCH 12/28] Add kaleido test that actually calls Kaleido and checks that the resulting bytes are reasonable --- .../plotly/tests/test_optional/test_kaleido/test_kaleido.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py index 7c35ba09f5a..53044f0575f 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_kaleido/test_kaleido.py @@ -23,6 +23,11 @@ def mocked_scope(): pio._kaleido.scope = original_scope +def test_kaleido_engine_to_image_returns_bytes(): + result = pio.to_image(fig, format="svg", engine="kaleido", validate=False) + assert result.startswith(b" Date: Wed, 8 Jul 2020 15:43:06 -0400 Subject: [PATCH 13/28] Remove broken EMF format as option --- packages/python/plotly/plotly/io/_kaleido.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/python/plotly/plotly/io/_kaleido.py b/packages/python/plotly/plotly/io/_kaleido.py index 0f88f9a971a..eea208dcf89 100644 --- a/packages/python/plotly/plotly/io/_kaleido.py +++ b/packages/python/plotly/plotly/io/_kaleido.py @@ -38,7 +38,6 @@ def to_image( - 'svg' - 'pdf' - 'eps' (Requires the poppler library to be installed and on the PATH) - - 'emf' ("kaleido" engine only, requires inkscape on the PATH) If not specified, will default to: - `plotly.io.kaleido.scope.default_format` if engine is "kaleido" @@ -166,7 +165,6 @@ def write_image( - 'svg' - 'pdf' - 'eps' (Requires the poppler library to be installed and on the PATH) - - 'emf' ("kaleido" engine only, requires inkscape on the PATH) 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 From f8bff562db3b3b28745453c4120f8ca11cf912ed Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 19:38:35 -0400 Subject: [PATCH 14/28] Remove broken EMF format as option --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 015327e9c29..a8d1ed40d58 100644 --- a/README.md +++ b/README.md @@ -133,12 +133,27 @@ jupyter labextension install @jupyter-widgets/jupyterlab-manager plotlywidget@4. Please check out our [Troubleshooting guide](https://plotly.com/python/troubleshooting/) if you run into any problems with JupyterLab. -### Static Image Export +### Static Image Export with Kaleido plotly.py supports static image export using the `to_image` and `write_image` -functions in the `plotly.io` package. This functionality requires the -installation of the plotly [orca](https://github.com/plotly/orca) command line utility and the -[`psutil`](https://github.com/giampaolo/psutil) Python package. +functions in the `plotly.io` module. This functionality requires the +[`kaleido`](https://github.com/plotly/Kaleido) package which can be installed +using pip... + +``` +$ pip install -U kaleido +``` + +or conda. +``` +$ conda install -c conda-forge kaleido +``` + +### Static Image Export with Orca + +While Kaleido is now the recommended approach, image export can also be supported +by the [orca](https://github.com/plotly/orca) command line utility and the + [`psutil`](https://github.com/giampaolo/psutil) Python package. These dependencies can both be installed using conda: From 827af91be81a19e950999b0f0d7dba209bd1571e Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Wed, 8 Jul 2020 20:16:32 -0400 Subject: [PATCH 15/28] Update image export documentation to recommend and describe Kaleido --- doc/python/orca-management.md | 58 +++++++++++++++++- doc/python/static-image-export.md | 98 +++++++++++++++---------------- 2 files changed, 104 insertions(+), 52 deletions(-) diff --git a/doc/python/orca-management.md b/doc/python/orca-management.md index 061cca29cd5..99b54c6d991 100644 --- a/doc/python/orca-management.md +++ b/doc/python/orca-management.md @@ -34,13 +34,65 @@ jupyter: --- ### Overview -This section covers the lower-level details of how plotly.py uses orca to perform static image generation. Please refer to the [Static Image Export](/python/static-image-export/) section for general information on creating static images from plotly.py figures. +This section covers the lower-level details of how plotly.py can use orca to perform static image generation. Please refer to the [Static Image Export](/python/static-image-export/) section for general information on creating static images from plotly.py figures. -### What is Orca? +### What is orca? Orca is an [Electron](https://electronjs.org/) application that inputs plotly figure specifications and converts them into static images. Orca can run as a command-line utility or as a long-running server process. In order to provide the fastest possible image export experience, plotly.py launches orca in server mode, and communicates with it over a local port. See https://github.com/plotly/orca for more information. By default, plotly.py launches the orca server process the first time an image export operation is performed, and then leaves it running until the main Python process exits. Because of this, the first image export operation in an interactive session will typically take a couple of seconds, but then all subsequent export operations will be significantly faster, since the server is already running. +### Installing orca +There are 3 general approaches to installing orca and its Python dependencies. + +##### conda +Using the [conda](https://conda.io/docs/) package manager, you can install these dependencies in a single command: +``` +$ conda install -c plotly plotly-orca==1.2.1 psutil requests +``` + +**Note:** Even if you do not want to use conda to manage your Python dependencies, it is still useful as a cross platform tool for managing native libraries and command-line utilities (e.g. git, wget, graphviz, boost, gcc, nodejs, cairo, etc.). For this use-case, start with [Miniconda](https://conda.io/miniconda.html) (~60MB) and tell the installer to add itself to your system `PATH`. Then run `conda install plotly-orca==1.2.1` and the orca executable will be available system wide. + +##### npm + pip +You can use the [npm](https://www.npmjs.com/get-npm) package manager to install `orca` (and its `electron` dependency), and then use pip to install `psutil`: + +``` +$ npm install -g electron@1.8.4 orca +$ pip install psutil requests +``` + +##### Standalone Binaries + pip +If you are unable to install conda or npm, you can install orca as a precompiled binary for your operating system. Follow the instructions in the orca [README](https://github.com/plotly/orca) to install orca and add it to your system `PATH`. Then use pip to install `psutil`. + +``` +$ pip install psutil requests +``` + + +### Install orca on Google Colab +``` +!pip install plotly>=4.7.1 +!wget https://github.com/plotly/orca/releases/download/v1.2.1/orca-1.2.1-x86_64.AppImage -O /usr/local/bin/orca +!chmod +x /usr/local/bin/orca +!apt-get install xvfb libgtk2.0-0 libgconf-2-4 +``` + +Once this is done you can use this code to make, show and export a figure: + +```python +import plotly.graph_objects as go +fig = go.Figure( go.Scatter(x=[1,2,3], y=[1,3,2] ) ) +fig.write_image("fig1.svg") +fig.write_image("fig1.png") +``` + +The files can then be downloaded with: + +```python +from google.colab import files +files.download('fig1.svg') +files.download('fig1.png') +``` + ### Create a Figure Now let's create a simple scatter plot with 100 random points of variying color and size. @@ -207,4 +259,4 @@ In addition to the `executable` property, the `plotly.io.orca.config` object can ### Saving Configuration Settings -Configuration options can optionally be saved to the `~/.plotly/` directory by calling the `plotly.io.config.save()` method. Saved setting will be automatically loaded at the start of future sessions. \ No newline at end of file +Configuration options can optionally be saved to the `~/.plotly/` directory by calling the `plotly.io.config.save()` method. Saved setting will be automatically loaded at the start of future sessions. diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 6d1b68b8bbe..27a16c76915 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -41,31 +41,20 @@ Plotly figures are interactive when viewed in a web browser: you can hover over -#### Install Dependencies -Static image generation requires the [orca](https://github.com/plotly/orca) commandline utility and the [psutil](https://github.com/giampaolo/psutil) and [requests](https://2.python-requests.org/en/master/) Python libraries. There are 3 general approach to installing these dependencies. - -##### conda -Using the [conda](https://conda.io/docs/) package manager, you can install these dependencies in a single command: +#### Install Dependencies (Kaleido) +Static image generation requires the [`kaleido`](https://github.com/plotly/Kaleido) package which can be installed using pip... ``` -$ conda install -c plotly plotly-orca==1.2.1 psutil requests +$ pip install -U kaleido ``` -**Note:** Even if you do not want to use conda to manage your Python dependencies, it is still useful as a cross platform tool for managing native libraries and command-line utilities (e.g. git, wget, graphviz, boost, gcc, nodejs, cairo, etc.). For this use-case, start with [Miniconda](https://conda.io/miniconda.html) (~60MB) and tell the installer to add itself to your system `PATH`. Then run `conda install plotly-orca==1.2.1` and the orca executable will be available system wide. - -##### npm + pip -You can use the [npm](https://www.npmjs.com/get-npm) package manager to install `orca` (and its `electron` dependency), and then use pip to install `psutil`: - -``` -$ npm install -g electron@1.8.4 orca -$ pip install psutil requests +or conda. ``` +$ conda install -c conda-forge kaleido +``` -##### Standalone Binaries + pip -If you are unable to install conda or npm, you can install orca as a precompiled binary for your operating system. Follow the instructions in the orca [README](https://github.com/plotly/orca) to install orca and add it to your system `PATH`. Then use pip to install `psutil`. +#### Install Dependencies (Orca) +While Kaleido is now the recommended approach, image export can also be supported by the [orca](https://github.com/plotly/orca) command line utility. See the [Orca Management](/python/orca-management/) section for instructions on installing, configuring, and troubleshooting orca. -``` -$ pip install psutil requests -``` ### Create a Figure @@ -157,33 +146,6 @@ fig.write_image("images/fig1.eps") **Note:** It is important to note that any figures containing WebGL traces (i.e. of type `scattergl`, `heatmapgl`, `contourgl`, `scatter3d`, `surface`, `mesh3d`, `scatterpolargl`, `cone`, `streamtube`, `splom`, or `parcoords`) that are exported in a vector format will include encapsulated rasters, instead of vectors, for some parts of the image. - -### Install orca on Google Colab -``` -!pip install plotly>=4.7.1 -!wget https://github.com/plotly/orca/releases/download/v1.2.1/orca-1.2.1-x86_64.AppImage -O /usr/local/bin/orca -!chmod +x /usr/local/bin/orca -!apt-get install xvfb libgtk2.0-0 libgconf-2-4 -``` - -Once this is done you can use this code to make, show and export a figure: - -```python -import plotly.graph_objects as go -fig = go.Figure( go.Scatter(x=[1,2,3], y=[1,3,2] ) ) -fig.write_image("fig1.svg") -fig.write_image("fig1.png") -``` - -The files can then be downloaded with: - -```python -from google.colab import files -files.download('fig1.svg') -files.download('fig1.png') -``` - - ### Get Image as Bytes The `plotly.io.to_image` function is used to return an image as a bytes object. You can also use the `.to_image` graph object figure method. @@ -215,7 +177,45 @@ img_bytes = fig.to_image(format="png", width=600, height=350, scale=2) Image(img_bytes) ``` -### Summary -In summary, to export high-quality static images from plotly.py, all you need to do is install orca, psutil, and requests and then use the `plotly.io.write_image` and `plotly.io.to_image` functions (or the `.write_image` and `.to_image` graph object figure methods). + +### Specify Image Export Engine +If `kaleido` is installed, it will automatically be used to perform image export. If it is not installed, plotly.py will attempt to use orca instead. The `engine` argument to the `to_image` and `write_image` functions can be used to override this default behavior. + +Here is an example of specifying that orca should be used: +```python +fig.to_image(format="png", engine="orca") +``` + +And, here is an example of specifying that Kaleido should be used: +```python +fig.to_image(format="png", engine="kaleido") +``` + + -If you want to know more about how the orca integration works, or if you need to troubleshoot an issue, please check out the [Orca Management](/python/orca-management/) section. \ No newline at end of file + +### Image Export Settings (Kaleido) +Various image export settings can be configured using the `plotly.io.kaleido.scope` object. For example, the `default_format` property can be used to specify that the default export format should be `svg` instead of `png` + +```python +import plotly.io as pio +pio.kaleido.scope.default_format = "svg" +``` + +Here is a complete listing of the available image export settings: + + - **`default_width`**: The default pixel width to use on image export. + - **`default_height`**: The default pixel height to use on image export. + - **`default_scale`**: The default image scale facor applied on image export. + - **`default_format`**: The default image format used on export. One of `"png"`, `"jpeg"`, `"webp"`, `"svg"`, `"pdf"`, or `"eps"`. + - **`mathjax`**: Location of the MathJax bundle needed to render LaTeX characters. Defaults to a CDN location. If fully offline export is required, set this to a local MathJax bundle. + - **`topojson`**: Location of the topojson files needed to render choropleth traces. Defaults to a CDN location. If fully offline export is required, set this to a local directory containing the [Plotly.js topojson files](https://github.com/plotly/plotly.js/tree/master/dist/topojson). + - **`mapbox_access_token`**: The default Mapbox access token. + + + +### Image Export Settings (Orca) +See the [Orca Management](/python/orca-management/) section for information on how to specify image export settings when using orca. + +### Summary +In summary, to export high-quality static images from plotly.py, all you need to do is install the `kaleido` package and then use the `plotly.io.write_image` and `plotly.io.to_image` functions (or the `.write_image` and `.to_image` graph object figure methods). From ef6e68d81838e27a7855a749a0585f84a204ffcf Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Thu, 9 Jul 2020 15:11:33 -0400 Subject: [PATCH 16/28] Add engine docstring to figure image export methods --- packages/python/plotly/plotly/basedatatypes.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index f91e4a96aee..f10f1daffa8 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -3172,6 +3172,12 @@ def to_image(self, *args, **kwargs): 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 + Returns ------- bytes @@ -3231,6 +3237,11 @@ def write_image(self, *args, **kwargs): 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 Returns ------- None From fc7d8569f3f601b03e370362634e8ccec915c6bb Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Fri, 10 Jul 2020 15:57:39 -0400 Subject: [PATCH 17/28] Change kaleido conda channel to plotly since it most likely won't be available on conda-forge initially --- README.md | 2 +- doc/python/static-image-export.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8d1ed40d58..78b38470275 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ $ pip install -U kaleido or conda. ``` -$ conda install -c conda-forge kaleido +$ conda install -c plotly kaleido ``` ### Static Image Export with Orca diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 27a16c76915..582aa77048d 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -49,7 +49,7 @@ $ pip install -U kaleido or conda. ``` -$ conda install -c conda-forge kaleido +$ conda install -c plotly kaleido ``` #### Install Dependencies (Orca) From aee0e0daf09fd3fe15440d94b008e5d2f755d7c1 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Sun, 12 Jul 2020 18:27:34 -0400 Subject: [PATCH 18/28] Conda package renamed from kaleido -> python-kaleido --- README.md | 2 +- doc/python/static-image-export.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78b38470275..ed7c65dbea1 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ $ pip install -U kaleido or conda. ``` -$ conda install -c plotly kaleido +$ conda install -c plotly python-kaleido ``` ### Static Image Export with Orca diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 582aa77048d..634a44d9139 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -49,7 +49,7 @@ $ pip install -U kaleido or conda. ``` -$ conda install -c plotly kaleido +$ conda install -c plotly python-kaleido ``` #### Install Dependencies (Orca) From 00987c05999b9b587a69b6644468cc807e5b2cb8 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:08:56 -0400 Subject: [PATCH 19/28] in README: indicate that Keleido is new and improved and orca is legacy --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ed7c65dbea1..d7ba3b8915b 100644 --- a/README.md +++ b/README.md @@ -150,9 +150,8 @@ $ conda install -c plotly python-kaleido ``` ### Static Image Export with Orca - -While Kaleido is now the recommended approach, image export can also be supported -by the [orca](https://github.com/plotly/orca) command line utility and the +While Kaleido is now the recommended image export approach because it is easier to install and more widely compatible, image export can also be supported +by the legacy [orca](https://github.com/plotly/orca) command line utility and the [`psutil`](https://github.com/giampaolo/psutil) Python package. These dependencies can both be installed using conda: From a25f5b27c710c7b3635e2c3657a8536304f5e598 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:13:56 -0400 Subject: [PATCH 20/28] Add Kaleido note to orca-management section --- doc/python/orca-management.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/python/orca-management.md b/doc/python/orca-management.md index 99b54c6d991..c6fcd7e8e2c 100644 --- a/doc/python/orca-management.md +++ b/doc/python/orca-management.md @@ -34,7 +34,11 @@ jupyter: --- ### Overview -This section covers the lower-level details of how plotly.py can use orca to perform static image generation. Please refer to the [Static Image Export](/python/static-image-export/) section for general information on creating static images from plotly.py figures. +This section covers the lower-level details of how plotly.py can use orca to perform static image generation. + +> Orca is no longer the recommended way to do static image export. We now recommend Kaleido, as described in the [Static Image Export](/python/static-image-export/) section . + +Please refer to the [Static Image Export](/python/static-image-export/) section for general information on creating static images from plotly.py figures. ### What is orca? Orca is an [Electron](https://electronjs.org/) application that inputs plotly figure specifications and converts them into static images. Orca can run as a command-line utility or as a long-running server process. In order to provide the fastest possible image export experience, plotly.py launches orca in server mode, and communicates with it over a local port. See https://github.com/plotly/orca for more information. From a033df0c3e10f550d7d8df0448e43bacd1eb49e6 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:19:07 -0400 Subject: [PATCH 21/28] JPEG typo --- doc/python/static-image-export.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 634a44d9139..5c3d000e823 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -37,7 +37,7 @@ jupyter: ### Interactive vs Static Export -Plotly figures are interactive when viewed in a web browser: you can hover over data points, pan and zoom axes, and show and hide traces by clicking or double-clicking on the legend. You can export figures either to static image file formats like PNG, JEPG, SVG or PDF or you can [export them to HTML files which can be opened in a browser and remain interactive](/python/interactive-html-export/). This page explains how to do the former. +Plotly figures are interactive when viewed in a web browser: you can hover over data points, pan and zoom axes, and show and hide traces by clicking or double-clicking on the legend. You can export figures either to static image file formats like PNG, JPEG, SVG or PDF or you can [export them to HTML files which can be opened in a browser and remain interactive](/python/interactive-html-export/). This page explains how to do the former. From d1fc9a8a98830abdef33bbb15ef2b9ee56228023 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:20:18 -0400 Subject: [PATCH 22/28] Merge "Install Dependency" sections and better explain that Kaleido is new and recommended --- doc/python/static-image-export.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 5c3d000e823..9113e194468 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -41,8 +41,8 @@ Plotly figures are interactive when viewed in a web browser: you can hover over -#### Install Dependencies (Kaleido) -Static image generation requires the [`kaleido`](https://github.com/plotly/Kaleido) package which can be installed using pip... +#### Install Dependencies +Static image generation requires either [Kaleido](https://github.com/plotly/Kaleido) (recommended) or [orca](https://github.com/plotly/orca) (legacy). The `kaleido` package can be installed using pip... ``` $ pip install -U kaleido ``` @@ -52,8 +52,7 @@ or conda. $ conda install -c plotly python-kaleido ``` -#### Install Dependencies (Orca) -While Kaleido is now the recommended approach, image export can also be supported by the [orca](https://github.com/plotly/orca) command line utility. See the [Orca Management](/python/orca-management/) section for instructions on installing, configuring, and troubleshooting orca. +While Kaleido is now the recommended approach, image export can also be supported by the legacy [orca](https://github.com/plotly/orca) command line utility. See the [Orca Management](/python/orca-management/) section for instructions on installing, configuring, and troubleshooting orca. From 2bdcfe210865695b9db89e64c5f55e6c2c039be8 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:21:27 -0400 Subject: [PATCH 23/28] Replace Orca with plotly.py when discussing supported image export formats --- doc/python/static-image-export.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 9113e194468..07f8a0306d3 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -104,7 +104,7 @@ If you are running this notebook live, click to [open the output directory](./im #### Raster Formats: PNG, JPEG, and WebP -Orca can output figures to several raster image formats including **PNG**, ... +plotly.py can output figures to several raster image formats including **PNG**, ... ```python fig.write_image("images/fig1.png") @@ -125,7 +125,7 @@ fig.write_image("images/fig1.webp") #### Vector Formats: SVG and PDF... -Orca can also output figures in several vector formats including **SVG**, ... +plotly.py can also output figures in several vector formats including **SVG**, ... ```python fig.write_image("images/fig1.svg") From 70c11ac67c02f4fc0cbe4003f99b75d0941c2ab1 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:24:04 -0400 Subject: [PATCH 24/28] varying type --- doc/python/static-image-export.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 07f8a0306d3..50e65dad1d4 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -57,7 +57,7 @@ While Kaleido is now the recommended approach, image export can also be supporte ### Create a Figure -Now let's create a simple scatter plot with 100 random points of variying color and size. +Now let's create a simple scatter plot with 100 random points of varying color and size. ```python import plotly.graph_objects as go From e350025724ab85c2ebbdc2da1737d7a75449279c Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:26:22 -0400 Subject: [PATCH 25/28] factor typo [ci skip] --- doc/python/orca-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/orca-management.md b/doc/python/orca-management.md index c6fcd7e8e2c..32efaf16253 100644 --- a/doc/python/orca-management.md +++ b/doc/python/orca-management.md @@ -254,7 +254,7 @@ In addition to the `executable` property, the `plotly.io.orca.config` object can - **`timeout`**: The number of seconds of inactivity required before the orca server is shut down. For example, if timeout is set to 20, then the orca server will shutdown once is has not been used for at least 20 seconds. If timeout is set to `None` (the default), then the server will not be automatically shut down due to inactivity. - **`default_width`**: The default pixel width to use on image export. - **`default_height`**: The default pixel height to use on image export. - - **`default_scale`**: The default image scale facor applied on image export. + - **`default_scale`**: The default image scale factor applied on image export. - **`default_format`**: The default image format used on export. One of `"png"`, `"jpeg"`, `"webp"`, `"svg"`, `"pdf"`, or `"eps"`. - **`mathjax`**: Location of the MathJax bundle needed to render LaTeX characters. Defaults to a CDN location. If fully offline export is required, set this to a local MathJax bundle. - **`topojson`**: Location of the topojson files needed to render choropleth traces. Defaults to a CDN location. If fully offline export is required, set this to a local directory containing the [Plotly.js topojson files](https://github.com/plotly/plotly.js/tree/master/dist/topojson). From 967b728a6dfdd40ec9daab2b0f97252fbcaaffcf Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:28:26 -0400 Subject: [PATCH 26/28] Update CHANGELOG.md Co-authored-by: Nicolas Kruchten --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2de4269ab6..d7df478ff65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added -- Added image export support using Kaleido. The image export backend can be configured using the new `engine` argument to `plotly.io.to_image` and `plotly.io.write_image`. The `engine` argument may be set to `"kaleido"`, `"orca"`, or `"auto"`. The default is `engine="auto"`, in which case the Kaleido backend is enabled if the `kaleido` package from PyPI is installed, otherwise Orca is used. ([#2613](https://github.com/plotly/plotly.py/pull/2613)). +- Added image export support using [Kaleido](https://github.com/plotly/Kaleido). The image export backend can be configured using the new `engine` argument to `plotly.io.to_image` and `plotly.io.write_image`. The `engine` argument may be set to `"kaleido"`, `"orca"`, or `"auto"`. The default is `engine="auto"`, in which case the Kaleido backend is enabled if the `kaleido` package from PyPI is installed, otherwise Orca is used. ([#2613](https://github.com/plotly/plotly.py/pull/2613)). - `px.NO_COLOR` constant to override wide-form color assignment in Plotly Express ([#2614](https://github.com/plotly/plotly.py/pull/2614)) - `facet_row_spacing` and `facet_col_spacing` added to Plotly Express cartesian 2d functions ([#2614](https://github.com/plotly/plotly.py/pull/2614)) From 81a0bc7384c6360c0b9e21068227b72628499f71 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:28:49 -0400 Subject: [PATCH 27/28] Update doc/python/static-image-export.md Co-authored-by: NickE <64649603+nicholas-esterer@users.noreply.github.com> --- doc/python/static-image-export.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 50e65dad1d4..62d87dd03e3 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -205,7 +205,7 @@ Here is a complete listing of the available image export settings: - **`default_width`**: The default pixel width to use on image export. - **`default_height`**: The default pixel height to use on image export. - - **`default_scale`**: The default image scale facor applied on image export. + - **`default_scale`**: The default image scale factor applied on image export. - **`default_format`**: The default image format used on export. One of `"png"`, `"jpeg"`, `"webp"`, `"svg"`, `"pdf"`, or `"eps"`. - **`mathjax`**: Location of the MathJax bundle needed to render LaTeX characters. Defaults to a CDN location. If fully offline export is required, set this to a local MathJax bundle. - **`topojson`**: Location of the topojson files needed to render choropleth traces. Defaults to a CDN location. If fully offline export is required, set this to a local directory containing the [Plotly.js topojson files](https://github.com/plotly/plotly.js/tree/master/dist/topojson). From 74c42741a0e65131ba30d41324861e5c885adfc1 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 14 Jul 2020 15:28:59 -0400 Subject: [PATCH 28/28] Update doc/python/orca-management.md Co-authored-by: NickE <64649603+nicholas-esterer@users.noreply.github.com> --- doc/python/orca-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/orca-management.md b/doc/python/orca-management.md index 32efaf16253..8df2062bdce 100644 --- a/doc/python/orca-management.md +++ b/doc/python/orca-management.md @@ -99,7 +99,7 @@ files.download('fig1.png') ### Create a Figure -Now let's create a simple scatter plot with 100 random points of variying color and size. +Now let's create a simple scatter plot with 100 random points of varying color and size. ```python import plotly.graph_objects as go