Source code for gravis._internal.plotting.data_structures
"""Data structures for representing JavaScript plots."""
import random as _random
import string as _string
from ..utils import operating_system as _operating_system
from . import rendering, template_system
[docs]class Figure:
"""Data structure for wrapping, displaying and exporting a JavaScript figure."""
def __init__(self, html_template):
"""Initialize a figure with a partly filled HTML template containing a visualization."""
self._html_template = html_template
# IPython integration
def _repr_html_(self):
"""Provide HTML text for integration with IPython rich display representation.
References
----------
- https://ipython.readthedocs.io/en/stable/config/integrating.html#rich-display
- https://ipython.readthedocs.io/en/stable/api/generated/IPython.core.formatters.html#IPython.core.formatters.HTMLFormatter
"""
return self.to_html_partial()
# Display in browser or notebook
[docs] def display(self, inline=False):
"""Display the plot in a webbrowser or as IPython rich display representation.
Parameters
----------
inline : bool
If True, the plot will be shown inline in a Jupyter notebook.
"""
if inline:
import IPython
html_text = self.to_html_partial()
html_object = IPython.display.HTML(html_text)
IPython.display.display(html_object)
else:
html_text = self.to_html_standalone()
_operating_system.open_in_webbrowser(html_text)
# Representation as text
[docs] def to_html_standalone(self):
"""Create a standalone HTML text representation that has all javascript code embedded."""
data = {
'RANDOM_ID': self._generate_random_id(),
'PREFIX': """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body style="margin:0;">""",
'LOAD_REQUIRE': template_system.load('third_party/require/require.min.js'),
'SUFFIX': """</body>
</html>""",
}
html_text = template_system.insert(self._html_template, data)
return html_text
[docs] def to_html_partial(self):
"""Create a dependent HTML text representation that loads javascript with require.js."""
data = {
'RANDOM_ID': self._generate_random_id(),
'PREFIX': '',
'LOAD_REQUIRE': template_system.load('third_party/require/require.min.js'),
'SUFFIX': '',
}
html_text = template_system.insert(self._html_template, data)
return html_text
[docs] def to_jpg(self, webdriver='chrome', capture_delay=3.5):
"""Create a JPEG text representation with base64 text encoding the binary data."""
html_text = self.to_html()
jpg_data = rendering.render_and_capture(html_text, 'jpg', webdriver, capture_delay)
return jpg_data
[docs] def to_png(self, webdriver='chrome', capture_delay=3.5):
"""Create a PNG text representation with base64 text encoding the binary data."""
html_text = self.to_html()
png_data = rendering.render_and_capture(html_text, 'png', webdriver, capture_delay)
return png_data
[docs] def to_svg(self, webdriver='chrome', capture_delay=3.5):
"""Create a SVG text representation."""
html_text = self.to_html()
svg_text = rendering.render_and_capture(html_text, 'svg', webdriver, capture_delay)
return svg_text
# Export as HTML file
[docs] def export_html(self, filepath, overwrite=False):
"""Export the plot as HTML file.
Parameters
----------
filepath : str
Filepath for the generated HTML file.
overwrite : bool
If True, overwrite the file if it already exists.
Raises
------
FileExistsError
If overwrite=False and there is already a file at the given filepath.
"""
# Precondition
if not overwrite:
_operating_system.is_file(filepath, raise_exception=True)
# Transformation
with open(filepath, 'w') as file_handle:
html_text = self.to_html()
file_handle.write(html_text)
[docs] def export_svg(self, filepath, overwrite=False, webdriver='chrome', capture_delay=3.5):
"""Export the plot as SVG file.
Parameters
----------
filepath : str
Filepath for the generated SVG file.
overwrite : bool
If True, overwrite the file if it already exists.
Raises
------
FileExistsError
If overwrite=False and there is already a file at the given filepath.
"""
# Precondition
if not overwrite:
_operating_system.is_file(filepath, raise_exception=True)
# Transformation
with open(filepath, 'w') as file_handle:
svg_text = self.to_svg(webdriver, capture_delay)
file_handle.write(svg_text)
[docs] def export_png(self, filepath, overwrite=False, webdriver='chrome', capture_delay=3.5):
"""Export the plot as PNG file.
Parameters
----------
filepath : str
Filepath for the generated PNG file.
overwrite : bool
If True, overwrite the file if it already exists.
Raises
------
FileExistsError
If overwrite=False and there is already a file at the given filepath.
"""
# Precondition
if not overwrite:
_operating_system.is_file(filepath, raise_exception=True)
# Transformation
with open(filepath, 'wb') as file_handle:
png_text = self.to_png(webdriver, capture_delay)
file_handle.write(png_text)
[docs] def export_jpg(self, filepath, overwrite=False, webdriver='chrome', capture_delay=3.5):
"""Export the plot as JPEG file.
Parameters
----------
filepath : str
Filepath for the generated JPEG file.
overwrite : bool
If True, overwrite the file if it already exists.
Raises
------
FileExistsError
If overwrite=False and there is already a file at the given filepath.
"""
# Precondition
if not overwrite:
_operating_system.is_file(filepath, raise_exception=True)
# Transformation
with open(filepath, 'wb') as file_handle:
jpg_text = self.to_jpg(webdriver, capture_delay)
file_handle.write(jpg_text)
@staticmethod
def _generate_random_id(length=16):
"""Generate a random identifier starting with "i and consisting of letters and digits."""
symbols = _string.ascii_letters + _string.digits
return 'i' + ''.join(_random.choice(symbols) for _ in range(length))