Monday, 24 July 2023

how to color a map after user selection in Dash using GeoJSON

I have a Dash app where I show a world map and expect user to select certain countries. After each selection, a callback function is triggered and I'd like to color each country selected. As a toy example, I am showing a US map with a state selection option. Here you can click on a state and it is printed on the screen. My question is that how I can color each state selected in red.

I have attached another callback to change the color, however, it is changing the color of the whole map rather than the ones that are selected. I have used the example shared at this post.

import random, json
import dash
from dash import dcc, html, Dash, callback, Output, Input, State
import dash_leaflet as dl
import geopandas as gpd
from dash import dash_table
from dash_extensions.javascript import assign

#https://gist.github.com/incubated-geek-cc/5da3adbb2a1602abd8cf18d91016d451?short_path=2de7e44
us_states_gdf = gpd.read_file("us_states.geojson")
us_states_geojson = json.loads(us_states_gdf.to_json())
# Color the feature saved in the hideout prop in a particular way (grey).
style_handle = assign("""function(feature, context){
    const match = context.props.hideout &&  context.props.hideout.properties.name === feature.properties.name;
    if(match) return {color:'#126'};
}""")

app = Dash(__name__)
app.layout = html.Div([
    dl.Map([
        dl.TileLayer(url="http://tile.stamen.com/toner-lite/{z}/{x}/{y}.png"),
        dl.GeoJSON(data=us_states_geojson, id="state-layer",
                   options=dict(style=style_handle), hideout=dict(click_feature=None))],
        style={'width': '100%', 'height': '250px'},
        id="map",
        center=[39.8283, -98.5795],
    ),
    html.Div(id='state-container', children=[]),  #
    dash_table.DataTable(id='state-table', columns=[{"name": i, "id": i} for i in ["state"]], data=[])
])
# Update the feature saved on the hideout prop on click.
app.clientside_callback("function(feature){return feature}",
                        Output("state-layer", "hideout"),
                        [Input("state-layer", "click_feature")])

app.clientside_callback(
    """
    function(clickFeature, currentData) {
        if(!clickFeature){
            return window.dash_clientside.no_update
        }

        const state = clickFeature.properties.NAME
        const currentStates = currentData.map(item => item.state)

        let newData = []
        if(!currentStates.includes(state)){
            newData = [...currentData, {"state": state}]
        }else{
            newData = currentData
        }

        const stateText = `Clicked: ${state}`
        return [newData, stateText]
    }
    """,
    Output("state-table", "data"),
    Output("state-container", "children"),
    Input("state-layer", "click_feature"),
    State("state-table", "data"),
)

if __name__ == '__main__':
    app.run_server(debug=True)



from how to color a map after user selection in Dash using GeoJSON

No comments:

Post a Comment