Python Dash - 同一回调函数中的动态和静态输入选项
Python Dash - Dynamic and Static input options in same callback function
我需要编写一个具有动态输入组件和静态输入组件的回调函数。但是把它们放在一起是抛出错误。
这是我目前所做的 -
@app.callback(
[Output("new_list", "children")],
[
#Static Input Component
Input("clear", "n_clicks"),
#Dynamic Input Component
Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)
],
)
###########################################################
## Updated sample working code
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash import callback_context
from dash.dependencies import Input, Output, State
import numpy as np
import pandas as pd
import dash_table as dt
item1 = ['A','A','B','B']
item2 = ["W","X","Y","Z"]
item3 = ["L",np.nan,'M','L']
item_list = pd.DataFrame(list(zip(item1,item2,item3)),columns=["item1","item2","item3"])
cat_list = item_list.item1.unique()
global itemlist
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
def Add_item(data,data2):
print("BILLING: Add_item()")
item_list = dbc.Card(children = [
generate_item(data,data2),
dbc.Row([
dbc.Col([
dbc.Button(
html.H5("Cancel"), id="cancel", className="ml-auto", color = "danger"
)
]),
dbc.Col([
dbc.Button(
html.H5("Clear"), id="clear", className="ml-auto", color = "info"
)
]),
],style = {"width": "71rem"})
],
id="modal-body-newitem"
)
return item_list
def generate_item(item_list,itemlist):
buttons = html.Div(children =[
dbc.Row([
dbc.Button(
html.H5(str('+ ' + a)),
id= str(a),
className="mb-3",
color="primary",
block=True
),
dbc.Collapse([
dbc.Card([
dbc.Row([
dbc.Col([dbc.Button(html.H5(str('+ ' + b)),className="mb-3",color="info",block=True, disabled = True)],width = 10),
dbc.Col([dbc.Input(type="number", min=0, max=20, step=1,value = itemlist.loc[itemlist.item == b,'qty'],id = b )],width = 2)
]) for b in item_list.loc[item_list.item1== a, ('item3','item2','item1')].stack().groupby(level=0).agg(' '.join).sort_values()
#,dbc.Card(dbc.CardBody(str("This content is for " + a)))
],body = True, style = {"width": "71rem", "justify": "centre", "align": "centre"})
],id= str("collapse" + a))
]) for a in item_list.item1.unique()
])
return buttons
app = dash.Dash(__name__,external_stylesheets=[dbc.themes.CYBORG])
app.config.suppress_callback_exceptions = True
server = app.server
app.title="Test"
app.layout = html.Div([
dbc.Card(
dbc.CardBody(
[
html.H5("New Item", className="card-title"),
Add_item(item_list,itemlist),
html.Div(id = 'new_list')
]
)
)
])
#Item Ctegory List
@app.callback(
[Output(str("collapse" + i), "is_open") for i in cat_list],
[Input(str(i), "n_clicks") for i in cat_list]+
[Input("cancel", "n_clicks")])
def toggle_collapse_category_box(*args):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:toggle_collapse_category_box: Call - "+str(callback_context.triggered))
if not callback_context.triggered or trigger["prop_id"].split(".")[0] == 'cancel':
print('MYBIZZAPP:toggle_collapse_category_box: Not Triggered/Cancel')
global isopn
isopn = [False] * len(cat_list)
else:
print('MYBIZZAPP:toggle_collapse_category_box: Triggered')
for i in range(len(cat_list)):
if cat_list[i] == trigger["prop_id"].split(".")[0]:
isopn[i] = not isopn[i]
return isopn
### Clear item list
@app.callback(
[Output(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)],
[Input("cancel", "n_clicks"),
Input("clear", "n_clicks")])
def clear_item_box(n2,n3):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:clear_item_box: Call - "+str(callback_context.triggered))
if trigger["prop_id"].split(".")[0] == 'cancel':
print("MYBIZZAPP:clear_item_box: cancel order")
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
elif trigger["prop_id"].split(".")[0] == 'clear':
print("MYBIZZAPP:clear_item_box: clear order")
return [0] * len(item_list)
#Menu item list
@app.callback(
[Output("new_list", "children")],
[Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)]+
[Input("clear", "n_clicks"),
Input("cancel", "n_clicks")])
def menu_item_list(*args):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:menu_item_list: Call - "+str(callback_context.triggered))
print(trigger["prop_id"].split(".")[0])
if not callback_context.triggered :
print('MYBIZZAPP:menu_item_list: Not Triggered')
global itemlist
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
else:
print('MYBIZZAPP:menu_item_list: Triggered')
itemlist.loc[itemlist.item == trigger["prop_id"].split(".")[0],'qty'] = trigger["value"]
if trigger["prop_id"].split(".")[0] == 'clear' or trigger["prop_id"].split(".")[0] == 'clear':
print('MYBIZZAPP:menu_item_list: Clear|Cancel')
itemlist['qty'] = 0
print('MYBIZZAPP:menu_item_list: Item List')
print(itemlist)
return ['Total items selected - ' + str(sum(itemlist.qty))]
if __name__ == '__main__':
app.run_server(debug=True)
如果我没有提到静态输入组件,代码可以正常工作。但是我也需要静态组件。
我正在尝试解决的总体问题是 - 我有动态输入文本框,如果在这些框中的任何一个中输入了一个值,则需要考虑该值并将其作为 table.此外,还有一个 'clear' 按钮。如果单击,所有值都应重新设置为默认的预定义值。
提前感谢您的帮助。
感谢您更新错误。这个问题来自你的列表理解。当您添加第一个输入时,它会为理解创建无效语法。不过,这应该可行:
@app.callback(
[Output("new_list", "children")],
[
#Static Input Component
Input("clear", "n_clicks"),
] + [
#Dynamic Input Component
Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)
],
)
我需要编写一个具有动态输入组件和静态输入组件的回调函数。但是把它们放在一起是抛出错误。
这是我目前所做的 -
@app.callback(
[Output("new_list", "children")],
[
#Static Input Component
Input("clear", "n_clicks"),
#Dynamic Input Component
Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)
],
)
###########################################################
## Updated sample working code
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash import callback_context
from dash.dependencies import Input, Output, State
import numpy as np
import pandas as pd
import dash_table as dt
item1 = ['A','A','B','B']
item2 = ["W","X","Y","Z"]
item3 = ["L",np.nan,'M','L']
item_list = pd.DataFrame(list(zip(item1,item2,item3)),columns=["item1","item2","item3"])
cat_list = item_list.item1.unique()
global itemlist
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
def Add_item(data,data2):
print("BILLING: Add_item()")
item_list = dbc.Card(children = [
generate_item(data,data2),
dbc.Row([
dbc.Col([
dbc.Button(
html.H5("Cancel"), id="cancel", className="ml-auto", color = "danger"
)
]),
dbc.Col([
dbc.Button(
html.H5("Clear"), id="clear", className="ml-auto", color = "info"
)
]),
],style = {"width": "71rem"})
],
id="modal-body-newitem"
)
return item_list
def generate_item(item_list,itemlist):
buttons = html.Div(children =[
dbc.Row([
dbc.Button(
html.H5(str('+ ' + a)),
id= str(a),
className="mb-3",
color="primary",
block=True
),
dbc.Collapse([
dbc.Card([
dbc.Row([
dbc.Col([dbc.Button(html.H5(str('+ ' + b)),className="mb-3",color="info",block=True, disabled = True)],width = 10),
dbc.Col([dbc.Input(type="number", min=0, max=20, step=1,value = itemlist.loc[itemlist.item == b,'qty'],id = b )],width = 2)
]) for b in item_list.loc[item_list.item1== a, ('item3','item2','item1')].stack().groupby(level=0).agg(' '.join).sort_values()
#,dbc.Card(dbc.CardBody(str("This content is for " + a)))
],body = True, style = {"width": "71rem", "justify": "centre", "align": "centre"})
],id= str("collapse" + a))
]) for a in item_list.item1.unique()
])
return buttons
app = dash.Dash(__name__,external_stylesheets=[dbc.themes.CYBORG])
app.config.suppress_callback_exceptions = True
server = app.server
app.title="Test"
app.layout = html.Div([
dbc.Card(
dbc.CardBody(
[
html.H5("New Item", className="card-title"),
Add_item(item_list,itemlist),
html.Div(id = 'new_list')
]
)
)
])
#Item Ctegory List
@app.callback(
[Output(str("collapse" + i), "is_open") for i in cat_list],
[Input(str(i), "n_clicks") for i in cat_list]+
[Input("cancel", "n_clicks")])
def toggle_collapse_category_box(*args):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:toggle_collapse_category_box: Call - "+str(callback_context.triggered))
if not callback_context.triggered or trigger["prop_id"].split(".")[0] == 'cancel':
print('MYBIZZAPP:toggle_collapse_category_box: Not Triggered/Cancel')
global isopn
isopn = [False] * len(cat_list)
else:
print('MYBIZZAPP:toggle_collapse_category_box: Triggered')
for i in range(len(cat_list)):
if cat_list[i] == trigger["prop_id"].split(".")[0]:
isopn[i] = not isopn[i]
return isopn
### Clear item list
@app.callback(
[Output(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)],
[Input("cancel", "n_clicks"),
Input("clear", "n_clicks")])
def clear_item_box(n2,n3):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:clear_item_box: Call - "+str(callback_context.triggered))
if trigger["prop_id"].split(".")[0] == 'cancel':
print("MYBIZZAPP:clear_item_box: cancel order")
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
elif trigger["prop_id"].split(".")[0] == 'clear':
print("MYBIZZAPP:clear_item_box: clear order")
return [0] * len(item_list)
#Menu item list
@app.callback(
[Output("new_list", "children")],
[Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)]+
[Input("clear", "n_clicks"),
Input("cancel", "n_clicks")])
def menu_item_list(*args):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:menu_item_list: Call - "+str(callback_context.triggered))
print(trigger["prop_id"].split(".")[0])
if not callback_context.triggered :
print('MYBIZZAPP:menu_item_list: Not Triggered')
global itemlist
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
else:
print('MYBIZZAPP:menu_item_list: Triggered')
itemlist.loc[itemlist.item == trigger["prop_id"].split(".")[0],'qty'] = trigger["value"]
if trigger["prop_id"].split(".")[0] == 'clear' or trigger["prop_id"].split(".")[0] == 'clear':
print('MYBIZZAPP:menu_item_list: Clear|Cancel')
itemlist['qty'] = 0
print('MYBIZZAPP:menu_item_list: Item List')
print(itemlist)
return ['Total items selected - ' + str(sum(itemlist.qty))]
if __name__ == '__main__':
app.run_server(debug=True)
如果我没有提到静态输入组件,代码可以正常工作。但是我也需要静态组件。
我正在尝试解决的总体问题是 - 我有动态输入文本框,如果在这些框中的任何一个中输入了一个值,则需要考虑该值并将其作为 table.此外,还有一个 'clear' 按钮。如果单击,所有值都应重新设置为默认的预定义值。
提前感谢您的帮助。
感谢您更新错误。这个问题来自你的列表理解。当您添加第一个输入时,它会为理解创建无效语法。不过,这应该可行:
@app.callback(
[Output("new_list", "children")],
[
#Static Input Component
Input("clear", "n_clicks"),
] + [
#Dynamic Input Component
Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)
],
)