Hello, I have the following app built using panel
that is an example of functional programming:
from bokeh.models.widgets.tables import NumberFormatter, StringFormatter
import intake
import pandas as pd
import panel as pn
pn.extension("tabulator")
url = "https://url/for/intake_catalog.yml"
cat = intake.open_catalog(url)
# access tutorial catalog
sub_cat= cat["sub_cat"]
# get list of datasets for descriptive statistics
datasets = [dataset for dataset in list(sub_cat) if "desc" in dataset]
dataset_select = pn.widgets.Select(
description = "Select a Dataset",
name="Dataset",
options=datasets
)
@pn.cache(per_session=True)
def _get_data(_dataset: str, _catalog: intake.Catalog = sub_cat) -> pd.DataFrame:
"""Reaches and caches data from intake catalog."""
return _catalog[_dataset].read()
def _get_description(_dataset: str, _catalog:intake.Catalog = sub_cat) -> str:
"""Returns description of dataset."""
_description = _catalog[_dataset].description
return _description
def create_bokeh_formatters(column_dict: dict) -> dict:
"""Create a dynamic list of formatted columns."""
formatters = {}
for column, dtype in column_dict.items():
if dtype == "float":
formatters[column] = NumberFormatter(format="0.00")
if dtype == "str":
formatters[column] = StringFormatter()
return formatters
@pn.depends(dataset_select)
def construct_tabulator(dataset: str, catalog:intake.Catalog = sub_cat) -> pd.DataFrame:
"""Create tabulator object based on changes to selected dataset."""
# create dataframe
_df = _get_data(dataset)
# create column formatters
_column_formatters = create_bokeh_formatters(_df.dtypes.to_dict())
_df_tabulator = pn.widgets.Tabulator(_df,
name="Tabulator",
hidden_columns=["index"],
disabled=True,
theme="modern",
formatters=_column_formatters
)
# get description for each dataset and render as html h2
_df_description = _get_description(dataset)
_description_display = pn.pane.Markdown(f"## {_df_description}")
# create a column
_df_display = pn.Column(_description_display, _df_tabulator)
return _df_display
pn.Column(dataset_select,
construct_tabulator
).servable()
This works great but when I try to create a more OOB Class based implementation, my app stops functioning when I add the create_bokeh_formatters
.
from bokeh.models.widgets.tables import NumberFormatter, StringFormatter
import intake
import pandas as pd
import panel as pn
import param
pn.extension("tabulator")
# intake catalog setup
url = "https://url/for/intake_catalog.yml"
cat = intake.open_catalog(url)
# access tutorial catalog
sub_cat= cat["sub_cat"]
# get list of datasets for descriptive statistics
datasets = [dataset for dataset in list(sub_cat) if "desc" in dataset]
# get data from catalog
def _get_data(_dataset: str, _catalog:intake.Catalog = sub_cat) -> pd.DataFrame:
return _catalog[_dataset].read()
def create_bokeh_formatters(column_dict: dict) -> dict:
"""Create a dynamic list of formatted columns."""
formatters = {}
for column, dtype in column_dict.items():
if dtype == "float":
formatters[column] = NumberFormatter(format="0.00")
if dtype == "str":
formatters[column] = StringFormatter()
return formatters
df_dtypes = {}
class DescTabulator(param.Parameterized):
dataset = param.Selector(objects=datasets)
dataframe = param.DataFrame(sub_cat[datasets[0]].read())
@param.depends("dataset", watch=True)
def _update_dataframe(self):
df = sub_cat[self.dataset].read()
globals()["df_dtypes"] = df.dtypes.to_dict()
self.dataframe = df
tab = DescTabulator()
tab_panel = pn.Param(tab, widgets={
"dataframe": dict(widget_type=pn.widgets.Tabulator,
hidden_columns=["index"],
formatters=create_bokeh_formatters(df_dtypes) # commenting out this line allows the app
# to update when a different dataset is collection
)
})
pn.Row(tab_panel).servable()
I was wondering if anyone has been able to custom format a Tabular using pn. Param? Thanks!