Need help with connecting dropdown to output a chart

I need help with the last function below(‘connect_dropdown(contents, filename, value)’) where ‘value’ is value from dropdown

import base64
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import pandas as pd
from io import StringIO
import io
import plotly.graph_objs as go
from plotly.offline import iplot, init_notebook_mode

def parse_contents(contents, filename):
content_type, content_string = contents.split(’,’)
decoded = base64.b64decode(content_string)
try:
if ‘csv’ in filename:
df = pd.read_csv(io.StringIO(decoded.decode(‘utf-8’)))
elif ‘xlsx’ in filename:
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return None
return df

def create_dropdown_list(df):
metric_name_list=[col for col in df.columns if ‘_name’ in col]
metric_level_list=[w.replace(’_name’, ‘’) for w in metric_name_list]
dropdown_list=[{‘label’: key, ‘value’: value} for (key,value) in zip(metric_level_list,metric_name_list)]
return dropdown_list

app = dash.Dash()

app.layout = html.Div([
html.H1([‘DASHBOARD’]),

html.Div([
    dcc.Upload(id='upload_data',
               multiple=False,
               style={'width': 105, 'display': 'inline-block', 'margin-left': 7},
               children=html.Button('Select File'),
              ),
],style={'width': '20%', 'display': 'inline-block'}),
    
html.Div([
    dcc.Dropdown(id='dropdown')
]),

html.Div([
dcc.Graph(id='number-out')
]),

html.Div(id='dimension-dropdown')

])

#app.config.supress_callback_exceptions = True

@app.callback(Output(‘dropdown’, ‘options’),
[Input(‘upload_data’, ‘contents’)],
[State(‘upload_data’, ‘filename’)])
def dynamic_control_maker(contents, filename):
df = parse_contents(contents, filename)
options =[{‘label’: j.capitalize(), ‘value’: j} for j in df.columns]
return options

@app.callback(Output(‘number-out’, ‘figure’),
[Input(‘upload_data’, ‘contents’)],
[State(‘dropdown’, ‘value’),
State(‘upload_data’, ‘filename’)])

def connect_dropdown(contents, filename, value):
#if not contents or not filename:
#return
df = parse_contents(contents, filename)
print(dynamic_control_maker(contents, filename))
wags = pd.DataFrame(df[‘Item’].value_counts()).reset_index()
wag1 = wags[:4]
return {‘data’:[go.Bar(
x=wag1.iloc[:,0],
y=wag1.iloc[:,1]
)]}

if name == ‘main’:
app.run_server()

Hey there, can you be a little more explicit on what you’re trying to accomplish here ?
You’re uploading a file, parsing through some if its content to create a dict that creates the dropdown options, and then selecting which of this options you want to show in a Bar graph.
To me it looks like the inputs are reversed, switch filename and value in your function and it should work.

Thanks for getting back to me. If you look at ‘Callback 2’ below - I’ve added a variable called ‘value1’. This variable needs to equate the value i click from the dropdown option so that I can output a chart. How do I do this? I keeps getting errors.

import base64
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import pandas as pd
from io import StringIO
import io
import plotly.graph_objs as go
from plotly.offline import iplot, init_notebook_mode

################################################################
####### Code below turns any file into a dataframe format.######
################################################################

def parse_contents(contents, filename):
content_type, content_string = contents.split(’,’)
decoded = base64.b64decode(content_string)
try:
if ‘csv’ in filename:
df = pd.read_csv(io.StringIO(decoded.decode(‘utf-8’)))
elif ‘xlsx’ in filename:
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return None
return df

################################################################
###################### Body/ Layout ############################
################################################################

app = dash.Dash()

app.layout = html.Div([
html.H1([‘DASHBOARD’]),

html.Div([
    dcc.Upload(id='upload_data',
               multiple=False,
               style={'width': 105, 'display': 'inline-block', 'margin-left': 7},
               children=html.Button('Select File'),
              ),
],style={'width': '20%', 'display': 'inline-block'}),
    
html.Div([
dcc.Graph(id='number-out')
]),

html.Div(id='dimension-dropdown')

])

#app.config.supress_callback_exceptions = True

################################################################
######################### Callbacks ############################
################################################################

######### Callback 1 - Adds options to dropdown ################
@app.callback(Output(‘dimension-dropdown’, ‘children’),
[Input(‘upload_data’, ‘contents’)],
[State(‘upload_data’, ‘filename’)])
def dynamic_control_maker(contents, filename):
df = parse_contents(contents, filename)
return dcc.Dropdown(
options =[{‘label’: j.capitalize(), ‘value’: j} for j in df.columns])

######### Callback 2 - Use dropdown above to ouput a chart ######
@app.callback(Output(‘number-out’, ‘figure’),
[Input(‘upload_data’, ‘contents’)],
[State(‘upload_data’, ‘filename’)])

def update_dropdown(contents, filename, value1):
#if not contents or not filename:
#return
df = parse_contents(contents, filename)

wags = pd.DataFrame(df[value1].value_counts()).reset_index() 
wag1 = wags[:4]
return {'data':[go.Bar(
        x=wag1.iloc[:,0],
        y=wag1.iloc[:,1]
        )]}

if name == ‘main’:
app.run_server()

The number of inputs in your function does not match the number of input/states from your callback.

A little clarification for what is coming, when I write Input with a capital I, I am talking about the Dash function, when I am writing input, understand it as in “the input of a function”.

When you add an Input or a State in your callback, you are adding actual inputs to the function.
Dash is going to look for the property of the specified id and use its value in your function as an input respective to the order of the Inputs and States in the callback.
This is important because this is what you got wrong in the first example when I said you swaped the inputs of your function.

When I write:

@app.callback(
	Output('messageDiv', 'children'),
	[Input('niceDropdown', 'value'),
	 Input('coolDropdown', 'value')]
	 )
def show_message_on_dropdown_change(value1, value2 ):
	return 'nice: {}, cool: {}'.format(value1, value2)

The value of niceDropdown goes into value1 and the value of coolDropdown goes into value2.
If instead I wrote:

@app.callback(
	Output('messageDiv', 'children'),
	[Input('coolDropdown', 'value'),
	 Input('niceDropdown', 'value')]
	 )
def show_message_on_dropdown_change(value1, value2 ):
	return 'nice: {}, cool: {}'.format(value1, value2)

We would get the opposite because the order of your Dash Inputs matter!
The function you decorated with the callback will receive its inputs in this order.

It would go the same way if you were to add State to your decorator, it would require you to add more arguments to your function for it to work, each argument corresponding to the property of the called id.

In your case, you have a function that is supposed to receive three arguments but that only receives two:

  • The content of upload_data
  • The filename of upload_data

As I was reading, I realized I missed a few things in the new code you sent:

  • dimmension-dropdown should be a dcc.Dropdown
  • if you want to change the ‘menu’ of a dropdown you change its options, not its children

Thank you so much. It now works nicely.