Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(maidr.show): support interactive maidr plots within Jupyter Notebooks, VS Code, Google Colab, and Quarto #64

Merged
merged 13 commits into from
Aug 21, 2024
51 changes: 51 additions & 0 deletions maidr/core/maidr.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations
from typing import Literal
import html as pyhtml

import io
import json
Expand All @@ -10,6 +11,7 @@

from matplotlib.figure import Figure

from IPython.display import display_html
from maidr.core.context_manager import HighlightContextManager
from maidr.core.plot import MaidrPlot

Expand Down Expand Up @@ -94,6 +96,41 @@ def show(self, renderer: Literal["auto", "ipython", "browser"] = "auto") -> obje
The renderer to use for the HTML preview.
"""
html = self._create_html_tag()
clean_html = pyhtml.escape(html.get_html_string())

if self._check_if_notebook():
# If this is a Jupyter Notebook, display the HTML content using an iframe to fix interactivity issues.

# The random_id is used to identify the iframe and its content
random_id = str(uuid.uuid4())

# Resizing script to fit the chart content within the iframe
resizing_script = f"""
<script>
function resizeIframe() {{
var iframe = document.getElementById('{random_id}');
iframe.style.height = iframe.contentWindow.document.body.scrollHeight + 50 + 'px';
}}
var iframe = document.getElementById('{random_id}');
iframe.onload = function() {{
resizeIframe();
iframe.contentWindow.addEventListener('resize', resizeIframe);
}};
window.onresize = resizeIframe;
</script>
"""

iframe = (
'<iframe id="' + random_id + '" '
'srcdoc="' + clean_html + '" frameBorder=0 scrolling=auto '
'style="width: 100%; height:100%" backgroundColor: #fff"></iframe>'
)
display_html(
iframe + resizing_script,
raw=True,
)
return None

return html.show(renderer)

def clear(self):
Expand All @@ -103,6 +140,20 @@ def destroy(self) -> None:
del self._plots
del self._fig

def _check_if_notebook(self) -> bool:
"""Returns True if the current environment is a IPython notebook."""
try:
import IPython # pyright: ignore[reportMissingModuleSource, reportUnknownVariableType]

ipy = ( # pyright: ignore[reportUnknownVariableType]
IPython.get_ipython() # pyright: ignore[reportUnknownMemberType, reportPrivateImportUsage]
)
if ipy:
return True
return False
except ImportError:
return False

def _create_html_tag(self) -> Tag:
"""Create the MAIDR HTML using HTML tags."""
tagged_elements = [element for plot in self._plots for element in plot.elements]
Expand Down
Loading