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.
CodePudding user response:
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)