The code displays a scatter map box of all public high schools in NYC. It takes all the information from a dataframe in pandas.
This thread (catch click) gave me the idea to update the html every time a user clicks on a map marker/school.
The app works but an error keeps popping up. Here is what I have so far:
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(id='graph'),
dcc.Dropdown(id='type_picker',options=schooltype,value=df4['school_type'][0]),
html.Div(id='click-data')
])
@app.callback(Output('graph', 'figure'),
[Input('type_picker', 'value')])
def update_figure(selected_school):
# Create Figure
filtered_school_type = df4[df4['school_type'] == selected_school]
interest_areas = list(filtered_school_type.interest1.unique())
schools=[]
for i in interest_areas:
df_sub=filtered_school_type[filtered_school_type.interest1==i]
schools.append(go.Scattermapbox(
lon = df_sub['Longitude'],
lat = df_sub['Latitude'],
mode='markers',
hoverinfo='name+text',
text=df_sub['School Name'],
customdata=df_sub['link'],
...
))
# Return figure for the function
return {
'data': schools,
'layout': go.Layout(
clickmode= 'event+select',
title='NYC schools',
showlegend = True,
mapbox=dict(
accesstoken=mapbox_access_token,
...),
)
}
@app.callback(
Output('click-data', 'children'),
[Input('graph', 'clickData')])
def display_click_data(clickData):
the_link=clickData['points'][0]['customdata']
school_name = clickData['points'][0]['text']
return html.Div([html.A(school_name, href=the_link)])
if __name__ == '__main__':
app.run_server()
The last callback updates the html link every time a user clicks on a different school. However, once I open the app, I get this error in my jupyter notebook:
File “<ipython-input-13-db4d08ed02db>”, line 71, in display_click_data
the_link=clickData[‘points’][0][‘customdata’]
TypeError: ‘NoneType’ object is not subscriptable
Anyone understand why this error is coming up?
Update/Solution:
It seams (according to this thread) that:
1 - Unspecified properties in the app.layout
are set to None
2 - When the app loads, it renders the layout
and then it fires off all of the callbacks that have inputs and outputs that are visible in the app.
3 - In this case, I think the callback click-data
is None
, because when the app initiates, no user has clicked on anything yet. So I added a condition to the code that appears to have worked.
def display_click_data(clickData):
if clickData is None:
return 'nothing yet'
else:
the_link=clickData['points'][0]['customdata']
school_name = clickData['points'][0]['text']
return html.A(school_name, href=the_link)