I’m trying to make a colored map based on some indicator value. The problem is the indicators values are different in their range of values so a unified color bar will make each indicator look the same, look at the next two photos:
This happens due to that the color bar range is fixed, and I can’t think of method to make it flexible based on the indicator value range (max would be top color, and min would be bottom color).
Here is my full code:
import dash_leaflet as dl
import dash_leaflet.express as dlx
from dash import Dash, html, Output, Input, dcc
from dash_extensions.javascript import arrow_function, assign
import geopandas as gpd
import json
hover_style= dict(weight=4, fillColor='grey')
gdf_gov = gpd.read_file('transformed_data.geojson')
gdf_gov.fillna(0, inplace=True)
# Rename the 'REGIONCODE' column to 'region_id'
region_names = gdf_gov['REGIONNAME_EN'].unique()
names = gdf_gov['indicator_name'].unique()
classes = [0, 10, 20, 50, 100, 200, 500, 1000]
colorscale = ['#FFEDA0', '#FED976', '#FEB24C', '#FD8D3C', '#FC4E2A', '#E31A1C', '#BD0026', '#800026']
style = dict(weight=2, opacity=1, color='white', dashArray='3', fillOpacity=0.7)
# Create colorbar.
ctg = ["{}+".format(cls, classes[i + 1]) for i, cls in enumerate(classes[:-1])] + ["{}+".format(classes[-1])]
colorbar = dlx.categorical_colorbar(categories=ctg, colorscale=colorscale, width=300, height=30, position="bottomleft")
# Geojson rendering logic, must be JavaScript as it is executed in clientside.
style_handle = assign("""function(feature, context){
const {classes, colorscale, style, colorProp} = context.props.hideout; // get props from hideout
const value = feature.properties[colorProp]; // get value the determines the color
for (let i = 0; i < classes.length; ++i) {
if (value > classes[i]) {
style.fillColor = colorscale[i]; // set the fill color according to the class
}
}
return style;
}""")
# Create geojson.
geojson = dl.GeoJSON(data=json.loads(gdf_gov.to_json()), # url to geojson file
options=dict(style=style_handle), # how to style each polygon
zoomToBounds=True, # when true, zooms to bounds when data changes (e.g. on load)
hoverStyle=arrow_function(dict(weight=5, color='#666', dashArray='')), # style applied on hover
hideout=dict(colorscale=colorscale, classes=classes, style=style, colorProp="indicator_value"),
id="geojson")
app = Dash()
app.layout = html.Div([
dl.Map(children=[dl.TileLayer(), geojson, colorbar],center=[24, 47.5], zoom =4, id="nothing"),
dcc.Dropdown(
id="region-dropdown",
options=[{'label': region, 'value': region} for region in region_names],
value=region_names[2],
clearable=False,
style={"color": "black"},
),
dcc.Dropdown(
id="name-dropdown",
options=[{'label': name, 'value': name} for name in names],
value=names[0],
clearable=False,
style={"color": "black"},
)],
style={'width': '100%', 'height': '50vh', 'margin': "auto", "display": "block"}, id="map")
@app.callback([Output('geojson', 'data')],
[Input('region-dropdown', 'value'),
Input('name-dropdown', 'value')])
def update_map(region, name):
filtered_gdf_gov = gdf_gov[gdf_gov['REGIONNAME_EN'] == region]
filtered_gdf_gov = filtered_gdf_gov[filtered_gdf_gov['indicator_name'] == name]
layer2_data = json.loads(filtered_gdf_gov.to_json())
return layer2_data,
if __name__ == '__main__':
app.run_server(debug=True, port=8052)```