Black Lives Matter. Please consider donating to Black Girls Code today.

How do I take the output of a callback as the input of a different callback?

I am trying to make an app that can display places of interest by inputting a location, radius of search, type of location to search and an optional keyword to qualify the location type to search. It uses the Google Places API, which accepts only GPS coordinates as the location input, it cannot accept the location name as input. However, as most people don’t know the GPS coordinates of a location, I want to also give them the ability to search for the GPS coordinates of a location by inputting the location name. Then, using these location coordinates and the other 3 inputs that the user will enter next, I will display a map in the dcc.Graph area below.

Following is my code which displays the GPS coordinates of an input location. Now, I want to make it such that if the user inputs a location name, then the returned GPS coordinates should get automatically put into the input textboxes for latitude and longitude below. How do I do that?

import dash
from dash.dependencies import Output, Input, State
import dash_core_components as dcc
import dash_html_components as html
import requests, json

app = dash.Dash()

app.layout = html.Div(children=[
		html.H3(children="Please input the GPS coordinates (i.e., latitude and longitude), radius of search (in metres), location type and keyword (option) to search for interesting places nearby. If you don't know the GPS coordinates, please enter the name of the location, and we'll help you find it.", style={'height':'8vh'}),
		html.Div([
			dcc.Input(id='input_loc_name', placeholder='Enter location name (like, Mountain View, CA)', type='text', style={'width': '20%', 'display': 'inline-block'}),
			html.Button('Submit', id='submit_loc_name'),
			html.H6(id='coordinates_display', style={'height':'6vh', 'font-size':'1.15em'}),
		]),
		html.Div([
			dcc.Input(id='input_lat', placeholder='Enter a latitude', type='text', style={'width': '10%', 'display': 'inline-block'}),
			dcc.Input(id='input_lon', placeholder='Enter a longitude', type='text', style={'width': '10%', 'display': 'inline-block'}),
			dcc.Input(id='input_radius', placeholder='Enter radius (in metres)', type='text', style={'width': '10%', 'display': 'inline-block'}),
			dcc.Input(id='input_type', placeholder='Enter type of location', type='text', style={'width': '10%', 'display': 'inline-block'}),
			dcc.Input(id='input_key', placeholder='Enter keyword (optional)', type='text', style={'width': '10%', 'display': 'inline-block'}),
		]),
		html.Button('Submit', id='submit_button'),
		html.Div([
			html.H3(id='output_text'),
			html.Div([dcc.Graph(id='output_graph')]),
			])
		])

google_API_key = "API_key"

def return_lat_lon(location_name):
	req = requests.get('https://maps.googleapis.com/maps/api/geocode/json?address='+location_name+'&key='+google_API_key)
	res = req.json()
	result = res['results'][0]
	lat = result['geometry']['location']['lat']
	lon = result['geometry']['location']['lng']
	        	        
	return lat, lon

@app.callback(
	Output('coordinates_display', 'children'),
	[Input('submit_loc_name', 'n_clicks')],
	[State('input_loc_name', 'value')])
def display_gps_coordinatates(n_clicks, input_loc_name):
	if n_clicks:
		if input_loc_name:
			lat, lon = return_lat_lon(input_loc_name)
			return "The GPS coordinates (latitude, longitude) of '{}' are: {}, {}".format(input_loc_name, lat, lon)
	else:
  		return dash.no_update

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

My callback function for making the map is as follows:

@app.callback(
	Output('output_graph', 'figure'),
	[Input('submit_button', 'n_clicks')],
	[State('input_lat', 'value'),
	State('input_lon', 'value'),
	State('input_radius', 'value'),
	State('input_type', 'value'),
	State('input_key', 'value')])
def update_output(n_clicks, lat_, lon_, radius, loc_type, keyword):
	if n_clicks:
        ### code to construct the map

So, I think I just need to figure out a way to add the first callback’s output as one of the inputs to the second callback. But assuming I find a way to do that, I fear it would throw error in the case that the user did not inout any location name in the textbox (as they knew what coordinates they wanted to input). So, how do I do this?

Hi there,

Try to other outputs to your display_gps_coordinatates function
For example change

with

[Output('coordinates_display', 'children'),Output('input_lat', 'value'),Output('input_lon', 'value')]

Change the return call of your function

def display_gps_coordinatates(n_clicks, input_loc_name):
	if n_clicks:
		if input_loc_name:
			lat, lon = return_lat_lon(input_loc_name)
            output_str = "The GPS coordinates (latitude, longitude) of '{}' are: {}, {}".format(input_loc_name, lat, lon)
			return output_str,lat,lon
	else:
  		return dash.no_update

Hope this helps

1 Like

you can store data inside an html div this way you can use this html div as an input or state parameter for another
callback so you can acces the information
the oficial documentation for this is in the dash page https://dash.plot.ly/sharing-data-between-callbacks