Hi folks!
I’m looking to create a choropleth map of US states within a dash app that allows users to click on the state in the map that then feeds other aspects of the app. I’ve been able to get it to work as expected, but I am running into an issue with the styling.
The basic idea is that the map is all states shown in white to begin, and as a user selects on a state, it changes color to indicate it has been selected. If the user clicks again on a selected state, it would return to white and deselect the state. I want to allow the users to have any number of states selected, as well as none selected at all.
However, the issue I’m having is that when no states are selected, all states are a different color that I have not defined in the graph. I am looking to make all of the states white if none are selected. My hypothesis is that it’s the mid-point of the color_continuous_scale, but I’ve not had any luck with using a color discrete map either. I have tested having an empty list in the location prop of the map, but this doesn’t then allow me to select any states as I am using the location through clickData to update the grid.
Here is the code that I am using to create the choropleth, as well as update it when clicked.
I am using the most up to date libraries of dash and plotly (dash==2.17.0, plotly==5.22.0) in a Docker container (Linux).
from dash import Dash, dcc, html, callback, Input, Output, State, Patch
import pandas as pd
import plotly.express as px
app = Dash(
__name__,
suppress_callback_exceptions=False,
)
def create_state_map():
state_df = pd.read_csv(
"https://raw.githubusercontent.com/jasonong/List-of-US-States/master/states.csv"
)
state_df["COLOR"] = [0 for i in range(len(state_df))]
fig = px.choropleth(
state_df,
color=state_df["COLOR"],
locations=state_df["Abbreviation"],
locationmode="USA-states",
scope="usa",
color_continuous_scale=[[0, "#ffffff"], [1, "#344ceb"]],
hover_data={"COLOR": False, "Abbreviation": False, "State": True},
)
fig.update_layout(coloraxis_showscale=False, margin=dict(l=0, r=0, t=0, b=0))
return fig
app.layout = html.Div(
[
dcc.Graph(id="map", figure=create_state_map()),
dcc.Store(id="state-list", data=[]),
]
)
@callback(
Output("map", "figure"),
Output("state-list", "data"),
Input("map", "clickData"),
State("state-list", "data"),
prevent_initial_call=True,
)
def select_states(clickData, state_list):
if clickData:
state = clickData["points"][0]["location"]
if state in state_list:
state_list.remove(state)
else:
state_list.append(state)
all_states = pd.read_csv(
"https://raw.githubusercontent.com/jasonong/List-of-US-States/master/states.csv"
)
all_states = all_states["Abbreviation"].to_list()
colors = {}
for row in all_states:
colors[row] = 0
if state_list is not None and state_list != []:
for state in state_list:
colors[state] = 1
patched = Patch()
patched["data"][0]["locations"] = list(colors.keys())
patched["data"][0]["z"] = list(colors.values())
return patched, state_list
if __name__ == "__main__":
app.run(debug=True)
Here is what the map looks like when no states are selected:
And with some states selected:
Many thanks to user jasonong on Github for the list of US states and their postal code abbreviations.
It feels like I have tried all methods of creating a choropleth map, and I have tried making the landcolor white as well, to no avail.
If anyone has any advice on how to make the map remain clickable while having an all white background when no states are selected, I would really appreciate it. Thanks in advance!