Reset FileInput with a watcher on its value

Hello there,

I am having a problem trying to dynamically reset a FileInput widget.
More precisely, I have two widgets :

  • A MultiSelect with several options
  • A FileInput to upload an Excel file enabling to have other selection possibilities that are not in the MultiSelect

I would need the FileInput file to be reset as it is on initialisation with a “No File Chosen” message each time something is selected in the MultiSelect.

Questions :

  • How do you catch events on a FileInput object using param variable ? (using param.depends and a variable param.FileSelector)
  • How do you modify the value of the FileInput widget so that both the stored value AND the displayed value are reset to initial empty value ?

Here’s a code snippet to illustrate the problem, nothing is printed when an excel file is uploaded :

import param, panel as pn
pn.extension()

#Modify to match any column name of your excel file
COLUMN_NAME = "store"

class Example(param.Parameterized):
    trigger_multi_list = param.Number(default=1)
    trigger_file_input = param.Number(default=1)
    multi_list = param.Parameter(pn.widgets.MultiSelect(options=['Apple', 'Banana', 'Orange', 'Lemon']))
    file_input = param.Parameter(pn.widgets.FileInput(accept='.xlsx', name='file_input'))
    stores_list = []

    @param.depends("multi_list.value", watch=True)
    def function_trigger_multi_list(self):
        self.trigger_multi_list += 1  # To trigger plot_data_trigger_multi_list
        
        
    @param.depends("file_input.value", watch=True)
    def function_trigger_file_input(self):
        with pd.ExcelFile(self.selector.store_file, engine="openpyxl") as excel:
            df_excel = pd.read_excel(excel)
        self.stores_list = list(df_excel[COLUMN_NAME].dropna().astype("str"))
        self.trigger_file_input += 1  # To trigger plot_data_trigger_file_input

    @param.depends("trigger_multi_list")
    def plot_data_trigger_multi_list(self):
        #print(self.multi_list.value, type(self.multi_list.value))
        return 'MULTI SELECT: ', self.multi_list.value, self.trigger_multi_list
    
    @param.depends("trigger_file_input", on_init=False)
    def plot_data_trigger_file_input(self):
        #print(self.stores_list, type(self.stores_list))
        return 'FILE INPUT: ', self.stores_list, self.trigger_file_input
    

    def __panel__(self):
        return pn.Row(self.multi_list, self.file_input, self.plot_data_trigger_multi_list, self.plot_data_trigger_file_input)

pn.panel(Example().__panel__).servable()

Hi @hadmaria,

Do you get any errors when you run the attached code? Try running it in book with nothing else loaded. I think there are some bits missing.

I changed self.selector.store_file to self.file_input.value then created an excel file with a single column “store” and some values, when I open I get this

23,45,56 being my values from the file

Thanks, Carl.

1 Like

Hi @hadmaria,

For the questions, one way I’ve seen is param.watch see in code below to capture an event. Maybe try integrating something like this into your code, the idea I think here is that a widget to restore to default that your looking for I think you need to add to a pn.Row or pn.Column so that it can be dynamically removed and added back. I don’t think you can simply change the value, perhaps you can I’ve not explored. This seems to be what your looking for with regards to resetting FileSelector, one caveat here is that you can’t re click on the already selected option in multi widget, you must click another

import panel as pn

class WidgetManager:
    def __init__(self):
        self.load_row = self.load_file_widget()
        self.widget_row = self.load_widgets()

    def load_file_widget(self):
        # Create a row of widgets for file load
        self.file_input = pn.widgets.FileInput(accept='.csv')
        load_row = pn.Row(self.file_input)
        return load_row

    def load_widgets(self):
        # Create a row of widgets
        self.multi_select = pn.widgets.MultiSelect(name='MultiSelect', options=['Option 1', 'Option 2', 'Option 3'])
        widget_row = pn.Row(self.multi_select)
        # Add callback function to MultiSelect widget
        self.multi_select.param.watch(self.reset_file_input, 'value')
        return widget_row

    def reset_file_input(self, event):
        print("reset file input")
        # Reset FileInput widget when MultiSelect widget is clicked
        # first remove, initially tried pop but clear seems to be the ticket here
        self.load_row.clear()
        # now you need to recreate the widget
        self.load_row.append(pn.widgets.FileInput(accept='json', multiple= False))


# Create an instance of the WidgetManager class
widget_manager = WidgetManager()



# Create a FastList dashboard and add the widgets to it
dashboard = pn.Column(pn.Column(
    widget_manager.widget_row,
    sizing_mode='stretch_width'),
                      pn.Column(widget_manager.load_row,)
)

# Show the dashboard
dashboard.show()

Another way not using class but quite similar whom I got the idea from is @riziles see the contribution here

https://discourse.holoviz.org/t/clear-fileinput-widget-after-file-uplaod/4759

Hope of some help, Carl.

2 Likes