0

I have a Dash app where the user is expected to use the click feature to enter data into multiple drop down and text menus via maps. I was wondering if it is possible to utilize client callback to avoid page refresh to speed up the application while still preserving the same behavior.

I am sharing a MWE with a single map and a single drop down menu. I do not have any experience with client callbacks. I was wondering if someone could provide help here with which I can make the required updates in my original code.

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


#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())

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")],
        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=[])
])

@app.callback(
    Output('state-table', 'data'),
    Output('state-container', 'children'),
    Input('state-layer', 'click_feature'),
    State('state-table', 'data')
)
def update_options(click_feature, current_data):
    if click_feature is None:
        raise dash.exceptions.PreventUpdate
    else:
        state = click_feature['properties']['NAME']
        if not any(d['state'] == state for d in current_data):
            current_data.append({'state': state})
        return current_data, f"Clicked: {state}"

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

enter image description here

sergey_208
  • 614
  • 3
  • 21
  • No refreshing of the page is happening though. Only rerenders, which are fine. Using client side callbacks won't change stuff needing to rerender. Dash won't need to make requests when `state-layer` changes if you use a client side callback though – 5eb Jun 14 '23 at 15:00

1 Answers1

1

Indeed, you can change your callback to be client-side, and thus speed up the interaction.

You have multiple ways to write client-side callbacks, as explained in the documentation. I would recommend using a separate .js file in the assets/ folder, but here is a quick example of writing the JS function in a python string. You should get the same interaction as before, without the client <-> server back and forth.

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"),
)
thmslmr
  • 1,251
  • 1
  • 5
  • 11
  • Thanks a bunch. Could you explain me little bit how you converted the current callback into the client-side callbacks? – sergey_208 Jun 15 '23 at 20:48
  • 1
    Unfortunately, there is no magic translator (that I'm aware off) to pass from a Python function to a JS one. So I just took your Python code and adapted it in javascript - with my not-so-good knowledge of the language. Few noticeable info: The JS equivalent of `raise dash.exceptions.PreventUpdate` is `return window.dash_clientside.no_update`, and returning a tuple (with the comma-separated values syntax) does not work, it needs to be a list. I recommend the [excellent Dash documentation to understand JS code as a Python developer](https://dash.plotly.com/react-for-python-developers) – thmslmr Jun 19 '23 at 11:54
  • 1
    Thanks for the help. I tried to adapt it to my original application, but it's quite confusing and more complicated. I'll go thru the link that you shared. – sergey_208 Jun 19 '23 at 14:03