ūüíł Reduce costs by consolidating proprietary analytics & reporting software to open-source & Dash.
Challenge us to replace your analytics with Dash and reduce costs.

Using a slider with a Choropleth Map and the data is not appearing sequentially

I am attempting to create a choropleth map using python. The map is for the number of babies given a specific name in each state. The slider is used to change the year and, therefore, change the number of babies for each state. I have been successful at pulling the data, placing it in a panda DataFrame, and initiating the map with the data. I have two issues best described with screenshots.
1)


2)

1) Upon initiation, the legend on the right seems to be showing numbers for all the combined years. The correct legend/numbers appear once the slider is moved. (As seen in the second image.)
2) The data for each year is not matching up with the year on the slider. See the hover box over California compared to the year selected on the slider. I have verified that the year data is accurate and the same for each state. The year on the map simply doesn’t match the year on the slider.

Below is my code. Any insights would be greatly appreciated.
#These are database tables for each state.
state_tables = [‚ÄėBabyNameAlabama‚Äô, ‚ÄėBabyNameAlaska‚Äô, ‚ÄėBabyNameArizona‚Äô, ‚ÄėBabyNameArkansas‚Äô, ‚ÄėBabyNameCalifornia‚Äô, ‚ÄėBabyNameColorado‚Äô, ‚ÄėBabyNameConnecticut‚Äô,
‚ÄėBabyNameDelaware‚Äô, ‚ÄėBabyNameDistrictColumbia‚Äô, ‚ÄėBabyNameFlorida‚Äô, ‚ÄėBabyNameGeorgia‚Äô, ‚ÄėBabyNameHawaii‚Äô, ‚ÄėBabyNameIdaho‚Äô, ‚ÄėBabyNameIllinois‚Äô,
‚ÄėBabyNameIndiana‚Äô, ‚ÄėBabyNameIowa‚Äô, ‚ÄėBabyNameKansas‚Äô, ‚ÄėBabyNameKentucky‚Äô, ‚ÄėBabyNameLousiana‚Äô, ‚ÄėBabyNameMaine‚Äô, ‚ÄėBabyNameMaryland‚Äô,
‚ÄėBabyNameMassachusetts‚Äô, ‚ÄėBabyNameMichigan‚Äô, ‚ÄėBabyNameMinnesota‚Äô, ‚ÄėBabyNameMissippi‚Äô, ‚ÄėBabyNameMissouri‚Äô, ‚ÄėBabyNameMontana‚Äô, ‚ÄėBabyNameNebraska‚Äô,
‚ÄėBabyNameNevada‚Äô, ‚ÄėBabyNameNewHampshire‚Äô, ‚ÄėBabyNameNewJersey‚Äô, ‚ÄėBabyNameNewMexico‚Äô, ‚ÄėBabyNameNewYork‚Äô, ‚ÄėBabyNameNorthCarolina‚Äô, ‚ÄėBabyNameNorthDakota‚Äô,
‚ÄėBabyNameOhio‚Äô, ‚ÄėBabyNameOklahoma‚Äô, ‚ÄėBabyNameOregon‚Äô, ‚ÄėBabyNamePennsylvania‚Äô, ‚ÄėBabyNameRhodeIsland‚Äô, ‚ÄėBabyNameSouthCarolina‚Äô, ‚ÄėBabyNameSouthDakota‚Äô, ‚ÄėBabyNameTennessee‚Äô,
‚ÄėBabyNameTexas‚Äô, ‚ÄėBabyNameUtah‚Äô, ‚ÄėBabyNameVermont‚Äô, ‚ÄėBabyNameVirginia‚Äô, ‚ÄėBabyNameWashington‚Äô, ‚ÄėBabyNameWestVirginia‚Äô, ‚ÄėBabyNameWisconsin‚Äô, ‚ÄėBabyNameWyoming‚Äô]

