How to create multiple instances of object and display methods

Hello, I am glad to have joined this community and am hoping to seek for some help:
I am working on creating a fiber photometry GUI that (should) eventually be able to read in multiple (at least 2) CSVs or pickled files and create object instances based on each file read in, then be able to call certain function methods/display plots etc.
The code below currently allows me to upload a CSV file containing the necessary information, read it and create a new object, and call some methods that display some Plotly visuals.
I am wondering how to go about being able to instantiate more objects (whilst keeping the first one created) and having a sort of dropdown menu where I can switch between views of each object and its called upon function methods/visuals.

class FiberGui(param.Parameterized):
    #Check: Are all these attributes necessary?
    data = pd.DataFrame()
    fpho_data_df = pd.DataFrame()
    file_input = param.Parameter()
    input_1 = param.Parameter()
    input_2 = param.Parameter()
    input_3 = param.Parameter()
    input_4 = param.Parameter()
    input_5 = param.Parameter()
    test_obj = param.Parameter()
    plot_pane = param.Parameter()
    plot_pane_2 = param.Parameter()
    plot_panes = param.Parameter()
    fitted_plot = param.Parameter()
    raw_plot = param.Parameter()
    # update_plot = param.Action(lambda x: x.param.trigger('update_plot'), label = 'Read CSV')

    def __init__(self, **params):
        self.param.file_input.default = pn.widgets.FileInput(accept = '.csv')

        self.raw_signal_plot_button = pn.widgets.Button(name = "Plot Raw Signal Graph", button_type = 'primary')
        self.fitted_exp_plot_button = pn.widgets.Button(name = "Plot Fitted Exp Graph", button_type = 'success')
        self.read_input_button = pn.widgets.Button(name = "Read CSV and Input Params")
        #Plot panes
        self.plot_pane = pn.pane.Plotly(height = 400, sizing_mode = "stretch_width")
        self.plot_pane_2 = pn.pane.Plotly(height = 600, sizing_mode = "stretch_width")
        self.plot_panes = pn.Column(self.plot_pane, self.raw_signal_plot_button, self.plot_pane_2, self.fitted_exp_plot_button)
        #Plot panes
        #Entry/Input params
        self.input_1 = pn.widgets.TextInput(name = 'Object Name', width = 90, placeholder = 'String')
        self.input_2 = pn.widgets.IntInput(name = 'Fiber Number', width = 90, placeholder = 'Int')
        self.input_3 = pn.widgets.IntInput(name = 'Animal Number', width = 90, placeholder = 'Int')
        self.input_4 = pn.widgets.TextInput(name = 'Exp Date', width = 90, placeholder = 'Date')
        self.input_5 = pn.widgets.TextInput(name = 'Exp Time', width = 90, placeholder = 'Time')

        self.entry_rows = pn.Column('FiberOBJ input', self.input_1, self.input_2, self.input_3, self.input_4, self.input_5, background = 'WhiteSmoke')
        #Entry/Input params
        self.side_view = None
        self.main_view = None
    #Adding raw csv input
    @pn.depends("file_input.value", watch = True)
    def _parse_file_input(self):
        value = self.file_input.value
        if value:
   = read_csv(self.file_input)
            print("read data")
            if not
                print("Dataframe empty")
            print("Error reading file")

    # @pn.depends("file_input.value", watch = True)
    def save_input_params(self, *args):
        obj_name = self.input_1.value
        fiber_num = self.input_2.value
        animal_num = self.input_3.value
        exp_date = self.input_4.value
        exp_time = self.input_5.value

        if not
            self.test_obj = createObj(, obj_name, fiber_num, animal_num, exp_date, exp_time)
            self.raw_plot = self.test_obj.raw_signal_trace()
            self.fitted_plot, self.fpho_data_df = self.test_obj.plot_fitted_exp()
            print("OBJ CREATED")
            print("Didnt create obj")

    def _side_view(self):
        self.side_view = pn.Column(
            pn.panel(self.file_input, width = 600)
            # pn.Row(self.entry_rows, width = 500)  
        return self.side_view
    @pn.depends('data', watch = True)
    def _main_view(self):
        self.main_view = pn.Column(
            pn.panel(self.plot_panes, width = 400)
        return self.main_view
    def get_raw_signal_plot(self, *args):
        #Adds plot pane to window
        self.plot_pane.object = self.raw_plot
        return self.plot_pane
    def get_fitted_exp_plot(self, *args):
        fitted_btn = pn.Row(self.fitted_exp_plot_button, width = 400)
        self.plot_pane_2.object = self.fitted_plot
        return self.plot_pane_2

fiber_examp = FiberGui()
fiber_side = fiber_examp._side_view()
fiber_main = fiber_examp._main_view()

# component = pn.Column(
#     description,
#     fiber_view
#     # sizing_mode='stretch_width'
# )
# component

template = pn.template.MaterialTemplate(site = "Fiber Photometry", title = 'FiberPho GUI',
                                       sidebar = ["**Upload CSV** and set **Input Parameters** for your fiber object here",
                                       main = [
                                           pn.Column(pn.panel(fiber_main, height = 700))

server = pn.serve(template, start = False, show = False, loop = loop, websocket_max_message_size = 10485760000, 
                  verbose = True,
                  threaded = False

Any help/guidance in the right direction would be appreciated!
Thank you

Hi @yobae

Welcome to the community :+1:

You can use a Selector parameter to keep track of your datasets and the current dataset.

from io import StringIO

import pandas as pd
import panel as pn
import param

pn.extension("tabulator", sizing_mode="stretch_width")


class Dataset(param.Parameterized):
    value = param.DataFrame()

class FiberGui(param.Parameterized):
    new_dataset_input = param.ClassSelector(class_=pn.widgets.FileInput, constant=True)

    def __init__(self, **params):
        params["new_dataset_input"]=pn.widgets.FileInput(accept = '.csv')

    @pn.depends("new_dataset_input.value", watch = True)
    def _parse_new_data_set(self):
        value = self.new_dataset_input.value
        if not value:

        string_io = StringIO(value.decode("utf8"))
        dataset = Dataset(value=pd.read_csv(string_io), name=self.new_dataset_input.filename)
        existing_datasets = self.param.dataset.objects
        self.param.dataset.objects=[*existing_datasets, dataset]
        self.dataset = dataset

    def output(self):
        if self.dataset:
            return pn.widgets.Tabulator(self.dataset.value.head(100), theme="fast", height=800, pagination="remote", page_size=25)
            return "No Datasets Loaded"

gui = FiberGui()

template = pn.template.FastListTemplate(
    site = "Awesome Panel", title = 'Fiber Photometry App with File Upload',
    sidebar = ["**Upload a new dataset** here", gui.new_dataset_input, pn.Param(gui, parameters=["dataset"], show_name=False)],
    main = [pn.panel(gui.output, loading_indicator=True)],
    accent_base_color=ACCENT_COLOR, header_background=ACCENT_COLOR

If you like this example please share on twitter or Linked In Panel on LinkedIn: #dataviz #python #datascience. Thanks


Just a small note: You should NOT use pickle as a way to upload data. The reason is it is not secure, see pickle — Python object serialization — Python 3.10.1 documentation and Exploiting Python pickles - David Hamann.


I appreciate the quick response. I have not gotten time to properly implement this into my current code, but I will be sure to update you and share on twitter/linkedin when I get the chance.
Thank you so much!

1 Like