How to use Button for Dash along with Upload function

Does anyone know if I am setting up this button(For Dash) correctly to be able to read the inputs of the dropdown and the upload function I have? What about my app.callback()? I need some help analyzing why it isn’t exactly working when I click submit and nothing happens.

#Uploading file definitions
def save_file(name, content):
    """Decode and store a file uploaded with Plotly Dash."""
    data = content.encode("utf8").split(b";base64,")[1]
    with open(os.path.join(UPLOAD_DIRECTORY, name), "wb") as fp:
        fp.write(base64.decodebytes(data))
def uploaded_files():
    """List the files in the upload directory."""
    files = []
    for filename in os.listdir(UPLOAD_DIRECTORY):
        path = os.path.join(UPLOAD_DIRECTORY, filename)
        if os.path.isfile(path):
            files.append(filename)
    return files
def file_download_link(filename):
    """Create a Plotly Dash 'A' element that downloads a file from the app."""
    location = "/download/{}".format(urlquote(filename))
    return html.A(filename, href=location)
    
@app.callback(
Output("file-list", "children"),
[Input("upload-data", "filename"), Input("upload-data", "contents")],)

def update_output(uploaded_filenames, uploaded_file_contents):
    """Save uploaded files and regenerate the file list."""

    if uploaded_filenames is not None and uploaded_file_contents is not None:
        for name, data in zip(uploaded_filenames, uploaded_file_contents):
            save_file(name, data)

    files = uploaded_files()
    if len(files) == 0:
        return [html.Li("No files yet!")]
    else:
        return [html.Li(file_download_link(filename)) for filename in files]

#Callback for dropdown menu
@app.callback(dash.dependencies.Output('dd-output-container', 'children'),[dash.dependencies.Input('Categories', 'value')])
def update_output_dropdown(value):
    return 'You have selected "{}"'.format(value)


#Callback for submitting everything.
@app.callback(Output('target', 'children'), Input('submit', 'n_clicks'))
def callback(n_clicks):
    if (n_clicks != 0):
        
        #Read the uploaded file and calculate the category from dropdown
        for file in uploaded_files():
            with open(file) as f:
                dfs = pd.read_excel(file)
                xl = pd.ExcelFile(dfs)
                if xl.parse(sheet_name= 'Spikes'): 

Here is a visual: Visual

Hi @babypastorkayvon

Your last callback has no “return” :thinking:

Oh, I didn’t show the rest of the code for the callback. It has a return at the end. It is just a long calculation which should return a graph.

Share the layout of your code to see the different id and components, otherwise there is difficult to find the problem. :woozy_face:

Yeah, sure. Here is the layout of the code:

UPLOAD_DIRECTORY = "Excel_Files"

if not os.path.exists(UPLOAD_DIRECTORY):
    os.makedirs(UPLOAD_DIRECTORY)

@server.route("/download/<path:path>")
def download(path):
    """Serve a file from the upload directory."""
    return send_from_directory(UPLOAD_DIRECTORY, path, as_attachment=True)



#Uploading file definitions
def save_file(name, content):
    """Decode and store a file uploaded with Plotly Dash."""
    data = content.encode("utf8").split(b";base64,")[1]
    with open(os.path.join(UPLOAD_DIRECTORY, name), "wb") as fp:
        fp.write(base64.decodebytes(data))
def uploaded_files():
    """List the files in the upload directory."""
    files = []
    for filename in os.listdir(UPLOAD_DIRECTORY):
        path = os.path.join(UPLOAD_DIRECTORY, filename)
        if os.path.isfile(path):
            files.append(filename)
    return files
def file_download_link(filename):
    """Create a Plotly Dash 'A' element that downloads a file from the app."""
    location = "/download/{}".format(urlquote(filename))
    return html.A(filename, href=location)
    
@app.callback(
Output("file-list", "children"),
[Input("upload-data", "filename"), Input("upload-data", "contents")],)

def update_output(uploaded_filenames, uploaded_file_contents):
    """Save uploaded files and regenerate the file list."""

    if uploaded_filenames is not None and uploaded_file_contents is not None:
        for name, data in zip(uploaded_filenames, uploaded_file_contents):
            save_file(name, data)

    files = uploaded_files()
    if len(files) == 0:
        return [html.Li("No files yet!")]
    else:
        return [html.Li(file_download_link(filename)) for filename in files]

