javascript 在Dash中通过Java脚本使用clientside_callback时出错- Python

5f0d552i  于 2023-06-28  发布在  Java
关注(0)|答案(1)|浏览(125)

我最近问了一个关于如何使用clientside_callback的问题(请参阅this),并且正在我自己的 Jmeter 板应用程序上进行实践。在我的 Jmeter 板中,我有一个Map,一个下拉菜单和一个按钮。用户通过点击在Map上选择州,并且还可以从下拉菜单中选择它们。但是,下拉菜单中也有ALL选项。至于按钮,它清除用户的选择。
我的应用程序可以使用常规的Dash回调,但我的目标是使用clientside_callback来加速这个过程。然而,我收到了多个错误与我的代码,由于Java脚本部分,我没有经验。
所以我希望有人能帮我。

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

options = [{'label': 'Select all', 'value': 'ALL'}, {'label': 'AK', 'value': 'AK'}, {'label': 'AL', 'value': 'AL'},
           {'label': 'AR', 'value': 'AR'}, {'label': 'AZ', 'value': 'AZ'}, {'label': 'CA', 'value': 'CA'},
           {'label': 'CO', 'value': 'CO'}, {'label': 'CT', 'value': 'CT'}, {'label': 'DE', 'value': 'DE'},
           {'label': 'FL', 'value': 'FL'}, {'label': 'GA', 'value': 'GA'}, {'label': 'HI', 'value': 'HI'},
           {'label': 'IA', 'value': 'IA'}, {'label': 'ID', 'value': 'ID'}, {'label': 'IL', 'value': 'IL'},
           {'label': 'IN', 'value': 'IN'}, {'label': 'KS', 'value': 'KS'}, {'label': 'KY', 'value': 'KY'},
           {'label': 'LA', 'value': 'LA'}, {'label': 'MA', 'value': 'MA'}, {'label': 'MD', 'value': 'MD'},
           {'label': 'ME', 'value': 'ME'}, {'label': 'MI', 'value': 'MI'}, {'label': 'MN', 'value': 'MN'},
           {'label': 'MO', 'value': 'MO'}, {'label': 'MS', 'value': 'MS'}, {'label': 'MT', 'value': 'MT'},
           {'label': 'NC', 'value': 'NC'}, {'label': 'ND', 'value': 'ND'}, {'label': 'NE', 'value': 'NE'},
           {'label': 'NH', 'value': 'NH'}, {'label': 'NJ', 'value': 'NJ'}, {'label': 'NM', 'value': 'NM'},
           {'label': 'NV', 'value': 'NV'}, {'label': 'NY', 'value': 'NY'}, {'label': 'OH', 'value': 'OH'},
           {'label': 'OK', 'value': 'OK'}, {'label': 'OR', 'value': 'OR'}, {'label': 'PA', 'value': 'PA'},
           {'label': 'RI', 'value': 'RI'}, {'label': 'SC', 'value': 'SC'}, {'label': 'SD', 'value': 'SD'},
           {'label': 'TN', 'value': 'TN'}, {'label': 'TX', 'value': 'TX'}, {'label': 'UT', 'value': 'UT'},
           {'label': 'VA', 'value': 'VA'}, {'label': 'VT', 'value': 'VT'}, {'label': 'WA', 'value': 'WA'},
           {'label': 'WI', 'value': 'WI'}, {'label': 'WV', 'value': 'WV'}, {'label': 'WY', 'value': 'WY'}]

state_abbreviations = {'Alabama': 'AL', 'Alaska': 'AK', 'Arizona': 'AZ', 'Arkansas': 'AR', 'California': 'CA', 'Colorado': 'CO',
          'Connecticut': 'CT', 'Delaware': 'DE', 'Florida': 'FL', 'Georgia': 'GA', 'Hawaii': 'HI', 'Idaho': 'ID',
          'Illinois': 'IL', 'Indiana': 'IN', 'Iowa': 'IA', 'Kansas': 'KS', 'Kentucky': 'KY', 'Louisiana': 'LA',
          'Maine': 'ME', 'Maryland': 'MD', 'Massachusetts': 'MA', 'Michigan': 'MI', 'Minnesota': 'MN',
          'Mississippi': 'MS', 'Missouri': 'MO', 'Montana': 'MT', 'Nebraska': 'NE', 'Nevada': 'NV',
          'New Hampshire': 'NH', 'New Jersey': 'NJ', 'New Mexico': 'NM', 'New York': 'NY', 'North Carolina': 'NC',
          'North Dakota': 'ND', 'Ohio': 'OH', 'Oklahoma': 'OK', 'Oregon': 'OR', 'Pennsylvania': 'PA',
          'Rhode Island': 'RI', 'South Carolina': 'SC', 'South Dakota': 'SD', 'Tennessee': 'TN', 'Texas': 'TX',
          'Utah': 'UT', 'Vermont': 'VT', 'Virginia': 'VA', 'Washington': 'WA', 'West Virginia': 'WV', 'Wisconsin':
              'WI', 'Wyoming': 'WY'}
