I am trying to create an interactive chart plotly-Choroplethmapbox.
Ideally I would like a world map, centered on Europe, which could show the outline of all world countries and plot a solid color, using a color scale based on a numeric dataset (e.g. a dataframe column values), and coloring only those countries that are present on such dataset.
I have asked chatgpt to sort this out, and unfortunately for any step forward, it makes two steps back, presenting recurring errors of undefined variable names. What I am pasting here is the latest working example, where unfortunately the colors do not appear.
import streamlit as st
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# Generate random data for countries
np.random.seed(0)
data = {
'Country': ['United States', 'Canada', 'Mexico', 'Germany', 'France', 'United Kingdom', 'China', 'India', 'Brazil'],
'Value': np.random.randint(1, 100, 9),
'lon': [-95.7129, -106.3468, -102.5528, 10.4515, 2.2137, -2.2426, 104.1954, 78.9629, -47.9292],
'lat': [37.0902, 56.1304, 23.6345, 51.1657, 46.6033, 53.9600, 35.8617, 20.5937, -14.2350]
}
df = pd.DataFrame(data)
# Load GeoJSON data for country boundaries
geojson = 'https://raw.githubusercontent.com/python-visualization/folium/master/examples/data/world-countries.json'
# Streamlit app
st.title('World Countries Map')
st.sidebar.header('Filter Options')
# Select the data variable for coloring the map
color_var = st.sidebar.selectbox('Select Data Variable', df.columns[1:])
# Create a trace for country outlines
trace_outline = go.Choroplethmapbox(
geojson=geojson,
locations=df['Country'],
z=[1] * len(df), # Assigning a constant value of 1 to show all countries as outlines
colorscale=[[0, 'rgba(0, 0, 0, 0)']], # Set the first element of the colorscale to transparent
marker_opacity=0,
hoverinfo='skip',
showscale=False
)
# Create a trace for the colored countries
trace_colored = go.Choroplethmapbox(
geojson=geojson,
locations=df['Country'],
z=df[color_var],
colorscale=[[0, 'rgba(0, 0, 0, 0)'], [1, 'blue']], # Set the colorscale to include a solid color
marker_opacity=0.8,
marker_line_color='black',
hovertemplate='<b>%{location}</b><br><br>' +
f'{color_var}: %{{z:.2f}}<extra></extra>',
)
# Set up the layout
layout = go.Layout(
mapbox_style='carto-positron',
mapbox_zoom=3, # Adjust the zoom level as needed
mapbox_center={"lat": 54.5260, "lon": 15.2551}, # Centered on Europe
margin={"r": 0, "t": 0, "l": 0, "b": 0}
)
# Combine the traces and layout into a figure
fig = go.Figure(data=[trace_outline, trace_colored], layout=layout)
# Add country labels
for country in df['Country']:
country_row = df[df['Country'] == country]
lon, lat = country_row['lon'], country_row['lat']
value = int(country_row[color_var].values[0])
fig.add_annotation(
x=float(lon),
y=float(lat),
text=str(value),
showarrow=False,
font=dict(color='white' if value > 50 else 'black')
)
# Render the map using Plotly in Streamlit
st.plotly_chart(fig, use_container_width=True)
Here is the previous code that did the job, in a graphically more 'crude' way:
import streamlit as st
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import numpy as np
# Generate random data for countries
np.random.seed(0)
data = {
'Country': ['United States', 'Canada', 'Mexico', 'Germany', 'France', 'United Kingdom', 'China', 'India', 'Brazil'],
'Value': np.random.randint(1, 100, 9)
}
df = pd.DataFrame(data)
# Load GeoJSON data for country boundaries
geojson = 'https://raw.githubusercontent.com/python-visualization/folium/master/examples/data/world-countries.json'
# Streamlit app
st.title('World Countries Map')
st.sidebar.header('Filter Options')
# Select the data variable for coloring the map
color_var = st.sidebar.selectbox('Select Data Variable', df.columns)
# Interactive map with Plotly
fig = px.choropleth(
df,
geojson=geojson,
locations='Country',
featureidkey='properties.name',
color=color_var,
color_continuous_scale='Viridis',
title='World Countries Map'
)
fig.update_geos(fitbounds='geojson', visible=True)
# Render the map using Plotly in Streamlit
st.plotly_chart(fig, use_container_width=True)