@param.depends button in class

tabedit = pn.widgets.Tabulator(
value=df_ora, show_index=False, selectable=True, disabled=True, theme=“site”, height=140
)

This selected in sidebar will render my plot on main. But I have a class that has a button to trigger an insert into the database.

sb = pn.Column(pn.bind(my_func,submitButton))

I need my dataframe to repull from the database and update tabedit = pn.widgets.Tabulator(
value=df_ora, show_index=False, selectable=True, disabled=True, theme=“site”, height=140
)

1 Like

I’m sorry but I don’t understand your question, could you rephrase it please and add a more complete example with code?

1 Like

If you are trying to show a pandas dataframe has a grid to allow users to select record and pass a value to a pn widget no problem. Now if you have a class with serveral functions with a submit button that will triger a database row insert, and you now need the dataframe outside the class to refresh. How do you get the dataframe to to update once a button has been clicked inside a class?

import LogUser as lg
import panel as pn
import param

user = "MYUSER"


df_ora = lg.get_user(user)
tabedit = pn.widgets.Tabulator(
    value=df_ora, show_index=False, selectable=True, disabled=True, theme="site", height=140
)

def compute_plot(selection):
    fp = (df_ora['FILE_PATH'].loc[df_ora.index[selection]])
    # print(type(fp))
    try:
        fpv = (list(fp)[0])
    except IndexError:
        fpv = None    
    pdf = fpv
    print(pdf)
    iframe = """<iframe width="1000" height="1000" src="http://myweb/pdfviewer/web/viewer.html?file={pdf_file}"
        frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>
        """.format(pdf_file=pdf)
    print(iframe)        
    pdf_viewer = pn.pane.HTML(iframe, height=1000)


    return pdf_viewer
plot = pn.bind(compute_plot, selection=tabedit.param.selection)


### Map type GUI
class Comp(param.Parameterized):
    submitButton =  pn.widgets.Button(name='Click me', button_type='primary', margin=(25,50))

    def inputpanel(self):
        return pn.Column('### Map Options',
            pn.Row(self.panel3)
        )
    
    def panel3(self):
        return pn.Row(
            pn.Column(self.submitButton),
        )   
    
    def my_func(click):
            # call the insert_dept function
            s_userinfo = 'MYUSER'
            s_keyargs = '{"MapGroup": "Reference", "MapType": "Comp", "A": "V1", "W": ["V2"], "Y1": "1", "X1": "V2"}'
            s_filepath = r'D:/pdfviewer/web/MY.pdf' 
            try:
                lg.insert_user(s_userinfo, s_keyargs, s_filepath)
            except Exception as e:
                print(e)

    sb = pn.Column(pn.bind(my_func,submitButton))


### Based On category and map type selected in side panel create gui from a class above
class GUI_Viewer(param.Parameterized):
    
    mapgroup = param.ObjectSelector(default='R', objects=['R', 'S'])
    
    maptype = param.ObjectSelector(default='Comp', objects=['Comp', 'L', 'W'])
    
    _maps = {'Reference'  : ['C', 'L', 'W'],
                  'Sur': ['D5', 'D6', 'Wat']}
    
    @param.depends('mapgroup', watch=True)
    def _update_countries(self):
        maps = self._maps[self.mapgroup]
        self.param['maptype'].objects = maps
        self.maptype = maps[0]

    @param.depends('maptype')
    def view(self):
        gui = ""
        print(self.maptype)
        if self.maptype == "Comp":
            gui = pn.Row(Comp().inputpanel, Comp.sb)
      
        return gui

viewer = GUI_Viewer(name='Map')

template = pn.template.FastGridTemplate(header_background="#54585A",
        site="", title="Map Store", logo="http://MYWEB/img/my.png",
        sidebar=pn.Column(viewer.param, tabedit)
        # config=config
        # main = content
    )   
template.main[:5, 0:] = pn.Row(viewer.view, plot)


app = template
##app.show()
app.show()

The Tabulator widget has a .value attribute that you can reassign with a new DataFrame. You could use that in your submit method.

An example:

import numpy as np
import pandas as pd
import panel as pn

pn.extension('tabulator')

# Create a DataFrame and a Tabulator widget
df = pd.DataFrame(np.random.rand(5, 5))
w = pn.widgets.Tabulator(df)
# Reassign the widget value with a new DataFrame.
w.value = pd.DataFrame(np.random.rand(5, 5))

Alternatively, instead of updating the whole table, you can decide to just patch it.

Regarding your code I’d advise you to try not to mix too many APIs of Panel (@param.depends, pn.bind, etc.). Not that the code won’t run, it’s just that it’s easier to reason about the code when you use just one API. In your case since you’re already creating a Parameterized class you could stick to that approach, which means you don’t need to use pn.bind but can just use @param.depends.

Thanks. I did notice some wierd behavior with bind on a button. The button would execute on load up, which is not the behavior i want.

This is a small example which shows how to get a Parameterized class to render one of its Parameters as a Button. For that you just declare a param.Event Parameter, give it a label that will be the Button title, and add a callback that will be called every time the Button is clicked.

import param
import panel

class P(param.Parameterized):

    submit = param.Event(label='Submit data')

    @param.depends('submit', watch=True)
    def _submit_cb(self):
        print('Callback triggered when the submit button is clicked')

p = P()
pn.Param(p.param)

As for your code, I don’t know if this is an indentation issue or not but it is a little awkward to declare sb in the class body, and for my_func not having self as an argument.

Thanks. I did notice some wierd behavior with bind on a button. The button would execute on load up, which is not the behavior i want.

When you ask panel to render Comp.sb in the view method, it will compute pn.Column(pn.bind(my_func,submitButton)) which will indeed trigger the bound function my_func. This is expected, any function/method foo that you ask Panel to render with pn.panel(foo) (or pn.Column(foo), etc.) will be called on render, since Panel needs something to get some objects :upside_down_face:

3 Likes

How to define things like margin and width now that pn.widgets.Button is replaced by param.Event()?