frames = []
#This for loop pulls rows based on the name and gender selected and adds them to the frames list.
for state in state_tables:
	var = state
	table = getattr(models, var)
	state_high = table.query.filter_by(baby_name=selected_name, gender=selected_gender).all()
	df = pd.DataFrame([(d.state, d.year, d.baby_name, d.count, d.rank) for d in state_high],
					columns=['state', 'year', 'baby_name', 'count', 'rank'])
	frames.append(df)
#This combines all the DataFrames into one.
new_df = pd.concat(frames)

year = '1910'
scl = [
    [0, 'rgb(242,240,247)'],
    [0.2, 'rgb(218,218,235)'],
    [0.4, 'rgb(188,189,220)'],
    [0.6, 'rgb(158,154,200)'],
    [0.8, 'rgb(117,107,177)'],
    [1.0, 'rgb(84,39,143)']
]
data_slider = []

for year in new_df['year'].unique():
	df_segmented = new_df[(new_df['year']== year)]

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

	data_each_yr = dict(
		type='choropleth',
		autocolorscale = False,
		locations = df_segmented['state'],
		z=df_segmented['count'].astype(float),
		locationmode='USA-states',
		colorscale = scl,
		text = "Rank: " + df_segmented['rank'] + " Year: " + df_segmented['year'],
		marker = dict(     # for the lines separating states
                    line = dict (
                              color = 'rgb(0,0,0)', 
                              width = 2) ), 
		colorbar= {'title':'# of Babies'})


	data_slider.append(data_each_yr)

steps = []
for i in range(len(data_slider)):
	step = dict(method='restyle',
				args=['visible', [False] * len(data_slider)],
				label='Year {}'.format(i + 1910))
	step['args'][1][i] = True
	steps.append(step)

sliders = [dict(active=0, pad={"t": 1}, steps=steps)]

new_layout = go.Layout(
	autosize = False, title = 'Number of Babies by State', width = 1000, height = 600,
    geo = go.layout.Geo(
        scope = 'usa',
        projection = go.layout.geo.Projection(type = 'albers usa'),
        showlakes = True,
        lakecolor = 'rgb(255, 255, 255)'),
    sliders=sliders,
)

fig_three = go.Figure(data = data_slider, layout = new_layout)

graphJSON_three = json.dumps(fig_three, cls=plotly.utils.PlotlyJSONEncoder)

return render_template('culture/baby_state_map.html', wins_graph_three=graphJSON_three)

If it helps, the top half of this image is the output for the combined DataFrame. The bottom half is the output for one state’s (California) DataFrame.

1 Like

hi @dustinmwest,

I wonder if this is a good use case for the new plotly_express library. See https://www.plotly.express/. This is a high-level API on top of plotly.py that greatly simplifies many plot types, including those with sliders/animations.

Here’s an example from the docs

import plotly_express as px
gapminder = px.data.gapminder()
px.choropleth(gapminder, locations="iso_alpha", color="lifeExp", hover_name="country", animation_frame="year",
             color_continuous_scale=px.colors.sequential.Plasma)

You would want to set scope = 'usa' as an argument to px.choropleth, but otherwise I think has a pretty similar structure to what you’re looking for.

-Jon

1 Like

Thank you @jmmease! It worked great.

I had never heard of plotly_express. It was fun learning something new. Still a few small bugs to address in making it appear as I want. But, it looks like it is going to do just what I want it to.

Thanks again!

1 Like

Hi @jmmease , this solution looks great! Thanks for sharing it with us.
I am trying to do a similar data viz with custom Choropleth map, but I cannot use the ‚Äúlocations‚ÄĚ option available in plotly express. However, I was able to get the viz but, on load all the frames load on top of each other just like the first issue described in the post above.
Could you please help me with this. Appreciate your help!

I figured out how to use ploty express to do it. The example using geojson helped me. https://plotly.com/python/mapbox-county-choropleth/

Thank you so much!