Toggling widget visibility with checkbox

This should be trivial, but I can’t see what the problem is:

df = pd.DataFrame({'A':[1,2,3],'B':['x','y','z']})
def Disp(CBValue):
    dfWidget.visble = CBValue
    print('CB Value: ',CBValue)

CB = pn.widgets.Checkbox(name='Show df',value=False)
dfWidget = pn.widgets.DataFrame(df,visible=False)

_ = pn.bind(Disp,CB,watch=True)

pn.Column(CB,dfWidget)

The checkbox appears and the dataframe widget is not displayed initially. Checking the box triggers the print statement but the dataframe widget is not displayed.

Panel version is 0.14.4, in case that is relevant.

Can anyone point out the problem? Any help is appreciated.

I have a workaround which bypasses the visibility attribute, but not being able to set it seems like a bug. Workaround:

df = pd.DataFrame({'A':[1,2,3],'B':['x','y','z']})
def Disp(CBValue):
    if CBValue:
        dfW = pn.widgets.DataFrame(df)
    else:
        dfW = None
    return dfW
        
CB = pn.widgets.Checkbox(name='Show df',value=False)
dfWidget = pn.bind(Disp,CB)

layout = pn.Column(CB,dfWidget)
layout.servable()

Use reactive parameters

import panel as pn
import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": ["x", "y", "z"]})

CB = pn.widgets.Checkbox(name="Show df", value=False)

pn.Column(
    CB, pn.widgets.DataFrame(df, visible=pn.bind(lambda value: value, CB))
).servable()

Even simpler. Thanks to some recent work from @philippjfr panel supports passing in parameter references. I don’t know if it is supported everywhere, but it is super neat.

import panel as pn
import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": ["x", "y", "z"]})

CB = pn.widgets.Checkbox(name="Show df", value=False)

pn.Column(
    CB, pn.widgets.DataFrame(df, visible=CB.param.value)
).servable()

Notice we pass in .param.value not .value.

This does not work in Panel 0.14.4. I get

ValueError: Boolean parameter 'visible' must be True or False, not <function _param_bind.<locals>.wrapped at 0x7f3753001b80>

This is beautiful syntax! Sadly, it doesn’t work in version 0.14.4, which I am stuck with because several other things break when I upgrade.

Thanks for your responses.

This maybe works in your version

import panel as pn
import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": ["x", "y", "z"]})


CB = pn.widgets.Checkbox(name="Show df", value=False)

def update(_):
    dfWidget.visible = CB.value


dfWidget = pn.widgets.DataFrame(df)

pn.Column(CB, dfWidget, pn.bind(update, CB)).servable()

Or you go the param way

import panel as pn
import pandas as pd
import param


class App(param.Parameterized):

    checkbox = param.Parameter()
    df_widget = param.Parameter()

    @param.depends("checkbox.value", watch=True, on_init=True)
    def update(self):
        self.df_widget.visible = self.checkbox.value

    def __panel__(self):
        return pn.Column(self.checkbox, self.df_widget)


app = App(
    checkbox=pn.widgets.Checkbox(name="Show df", value=False),
    df_widget=pn.widgets.DataFrame(
        pd.DataFrame({"A": [1, 2, 3], "B": ["x", "y", "z"]})
    ),
)

pn.Column(app).servable()

It does work ! I didn’t know you could embed a reactive function in a layout. For readability, I changed the bound function to

def update(Toggle):
    dfWidget.visible = Toggle

Thanks for your help.