Hi, still fairly new to using plotly and dash. I’m making a choropleth graph that shows the ratio between two sets of data for England. The map works, the issue is that whenever I click on a local authority area and select it, then change the map using a dropdown the new choropleth map shows up not fully coloured in.
I believe this is probably to do with the ClickData being in a location that is no longer on the new choropleth map, so it just shows nothing or a random area.
For example:
I don’t click on an area (so presume no ClickData stored?) and choose london or any other region from the dropdown, all good:
But then if I click on an area and then, with it selected, choose another region from the dropdown (for example the South West) to create a new map, the new map loads like this:
I’ve tried creating a callback so that ClickData for the graph is None when the dropdown value changes, but that hasn’t seemed to have worked.
The code:
import dash
import pandas as pd
import plotly.express as px
from dash import Dash, dcc, html, Input, Output, State
import dash_bootstrap_components as dbc
import plotly.graph_objs as go
from dash_bootstrap_components.themes import UNITED
from dash_bootstrap_templates import load_figure_template
import numpy as np
#Load app and template
app = dash.Dash(external_stylesheets=[dbc.themes.UNITED])
load_figure_template("UNITED")
#Load data
df = pd.read_csv(r"LAlookup.csv")
earningdf = pd.read_csv(r"Medianincome.csv")
housedf = pd.read_csv(r"Medianhouseprice.csv")
#Set up options for year dropdown ---------------------------------------------
years_list = list(earningdf)
years_list.remove("LAD21NM")
for x in years_list:
earningdf[x] = pd.to_numeric(earningdf[x], errors='coerce')
years_options_list = []
for y in years_list:
years_dict = dict()
years_dict["label"] = y
years_dict["value"] = y
years_options_list.append(years_dict)
# Set up options for region dropdown ---------------------------------------------------
regions = list(df.Region.unique())
regions = [item for item in regions if not (pd.isnull(item)) == True]
region_options_list = []
for region in regions:
region_dict = dict()
region_dict["label"] = str(region)
region_dict["value"] = str(region)
region_options_list.append(region_dict)
#To create dataframe used for graph -------------------------------------------------------------
def basicdataframe(region, year):
newdf = df[df["Region"] == region]
earningdfbyyear = earningdf [["LAD21NM", year]]
housedfbyyear = housedf [["LAD21NM", str(year)]]
df1 = pd.merge(
left=newdf,
right=earningdfbyyear,
left_on='LAD21NM',
right_on='LAD21NM',
how='left')
df2 = pd.merge(left=df1,
right=housedfbyyear,
left_on='LAD21NM',
right_on='LAD21NM',
how='left'
)
earningcolname = (year + "_x")
housecolname = (year + "_y")
def ratio_row(row):
x = row[housecolname]
y = row[earningcolname]
z = x/y
return z
df2['Ratio'] = df2.apply(lambda row: ratio_row(row), axis=1)
df2.rename(columns = {"LAD21NM": "Local Authority"}, inplace = True)
df2['pct_rank'] = (df2['Ratio'].rank(pct=True))*100
df2['pct_rank'] = df2['pct_rank'].replace(np.nan, "")
df2 = df2.round(1)
return df2
#######---------------------- region filter Div ---------------------------------
region_filter = html.Div(
[html.P(
"selected region: ", className="lead"
),
html.Div(dcc.Dropdown(id='region_picker', options=region_options_list, value="England", clearable=False), style={
'width': '80%'
}),
html.Br(),
],
style = {"padding": "0.5rem 0.5rem 0.5rem"}
)
#-------------------graph Div -----------------------------------
graph_bar = html.Div ([
html.Div(dcc.Graph(id='graph',
style = {'width': '50vw', 'height': '70vh', "margin-left": "5px"}, config= {'displayModeBar': False}),
style={'width': '100%', 'position':'relative'})
])
#------------------------- year filter Div ---------------------
year_filter = html.Div(
[html.P(
"selected year: ", className="lead"
),
html.Div(dcc.Dropdown(id='year_picker', options=years_options_list, value="2021", clearable = False),
style={
'width': '60%', "float":"left"}),
html.Br(),
],
style = {"padding": "0.5rem 0.5rem 0.5rem" }
)
#-------------- app layout -----------------------------
app.layout = dbc.Container(children=[
dbc.Row([
dbc.Col(region_filter),
dbc.Col(year_filter)
]),
dbc.Row(
[
dbc.Col(graph_bar),
])
], fluid=True)
# Choropleth callback and figure creation
@app.callback(
Output("graph", "figure"),
Input("region_picker", "value"),
Input("year_picker", "value"),
)
def display_choropleth(region, year):
#Use data frame function to create dataframe for selected region and year
choropleth_df = basicdataframe(region, year)
# Set up json file
with open(r"Local_Authority_Districts_(December_2021)_GB_BFC4.json") as json_file:
geojson = json.load(json_file)
# create figure
fig = px.choropleth_mapbox(choropleth_df, geojson=geojson, color=choropleth_df["Ratio"],
locations=choropleth_df["Local Authority"], featureidkey="properties.LAD21NM",
color_continuous_scale= "YlOrRd",
hover_data= ["Local Authority"], opacity=0.7,
)
fig.update_geos(fitbounds="locations", visible=False)
fig.update_layout(autosize=False, margin={"r": 0, "t": 0, "l": 0, "b": 0, "autoexpand": True, "pad": 1}, width=900)
#Centres to use in mapbox_center zoom
centre_lat_long = {"England": {"lat": 52.567004, "lon": -1.180832},
"East of England": {"lat": 52.238061, "lon": 0.571506},
"West Midlands": {"lat": 52.523157, "lon": -2.189539},
"East Midlands": {"lat": 52.871699, "lon": -0.679063},
"South East": {"lat": 51.281418, "lon": -0.339193},
"South West": {"lat": 51.065737, "lon": -2.890518},
"North West": {"lat": 54.046005, "lon": -2.562678},
"North East": {"lat": 55.088114, "lon": -1.655882},
"London": {"lat": 51.507204, "lon": -0.119856},
"Yorkshire and The Humber": {"lat": 53.920193, "lon": -1.097800}
}
#To get zoom right when different regions are selected
non_london_zoom = 7
zoom_for_mapbox = {"England": 5.5,
"East of England": non_london_zoom,
"West Midlands": non_london_zoom,
"East Midlands":non_london_zoom ,
"South East": non_london_zoom,
"South West": 6.5,
"North West": non_london_zoom,
"North East": non_london_zoom,
"London": 9,
"Yorkshire and The Humber":non_london_zoom
}
#Update layout of fig
fig.update_layout(mapbox_style="carto-positron",
mapbox_zoom= zoom_for_mapbox[region],
mapbox_center={"lat": centre_lat_long[region]["lat"], "lon": centre_lat_long[region]["lon"]},
margin={"r":0,"t":0,"l":0,"b":0},
uirevision='constant')
fig.update_layout(coloraxis_colorbar=dict(
# title="Vacant homes to homeless ratio",
yanchor="top", y=1,
xanchor="left", x=1,
dtick=5))
fig.update_layout(clickmode='event+select')
return fig
app.run_server(debug=True) ```
Any help is really appreciated