I’m creating a simple version of awesome-panel/pandas_profiling_app.py at master · MarcSkovMadsen/awesome-panel · GitHub
I’m using pn.panel.HTML
to display the html report (in a jupyterlab notebook (where i’m doing my development it overwrites the top bar)). However, calling pn.pane.HTML(profile_html)
overwrite the top bar of my jupyterlab.
Is pn.pane.HTML(profile_html)
the correct command to use? Should it be wrapped in something else?
Code:
import pandas as pd
import panel as pn
from pandas_profiling import ProfileReport
pn.extension()
df = pd.read_csv(
"https://raw.githubusercontent.com/MarcSkovMadsen/awesome-panel/master/application/pages/awesome_panel_express_tests/PerspectiveViewerData.csv"
)
profile = ProfileReport(df, title="title", minimal=False)
profile_html = profile.to_html()
pn.pane.HTML(profile_html)
Note: i’ll eventually be deploying this via cdsdasboards in jupyterhub.
Hoxbro
March 10, 2022, 8:30am
2
Maybe I’m missing something, but can’t you just output profile directly?
If you must use pn.pane.HTML
you can do something like what @Marc did and wrap it into an iframe.
import html
html_report = html.escape(profile.to_html())
pn.pane.HTML(f"""<iframe style="width: 100%; height: 710px; overflow: auto;" frameborder=0 srcdoc="{html_report}" """, sizing_mode="stretch_width")
1 Like
Maybe I’m missing something, but can’t you just output profile directly?
Yes, but how you would you embed it into a panel app?
app.py:
import pandas as pd
from pandas_profiling import ProfileReport
df = pd.read_csv(
"https://raw.githubusercontent.com/MarcSkovMadsen/awesome-panel/master/application/pages/awesome_panel_express_tests/PerspectiveViewerData.csv"
)
ProfileReport(df, title="title", minimal=False)
$ panel serve app.py
The jupyterlab header issue goes away when you close the notebook.
Thanks. I’ll take a look at the iframe approach
The iframe option is definitely the best approach:
import pandas as pd
from pandas_profiling import ProfileReport
from pandas_profiling.report.presentation.flavours.widget.notebook import get_notebook_iframe
df = pd.read_csv(
"https://raw.githubusercontent.com/MarcSkovMadsen/awesome-panel/master/application/pages/awesome_panel_express_tests/PerspectiveViewerData.csv"
)
report = ProfileReport(df, title="title", minimal=False)
pn.pane.HTML(get_notebook_iframe(report.config, report), sizing_mode='stretch_width')
If you were to submit a PR containing this so that Panel knows how to render a Pandas Profiling report I’d happily accept it:
from panel.pane.markup import HTML, DivPaneBase, escape
class ProfileReport(HTML):
@classmethod
def applies(cls, obj):
module = getattr(obj, '__module__', '')
name = type(obj).__name__
if module.startswith('pandas_profiling') and name == 'ProfileReport':
return 0.3
else:
return False
def _get_properties(self):
from pandas_profiling.report.presentation.flavours.widget.notebook import get_notebook_iframe
properties = DivPaneBase._get_properties(self)
html = '' if self.object is None else get_notebook_iframe(self.object.config, self.object)._repr_html_()
return dict(properties, text=escape(html))
3 Likes
Marc
March 10, 2022, 6:41pm
5
You made it before me @philippjfr . Would you accept PRs for other kinds of Auto Generated Data Reports? For example Lux?
My take on a solution would be this one.
import html
import pandas as pd
import panel as pn
from pandas_profiling import ProfileReport
pn.extension(sizing_mode="stretch_width", template="fast")
ACCENT_COLOR = "#FAAA8D"
def to_pandas_profile_pane(profile: ProfileReport, height=700, **params) -> pn.pane.HTML:
profile_html = profile.to_html()
html_report = html.escape(profile_html)
return pn.pane.HTML(
f"""<iframe style="width: 100%; height: {height}px; overflow: auto;" frameborder=0 srcdoc="{html_report}"></iframe>""",
**params,
)
if not "profile" in pn.state.cache:
data = pd.read_csv(
"https://raw.githubusercontent.com/MarcSkovMadsen/awesome-panel/master/application/pages/awesome_panel_express_tests/PerspectiveViewerData.csv"
)
profile = pn.state.cache["profile"] = ProfileReport(data, title="title", minimal=False)
else:
profile = pn.state.cache["profile"]
to_pandas_profile_pane(profile).servable()
pn.state.template.param.update(
site="Awesome Panel",
title="Pandas Profile Report",
accent_base_color=ACCENT_COLOR,
header_background=ACCENT_COLOR,
)
2 Likes
Thanks for all the info here.
For performance reasons i’m starting with the html file after saving it in another script.
Code works well now:
app.ipynb:
import panel as pn
import s3fs
pn.extension(sizing_mode="stretch_width")
fs = s3fs.S3FileSystem()
with fs.open(
f"s3://BUCKET/profile_report_escaped.html",
"r",
) as f:
profile_html_escaped = f.read()
pn.pane.HTML(
f"""<iframe style="width: 100%; height: 700px; overflow: auto;" frameborder=0 srcdoc="{profile_html_escaped}"></iframe>""",
)
or
app.py:
import panel as pn
import s3fs
pn.extension(sizing_mode="stretch_width")
fs = s3fs.S3FileSystem()
with fs.open(
f"s3://BUCKET/profile_report_escaped.html",
"r",
) as f:
profile_html_escaped = f.read()
pn.pane.HTML(
f"""<iframe style="width: 100%; height: 700px; overflow: auto;" frameborder=0 srcdoc="{profile_html_escaped}"></iframe>""",
).servable()
2 Likes