1
|
|
"""
|
2
|
|
Defines utilities to save panel objects to files as HTML or PNG.
|
3
|
|
"""
|
4
|
6
|
from __future__ import absolute_import, division, unicode_literals
|
5
|
|
|
6
|
6
|
import io
|
7
|
|
|
8
|
6
|
from six import string_types
|
9
|
|
|
10
|
6
|
import bokeh
|
11
|
|
|
12
|
6
|
from bokeh.document.document import Document
|
13
|
6
|
from bokeh.embed import file_html
|
14
|
6
|
from bokeh.io.export import export_png
|
15
|
6
|
from bokeh.resources import CDN, INLINE
|
16
|
6
|
from pyviz_comms import Comm
|
17
|
|
|
18
|
6
|
from ..config import config
|
19
|
6
|
from .embed import embed_state
|
20
|
6
|
from .model import add_to_doc
|
21
|
6
|
from .state import state
|
22
|
|
|
23
|
|
|
24
|
|
#---------------------------------------------------------------------
|
25
|
|
# Private API
|
26
|
|
#---------------------------------------------------------------------
|
27
|
|
|
28
|
6
|
def save_png(model, filename, template=None, template_variables=None):
|
29
|
|
"""
|
30
|
|
Saves a bokeh model to png
|
31
|
|
|
32
|
|
Arguments
|
33
|
|
---------
|
34
|
|
model: bokeh.model.Model
|
35
|
|
Model to save to png
|
36
|
|
filename: str
|
37
|
|
Filename to save to
|
38
|
|
template:
|
39
|
|
template file, as used by bokeh.file_html. If None will use bokeh defaults
|
40
|
|
template_variables:
|
41
|
|
template_variables file dict, as used by bokeh.file_html
|
42
|
|
"""
|
43
|
0
|
from bokeh.io.webdriver import webdriver_control
|
44
|
0
|
if not state.webdriver:
|
45
|
0
|
state.webdriver = webdriver_control.create()
|
46
|
|
|
47
|
0
|
webdriver = state.webdriver
|
48
|
|
|
49
|
0
|
try:
|
50
|
0
|
if template:
|
51
|
0
|
def get_layout_html(obj, resources, width, height):
|
52
|
0
|
return file_html(
|
53
|
|
obj, resources, title="", template=template,
|
54
|
|
template_variables=template_variables,
|
55
|
|
suppress_callback_warning=True, _always_new=True
|
56
|
|
)
|
57
|
0
|
old_layout_fn = bokeh.io.export.get_layout_html
|
58
|
0
|
bokeh.io.export.get_layout_html = get_layout_html
|
59
|
0
|
export_png(model, filename=filename, webdriver=webdriver)
|
60
|
0
|
except Exception:
|
61
|
0
|
raise
|
62
|
|
finally:
|
63
|
0
|
if template:
|
64
|
0
|
bokeh.io.export.get_layout_html = old_layout_fn
|
65
|
|
|
66
|
|
|
67
|
|
#---------------------------------------------------------------------
|
68
|
|
# Public API
|
69
|
|
#---------------------------------------------------------------------
|
70
|
|
|
71
|
6
|
def save(panel, filename, title=None, resources=None, template=None,
|
72
|
|
template_variables=None, embed=False, max_states=1000,
|
73
|
|
max_opts=3, embed_json=False, json_prefix='', save_path='./',
|
74
|
|
load_path=None, progress=True, embed_states={}):
|
75
|
|
"""
|
76
|
|
Saves Panel objects to file.
|
77
|
|
|
78
|
|
Arguments
|
79
|
|
---------
|
80
|
|
panel: Viewable
|
81
|
|
The Panel Viewable to save to file
|
82
|
|
filename: string or file-like object
|
83
|
|
Filename to save the plot to
|
84
|
|
title: string
|
85
|
|
Optional title for the plot
|
86
|
|
resources: bokeh resources
|
87
|
|
One of the valid bokeh.resources (e.g. CDN or INLINE)
|
88
|
|
template:
|
89
|
|
template file, as used by bokeh.file_html. If None will use bokeh defaults
|
90
|
|
template_variables:
|
91
|
|
template_variables file dict, as used by bokeh.file_html
|
92
|
|
embed: bool
|
93
|
|
Whether the state space should be embedded in the saved file.
|
94
|
|
max_states: int
|
95
|
|
The maximum number of states to embed
|
96
|
|
max_opts: int
|
97
|
|
The maximum number of states for a single widget
|
98
|
|
embed_json: boolean (default=True)
|
99
|
|
Whether to export the data to json files
|
100
|
|
json_prefix: str (default='')
|
101
|
|
Prefix for the randomly json directory
|
102
|
|
save_path: str (default='./')
|
103
|
|
The path to save json files to
|
104
|
|
load_path: str (default=None)
|
105
|
|
The path or URL the json files will be loaded from.
|
106
|
|
progress: boolean (default=True)
|
107
|
|
Whether to report progress
|
108
|
|
embed_states: dict (default={})
|
109
|
|
A dictionary specifying the widget values to embed for each widget
|
110
|
|
"""
|
111
|
6
|
from ..pane import PaneBase
|
112
|
6
|
from ..template import Template
|
113
|
|
|
114
|
6
|
if isinstance(panel, PaneBase) and len(panel.layout) > 1:
|
115
|
0
|
panel = panel.layout
|
116
|
|
|
117
|
6
|
as_png = isinstance(filename, string_types) and filename.endswith('png')
|
118
|
|
|
119
|
6
|
if isinstance(panel, Document):
|
120
|
0
|
doc = panel
|
121
|
|
else:
|
122
|
6
|
doc = Document()
|
123
|
|
|
124
|
6
|
comm = Comm()
|
125
|
6
|
with config.set(embed=embed):
|
126
|
6
|
if isinstance(panel, Document):
|
127
|
0
|
model = panel
|
128
|
6
|
elif isinstance(panel, Template):
|
129
|
0
|
panel._init_doc(doc, title=title)
|
130
|
0
|
model = doc
|
131
|
|
else:
|
132
|
6
|
model = panel.get_root(doc, comm)
|
133
|
6
|
if embed:
|
134
|
6
|
embed_state(
|
135
|
|
panel, model, doc, max_states, max_opts, embed_json,
|
136
|
|
json_prefix, save_path, load_path, progress, embed_states
|
137
|
|
)
|
138
|
|
else:
|
139
|
0
|
add_to_doc(model, doc, True)
|
140
|
|
|
141
|
6
|
if as_png:
|
142
|
0
|
return save_png(model, filename=filename, template=template,
|
143
|
|
template_variables=template_variables)
|
144
|
6
|
elif isinstance(filename, string_types) and not filename.endswith('.html'):
|
145
|
0
|
filename = filename + '.html'
|
146
|
|
|
147
|
6
|
kwargs = {}
|
148
|
6
|
if title is None:
|
149
|
6
|
title = 'Panel'
|
150
|
6
|
if resources is None:
|
151
|
6
|
resources = CDN
|
152
|
0
|
elif isinstance(resources, str):
|
153
|
0
|
if resources.lower() == 'cdn':
|
154
|
0
|
resources = CDN
|
155
|
0
|
elif resources.lower() == 'inline':
|
156
|
0
|
resources = INLINE
|
157
|
|
else:
|
158
|
0
|
raise ValueError("Resources %r not recognized, specify one "
|
159
|
|
"of 'CDN' or 'INLINE'." % resources)
|
160
|
|
|
161
|
6
|
if template:
|
162
|
0
|
kwargs['template'] = template
|
163
|
6
|
if template_variables:
|
164
|
0
|
kwargs['template_variables'] = template_variables
|
165
|
|
|
166
|
6
|
html = file_html(doc, resources, title, **kwargs)
|
167
|
6
|
if hasattr(filename, 'write'):
|
168
|
6
|
if isinstance(filename, io.BytesIO):
|
169
|
0
|
html = html.encode('utf-8')
|
170
|
6
|
filename.write(html)
|
171
|
|
else:
|
172
|
6
|
with io.open(filename, mode="w", encoding="utf-8") as f:
|
173
|
6
|
f.write(html)
|