from io import StringIO
from pathlib import Path
import pandas as pd
import panel as pn
from panel_gwalker import GraphicWalker
pn.extension("filedropper", sizing_mode="stretch_width", notifications=True)
ROOT = Path(__file__).parent
PANEL_GW_URL = "https://github.com/panel-extensions/panel-graphic-walker"
GW_LOGO = "https://kanaries.net/_next/static/media/kanaries-logo.0a9eb041.png"
GW_API = "https://github.com/Kanaries/graphic-walker"
GW_GUIDE_URL = "https://docs.kanaries.net/graphic-walker/data-viz/create-data-viz"
SPEC_CAPACITY_STATE = "https://cdn.jsdelivr.net/gh/panel-extensions/panel-graphic-walker@main/examples/reference_app/spec_simple.json"
SPEC_SIMPLE = "https://cdn.jsdelivr.net/gh/panel-extensions/panel-graphic-walker@main/examples/reference_app/spec_capacity_state.json"
ACCENT = "#5B8FF9"
def _label(value):
return pn.pane.Markdown(value, margin=(-20, 5))
def _section_header(value):
return pn.pane.Markdown(value, margin=(-5, 5))
@pn.cache
def get_data():
return pd.read_parquet(
"https://datasets.holoviz.org/windturbines/v1/windturbines.parq"
)
def get_example_download():
df = pd.DataFrame(
{"country": ["Denmark", "Germany"], "population": [5_000_000, 80_000_000]}
)
sio = StringIO()
df.to_csv(sio, index=False)
sio.seek(0)
return sio
button_style = dict(button_type="primary", button_style="outline")
walker = GraphicWalker(
get_data(),
spec=SPEC_CAPACITY_STATE,
sizing_mode="stretch_both",
kernel_computation=True,
)
core_settings = pn.Column(
walker.param.kernel_computation,
walker.param.spec,
walker.param.config,
walker.param.renderer,
pn.widgets.IntInput.from_param(
walker.param.page_size, visible=walker.is_enabled("page_size")
),
pn.widgets.Checkbox.from_param(
walker.param.hide_profiling, visible=walker.is_enabled("hide_profiling")
),
pn.widgets.IntInput.from_param(
walker.param.index, visible=walker.is_enabled("index")
),
pn.widgets.RadioButtonGroup.from_param(
walker.param.tab,
visible=walker.is_enabled("tab"),
button_type="primary",
button_style="outline",
),
pn.widgets.TextInput.from_param(
walker.param.container_height, visible=walker.is_enabled("container_height")
),
name="Core",
)
style_settings = pn.Column(
_label("Appearance"),
pn.widgets.RadioButtonGroup.from_param(walker.param.appearance, **button_style),
_label("Theme Key"),
pn.widgets.RadioButtonGroup.from_param(walker.param.theme_key, **button_style),
name="Style",
)
file_upload = pn.widgets.FileDropper(
accepted_filetypes=["text/csv"],
multiple=False,
max_file_size="5MB",
styles={"border": "1px dashed black", "border-radius": "4px"},
height=85,
)
file_download = pn.widgets.FileDownload(
callback=get_example_download, filename="example.csv"
)
export_controls = walker.export_controls()
exported = pn.rx("""
```bash
{value}
```
""").format(value=export_controls.param.value)
export_section = pn.Column(export_controls, exported, name="Export")
save_section = pn.Column(walker.save_controls(), name="Save")
docs_section = f"## Docs\n\n- [panel-graphic-walker]({PANEL_GW_URL})\n- [Graphic Walker Usage Guide]({GW_GUIDE_URL})\n- [Graphic Walker API]({GW_API})"
def _apply_spec(value):
if walker.spec == value:
walker.param.trigger("spec")
else:
walker.spec = value
simple_spec = pn.widgets.Button(
name="Simple",
button_type="primary",
button_style="outline",
on_click=lambda event: _apply_spec(SPEC_SIMPLE),
)
initial_spec = pn.widgets.Button(
name="Initial",
button_type="primary",
button_style="outline",
on_click=lambda event: _apply_spec(SPEC_CAPACITY_STATE),
)
no_spec = pn.widgets.Button(
name="No Spec",
button_type="primary",
button_style="outline",
on_click=lambda event: _apply_spec(None),
)
@pn.depends(file_upload, watch=True)
def _update_walker(value):
if value:
text = next(iter(value.values()))
df = pd.read_csv(StringIO(text))
if not df.empty:
walker.object = df
# Can be removed once https://github.com/panel-extensions/panel-graphic-walker/issues/33 is resolved
pn.state.notifications.success(
"New dataset uploaded. Add a new chart to use it.", duration=5000
)
pn.template.FastListTemplate(
logo=GW_LOGO,
title="Panel Graphic Walker Reference App",
sidebar=[
"## Data Input",
file_upload,
file_download,
"## Spec Input",
pn.Row(simple_spec, no_spec, initial_spec),
"## Settings",
pn.Accordion(
core_settings,
style_settings,
export_section,
save_section,
width=320,
active=[0],
),
docs_section,
],
main=[walker],
main_layout=None,
accent="#5B8FF9",
).servable()