Callback return not working

Locally (through anaconda) this app runs fine and all the returns work but when I put my app on a webfaction flask server the “Years for Payback” callback doesn’t return a value (but prints one in the log) I’ve been looking at this for days and my other resources came up empty, additionally there’s nothing in the log showing an error. What’s the deal?

I’ve hardcoded inputs for ease of use for anyone helping, all you have to do is type in say, 400, in the Cost of Retrofit box.

the callback at issue is:
@app.callback(Output(‘payback’,‘value’), [Input(‘savings’,‘value’),Input(‘cost’,‘value’)])
def payback(savings,cost):
if savings is None or cost is None:
return None
else:
payback = float(cost) / float(savings)
payback = np.round(payback,2)
print(payback)
return payback

full code below:

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd 
import numpy as np
from textwrap import dedent
import os

from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)
server = app.server #this is the underlying flask app

this_dir = os.path.dirname(os.path.realpath(__file__))
data_dir = os.path.join(this_dir, 'static')

app.css.append_css({
    'external_url': 'http://windowreplacementpaybackcalc.cchrc.org/static/style.css',
})


# Overriding the index template allows you to change the title of the
# application and load external resources.
app.index_string = '''
<!DOCTYPE html>
<html>
    <head>
        {%metas%}
        <title>Window Replacement Payback Calculator</title>
        {%favicon%}
        <link rel="icon" href="/assets/favicon.ico">
         {%css%}
        <link rel="stylesheet" href="/static/style.css">
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto">
    </head>
    <body>
        {%app_entry%}
        <footer>
            {%config%}
            {%scripts%}
        </footer>
    </body>
</html>
'''

#declarations
hrs = 24
oilbtu = 140000 #in one gallon of fuel
natgasbtu = 100000 #in one ccf of natgas


# -- layout -- #
app.layout = html.Div([
    html.Div([
	html.H1('Location Information'),
	html.Label('Select your location'),
		dcc.Dropdown(
	    id='city',
		options=[
			{'label': 'Anchorage', 'value': 'home'},
			{'label': 'Annette', 'value': 'base'},
			{'label': 'Bethel', 'value': '13098'},
			{'label': 'Bettles', 'value': '15689'},
			{'label': 'Big Delta', 'value': '13535'},
			{'label': 'Cold Bay', 'value': '9733'},
			{'label': 'Fairbanks', 'value': '13940'},
			{'label': 'Gulkana', 'value': '13807'},
			{'label': 'Homer', 'value': '10054'},
			{'label': 'Juneau', 'value': '8897'},
			{'label': 'King Salmon', 'value': '11456'},
			{'label': 'Kodiak', 'value': '8817'},
			{'label': 'Kotzebue', 'value': '15812'},
			{'label': 'Mcgrath', 'value': '14396'},
			{'label': 'Nome', 'value': '14129'},
			{'label': 'St. Paul Island', 'value': '11031'},
			{'label': 'Talkeetna', 'value': '11606'},
			{'label': 'Unalakleet', 'value': '13795'},
			{'label': 'Utqiagvik', 'value': '20226'},
			{'label': 'Valdez', 'value': '9953'},
			{'label': 'Yakutat', 'value': '9485'}
],
        value = '13940',
		),
    html.Br(),
    html.Label('Heating Degree Days'),
	html.Br(),
	dcc.Input(id='hdd', type='text',value='13940'),
    html.Br(),	
	html.Label('Fuel Type'),
	dcc.RadioItems(id='fuel_type',
        options=[
        {'label': 'heating fuel', 'value': 'fuel'},
        {'label': 'natural gas', 'value': 'natgas'},
    ],
    value='fuel',
    ),
	html.Br(),
	html.Label('Solar Heat Gain Coefficient (%)'),
	html.Br(),
	dcc.Input(id='shgc', type='number',value='0.7'),
    html.Br(),
	html.Label('Fuel Cost ($)'),
	html.Br(),
	dcc.Input(id='fuelprice', type='number',value='3.0'),html.Abbr(" &nbsp; ", title="please enter the price per unit (gal for oil or ccf for natural gas)"),
	html.Br(),
	html.Label('Heating AFUE (%)'),
	html.Br(),
	dcc.Input(id='afue', type='number',value='0.87'),html.Abbr(" &nbsp; ", title="also known as Annualized Fuel Use/Utilization Efficiency, this information is on a sticker  or in the manual for your heating system"),
	html.Br(),
	html.Label('Heating Cost Multiplier ($)'),
	html.Br(),
	dcc.Input(id='hcmlt',type='number'),
	],id='location'),
	html.Div([
	html.H1('Existing Windows'),
    html.Label('Area of existing window'),
	html.Br(),
	dcc.Input(id='ex_area', type='number',value='16'),
	html.Br(),
	html.Label('Window U Value'),
	html.Br(),
	dcc.Input(id='ex_uval', type='number',value='1.8'),
	html.Br(),
	html.Label('BTU Heat Factor'),
	html.Br(),
	dcc.Input(id='ex_btuhf', type='text'),
	html.Br(),
	html.Label('Annual Heating Cost '),
	html.Br(),
	dcc.Input(id='ex_ahc',type='number'),html.Abbr(" &nbsp; ", title="heating cost through the window"),
	], id='existing'),
	html.Div([
	html.H1('New Windows'),
	html.Label('Area of new window'),
	html.Br(),
	dcc.Input(id='nw_area', type='number',value='16'),
	html.Br(),
	html.Label('New Window U Value'),
	html.Br(),
	dcc.Input(id='nw_uval', type='number',value='0.2'),
	html.Br(),
	html.Label('New Window BTU Heat Factor'),
	html.Br(),
	dcc.Input(id='nw_btuhf', type='text'),
	html.Br(),
	html.Label('Annual Heating Cost'),
	html.Br(),
	dcc.Input(id='nw_ahc',type='number'),html.Abbr(" &nbsp; ", title="heating cost through the window"),
	], id='new'),
	html.Div([
	html.H1('Cost Savings & Payback'),
	html.Label('Cost of Retrofit'),
	html.Br(),
	dcc.Input(id='cost',type='number'),
	html.Br(),
	html.Label('Annual Savings'),
	html.Br(),
	dcc.Input(id='savings',type='number'),
	html.Br(),
	html.Label('Years for Payback'),
	html.Br(),
	dcc.Input(id='payback',type='number'),
	], id='costs'),
	html.Div([
	dcc.Input(id='sub1',type='number'),
	dcc.Input(id='sub2',type='number'),
	], id='hidden'),
], id='main')

