How to Combine a Slider with a Drop Down for Plotly Choropleth?

Question:

How do I combine a slider and button/drop down in a choropleth to work correctly?

I am trying to create a choropleth of US states where the colors represent median home sale price for a given date, slider, and property type, drop down/button. I have a csv data that contains median sale prices of a state for various dates and various property types. I am able to create a choropleth for a specific property type, e.g., townhouse, across various dates in a slider, but when I try adding a button as a dropdown to differentiate property types, e.g., townhouse vs condo, the choropleth data in plotly is not correct. My confusion is not knowing how to link the button with updating the data or trace in the choropleth object correctly. For example, I can create choropleths with sliders for each individual property type, but when linking it together with a button or dropdown, I cannot get it to work properly.

For simplicity, I condense my dataset to only two dates, 2/29/2012 and 6/30/2022, for the slider, and two property types, Townhouse and All Residential. The dataframe is called df_state3.

#list populates the data for each slider "date"
data_slider3 = []
for date in sorted_dates3:
    df_segmented =  df_state3[(df_state3['period_end']== date)]

    for col in df_segmented.columns:
        df_segmented[col] = df_segmented[col].astype(str)

    data_each_date = dict(
                        type='choropleth',
                        showlegend = False,
                        locations = df_segmented['state_code'],
                        z=df_segmented['median_sale_price'].astype(float), #choropleth value-to-color mapping set in 'z'
                        locationmode='USA-states',
                        colorscale = color_scale,
                        colorbar= {'title':'Median Sale Prices'})

    data_slider3.append(data_each_date)
#builds the actual slider object
steps3 = []
for i in range(len(data_slider3)):
    step = dict(method='restyle',
                args=['visible', [False] * len(data_slider3)],
                label='{}'.format(sorted_dates3[i]))
    step['args'][1][i] = True
    steps3.append(step)

sliders3 = [dict(active=0, pad={"t": 1}, steps=steps3)]
#set up the layout for the image
layout3 = dict(title ='Median Sale Prices in US (2012 - 2022)',
              geo=dict(scope='usa',
                       projection={'type': 'albers usa'}),
              sliders=sliders3)
#put whole image together and plot it
fig3 = dict(data=data_slider3, layout=layout3)
**#add buttons
property_set = set(df_state3['property_type'].values.tolist())
property_list = list(property_set)

buttons = []
for value in property_list:
  df_by_property = df_state3[(df_state3['property_type'] == value)]

  buttons.append(dict(method = "restyle",
                # args = ['type', 'bar'],
                args = [{'z': [df_by_property["median_sale_price"]] }],
                label = value)
  )


fig3['layout'].update(width=700,
                  coloraxis_colorbar_thickness=23,
                  updatemenus=[dict(y=1.1,
                                    x=0.275,
                                    xanchor='right',
                                    yanchor='top',
                                    active=0,
                                    buttons=[button for button in buttons])
                                    
                              ]) **

This is the result I get:
choropleth with incorrect values

In bold is where I add the buttons/drop down for property type and am not doing it correctly, i.e., knowing how to properly update the slider and date values shown in the choropleth based on the chosen button.

Asked By: Michael Ho

||

Answers:

I found out about the dash framework and used it with plotly to achieve the drop down with the slider.

Result: state choropleth with dropdown and slider

Below is my code using dash and plotly, where df is my dataframe in a csv:

# App layout
#what goes inside dash layout are the dash components and any html we need
app.layout = html.Div([

    html.H1("Redfin Choropleth Data", style={'text-align': 'center'}), #html Title

    html.Div(id='metric_title', children=["Metric"], style = {'font-weight': 'bold'}),

    #components, e.g., drop downs, sliders
    #first drop down by metric
    dcc.Dropdown(id="metric",
                 placeholder = "Select Metric",
                 options=metric_set,
                 value=metric_set[0],
                 style={'width': "60%",}
                 ),

    html.Br(), #space between dropdowns

    html.Div(id='property_title', style = {'font-weight': 'bold'}, 
    children = ["Property Type"]
    ),

    #second drop down for property type
    dcc.Dropdown(id="property_type",
                 placeholder = "Select Property Type",
                 options=property_set,
                 value=property_set[0],
                 style={'width': "60%"},
                 ),

    
    html.Br(), #space
    
    #create div element, e.g., text to display dropdown selection
    html.Div(id='output_container', children=[]),

    html.Br(), #space

    #graph object, e.g., choropleth
    dcc.Graph(id='choropleth', figure={}),

    

    #slider object
    dcc.Slider(0, len(sorted_dates), step = None, #min value of 0 and max of number of unique dates
               value=0, #where the slider starts
               marks = slider_labels,
               tooltip={"placement": "bottom", "always_visible": True}, #place slider at bottom of graph
               id='date_chosen')

])

# Connect the Plotly graphs with Dash Components
@app.callback(
    Output(component_id='output_container', component_property='children'),
    Output(component_id='choropleth', component_property='figure'),
    Input(component_id='property_type', component_property='value'),
    Input(component_id = 'metric', component_property = 'value'),
    Input(component_id='date_chosen', component_property='value'))


def update_graph(property_type, metric, date_chosen, hover):

    container = "Date Selected: {}".format(sorted_dates[date_chosen])

    dff = df.copy()
    dff = dff[['period_begin', 'period_end', 'state_code', 'median_sale_price', 'median_sale_price_mom', 
    'median_ppsf', 'median_ppsf_mom', 'property_type']]
    dff = dff[dff['property_type'] == property_type]
    dff = dff[dff['period_end'] == pd.to_datetime(sorted_dates[date_chosen], format="%Y/%m/%d")]


    # Plotly Express
    fig = px.choropleth(
        data_frame=dff,
        locationmode='USA-states',
        locations='state_code',
        scope="usa",
        color='{}'.format(metric),
        hover_data=['state_code', '{}'.format(metric)],
        # color_continuous_scale= color_scale
        color_continuous_scale = "Viridis"
    )
    return container, fig

if __name__ == '__main__':
    app.run_server(debug=False)
Answered By: Michael Ho