在IPython笔记本小部件和Spyre中动态更改下拉菜单

22

我在IPython笔记本中有一个下拉菜单(作为HTML小部件的一部分),在Spyre应用程序中也有一个(作为dropdown元素),用于选择一个洲,我想添加第二个下拉菜单来选择该洲内的国家。显然,第二个下拉菜单中的选项取决于第一个下拉菜单的值。我正在努力找到一种方便的方法来具有更新此UI元素的回调函数。

我在IPython笔记本中几乎完成了这个任务,在被调用的函数中,我会创建带有第二个下拉菜单的第二个interact元素。但是,每当我更改第一个下拉菜单时,都会创建一个新的下拉菜单元素,因此我将随着每次更改而得到一个额外的下拉菜单。但我只想更新一个下拉菜单,就这些。

希望问题清楚明确。谢谢你。

5个回答

25

使用interactive代替interact并更新您的小部件:

from IPython.html import widgets
from IPython.display import display

geo={'USA':['CHI','NYC'],'Russia':['MOW','LED']}

def print_city(city):
    print city

def select_city(country):
    cityW.options = geo[country]


scW = widgets.Select(options=geo.keys())
init = scW.value
cityW = widgets.Select(options=geo[init])
j = widgets.interactive(print_city, city=cityW)
i = widgets.interactive(select_city, country=scW)
display(i)
display(j)

7
注意:IPython.html.widgets 已经迁移到 ipywidgets。请使用 import ipywidgets as widgets - Kamil Sindi

9

票数最高的答案虽然有用,但对我来说有些笨拙。经过一番搜索,我发现基于Jupyter文档这里的答案更适合我。我进行了改编并提供以下内容。

from ipywidgets import interact, Dropdown

geo = {'USA':['CHI','NYC'],'Russia':['MOW','LED']}
countryW = Dropdown(options = geo.keys())
cityW = Dropdown()

def update_cityW_options(*args): # *args represent zero (case here) or more arguments.
    cityW.options = geo[countryW.value]
cityW.observe(update_cityW_options) # Here is the trick, i.e. update cityW.options based on countryW.value.

@interact(country = countryW, city = cityW)
def print_city(country, city):
    print(country, city)

作为另一种选择,我还发现我可以在“print_city”函数内直接更新“cityW.options”,这是更加清晰的做法!
from ipywidgets import interact, Dropdown

geo = {'USA':['CHI','NYC'],'Russia':['MOW','LED']}
countryW = Dropdown(options = geo.keys())
cityW = Dropdown()

@interact(country = countryW, city = cityW)
def print_city(country, city):
    cityW.options = geo[country] # Here is the trick, i.e. update cityW.options based on country, namely countryW.value.
    print(country, city)

这似乎确实是一个好的解决方案,除非你的中介工作不是微不足道的(那么在城市发生变化时重新计算城市选项有点浪费)。但对于许多用例来说,这可能是可以接受的。 - ILoveCoding
第二种方法真的很棒! - Andy

4
import datetime
import ipywidgets as ipyw

from bokeh.models.widgets.inputs import AutocompleteInput
from IPython.display import display

dp1 = ipyw.Dropdown(options = ['Asia','Europe','Africa'])
dp2 = ipyw.Dropdown(options = ['India','China','Pakistan','Tibet'])
asia_list = ['India','China','Pakistan','Tibet']
europe_list = ['Germany','France','Italy']
africa_list = ['south africa','Nigeria','Kenya']
global_vbox = ipyw.VBox()
global_vbox.children = [dp1,dp2]
display(global_vbox)
def continent_change_event(x):
    global dp1
    global dp2
    list_name = dp1.value
    dp2.index = None #This line is very important for setting the values for widgets other than widget with observe method
    dp2.index = 0
    if(list_name == 'Asia'):
        dp2.options = asia_list
    elif(list_name == 'Europe'):
        dp2.options = europe_list
    else:
        dp2.options = africa_list

dp1.observe(continent_change_event)

2

对于那些使用 widgets.interactive 的人:在您的主要函数中更新动态小部件的选项:

import ipywidgets as widgets 
geo={'USA':['CHI','NYC'],'Russia':['MOW','LED']}

def main_function(city, country):
    print (f'{city} is a city in {country}')
    cityW.options = geo[country]    

scW = widgets.Select(options=geo.keys())
cityW = widgets.Select(options=geo[init])

widgets.interactive(main_function, city=cityW, country=scW)

注意:这与最高评分答案的区别在于只有一个交互函数而不是两个。奖励:如果您想将固定参数传递给主函数,请使用name=widgets.fixed("Bob")请参见此处)。


如果你的两个函数执行起来很快,那么这确实可以很好地工作。但是,如果基于国家派生cityW选项需要很长时间,那么在每次城市更改时都这样做将是浪费,而不仅仅是在国家更改时。 在执行工作(打印)之前,你需要更新城市选项,否则你可能会打印"MOW是美国的一个城市..."。 - ILoveCoding

0

我采用了Fei Yao的解决方案替换

cityW.observe(update_cityW_options)

for

countryW.observe(update_cityW_options)

因为显示的城市应该取决于国家(我认为)。

同时将 Dropdown 替换为 Select(需要更少的点击)。

from ipywidgets import interact, Dropdown, Select

geo = {'USA':['CHI','NYC'],'Russia':['MOW','LED']}
countryW = Select(options = geo.keys())
cityW = Select()

def update_cityW_options(*args): # *args represent zero (case here) or more arguments.
    cityW.options = geo[countryW.value]

countryW.observe(update_cityW_options) # Here is the trick, i.e. update cityW.options based on countryW.value.
#---
@interact(country = countryW, city = cityW)
def print_city(country, city):
    print(country, city)

它看起来像这样。

enter image description here

下面的部分#---是不必要的,除非您想打印所选组合(原问题并没有要求)。
如果您删除它,只需添加
# display the widgets
countryW
cityW 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接