# -- callbacks -- #

#step 1 look up AFI
@app.callback(Output('hdd', 'value'), [Input('city','value')])
def findhdd(value):
    hdd = '{}'.format(value)
    return hdd

#subcalc1 hdd * hrs * shgc * fuel cost
@app.callback(Output('sub1', 'value'), [Input('hdd','value'),Input('shgc','value'),Input('fuelprice','value')])
def sub1(hdd,shgc,fuelprice):
    if hdd is None or shgc is None or fuelprice is None:
        return None
    else:
        sub1 = int(hdd) * hrs * float(shgc) * float(fuelprice)
        sub1 = np.round(sub1,0)
    return sub1

#subcalc2 btu * afue
@app.callback(Output('sub2','value'), [Input('fuel_type','value'),Input('afue','value')])
def sub2(fuel_type,afue):
    if fuel_type is None or afue is None:
        return None
    else:     
        if fuel_type == 'fuel':
            sub2 = int(oilbtu) * float(afue)
            sub2 = np.round(sub2)
        elif fuel_type == 'natgas': 
            sub2 = int(natgasbtu) * float(afue)
            sub2 = np.round(sub2)
        return sub2

#heatcostmultiplier
@app.callback(Output('hcmlt','value'), [Input('sub1','value'), Input('sub2','value')])
def hcmlt(sub1,sub2):
    if sub1 is None or sub2 is None:
        return None
    else:    
        hcmlt = int(sub1) / int(sub2)
        hcmlt = np.round(hcmlt,2)
    return hcmlt

#oldbtuheatfactor
@app.callback(Output('ex_btuhf','value'), [Input('ex_area','value'),Input('ex_uval','value')])
def ex_btuhf(ex_area,ex_uval):
    if ex_area is None or ex_uval is None:
        return None
    else:
        ex_btuhf = int(ex_area) * float(ex_uval)
        ex_btuhf = np.round(ex_btuhf,6)
    return ex_btuhf
 
