说我有3个具有不同列名的数据集。我想制作一个绘图仪表板应用程序,在该应用程序中,根据用户选择的数据集,该应用程序应在文本区域(水平条,类似按钮但不可单击)中显示列名称。到目前为止,我已经可以做到这一点,下面是该代码:
import pandas as pd
import numpy as np
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
data1 = {'Col1':['A', 'B', 'C', 'D', 'E'],
'Col2':list(np.random.randn(5))}
data2 = {'Col1':['F', 'G', 'H', 'I', 'J'],
'Col2':list(np.random.randn(5))}
data3 = {'Col1':['K', 'L', 'M', 'N', 'O'],
'Col2':list(np.random.randn(5))}
df1 = pd.DataFrame(data1, columns=['Col1', 'Col2'])
df2 = pd.DataFrame(data2, columns=['Col1', 'Col2'])
df3 = pd.DataFrame(data3, columns=['Col1', 'Col2'])
app = dash.Dash()
app.layout = html.Div([
html.Div([dcc.Dropdown(
id='dropdown',
options=[{'label': 'Option 1', 'value': 1},
{'label': 'Option 2', 'value': 2},
{'label': 'Option 3', 'value': 3}],
placeholder='Select the dataset...',
)]),
html.Div(id='output')
])
@app.callback(
dash.dependencies.Output('output', 'children'),
[dash.dependencies.Input('dropdown', 'value')])
def update_output(selected):
if selected==1:
df = df1
elif selected==2:
df = df2
elif selected==3:
df = df3
columns = df.Col1.values
divs=[]
for i in range(len(columns)):
divs.append(
dcc.Graph(
figure=go.Figure(
data=[go.Bar(
x=[10],
y=[columns[i]],
orientation = 'h',
text=['Column number {}: {}'.format(i+1, columns[i])],
textposition = 'inside',
marker = dict(color = 'rgb(158,202,225)'),
)
],
layout=go.Layout(
xaxis=dict(showticklabels=False, fixedrange=True),
yaxis=dict(showticklabels=False, fixedrange=True),
)
),
hoverData='',
style={'width': 400, 'height':250, 'padding': 1},
id='dynamic-text-area-'+format(i)
),
)
divs.append(html.Div(style={'height': '1'}))
return divs
if __name__ == '__main__':
app.run_server(debug=True)
现在,我想添加另一种功能,每当用户将鼠标悬停在这些列名称中的任何一个上时,都将弹出一个饼状图以显示一些信息(出于演示目的,我将在下面的代码中使用一些简单的虚拟信息)。因此,我在应用程序布局中添加了一个名为pie-chart-div
的div,并在循环内添加了一个回调,并使用动态创建的文本区域图形ID作为输入来输出饼图,如下所示:
for i in range(len(columns)):
'''
###
The rest of the stuff written above
###
'''
@app.callback(dash.dependencies.Output('pie-chart-div', 'children'),
[dash.dependencies.Input('dropdown', 'value'),
dash.dependencies.Input('dynamic-text-area-{}'.format(i), 'hoverData')])
def update_graph(df, hoverData):
values = [df[df.Col1==hoverData].Col2.iloc[0], sum(df.Col2)]
labels = ['Selected column','All other columns']
trace = go.Pie(values=values, labels = labels)
fig = dcc.Graph(
id='graph',
figure={
'data': [trace],
'layout': {
'height': 400,
'width': 400,
'showlegend': False
}
}
)
return fig
问题是,这将导致错误,表明它无法在应用程序布局中显示图形ID。这是因为破折号无法处理动态图形创建,如here所述。这是完整的错误:
File "C:\Users\h473\Desktop\example_app.py", line 82, in update_output
dash.dependencies.Input('dynamic-text-area-{}'.format(i), 'hoverData')])
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\dash\dash.py", line 827, in callback
self._validate_callback(output, inputs, state, events)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\dash\dash.py", line 631, in _validate_callback
).replace(' ', ''))
dash.exceptions.NonExistantIdException:
Attempting to assign a callback to the
component with the id "dynamic-text-area-0" but no
components with id "dynamic-text-area-0" exist in the
app's layout.
Here is a list of IDs in layout:
['dropdown', 'output', 'pie-chart-div']
If you are assigning callbacks to components
that are generated by other callbacks
(and therefore not in the initial layout), then
you can suppress this exception by setting
`app.config['suppress_callback_exceptions']=True`.
所以,我尝试插入行中
app.config['suppress_callback_exceptions']=True
但这会带来另一个错误,表明pie-chart-div
已被使用并且无法重复使用:
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\dash\dash.py", line 911, in dispatch
return self.callback_map[target_id]['callback'](*args)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\dash\dash.py", line 851, in add_context
output_value = func(*args, **kwargs)
File "C:\Users\h473\Desktop\NPS SHAP Dashboard\ex.py", line 902, in update_output
dash.dependencies.Input('dynamic-text-area-{}'.format(i), 'hoverData')])
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\dash\dash.py", line 827, in callback
self._validate_callback(output, inputs, state, events)
File "C:\Users\h473\AppData\Local\Programs\Python\Python35\lib\site-packages\dash\dash.py", line 708, in _validate_callback
output.component_property).replace(' ', ''))
dash.exceptions.CantHaveMultipleOutputs:
You have already assigned a callback to the output
with ID "pie-chart-div" and property "children". An output can only have
a single callback function. Try combining your inputs and
callback functions together into one function.
那么,我该如何解决并使其正常工作?
这是我的完整代码:
import pandas as pd
import numpy as np
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
data1 = {'Col1':['A', 'B', 'C', 'D', 'E'],
'Col2':list(np.random.randn(5))}
data2 = {'Col1':['F', 'G', 'H', 'I', 'J'],
'Col2':list(np.random.randn(5))}
data3 = {'Col1':['K', 'L', 'M', 'N', 'O'],
'Col2':list(np.random.randn(5))}
df1 = pd.DataFrame(data1, columns=['Col1', 'Col2'])
df2 = pd.DataFrame(data2, columns=['Col1', 'Col2'])
df3 = pd.DataFrame(data3, columns=['Col1', 'Col2'])
app = dash.Dash()
app.layout = html.Div([
html.Div([dcc.Dropdown(
id='dropdown',
options=[{'label': 'Dataset 1', 'value': 1},
{'label': 'Dataset 2', 'value': 2},
{'label': 'Dataset 3', 'value': 3}],
placeholder='Select the dataset...',
)]),
html.Div(id='output'),
html.Div(id='pie-chart-div')
])
@app.callback(
dash.dependencies.Output('output', 'children'),
[dash.dependencies.Input('dropdown', 'value')])
def update_output(selected):
if selected==1:
df = df1
elif selected==2:
df = df2
elif selected==3:
df = df3
columns = df.Col1.values
divs=[]
for i in range(len(columns)):
divs.append(
dcc.Graph(
figure=go.Figure(
data=[go.Bar(
x=[10],
y=[columns[i]],
orientation = 'h',
text=['Column number {}: {}'.format(i+1, columns[i])],
textposition = 'inside',
marker = dict(color = 'rgb(158,202,225)'),
)
],
layout=go.Layout(
xaxis=dict(showticklabels=False, fixedrange=True),
yaxis=dict(showticklabels=False, fixedrange=True),
)
),
hoverData='',
style={'width': 400, 'height':250, 'padding': 1},
id='dynamic-text-area-{}'.format(i)
),
)
divs.append(html.Div(style={'height': '1'}))
@app.callback(dash.dependencies.Output('pie-chart-div', 'children'),
[dash.dependencies.Input('dropdown', 'value'),
dash.dependencies.Input('dynamic-text-area-{}'.format(i), 'hoverData')])
def update_graph(df, hoverData):
values = [df[df.Col1==hoverData].Col2.iloc[0], sum(df.Col2)]
labels = ['Selected column','All other columns']
trace = go.Pie(values=values, labels = labels)
fig = dcc.Graph(
id='graph',
figure={
'data': [trace],
'layout': {
'height': 400,
'width': 400,
'showlegend': False
}
}
)
return fig
return divs
if __name__ == '__main__':
app.run_server(debug=True)