Skip to content
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

Export to file-like object #938

Merged
merged 20 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Next Next commit
Add to_svg, to_html, to_png, to_pdf functions to PlotSpec and SupPlot…
…sSpec
  • Loading branch information
RYangazov committed Dec 5, 2023
commit d725a257dcccd334f0d7c186e488164899d7d9d2
136 changes: 136 additions & 0 deletions python-package/lets_plot/frontend_context/_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Copyright (c) 2019. JetBrains s.r.o.
# Use of this source code is governed by the MIT license that can be found in the LICENSE file.
#
import io
from typing import Dict, Any

from ._frontend_ctx import FrontendContext
Expand Down Expand Up @@ -119,3 +120,138 @@ def _as_html(plot_spec: Dict) -> str:
"""

return _frontend_contexts[TEXT_HTML].as_str(plot_spec)


def to_svg(spec: Any, path):
"""
Export plot or `bunch` to a file in SVG format.

Parameters
----------
spec : `PlotSpec` or `SupPlotsSpec` or `GGBunch`
Plot specification to export.
path : file-like object
File-like object to write SVG to.
"""
if not (isinstance(spec, PlotSpec) or isinstance(spec, SupPlotsSpec) or isinstance(spec, GGBunch)):
raise ValueError("PlotSpec, SupPlotsSpec or GGBunch expected but was: {}".format(type(spec)))

from .. import _kbridge as kbr

svg = kbr._generate_svg(spec.as_dict())
if isinstance(path, str):
with io.open(path, mode="w", encoding="utf-8") as f:
f.write(svg)
else:
path.write(svg.encode())


def to_html(spec: Any, path, iframe: bool = False):
"""
Export plot or `bunch` to a file in SVG format.

Parameters
----------
spec : `PlotSpec` or `SupPlotsSpec` or `GGBunch`
Plot specification to export.
path : str, file-like object
Filename to save HTML under,
or file-like object to write HTML to.
iframe : bool, default=False
Whether to wrap HTML page into a iFrame.
"""
if not (isinstance(spec, PlotSpec) or isinstance(spec, SupPlotsSpec) or isinstance(spec, GGBunch)):
raise ValueError("PlotSpec, SupPlotsSpec or GGBunch expected but was: {}".format(type(spec)))

from .. import _kbridge as kbr

html_page = kbr._generate_static_html_page(spec.as_dict(), iframe)
if isinstance(path, str):
with io.open(path, mode="w", encoding="utf-8") as f:
f.write(html_page)
else:
path.write(html_page.encode())

def to_png(spec: Any, path, scale: float = 2.0):
"""
Export plot or `bunch` to a file in PNG format.

Parameters
----------
spec : `PlotSpec` or `SupPlotsSpec` or `GGBunch`
Plot specification to export.
path : str, file-like object
Filename to save PNG under,
or file-like object to write PNG to.
scale : float, default=2.0
Scaling factor for raster output.

Notes
-----
Export to PNG file uses the CairoSVG library.
CairoSVG is free and distributed under the LGPL-3.0 license.
For more details visit: https://cairosvg.org/documentation/

"""
if not (isinstance(spec, PlotSpec) or isinstance(spec, SupPlotsSpec) or isinstance(spec, GGBunch)):
raise ValueError("PlotSpec, SupPlotsSpec or GGBunch expected but was: {}".format(type(spec)))

try:
import cairosvg


except ImportError:
import sys
print("\n"
"To export Lets-Plot figure to a PNG file please install CairoSVG library to your Python environment.\n"
"CairoSVG is free and distributed under the LGPL-3.0 license.\n"
"For more details visit: https://cairosvg.org/documentation/\n", file=sys.stderr)
return None

from .. import _kbridge
# Use SVG image-rendering style as Cairo doesn't support CSS image-rendering style,
svg = _kbridge._generate_svg(spec.as_dict(), use_css_pixelated_image_rendering=False)

cairosvg.svg2png(bytestring=svg, write_to=path, scale=scale)

def to_pdf(spec: Any, path, scale: float = 2.0):
"""
Export plot or `bunch` to a file in PDF format.

Parameters
----------
spec : `PlotSpec` or `SupPlotsSpec` or `GGBunch`
Plot specification to export.
path : str, file-like object
Filename to save PDF under,
or file-like object to write PDF to.
scale : float, default=2.0
Scaling factor for raster output.

Notes
-----
Export to PDF file uses the CairoSVG library.
CairoSVG is free and distributed under the LGPL-3.0 license.
For more details visit: https://cairosvg.org/documentation/

