Exporting PerspectiveWidget to Static HTML Fails
Opened this issue · 0 comments
ruoyu0088 commented
I am experiencing issues when converting the PerspectiveWidget object into a static HTML file using the following code:
import perspective
from perspective import widget
import pandas as pd
widget.set_jupyter_html_export(True)
df = pd.DataFrame(dict(
x=[1.0, 2.0, 3.0],
y=[1.0, 3.0, 2.0]
))
w = widget.PerspectiveWidget(df)
with open("tmp.html", "w") as f:
f.write("<html><body>")
f.write(w._repr_mimebundle_()['text/html'])
f.write("</body></html>")
However, the output tmp.html
file does not display the Perspective view correctly due to the following issues:
viewerId
is not assigned as a string.viewerAttrs
is not a properly formatted JSON object.- The call to
await perspective.worker().table(data.buffer)
raisesTypeError
. - The
href
attribute for the stylesheet is incorrect.
<html><body><script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective@3.1.4/dist/cdn/perspective.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer@3.1.4/dist/cdn/perspective-viewer.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-datagrid@3.1.4/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-d3fc@3.1.4/dist/cdn/perspective-viewer-d3fc.js"></script>
<link rel="stylesheet" crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-themes@3.1.4/dist/css/themes.css" />
<div class="perspective-envelope" id="perspective-envelope-a512580a2efc414e960615bc991de7a9">
<script type="application/vnd.apache.arrow.file">
/////9gAAAAQAAAAAAAKAAwABgAFAAgACgAAAAABBAAMAAAACAAIAAAABAAIAAAABAAAAAMAAABw
AAAAMAAAAAQAAACs////AAABAxAAAAAUAAAABAAAAAAAAAABAAAAeQAAANr///8AAAIA1P///wAA
AQMQAAAAGAAAAAQAAAAAAAAAAQAAAHgABgAIAAYABgAAAAAAAgAQABQACAAGAAcADAAAABAAEAAA
AAAAAQIQAAAAIAAAAAQAAAAAAAAABQAAAGluZGV4AAAACAAMAAgABwAIAAAAAAAAAUAAAAD/////
6AAAABQAAAAAAAAADAAWAAYABQAIAAwADAAAAAADBAAYAAAASAAAAAAAAAAAAAoAGAAMAAQACAAK
AAAAfAAAABAAAAADAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAA
AAAYAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAYAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAwAAAAAAAA
ABgAAAAAAAAAAAAAAAMAAAADAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAMAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAADwPwAAAAAAAABAAAAAAAAACEAA
AAAAAADwPwAAAAAAAAhAAAAAAAAAAED/////AAAAAA==
</script>
<perspective-viewer style="height: 690px;"></perspective-viewer>
<script type="module">
// from MDN
function base64ToBytes(base64) {
const binString = atob(base64);
return Uint8Array.from(binString, (m) => m.codePointAt(0));
}
import * as perspective from "https://cdn.jsdelivr.net/npm/@finos/perspective@3.1.4/dist/cdn/perspective.js";
const viewerId = a512580a2efc414e960615bc991de7a9;
const currentScript = document.scripts[document.scripts.length - 1];
const envelope = document.getElementById(`perspective-envelope-${viewerId}`);
const dataScript = envelope.querySelector('script[type="application/vnd.apache.arrow.file"]');;
if (!dataScript)
throw new Error('data script missing for viewer', viewerId);
const data = base64ToBytes(dataScript.textContent);
const viewerAttrs = {'group_by': [], 'split_by': [], 'filter': [], 'sort': [], 'aggregates': {}, 'columns': ['index', 'x', 'y'],
'expressions': {}, 'plugin': 'Datagrid', 'plugin_config': {}, 'theme': None, 'settings': True, 'title': None, 'version': '3.1.4'};
// Create a new worker, then a new table promise on that worker.
const table = await perspective.worker().table(data.buffer);
const viewer = envelope.querySelector('perspective-viewer');
viewer.load(table);
viewer.restore(viewerAttrs);
</script>
</div>
</body></html>
After applying the modifications below, the output HTML file renders correctly:
widget/__init__.py
***************
*** 17,19 ****
import importlib
!
from string import Template
--- 17,19 ----
import importlib
! import json
from string import Template
***************
*** 259,264 ****
psp_cdn_perspective_viewer_themes=psp_cdn(
! "perspective-viewer-themes", "css/themes.css"
),
viewer_id=self.model_id,
! viewer_attrs=viewer_attrs,
b64_data=b64_data.decode("utf-8"),
--- 259,264 ----
psp_cdn_perspective_viewer_themes=psp_cdn(
! "perspective-viewer", "css/themes.css"
),
viewer_id=self.model_id,
! viewer_attrs=json.dumps(viewer_attrs),
b64_data=b64_data.decode("utf-8"),
templates/exported_widget.html.template
***************
*** 19,21 ****
import * as perspective from "$psp_cdn_perspective";
! const viewerId = $viewer_id;
const currentScript = document.scripts[document.scripts.length - 1];
--- 19,21 ----
import * as perspective from "$psp_cdn_perspective";
! const viewerId = "$viewer_id";
const currentScript = document.scripts[document.scripts.length - 1];
***************
*** 29,31 ****
// Create a new worker, then a new table promise on that worker.
! const table = await perspective.worker().table(data.buffer);
const viewer = envelope.querySelector('perspective-viewer');
--- 29,32 ----
// Create a new worker, then a new table promise on that worker.
! const worker = await perspective.worker();
! const table = worker.table(data.buffer);
const viewer = envelope.querySelector('perspective-viewer');