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

2024-06-26 14:59:00 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

enter image description here

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

#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)

当我按下按钮时(在我已经选择了实体和时间之后)出现的错误是

{'SHB 67-34': {'domain': site_id
183    jonah-energy
Name: db, dtype: object, 'site_slug': site_id
183    10004-24
Name: slug, dtype: object, 'start_date': '2019-09-26 15:00:00', 'end_date': '2020-12-17 21:00:00'}, 'SHB 75-34': {'domain': site_id
184    jonah-energy
Name: db, dtype: object, 'site_slug': site_id
184    10005-40
Name: slug, dtype: object, 'start_date': '2019-09-26 15:00:00', 'end_date': '2020-12-17 21:00:00'}, 'SHB 77-34': {'domain': site_id
185    jonah-energy
Name: db, dtype: object, 'site_slug': site_id
185    10006-46
Name: slug, dtype: object, 'start_date': '2019-09-26 15:00:00', 'end_date': '2020-12-17 21:00:00'}}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
TypeError: 'NoneType' object is not callable

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

任何帮助都会非常感激


Tags: the数据selfiddfdateobjectsite
1条回答
网友
1楼 · 发布于 2024-06-26 14:59:00

这里的问题非常微妙

您需要将可调用的self._on_button_clicked传递给self.w3.on_click。当前代码调用self._on_button_clicked函数,并传递函数的返回值,该值实际上是无的。然后,当您单击按钮时,on_click尝试调用None,因此您会出错

请尝试思考以下代码:

value = self._on_button_clicked(self.dict)
self.w3.on_click(value)

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

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

  1. self.w3.on_click(self._on_button_clicked)#传递函数本身,而不是调用该函数的结果

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

    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

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

相关问题 更多 >