#annlheatingcost existing
@app.callback(Output('ex_ahc','value'), [Input('ex_btuhf','value'), Input('hcmlt','value')])
def ex_ahc(ex_btuhf,hcmlt):
    if ex_btuhf is None or hcmlt is None:
        return None
    else: 
        ex_ahc = float(ex_btuhf) * float(hcmlt)
        ex_ahc = np.round(ex_ahc,2)
    return ex_ahc

#newbtuheatfactor
@app.callback(Output('nw_btuhf','value'), [Input('nw_area','value'),Input('nw_uval','value')])
def nw_btuhf(nw_area,nw_uval):
    if nw_area is None or nw_uval is None:
        return None
    else:    
        nw_btuhf = int(nw_area) * float(nw_uval)
        nw_btuhf = np.round(nw_btuhf,6)
    return nw_btuhf
 
#annlheatingcost new
@app.callback(Output('nw_ahc','value'), [Input('nw_btuhf','value'), Input('hcmlt','value')])
def ex_ahc(nw_btuhf,hcmlt):
    if nw_btuhf is None or hcmlt is None:
       return None
    else:
        nw_ahc = float(nw_btuhf) * float(hcmlt)
        nw_ahc = np.round(nw_ahc,2)
    return nw_ahc

#annl savings
@app.callback(Output('savings','value'), [Input('ex_ahc','value'),Input('nw_ahc','value')])
def savings(ex_ahc,nw_ahc): 
    if ex_ahc is None or nw_ahc is None:
        return None
    else:
        savings = float(ex_ahc) - float(nw_ahc)
        savings = float(np.round(savings,2))
    return savings

@app.callback(Output('payback','value'), [Input('savings','value'),Input('cost','value')])
def payback(savings,cost):
    if savings is None or cost is None:
        return None
    else:
        payback = float(cost) / float(savings)
        payback = np.round(payback,2)
        print(payback)
    return payback


if __name__ == '__main__':
    app.run_server(host="0.0.0.0",debug=True) 

Very strange… I have no idea, but the first thing I’d try is upgrading Dash - your index string, with no {%renderer%}, implies older than v0.39, and we’ve improved a lot of things in the last 6 months to v1.2 :slight_smile:

Next thing I’d try is inspecting that _dash-update-component request in the browser’s network tab. It should have status code 200 and a response content something like:
{"response": {"props": {"value": 2.71}}}

1 Like

I’ve updated everything and reran the code, same issue.

The response content is:
{“output”:{“id”:“payback”,“property”:“value”},“inputs”:[{“id”:“savings”,“property”:“value”,“value”:147.72},{“id”:“cost”,“property”:“value”,“value”:400}]}

print still returns the correct value but it never makes it to the input box - and I’ve tried several.

update: in testing I have found that it’s always the final callback that fails whether or not I cut everything to just the initial callback or leave them all in, the last one always fails.

That’s the request content - which we know is right because you’re seeing the correct output of print(payback) on the server side. The response is in its own sub-tab:
13%20PM
It may also be useful to know the status code (should be 200) and response headers, from the Headers sub-tab:
33%20PM

ah, thanks for that tip :slight_smile:

the response is {“response”: {“props”: {“value”: 13.73}}}

and the status is 200

The code is live here http://windowreplacementpaybackcalc.cchrc.org/ I added a final callback, that doesn’t work, so I can get the callback I need to run running. I’m still seeing the last callback not working even if I know it’s a tested and accurate one that works (like I delete all my callbacks except the first one and it failed). This is quite perplexing.

Clever workaround! But are you sure you’ve updated to the latest dash? It looks to me like the problem is components that aren’t connected as an input or state to another callback don’t get their props updated - which we fixed back in March https://github.com/plotly/dash-renderer/pull/126

The version of dash-renderer I see loaded on your site is 1.0.0-alpha2, which is back from December 2018 https://pypi.org/project/dash-renderer/#history

2 Likes

You are a genius! :smiley:

while I had run the pip updates, even though they were in a virtual env they were outside the container so my updates weren’t taking. I backed out of the venv and updated everything and all is good again. Thank you very much for your time on this, it was much appreciated. Cheers.

1 Like