Result Visualization with a panel application#

This notebook serves a panel webpage for result visualization. Notably, it assumes that it exists, in each tag folder:

  1. ts_track_plot.html

  2. states.mp4

As a user, you don’t need to understand the implementation part of the notebook. However, please update the 2nd cell below w.r.t the path of the results’ location.

The variable is scratch_root.

Important#

Do not use the shortcut in the header above the notebook Panel logo.

Instead, do View -> Open with Panel in New Browser Tab (last option).

import html
import os
from pathlib import Path

import panel as pn
import s3fs

pn.extension(design="material", sizing_mode="stretch_width")
# root of the results
RESULT_ROOT = f"s3://gfts-ifremer/kbatch_papermill/{os.getenv("JUPYTERHUB_USER")}"
# where to cache/store the results in your home
# as time of writing, they are consisting of .html and .mp4 files.
# (feel free to change it)
LOCAL_ROOT = "panel_data"
# furthermore, set the variable below to True to update any potential cached result.
# (Otherwise the app will display the current files found there!)
ERASE = True
CACHE_PATH = Path(LOCAL_ROOT)
os.makedirs(CACHE_PATH, exist_ok=True)
# expected outcomes from the nbs
RESULT_FILES = ["states.mp4", "ts_track_plot.html"]
storage_options = {
    "anon": False,
    "client_kwargs": {
        "endpoint_url": "https://s3.gra.perf.cloud.ovh.net",
        "region_name": "gra",
    },
}
S3 = s3fs.S3FileSystem(
    anon=False,
    client_kwargs={
        "endpoint_url": "https://s3.gra.perf.cloud.ovh.net",
    },
)
tag_list = [tag.split("/")[-1] for tag in S3.ls(RESULT_ROOT) if "nbs" not in tag]
# create the local FS
for tn in tag_list:
    os.makedirs(CACHE_PATH / tn, exist_ok=True)
print("Tags available:\n", tag_list)

Functions#

Fetch the bucket#

def get_html_data(filepath: str, erase: bool):
    try:
        local_fp = CACHE_PATH / filepath / "ts_track_plot.html"
        remote_fp = f"{RESULT_ROOT}/" + str(Path(filepath) / "ts_track_plot.html")
        if erase or not os.path.isfile(local_fp):
            print("downloading html file for path...", filepath)
            S3.get_file(remote_fp, local_fp)
    except Exception as e:
        print(e)
    return local_fp


def get_video_data(filepath: str, erase: bool):
    try:
        local_fp = CACHE_PATH / filepath / "states.mp4"
        remote_fp = f"{RESULT_ROOT}/" + str(Path(filepath) / "states.mp4")
        if erase or not os.path.isfile(local_fp):
            print("downloading video file for path...", filepath)
            S3.get_file(remote_fp, local_fp)
    except Exception as e:
        print(e)
        print(remote_fp)
    return local_fp

run the following to directly download the results locally. It can smooth the panel’s responsiveness.

for tag_name in tag_list:
    get_html_data(tag_name)
    get_video_data(tag_name)

Build the panel object#

@pn.cache()
def get_ts_plot(tag_name: str, erase: bool):
    # downloads locally the result if needed
    html_fn = get_html_data(Path(tag_name), erase)
    try:
        with open(html_fn, "r") as html_file:
            html_content = html_file.read()
        height = 100
    except Exception as e:
        html_content = str(e)
        height = 10

    escaped_html = html.escape(html_content)
    iframe_html = f'<iframe srcdoc="{escaped_html}" style="height:{height}%; width:100%" frameborder="0"></iframe>'
    return pn.pane.HTML(
        iframe_html, sizing_mode=f"stretch_{"width" if height != 100 else "both"}"
    )


@pn.cache()
def get_video_plot(tag_name: str, erase: bool):
    # downloads locally the result if needed
    video_fp = get_video_data(Path(tag_name), erase)
    video_fn = str(video_fp)
    try:
        video = pn.pane.Video(
            video_fn,
            loop=False,
            autoplay=False,
            width=1000,
            # it should horizontally align the video HTLM element but without specific width it uses all the page's height...
            styles={
                "display": "flex",
                "justify-content": "center",
                "margin-left": "25%",
                "margin-right": "25%",
                "width": "auto",
            },
        )
    except Exception as e:
        video = pn.pane.HTML(str(e))
    return video

panel App (ending with a .servable object)#

tag_widget = pn.widgets.Select(name="tag_name", value=tag_list[0], options=tag_list)

ts_plot = pn.bind(get_ts_plot, tag_name=tag_widget, erase=ERASE)
mov_plot = pn.bind(get_video_plot, tag_name=tag_widget, erase=ERASE)
column = pn.Column(ts_plot, mov_plot)

pn.template.MaterialTemplate(
    site="Panel",
    title="Result Viz",
    sidebar=[tag_widget],
    main=column,
).servable();

Notes#

In case of issues, suspected bugs and improvement suggestions, please open an issue on GitHub.