Black Lives Matter. Please consider donating to Black Girls Code today.

Dropdown input to figure is feeding previous value

I have built a number of Dash visualizations and have run into a new problem. Am trying to change the data source and geojson for a px.choropleth_mapbox figure from a dropdown, and it appears that something in the logic is out of sync such that the figure is being built off of the previously selected option.

The 3 options are:

  • Texas
  • Louisiana
  • Both States

and the page defaults to using the TX data.

If you select ‘Louisiana’ 1 time the dropdown change and the test message div reading the value of the dropdown changes, but the graph does not. If you then select ‘Both’ the dropdown and testdiv switch to the Both options, but the graph switches to Louisiana. So the dropdown and test message div always show choice N while the figure for the graph seems to be at choice N-1.

Have been fighting with this for hours and am stuck. Assume it is something somewhere in the callback lifecycle but can’t figure it out.

Code:

# DASH libraries
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction

# Managing Data
from urllib.request import urlopen
import pandas as pd
import time
import datetime as dt
import json

#Plotting Libraries
import plotly.express as px
import plotly.graph_objects as go

# MAP INFORMATION BY COUNTY
# Load county Data for mapping
with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
    counties_geojson = json.load(response)

txla_counties = {'type': 'FeatureCollection', 'features': []}
for county in counties_geojson['features']:
    if county['properties']['STATE'] in ['22','48']:
        txla_counties['features'].append(county)
tx_counties = {'type': 'FeatureCollection', 'features': []}
for county in txla_counties['features']:
    if county['properties']['STATE'] in ['48']:
        tx_counties['features'].append(county)
la_counties = {'type': 'FeatureCollection', 'features': []}
for county in txla_counties['features']:
    if county['properties']['STATE'] in ['22']:
        la_counties['features'].append(county)


# READ IN NYT DATA AND PROCESS
# Get NY Times by County Data
nyt_data = 'https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-counties.csv'
nyt = pd.read_csv(nyt_data, dtype={'fips': object},parse_dates=['date'])
# Process date information
nyt['dayofyear'] = nyt['date'].dt.dayofyear
nyt['Date'] = nyt['date'].dt.strftime("%m/%d")
# County data = data with fips values for county data [** TODO: figure outgeojson for NYC and KC**]
nyt_state = nyt[nyt['fips'].notnull()]
# Start data March 3
nyt_state = nyt_state[nyt_state['dayofyear']>62]

#TX AND LA SPECIFIC DATA
#Get TX and LA data
tx_la_data = nyt_state[nyt_state['state'].isin(['Texas','Louisiana'])]
tx_data = tx_la_data[tx_la_data['state'] == 'Texas']
la_data = tx_la_data[tx_la_data['state'] == 'Louisiana']
dates_dict = pd.Series(tx_la_data.Date.values,index=tx_la_data.dayofyear).to_dict()
# 3 Limit labels to every 3 days
for i in dates_dict:
    if (i + 1) % 3 != 0:
        dates_dict[i] = ''
date_min = tx_la_data.dayofyear.min()
date_max = tx_la_data.dayofyear.max()


# Get options lists from data sources
metrics = nyt_state.columns


# PAGE LAYOUT
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


#app.config.suppress_callback_exceptions = True

app.layout =  html.Div([
        html.Div([
            html.H3(['Covid19 Spread: Texas'],className='nine columns'),
            html.Div([
                dcc.Dropdown(id='location',
                    options=[{'label':'Texas','value':'TX'},
                        {'label':'Louisiana','value':'LA'},
                        {'label':'Texas & Louisiana','value':'Both'}],
                        value = 'TX'
                    ),
                html.Div(id='messagediv'),
            ],className='three columns')
        ],className='row'),
        html.Div([
            html.P(['Show values for:'],className='two columns'),
            html.Div([
                dcc.Dropdown(id='metric',
                    options=[dict(label=x, value=x) for x in metrics],
                    value='cases',
                    # style={'width':'200px','margin':'0px 30px 0px 5px'}
                    ),
            ],className='two columns'),
            html.Span(['on:'], className='one column'),
            html.Div([
            dcc.Slider(
                id='date_slider',
                min=date_min,
                max=date_max,
                step=None,
                value=date_max,
                marks={i: dates_dict[i] for i in dates_dict})
            ],className='seven columns'),
        ], className='row', style={'margin-top':'15px'}),
        html.Div([
            dcc.Loading([
                dcc.Graph(id='map',className='six columns'),
            ]),
        ],className='row'),
    ],id='main_content')

# Add State selection list to store
@app.callback(
    [Output('messagediv','children'),Output('map','figure')],
    [Input('location', 'value'),Input('metric', 'value'),Input('date_slider', 'value')])
def update_map(location, metric,mapdate):
    messagediv = html.P('Selected Location: ' + location)
    if location == 'Both':
        geojson = txla_counties
        df = tx_la_data
    if location == 'TX':
        geojson = tx_counties
        df = tx_data
    if location == 'LA':
        geojson = la_counties
        df = la_data
    mapfig = px.choropleth_mapbox(df, geojson=geojson, locations='fips', color=metric,
                                zoom=4, center = {"lat": 31.9686, "lon": -98.5018},
                                mapbox_style="carto-positron")
    return  messagediv, mapfig

if __name__ == '__main__':
    app.run_server(debug=True,port=8040)

Versions:
Python 3.7.4
plotly 4.5.4 pypi_0 pypi
plotly-orca 1.2.1 1 plotly
plotly_express 0.4.1 py_0 plotly
dash 1.9.1 pypi_0 pypi
dash-core-components 1.8.1 pypi_0 pypi
dash-html-components 1.0.2 pypi_0 pypi
dash-leaflet 0.0.3 pypi_0 pypi
dash-renderer 1.2.4 pypi_0 pypi
dash-table 4.6.1 pypi_0 pypi