states =  list(state_abbreviations.values())
app = Dash(__name__)
app.layout = html.Div([
#Store lists to use in the callback
    dcc.Store(id='options-store', data=json.dumps(options)),
    dcc.Store(id='states-store', data=json.dumps(states)),
    dcc.Store(id='states-abbrevations', data=json.dumps(state_abbreviations)),
#US Map here
    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],
    ),
#Drop down menu here
    html.Div(className='row', children=[
        dcc.Dropdown(
            id='state-dropdown',
            options=[{'label': 'Select all', 'value': 'ALL'}] +
                    [{'label': state, 'value': state} for state in states],
            value=[],
            multi=True,
            placeholder='States'
        )]),
    html.Div(className='one columns', children=[
        html.Button(
            'Clear',
            id='clear-button',
            n_clicks=0,
            className='my-button'
        ),
    ]),

])

@app.callback(
    Output('state-dropdown', 'value', allow_duplicate=True),
    [Input('clear-button', 'n_clicks')],
    prevent_initial_call=True
)
def clear_tab(user_click):
    if user_click:
        return []
    else:
        raise dash.exceptions.PreventUpdate

app.clientside_callback(
    """
    function(click_feature, selected_states, defaults_options, states, states_abbreviations) {

        let options = defaults_options
        let select_all_selected = selected_states.includes('ALL');
        let list_states;

        if (select_all_selected) {
            options = [{'label': 'Select All', 'value': 'ALL'}];
            selected_states = states;
            list_states = 'ALL';
        } else {
            list_states = selected_states;

            if (click_feature && dash.callback_context.triggered[0]['prop_id'].split('.')[0] == 'state-layer') {
                let state_name = state_abbreviations[click_feature["properties"]["NAME"]];
                if (!selected_states.includes(state_name)) {
                    selected_states.push(state_name);
                    list_states = selected_states;
                }
            }
        }

        return [options, list_states];
    }
     """,
    Output('state-dropdown', 'options'),
    Output('state-dropdown', 'value'),
    Input('state-layer', 'click_feature'),
    Input('state-dropdown', 'value'),
    State('options-store', 'data'),
    State('states-store', 'data'),
    State('states-abbrevations', 'data'),
    prevent_initial_call=True
)
if __name__ == '__main__':
    app.run_server(debug=True)
y3bcpkx1

y3bcpkx11#

你不需要将存储数据序列化为JSON字符串(或者这样做,你必须使用JSON.parse()客户端将它们反序列化回来,但Dash已经在内部完成了),所以第一件事是在应用程序布局中解决这个问题,以便在客户端回调中接收正确的JS对象:

#Store lists to use in the callback
dcc.Store(id='options-store', data=options),
dcc.Store(id='states-store', data=states),
dcc.Store(id='states-abbrevations', data=state_abbreviations),
# ...

第二件事是在客户端回调中使用dash_clientside而不是dash,这样你就可以获得回调上下文等,并且还修复了states_abbreviations的拼写错误:

function(click_feature, selected_states, defaults_options, states, states_abbreviations) {
    let options = defaults_options;
    let select_all_selected = selected_states.includes('ALL');
    let list_states;

    if (select_all_selected) {
        options = [{'label': 'Select All', 'value': 'ALL'}];
        selected_states = states;
        list_states = 'ALL';
    } else {
        list_states = selected_states;

        if (click_feature && dash_clientside.callback_context.triggered[0]['prop_id'].split('.')[0] == 'state-layer') {
            let state_name = states_abbreviations[click_feature["properties"]["NAME"]];
            if (!selected_states.includes(state_name)) {
                selected_states.push(state_name);
                list_states = selected_states;
            }
        }
    }

    return [options, list_states];
}

相关问题