Skip to content

Commit

Permalink
save_as_html feature (#170)
Browse files Browse the repository at this point in the history
* note this requires unpkg depedency from latest npm release (for now download https://github.com/lux-org/lux-widget/blob/master/luxwidget/nbextension/static/index.js, rename it luxwidget.js and place it in the same directory as the exported HTML)
  • Loading branch information
dorisjlee committed Dec 5, 2020
1 parent 3b316d9 commit 868156d
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 5 deletions.
4 changes: 0 additions & 4 deletions doc/index.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
Lux: A Python API for Intelligent Visual Discovery
====================================================

.. .. image:: https://raw.githubusercontent.com/lux-org/lux-resources/master/logo.png
.. :width: 400
.. :alt: Lux Logo
Lux is a Python library that makes data science easier by automating certain aspects of the data exploration process. Lux is designed to facilitate faster experimentation with data, even when the user does not have a clear idea of what they are looking for. Lux is integrated with an `interactive Jupyter widget <https://github.com/lux-org/lux-widget>`_ that allows users to quickly browse through large collections of data directly within their Jupyter notebooks.

This website contains pages that overview of the basic and advanced functionalities supported in Lux. If you prefer to follow along these tutorial on your own in a Jupyter notebook, you can clone `this repo <https://github.com/lux-org/lux-binder>`_ to download the `tutorials <https://github.com/lux-org/lux-binder/tree/master/tutorial>`_ or launch a live notebook `via Binder <https://mybinder.org/v2/gh/lux-org/lux-binder/master?urlpath=tree/tutorial>`_ to try it out.
Expand Down
89 changes: 88 additions & 1 deletion lux/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def __init__(self, *args, **kw):
self._saved_export = None
self._current_vis = []
self._prev = None
self._widget = None
super(LuxDataFrame, self).__init__(*args, **kw)

self.table_name = ""
Expand Down Expand Up @@ -514,7 +515,7 @@ def exported(self) -> Union[Dict[str, VisList], VisList]:
When all the exported vis is from the same tab, return a VisList of selected visualizations. -> VisList(v1, v2...)
When the exported vis is from the different tabs, return a dictionary with the action name as key and selected visualizations in the VisList. -> {"Enhance": VisList(v1, v2...), "Filter": VisList(v5, v7...), ..}
"""
if not hasattr(self, "_widget"):
if self.widget is None:
warnings.warn(
"\nNo widget attached to the dataframe."
"Please assign dataframe to an output variable.\n"
Expand Down Expand Up @@ -791,6 +792,92 @@ def rec_to_JSON(recs):
del rec_lst[idx]["collection"]
return rec_lst

def save_as_html(self, filename: str = "export.html") -> None:
"""
Save dataframe widget as static HTML file
Parameters
----------
filename : str
Filename for the output HTML file
"""

if self.widget is None:
self.maintain_metadata()
self.maintain_recs()

from ipywidgets.embed import embed_data

data = embed_data(views=[self.widget])

import json

manager_state = json.dumps(data["manager_state"])
widget_view = json.dumps(data["view_specs"][0])

# Separate out header since CSS file conflict with {} notation in Python format strings
header = """
<head>
<title>Lux Widget</title>
<link rel="lux" type="image/png" sizes="96x96" href="https://github.com/lux-org/lux-resources/blob/master/logo/favicon-96x96.png?raw=True">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<!-- Load RequireJS, used by the IPywidgets for dependency management -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"
integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA="
crossorigin="anonymous">
</script>
<!-- Load IPywidgets bundle for embedding. -->
<script src="https://unpkg.com/@jupyter-widgets/html-manager@^0.18.0/dist/embed-amd.js"
crossorigin="anonymous">
</script>
<style type="text/css">
#intentBtn, #warnBtn, #exportBtn{
display: none;
}
#deleteBtn {
right: 10px !important;
}
#footer-description{
margin: 10px;
text-align: right;
}
</style>
</head>
"""
html_template = """
<html>
{header}
<body>
<script type="application/vnd.jupyter.widget-state+json">
{manager_state}
</script>
<script type="application/vnd.jupyter.widget-view+json">
{widget_view}
</script>
<div id="footer-description">
These visualizations were generated by <a href="https://github.com/lux-org/lux/"><img src="https://raw.githubusercontent.com/lux-org/lux-resources/master/logo/logo.png" width="65px" style="vertical-align: middle;"></img></a>
</div>
</body>
</html>
"""

manager_state = json.dumps(data["manager_state"])
widget_view = json.dumps(data["view_specs"][0])
rendered_template = html_template.format(
header=header, manager_state=manager_state, widget_view=widget_view
)
with open(filename, "w") as fp:
fp.write(rendered_template)
print(f"Saved HTML to {filename}")

# Overridden Pandas Functions
def head(self, n: int = 5):
self._prev = self
Expand Down

0 comments on commit 868156d

Please sign in to comment.