I am a begginer with Dash. I tried to make an interactive application which retrieve a list of public companies for a given city, then to display them in a DashTable and in DashLeaflet map with markers.
I have an input filled by user (the city), and I retrieve the list of companies with open data API, geocode them, and display them in dashtable and in the map.
def get_markers(df):
markers = []
for i in range(len(df)):
markers.append(
dl.Marker(
id=df.loc[i,"siret"],
draggable=True,
title=df.loc[i, "siret"],
position=(df.loc[i, "lat"], df.loc[i, "lon"]),
children=[dl.Tooltip(df.loc[i, :]),
dl.Popup(df.loc[i, "enseigneEtablissement"])]
))
return markers
app = dash.Dash(__name__, serve_locally=False)
app.layout = html.Div(children=[
html.H1(children='Hello Dash'),
dcc.Store(id='clientside-store'),
dl.Map([dl.TileLayer()],
id="map",
center=[39, -98],
zoom=4,
style={'width': '1000px', 'height': '500px'}),
dcc.Input(id="input", type="text", placeholder="n°SIREN", value=''),
html.Button('Rechercher les établissements', id='button'),
dash.dash_table.DataTable(id='dashTable')
])
@app.callback(Output('clientside-store', 'data'),
[Input(component_id='button', component_property='n_clicks')],
[State(component_id='input', component_property='value')]
)
def update_table(n_clicks, input_value):
if n_clicks is not None:
df = getEtablissements(input_value)
return df.to_dict(orient='records')
else:
return dash.no_update
@app.callback(Output("map", "children"),
Output("dashTable", "data"),
Output("dashTable", "columns"),
Input('clientside-store', 'data'))
def store_to_map_n_table(store_data):
df = pd.DataFrame(store_data)
columns = [{'name': col, 'id': col} for col in df.columns]
return [dl.TileLayer()] + get_markers(df), df.to_dict(orient='records'), columns
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
After that, I want to make editable marker in the map. The user could move the marker and stock the new location.
I already have a script to get the new location after a drag and drop of markers:
# Marker location updating
@app.callback(Output('clientside-store', 'data'),
dict(positions = [Input(lbl, "position") for lbl in **'data'**.siret]),
State('clientside-store', 'data'),
prevent_initial_call=True)
def update_store_data(positions, data):
df = pd.DataFrame(data)
marker_id_clicked = dash.callback_context.triggered[0]['prop_id'].split('.')[0]
location = dash.callback_context.inputs[marker_id_clicked + '.position']
df.loc[df['id'] == marker_id_clicked, 'lat'] = location[0]
df.loc[df['id'] == marker_id_clicked, 'lon'] = location[1]
return df.to_dict('records')
I have to use the existing data in DashStore, to create the inputs for each Markers. And finally return the new location in the DashStore. Resume, I have two problems :
- make two call back with the same output : DashStore data
- use dynamic DashStore data as inputs of callback