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
61 changes: 60 additions & 1 deletion maidr/core/maidr.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

from typing import Literal
import html as pyhtml

import io
import json
Expand All @@ -10,6 +12,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 @@ -158,10 +161,43 @@ def _unique_id() -> str:
"""Generate a unique identifier string using UUID4."""
return str(uuid.uuid4())

@staticmethod
def _check_if_notebook() -> bool:
"""Returns True if the current environment is a IPython notebook."""
try:
from IPython.core.interactiveshell import InteractiveShell

return (
InteractiveShell.initialized()
and InteractiveShell.instance() is not None
)
except ImportError:
return False

@staticmethod
def _inject_plot(plot: HTML, maidr: str) -> Tag:
"""Embed the plot and associated MAIDR scripts into the HTML structure."""
return tags.html(

# The random_id is used to identify the iframe and its content
random_id = Maidr._unique_id()

# Resizing script to fit the chart content within the iframe
resizing_script = f"""
<script type="text/javascript">
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>
"""

base_html = tags.html(
tags.head(
tags.meta(charset="UTF-8"),
tags.title("MAIDR"),
Expand All @@ -179,3 +215,26 @@ def _inject_plot(plot: HTML, maidr: str) -> Tag:
),
tags.script(maidr),
)

if Maidr._check_if_notebook():
# If this is a Jupyter Notebook, display the HTML
# content using an iframe to fix interactivity issues.
clean_html = pyhtml.escape(base_html.get_html_string())

iframe = f"""
<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 tags.br()

return base_html
Loading