"""
if not (isinstance(spec, PlotSpec) or isinstance(spec, SupPlotsSpec) or isinstance(spec, GGBunch)):
raise ValueError("PlotSpec, SupPlotsSpec or GGBunch expected but was: {}".format(type(spec)))

try:
import cairosvg


except ImportError:
import sys
print("\n"
"To export Lets-Plot figure to a PDF file please install CairoSVG library to your Python environment.\n"
"CairoSVG is free and distributed under the LGPL-3.0 license.\n"
"For more details visit: https://cairosvg.org/documentation/\n", file=sys.stderr)
return None

from .. import _kbridge
# Use SVG image-rendering style as Cairo doesn't support CSS image-rendering style,
svg = _kbridge._generate_svg(spec.as_dict(), use_css_pixelated_image_rendering=False)

cairosvg.svg2pdf(bytestring=svg, write_to=path, scale=scale)
111 changes: 111 additions & 0 deletions python-package/lets_plot/plot/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,117 @@ def show(self):
from ..frontend_context._configuration import _display_plot
_display_plot(self)

def to_svg(self, path):
"""
Save a plot in SVG format.

Examples
--------
.. jupyter-execute::
:linenos:
:emphasize-lines: 4

import numpy as np
import io
from lets_plot import *
LetsPlot.setup_html()
n = 60
np.random.seed(42)
x = np.random.choice(list('abcde'), size=n)
y = np.random.normal(size=n)
p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + \
geom_jitter()
file_like = io.BytesIO()
p.to_svg(file_like)
with open("out.svg", "wb") as f:
f.write(file_like.getbuffer())
"""
from ..frontend_context._configuration import to_svg
to_svg(self, path)

def to_html(self, path, iframe=False, scale=2.0):
"""
Save a plot in HTML format.

Examples
--------
.. jupyter-execute::
:linenos:
:emphasize-lines: 4

import numpy as np
import io
from lets_plot import *
LetsPlot.setup_html()
n = 60
np.random.seed(42)
x = np.random.choice(list('abcde'), size=n)
y = np.random.normal(size=n)
p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + \
geom_jitter()
file_like = io.BytesIO()
p.to_html(file_like)
with open("out.html", "wb") as f:
f.write(file_like.getbuffer())
"""
from ..frontend_context._configuration import to_html
to_html(self, path, iframe, scale)

def to_png(self, path, scale=2.0):
"""
Save a plot in PNG format.

Examples
--------
.. jupyter-execute::
:linenos:
:emphasize-lines: 4

import numpy as np
import io
from lets_plot import *
LetsPlot.setup_html()
n = 60
np.random.seed(42)
x = np.random.choice(list('abcde'), size=n)
y = np.random.normal(size=n)
p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + \
geom_jitter()
file_like = io.BytesIO()
p.to_png(file_like)
with open("out.html", "wb") as f:
f.write(file_like.getbuffer())
"""
from ..frontend_context._configuration import to_png
to_png(self, path, scale)

def to_pdf(self, path, scale=2.0):
"""
Save a plot in PDF format.

Examples
--------
.. jupyter-execute::
:linenos:
:emphasize-lines: 4

import numpy as np
import io
from lets_plot import *
LetsPlot.setup_html()
n = 60
np.random.seed(42)
x = np.random.choice(list('abcde'), size=n)
y = np.random.normal(size=n)
p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + \
geom_jitter()
file_like = io.BytesIO()
p.to_pdf(file_like)
with open("out.html", "wb") as f:
f.write(file_like.getbuffer())
"""
from ..frontend_context._configuration import to_pdf
to_pdf(self, path, scale)

class LayerSpec(FeatureSpec):
"""
Expand Down
28 changes: 28 additions & 0 deletions python-package/lets_plot/plot/subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,31 @@ def show(self):
"""
from ..frontend_context._configuration import _display_plot
_display_plot(self)

def to_svg(self, path):
"""
Save all plots currently in SVG.
"""
from ..frontend_context._configuration import to_svg
to_svg(self, path)

def to_html(self, path, iframe=False, scale=2.0):
"""
Save all plots currently in SVG.
"""
from ..frontend_context._configuration import to_html
to_html(self, path, iframe, scale)

def to_png(self, path, scale=2.0):
"""
Save all plots currently in SVG.
"""
from ..frontend_context._configuration import to_png
to_png(self, path, scale)

def to_pdf(self, path, scale=2.0):
"""
Save all plots currently in SVG.
"""
from ..frontend_context._configuration import to_pdf
to_pdf(self, path, scale)