#Callback for dropdown menu
@app.callback(dash.dependencies.Output('dd-output-container', 'children'),[dash.dependencies.Input('Categories', 'value')])
def update_output_dropdown(value):
    return 'You have selected "{}"'.format(value)


def calculation():
    #Read the uploaded file and calculate the category from dropdown
        for file in uploaded_files():
            with open(file) as f:
                dfs = pd.read_excel(file)
                xl = pd.ExcelFile(dfs)
                if xl.parse(sheet_name= 'Spikes'):
                    # Define if we analyzing Premium or Cut Spikes
                    # Define if the data is reliable 
                    dfs.loc[(dfs['Fastener_Presence'] !='X') & (dfs['Concrete_or_Timber'] == 'Wooden'), 'Timber_Fastener_Type'] = 'Premium'
                    dfs.loc[(dfs['Fastener_Presence'] =='X') & (dfs['Concrete_or_Timber'] == 'Wooden'), 'Timber_Fastener_Type'] = 'Cut Spikes'
                    dfs.loc[(dfs['Spike_Presence'] =='X') & (dfs['Fastener_Presence'] == 'X'), 'Timber_Fastener_Type'] = 'Error'
                    # dfs.to_excel("Test_Type.xlsx")

                    # Cleaning the data
                    dfs = dfs[dfs.Concrete_or_Timber != 'Concrete']
                    dfs = dfs[dfs.Timber_Fastener_Type != 'Error']
                    dfs = dfs.reset_index(drop=True)
                    dfs['Spike_Presence'] = dfs.Spike_Presence.replace('X',0)
                    dfs['Spike_Presence'] = dfs.Spike_Presence.replace('x',0)
                    dfs['Fastener_Presence'] = dfs.Fastener_Presence.replace('X',0)
                    dfs['Fastener_Presence'] = dfs.Fastener_Presence.replace('x',0)

                    # dfs.to_excel("Test_Type.xlsx")


                    # Make sure we are working with floats
                    dfs['Spike_Presence'] = dfs['Spike_Presence'].astype(float)
                    dfs['Fastener_Presence'] = dfs['Fastener_Presence'].astype(float)

                    #Function to calculate how many fasteners in 5 ties window
                    def g(column,i):
                        a = np.sum(column[i-2:i+3].to_list())
                        return a

                    # Create new dataframe to receive all the calculations from function g
                    dfsnew = pd.DataFrame(columns=['Spike_Presence_5_Ties','Fastener_Presence_5_Ties'])

                    # Passing function in the dataframe
                    for j in range(0, len(dfs)):
                        Spike_Presence_5_Ties = g(dfs['Spike_Presence'], i=j)
                        Fastener_Presence_5_Ties = g(dfs['Fastener_Presence'], i=j)

                        dfsnew = dfsnew.append({'Spike_Presence_5_Ties':Spike_Presence_5_Ties,
                                                'Fastener_Presence_5_Ties': Fastener_Presence_5_Ties
                                                }, ignore_index=True, verify_integrity=False, sort=False)

                    # dfsnew.to_excel("Test.xlsx")
                    dfs1 = pd.concat([dfs, dfsnew], axis=1)
                    # Rename dataframe dfs1
                    dfspike = dfs1

                    # Define rules. Data x means percentage to consider a bad spot. Data y means the value from 0 to 1 for each one of the percentages
                    # Cut Spikes Rules
                    datax = [0,5,10,15,20,25,30,35,38,40]
                    datay = [1,1,1,1,0.8,0.6,0.4,0.2,0.1,0]
                    # Define rules. Data x means percentage to consider a bad spot. Data y means the value from 0 to 1 for each one of the percentages
                    # Premium Rules
                    datax1 = [0,2,4,6,8,10,12,14,16,18,20]
                    datay1 = [1,1,1,0.8,0.6,0.5,0.4,0.35,0.3,0,0]
                    x1 = np.array(datax1)
                    y1=np.array(datay1)
                    z1 = np.polyfit(x1,y1,2)
                    print ('{0}x^2 + {1}x + {2}'.format(*z1))
                    x = np.array(datax)
                    y=np.array(datay)
                    z = np.polyfit(x,y,2)
                    print ('{0}x^2 + {1}x + {2}'.format(*z))

                    def print_graph_cut_spikes(S):
                        # Plotting the degradation function - Cut Spikes
                        S = lambda x: z[0]*x**2 + z[1]*x + z[2]
                        xs = np.linspace(0,40,240)
                        ys = S(xs)
                        #fig = plt.figure(figsize=(20,12))
                        fig4 = px.line(x = xs, y = ys, title= 'Cut Spikes Degradation Function') 
                        return fig4
                    

                    def print_graph_premium_spikes(S1):
                        # Plotting the degradation function - Premium E-Clips
                        S1 = lambda x: z1[0]*x**2 + z1[1]*x + z1[2]

                        xs = np.linspace(0,20,240)
                        ys = S1(xs)

                        fig5 = px.line(x = xs, y = ys, title= 'Cut Spikes Degradation Function') 
                        return fig5
                    


                    def FSpikes(x):

                        res = z[0]*(x)**2 + z[1]*(x) + z[2]

                        if res<0:
                            res=0
                        else:
                            res = res
                        if res>1:
                            res=1

                        return res

                    def FPremium (s,c):   # s = number of spikes, c = number of e-clips

                        res_s = z[0]*(s)**2 + z[1]*(s) + z[2]
                        res_c = z1[0]*(c)**2 + z1[1]*(c) + z1[2]

                        resf = 0.4*res_s + 0.6*res_c #Spikes represent 40% of the strenght and e-clips 60%

                        if resf<0:
                            resf=0
                        else:
                            resf = resf
                        if resf>1:
                            resf=1

                        return resf



                    dfspike['Health'] = dfspike.apply(lambda row : FSpikes(row['Spike_Presence_5_Ties']) if row['Timber_Fastener_Type'] == 'Cut Spikes' else FPremium(row['Spike_Presence_5_Ties'],row['Fastener_Presence_5_Ties'] ) , result_type='expand', axis=1)
                    dfspike = dfspike.reset_index(drop=True)


                    DF1 = dfspike.drop(['Spike_Presence','Fastener_Presence','Timber_Fastener_Type','Spike_Presence_5_Ties','Fastener_Presence_5_Ties'], axis=1)

                    df2 = pd.read_excel (r'TQI_Data.xlsx', sheet_name='Fasteners')

                    # Cleaning the data
                    df2 = df2[df2.Concrete_or_Timber != 'Wooden']
                    df2 = df2.reset_index(drop=True)
                    df2['Fastener_Presence_Correct'] = df2.Fastener_Presence.replace('X',4)

                    #Function to calculate how many fasteners in 5 ties window
                    def f(column,i):
                        a = np.sum(column[i-2:i+3].to_list())
                        return a
                    # Create new dataframe to receive results from funtion f
                    df2new = pd.DataFrame(columns=['Fastener_Presence_5_Ties'])
                    df2['Fastener_Presence_Correct'] = df2['Fastener_Presence_Correct'].astype(float)

                    # Passing function in the dataframe
                    for j in range(0, len(df2)):
                        Fastener_Presence_5_Ties = f(df2['Fastener_Presence_Correct'], i=j)

                        df2new = df2new.append({'Fastener_Presence_5_Ties':Fastener_Presence_5_Ties
                                                }, ignore_index=True, verify_integrity=False, sort=False)
                    # Concatanate the two dataframes
                    df2 = pd.concat([df2, df2new], axis=1)

                    # Define rules. Data x means percentage to consider a bad spot. Data y means the value from 0 to 1 for each one of the percentages
                    # Concrete Ties
                    datax2 = [0,2,4,6,8,10,12,14,16,18,20]
                    datay2 = [1,1,1,0.6,0.4,0.35,0.3,0.25,0.1,0,0]


                    x2 = np.array(datax2)
                    y2=np.array(datay2)
                    z2 = np.polyfit(x2,y2,2)

                    print ('{0}x^2 + {1}x + {2}'.format(*z2))

                    def concrete_graph(H):
                        # Plotting the degradation function
                        H = lambda x: z2[0]*x**2 + z2[1]*x + z2[2]

                        xs = np.linspace(0,20,10)
                        ys = H(xs)
                        fig6 = px.line(x = xs, y = ys, title= 'Concrete Ties')
                        return fig6
                    

                    #Defining the function that pass the measured value, divide it by the design height (resulting the porcentage) and return the track health based on the created rule
                    def FConcrete(x):

                        resconc = z2[0]*(x)**2 + z2[1]*(x) + z2[2]

                        if resconc<0:
                            resconc=0
                        if resconc>1:
                            resconc=1
                        else:
                            resconc = resconc

                        return resconc

                    # Calculate Health Index for Concrete
                    df2['Health'] = df2.apply(lambda row : FConcrete(row['Fastener_Presence_5_Ties']), result_type='expand', axis=1)
                    DF2 = df2.drop(['Fastener_Presence','Fastener_Presence_Correct','Fastener_Presence_5_Ties'], axis=1)
                    DF2

                    # Merge DF1 and DF2. 
                    # This will result the totality of the loop Fasteners Health Index.
                    DF = pd.concat([DF1, DF2],axis=0)
                    DF = DF.sort_values(by=['Stationing'],axis=0)
                    DF = DF.reset_index(drop=True)

                    # Gambiarra do carai pra n corrigir entre stationings 3810.368 e 4525.509
                    df_gambiarra = pd.DataFrame({'Stationing':[4525],'Concrete_or_Timber':['Wooden'],'Health':[0]})
                    DF = pd.concat([DF, df_gambiarra],axis=0)
                    DF = DF.sort_values(by=['Stationing'],axis=0)
                    DF = DF.reset_index(drop=True)
                    print(DF)
                    #DF.to_excel("Test.xlsx")

                    def Health_Graph(DF):
                        ax_DF = px.line(DF, x = 'Stationing', y = 'Health', title= 'Fastener Health Index')
                        return ax_DF 
                    Health_Graph(DF)

