I’m quite new to dash but I’m trying to put together a data dashboard. Of the things I want to have is a drop down, that based on the input, renders 1 of two pie charts. The logic to structure the pie chart is included in my callback function. It is saying it is expecting 1 output but it had two. I’ve had a look online and tried different suggestions. I think I’m pretty close to getting this to work, there is just something dumb I’m not doing.
I know people here are wizards, so I was hoping someone might be able to help me. Also if anyone is Dash savvy, can you point me in the direction of good documentation to learn how to orient this, so I can change the layout to make these plots fit better together in a dashboard, rather than just a web page?
So much love
Thanks
import pandas as pd import dash import dash_html_components as html import dash_core_components as dcc from dash.dependencies import Input, Output, State from jupyter_dash import JupyterDash import plotly.graph_objects as go import plotly.express as px from dash import no_update import plotly.figure_factory as ff app = dash.Dash(__name__) df = pd.read_csv('nyc-jobs.csv') #top job categories counts = df['Job Category'].value_counts() counts = pd.DataFrame(counts) counts = counts.head(10) counts.sort_values(['Job Category'],ascending=True, inplace = True) fig = px.bar(df, y=counts.index, x=counts['Job Category']) #Salary range distribution salary_counts = df['Salary Range To'].value_counts() salary_counts = pd.DataFrame(counts) group_labels = ['Salary Range From','Salary Range To'] fig3 = ff.create_distplot([df['Salary Range From'],df['Salary Range To']], group_labels, bin_size= 10000) fig4 = go.Figure() fig4.add_trace(go.Box(y=df['Salary Range From'], name='Salary Range From', marker_color = 'indianred')) fig4.add_trace(go.Box(y=df['Salary Range To'], name = 'Salary Range To', marker_color = 'lightseagreen')) # # of positions df.sort_values(by = ['# Of Positions'], ascending = True, inplace = True) df_group = df.groupby(['Business Title']).mean(['# Of Positions']) df_group.sort_values('# Of Positions', ascending = True, inplace = True) df_group.index = df_group.index.str.capitalize() fig5 = px.bar(df, y=df_group.index[-5:], x=df_group['# Of Positions'][-5:]) app.layout = html.Div([ html.H1("New York City Job Postings", style = {'text-align': 'center', 'font-family': 'Helvetica'}), #Job postings graph dcc.Graph( id='Top Job Postings', figure=fig ), html.Div([html.H2('Report Type:', style={'margin-right': '2em', 'font-family': 'Helvetica'}),]), dcc.Dropdown(id='input-type', options=[ {'label': 'Full vs part time report ', 'value': 'OPT1'}, {'label': 'Posting type', 'value': 'OPT2'} ], placeholder='Select a report type', multi=False, clearable=False, style={'width':800, 'padding':3, 'font-size':20, 'text-align-last':'center', 'font-family': 'Helvetica'}), html.Div(id='output_container', children=[]), html.Div(dcc.Graph(id='pie_chart_reports')), #Salary Distributions dcc.Graph( id="Salary Distribution", figure = fig3), dcc.Graph( id="Salary Distribution boxplot", figure = fig4), dcc.Graph( id='Highest number of positions', figure=fig5 ) ]) @app.callback( [Output(component_id='pie_chart_reports', component_property='figure')], [Input(component_id='input-type', component_property='value')] ) def update_graph(report_type): dff = df container = "The chosen report was: {}".format(report_type) if report_type == 'OPT1': #full time vs part time ft_pt = dff['Full-Time/Part-Time indicator'] ft_pt.fillna('Not listed', inplace = True) ft_pt.replace('F', 'Full Time', inplace = True) ft_pt.replace('P', 'Part Time', inplace = True) value_counts_ft_pt = dff['Full-Time/Part-Time indicator'].value_counts() labels_ft_pt = value_counts_ft_pt.index.tolist() fig1 = px.pie(dff, values = value_counts_ft_pt, names = labels_ft_pt) return container, dcc.Graph(id='pie_chart_reports',figure=fig1) else: #internal vs externl value_counts_posting_type = dff['Posting Type'].value_counts() labels_posting_type = value_counts_posting_type.index.tolist() fig2 = px.pie( df, values = value_counts_posting_type, names = labels_posting_type, color_discrete_sequence=px.colors.sequential.Bluyl) return container, dcc.Graph(id='pie_chart_reports',figure=fig2) if __name__ == '__main__': app.run_server(debug=True)
Advertisement
Answer
The first problem is that your callback has one output, but you return a tuple of two things. So you could add an Output
that targets the element which you want to have the value of content
, I’m guessing that element is the element with id output_container
. The other option is to remove content
from the return statement.
The second problem is that you have the Output
surrounded by a list, so dash expects the return value to be a list containing one value. You can remove the list surrounding your Ouput
so it expects a tuple
Output(component_id='pie_chart_reports', component_property='figure')
or you can surround your return values with a list.
The third problem is that you target the component_property
figure
, but you’re returning a Graph
component. So you should return fig1
instead of dcc.Graph(id='pie_chart_reports', figure=fig1)
for example.