Python 如何保存ipywidget输出并将其链接到按钮,以使用保存的输入运行另一个函数

Python 如何保存ipywidget输出并将其链接到按钮,以使用保存的输入运行另一个函数,python,jupyter-notebook,widget,ipywidgets,Python,Jupyter Notebook,Widget,Ipywidgets,这将是一个很长的问题,所以我会尽量把它分解,所以请耐心听我说。我的想法是使用jupyter小部件创建一个jupyter笔记本应用程序。我的应用程序将使用API获取一些信息,但它首先需要一些输入,这些输入是时间和实体名称,其中也包含一些元数据。因为我在这里合并了不同的IPyWidget(选择多个2个日期选择器小部件(开始、结束)和按钮,它们最终将加载从数据库获取数据的函数。) 目前,我的小部件如下所示: 我能够获得多个实体(“井”)(具有自己的元数据,并指定开始和结束日期,并将其保存在字典中)。

这将是一个很长的问题,所以我会尽量把它分解,所以请耐心听我说。我的想法是使用jupyter小部件创建一个jupyter笔记本应用程序。我的应用程序将使用API获取一些信息,但它首先需要一些输入,这些输入是时间和实体名称,其中也包含一些元数据。因为我在这里合并了不同的IPyWidget(选择多个2个日期选择器小部件(开始、结束)和按钮,它们最终将加载从数据库获取数据的函数。)

目前,我的小部件如下所示:

我能够获得多个实体(“井”)(具有自己的元数据,并指定开始和结束日期,并将其保存在字典中)。我已经创建了一个按钮,但我很难将按钮链接到已经保存的数据,以便在每次运行时单击“运行”来运行我的函数。这是我的密码:

#I created a class to add multiple widgets
class SelectMutipleInteract(widgets.HBox):
        
    def __init__(self,api_obj):
        #In my init function I'm obtaining all the entities to be stored in the Selectmultiple widget
        env='prod'
        pre_df = api_obj.search_sites_by_name('',env).set_index('site_id').sort_index(ascending=True)
        pre_df = pre_df[pre_df['db'].str.contains('jon')]
        self.pre_df = pre_df
        
        self.w = widgets.SelectMultiple(
            options = pre_df.name.values,
            rows = len(pre_df),
            description = 'Wells',
            disabled = False)
        #From that same data I get initial start and end dates (which I'll be able to change based on the time I want)
        try:
            self.start_date = datetime.strptime(self.pre_df.sort_values(by='date_created')['date_created'].values[0],'%Y-%m-%dT%H:%M:%SZ')
            self.start_date = pd.Series(self.start_date).dt.round('H')[0]
        except:
            'TypeError'
        
        try:
            self.start_date = datetime.strptime(self.pre_df.sort_values(by='date_created')['date_created'].values[0],'%Y-%m-%dT%H:%M:%S.%fZ') 
            self.start_date = pd.Series(self.start_date).dt.round('H')[0]
        except:
            'TypeError'
        
        try:
            self.end_date = datetime.strptime(self.pre_df.sort_values(by='last_transmission',ascending=False)['last_transmission'].values[0],'%Y-%m-%dT%H:%M:%SZ')
            self.end_date = pd.Series(self.end_date).dt.round('H')[0]
        except:
            'TypeError'
            
        try:
            self.end_date = datetime.strptime(self.pre_df.sort_values(by='last_transmission',ascending=False)['last_transmission'].values[0],'%Y-%m-%dT%H:%M:%S.%fZ')
            self.end_date = pd.Series(self.end_date).dt.round('H')[0]
        except:
            'TypeError'

        # I created the rest of the widgets
        self.w1 = widgets.DatePicker(
                    description='Pick Start Date',
                    value = self.start_date)
        
        self.w2 = widgets.DatePicker(
                    description='Pick End Date',
                    value=self.end_date)
        
        self.w3 = widgets.Button(
                    description='Run',
                    button_style='info')
        
        self.selectors = [self.w,self.w1,self.w2,self.w3]
        
        #I think this as a super class and then each object to be assigned together
        super().__init__(children=self.selectors)
        self._set_observes()
        
    def _set_observes(self):
        self.selectors1 = self.selectors[:3]
        for widg in self.selectors1:
            widg.observe(self._observed_function_widgets1, names='value')
            
    #Observed function will work as the place to store the metadata        
    def _observed_function_widgets1(self,widg):
        self.dict = {}
        self.list_a = []
        
        for widg in self.selectors1:
            if type(widg.get_interact_value())==tuple:
                self.list_a.append(widg.get_interact_value())
            else:
                self.list_a.append(datetime.strftime(widg.get_interact_value(), '%Y-%m-%d %H:%M:%S'))
                
        for well in self.list_a[0]:
            a = self.pre_df.loc[self.pre_df['name']==well,:]
            self.dict[well]= {'domain':a['db'],'site_slug':a['slug'],'start_date':self.list_a[1],
                                'end_date':self.list_a[2]}
        
        print(self.dict)
        
        #This is where I put the connection of the button but I'm getting an error
        self.w3.on_click(self._on_button_clicked(self.dict))
        
        
    def _on_button_clicked(self,dict1):
        #Here I should run the final function
        print(1)
        print(dict1)
        
        
SelectMutipleInteract(api_obj)
当我按下按钮时(在我已经选择了实体和时间之后)出现的错误是

整个想法是(一旦选择并存储了数据)然后运行最后一个函数,但是我很难对按钮上的创建进行概念化,因为您需要先运行几个小部件来获取数据并存储数据,然后单击按钮以该数据运行函数。我正在一起创建小部件布局


任何帮助都将不胜感激。

这里的问题非常微妙

您需要将可调用的
self传递到
self.w3。单击
按钮。您当前的代码调用
self.\u在按钮上单击
函数,并传递函数的返回值,该值实际上为无。然后,当您单击按钮时,单击上的
会尝试调用None,从而导致您的错误

请尝试思考以下代码:

value = self._on_button_clicked(self.dict)
self.w3.on_click(value)
这是与当前代码完全相同的实现,但希望它能说明为什么您的代码不起作用
value
为None,然后单击按钮时告诉按钮调用None

要避免这种情况,请进行以下更改:

  • self.w3.on_单击(self.\u on_按钮_单击)
    #传递函数本身,而不是调用该函数的结果

  • 更改观察到的函数代码,以获取正文中所需的变量


  • 在大多数情况下,最好在观察到的函数中获取所需的变量,而不是在单击
    赋值时尝试传递它们。如果您真的无法获取函数中所需的变量(例如,变量超出范围),则可以使用functools.partial。

    Hello ac24,它工作得很好!!非常感谢你!!
    value = self._on_button_clicked(self.dict)
    self.w3.on_click(value)
    
        def _on_button_clicked(self, button):  # the button arg gets passed, but you don't need it.
            #Here I should run the final function
            print(1)
            print(self.dict) # grab the instance variables you want