#Callback for submitting everything.
@app.callback(Output('target', 'children'), Input('submit', 'n_clicks'))
def callback(n_clicks):
    if (n_clicks != 0):
        #xl = pd.ExcelFile(dfs)
        calculation()
        #if xl.parse(sheet_name= 'Spikes'):


app.layout = html.Div(
    children=[
    html.H1(children='RailTec Dashboard'),
    #Uploading the files to the board. We want to make sure that two files can be uploaded, read, and grab the same categories to the direct coorelated category.
    #For choosing files between tabs
    html.Div(
    [
        html.H2("Upload"),
        dcc.Upload(
            id="upload-data",
            children=html.Div(
                ["Drag and drop or click to select a file to upload."]
            ),
            style={
                "width": "100%",
                "height": "60px",
                "lineHeight": "60px",
                "borderWidth": "1px",
                "borderStyle": "dashed",
                "borderRadius": "5px",
                "textAlign": "center",
                "margin": "10px",
            },
            multiple=True,
        ),
        html.H2("File List"),
        html.Ul(id="file-list"),
    ],
    style={"max-width": "500px"},
    ),
    #Drop Down Menu for the categories. 
    dcc.Dropdown(
        id = 'Categories',
        options=[
            {'label': 'Spikes', 'value': 'Spikes'},
            {'label': 'Fasteners', 'value': 'Fasteners'},
            {'label': 'Ballast Level', 'value': 'Ballast Level'},
            {'label': 'Spikes Med', 'value': 'Spikes'},
            {'label': 'Fasteners Med', 'value': 'Fasteners'},
            {'label': 'Ballast Level Med', 'value': 'Ballast Level'},
            {'label': 'Spikes Bad', 'value': 'Spikes'},
            {'label': 'Fasteners Bad', 'value': 'Fasteners'},
            {'label': 'Ballast Level Bad', 'value': 'Ballast Level'}
        ],
        placeholder="Select a category",
        value = "Spikes"
    ),
    html.Div(id='dd-output-container', children = []),

    html.Form([
    #Enter button Event to trigger app callback for dropdown and upload data to submit what to calculate.
    html.Div(id='target'),
    html.Button('Submit',id='submit', n_clicks=0),
    ]),

    dcc.Graph(
    id='Concrete_Health_method',
    figure= calculation(),
    #calculator_1.graph_concrete(df2)
    style ={'display': 'inline-block'})
    ])