Skip to content

Commit 4f50bb6

Browse files
committed
🧹 cleanup code
1 parent 8a86d71 commit 4f50bb6

File tree

1 file changed

+65
-21
lines changed

1 file changed

+65
-21
lines changed

plotly_resampler/figure_resampler/figure_resampler.py

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from typing import Tuple, List
1515

1616
import uuid
17+
import base64
1718
import dash
1819
import plotly.graph_objects as go
1920
from dash import Dash
@@ -27,7 +28,24 @@
2728
from .utils import is_figure, is_fr
2829

2930

30-
class JupyterDashCustomOutput(JupyterDash):
31+
class JupyterDashPersistentInlineOutput(JupyterDash):
32+
""" Extension of the JupyterDash class to support the custom inline output.
33+
34+
Specifically we embed a div in the notebook to display the figure inline.
35+
- In this div the figure is shown as an iframe when the server (of the dash app)
36+
is alive.
37+
- In this div the figure is shown as an image when the server (of the dash app)
38+
is dead.
39+
40+
As the HTML & javascript code is embedded in the notebook output, which is loaded
41+
each time you open the notebook, the figure is always displayed (either as iframe
42+
or just an image).
43+
Hence, this extension enables to maintain always an output in the notebook.
44+
45+
Note: this subclass is only used when the mode is set to `"inline_persistent"` in
46+
the `FigureResampler.show_dash` method. However, the mode should be passed as
47+
`"inline"` since this subclass overwrites the inline behavior.
48+
"""
3149

3250
def __init__(self, *args, **kwargs):
3351
super().__init__(*args, **kwargs)
@@ -41,26 +59,31 @@ def broadcast_alive():
4159
return "Alive"
4260

4361
def _display_inline_output(self, dashboard_url, width, height):
44-
# TODO: width en height gebruiken
45-
# TODO: text displayen in de output :check:
62+
"""Display the dash app persistent inline in the notebook.
63+
64+
The figure is displayed as an iframe in the notebook if the server is reachable,
65+
otherwise as an image.
66+
"""
4667
# TODO: check if in case of crash wel error gelogged wordt
47-
import base64
68+
# TODO: add option to opt out of this
4869
from IPython.display import display
4970

5071
# Get the image from the dashboard and encode it as base64
51-
fig = self.layout.children[0].figure
72+
fig = self.layout.children[0].figure # is stored there in the show_dash method
5273
fig_base64 = base64.b64encode(fig.to_image("png")).decode("utf8")
5374

75+
# The unique id of this app
76+
# This id is used to couple the output in the notebook with this app
77+
# A fetch request is performed to the _is_alive_{uid} endpoint to check if the
78+
# app is still alive.
5479
uid = self._uid
5580

56-
print("width: " + str(width))
57-
print("height: " + str(height))
58-
81+
# The html (& javascript) code to display the app / figure
5982
display(
6083
{
6184
"text/html":
6285
f"""
63-
<div id='PR_div__{uid}' class='container'></div>
86+
<div id='PR_div__{uid}'></div>
6487
<script type='text/javascript'>
6588
""" +
6689
"""
@@ -81,7 +104,7 @@ def _display_inline_output(self, dashboard_url, width, height):
81104
const controller = new AbortController();
82105
const signal = controller.signal;
83106
84-
return fetch(url + is_alive_suffix, {signal: signal})
107+
return fetch(url + is_alive_suffix, {method: 'GET', signal: signal})
85108
.then(response => response.text())
86109
.then(data =>
87110
{
@@ -93,36 +116,42 @@ def _display_inline_output(self, dashboard_url, width, height):
93116
console.log("Server is dead");
94117
imageOutput(pr_div, pr_img_src);
95118
}
96-
}
119+
}
97120
)
98121
.catch(error => {
99122
console.log("Server is unreachable");
100123
imageOutput(pr_div, pr_img_src);
101124
})
102125
}
103126
104-
setOutput(500);
127+
setOutput(350);
105128
106129
function imageOutput(element, pr_img_src) {
107130
console.log('Setting image');
108-
109-
var pr_text = document.createElement("p");
110-
pr_text.setAttribute("style", 'color:red');
111-
pr_text.innerHTML = 'Server unreachable - using image instead';
112-
element.appendChild(pr_text);
113-
114131
var pr_img = document.createElement("img");
115132
pr_img.setAttribute("src", pr_img_src)
133+
pr_img.setAttribute("alt", 'Server unreachable - using image instead');
134+
""" +
135+
f"""
136+
pr_img.setAttribute("width", '{width}');
137+
pr_img.setAttribute("height", '{height}');
138+
""" +
139+
"""
116140
element.appendChild(pr_img);
117141
}
118142
119143
function iframeOutput(element, url) {
120144
console.log('Setting iframe');
121145
var pr_iframe = document.createElement("iframe");
122146
pr_iframe.setAttribute("src", url);
123-
pr_iframe.setAttribute("width", '100%');
124-
pr_iframe.setAttribute("height", '468px');
125147
pr_iframe.setAttribute("frameborder", '0');
148+
pr_iframe.setAttribute("allowfullscreen", '');
149+
""" +
150+
f"""
151+
pr_iframe.setAttribute("width", '{width}');
152+
pr_iframe.setAttribute("height", '{height}');
153+
""" +
154+
"""
126155
element.appendChild(pr_iframe);
127156
}
128157
</script>
@@ -131,6 +160,9 @@ def _display_inline_output(self, dashboard_url, width, height):
131160
)
132161

133162
def _display_in_jupyter(self, dashboard_url, port, mode, width, height):
163+
"""Override the display method to display to retain some output when displaying
164+
inline in jupyter.
165+
"""
134166
if mode == "inline":
135167
self._display_inline_output(dashboard_url, width, height)
136168
else:
@@ -296,6 +328,11 @@ def show_dash(
296328
web browser.
297329
* ``"inline"``: The app will be displayed inline in the notebook output
298330
cell in an iframe.
331+
* ``"inline_persistent"``: The app will be displayed inline in the
332+
notebook output cell in an iframe, if the app is not reachable a static
333+
image of the figure is shown. Hence this is a persistent version of the
334+
``"inline"`` mode, allowing users to see a static figure in other
335+
environments, browsers, etc.
299336
* ``"jupyterlab"``: The app will be displayed in a dedicated tab in the
300337
JupyterLab interface. Requires JupyterLab and the ``jupyterlab-dash``
301338
extension.
@@ -321,7 +358,14 @@ def show_dash(
321358
graph_properties = {} if graph_properties is None else graph_properties
322359
assert "config" not in graph_properties.keys() # There is a param for config
323360
# 1. Construct the Dash app layout
324-
app = JupyterDashCustomOutput("local_app")
361+
if mode is "inline_persistent":
362+
# Inline persistent mode: we display a static image of the figure when the
363+
# app is not reachable
364+
# Note: this is the "inline" behavior of JupyterDashInlinePersistentOutput
365+
mode = "inline"
366+
app = JupyterDashPersistentInlineOutput("local_app")
367+
else:
368+
app = JupyterDash("local_app")
325369
app.layout = dash.html.Div(
326370
[
327371
dash.dcc.Graph(

0 commit comments

Comments
 (0)