0

I have created a function that generates a map with the user's lat and lon and returns the next time that the International Space Station will be over the user's location. I have created a button and using the on_click function should generate the map using the lat and lon as variables but apparently, the map object is not callable. I tested this using the callable function for the generate_map function and it returned True indicating that that function IS callable. Below is the code. Any tips would be greatly appreciated.

#Retrieve ISS location from the web
url = 'http://api.open-notify.org/iss-now.json'
response = urllib.request.urlopen(url)
result = json.loads(response.read())

#Define the location as latitude and longtitude
location = result['iss_position']
lat = float(location['latitude'])
lon = float(location['longitude'])

#Generate a map illustrating the current position of the ISS
center = [lat, lon] # The centre of the map will be the latitude and longtitude of the ISS
zoom = 1.5
m = Map(basemap=basemaps.Esri.WorldImagery, center=center, zoom=zoom, close_popup_on_click=False)

# Mark the position of the ISS on the map
icon1 = AwesomeIcon(name='space-shuttle', marker_color='blue', icon_color='white', spin=False)
marker = Marker(icon=icon1, location=(lat, lon), draggable=False) # Add a marker at the current location of the ISS that cannot be moved
m.add_layer(marker)

#Recieve the users latitude
input_text_lat = widgets.IntText('-35')
input_text_lat

#Recieve the users longitude
input_text_lon = widgets.IntText('150')
input_text_lon

def generate_map():
    user_location = input_text_lat.value, input_text_lon.value
    url ='http://api.open-notify.org/iss-pass.json'
    url = url + '?lat=' + str(input_text_lat.value) + '&lon=' + str(input_text_lon.value) #The URL requires inputs for lat and lon. The users location are the inputs here.
    response = urllib.request.urlopen(url)
    result = json.loads(response.read())

    #Convert the Unix Timestamp to date and time format
    over = (result['response'][1]['risetime'])
    date_time = datetime.datetime.utcfromtimestamp(over).strftime('%d-%m-%Y at %H:%M:%S') #These place holders define the format of the displayed date and time.
    print('The ISS will pass over you on the', date_time)

    # Mark the position of the user on the map and display a message with the date and time of the next passover.
    icon2 = AwesomeIcon(name='user', marker_color='lightred', icon_color='white', spin=False)
    marker2 = Marker(icon=icon2, location=user_location, draggable=False, title='Location') #Add  marker at the current location of the ISS that cannot be moved
    m.add_layer(marker2) # Add layer that includes the users position
    return m

button = widgets.Button(
    description='Generate map',
    disabled=False,
    button_style='success', # 'success', 'info', 'warning', 'danger' or ''
    tooltip='Click me',
)

button.on_click(generate_map())
button
LEJ2474
  • 43
  • 6
  • 1
    I'm not familiar with this library, but you likely mean `button.on_click(generate_map)`. You're currently calling the function, then passing the returned value to `on_click`, instead of passing the function. Also in the future, please include the full error with trace. – Carcigenicate Jun 02 '21 at 23:52
  • Thank you for the info, I was unaware I was doing that. When I run it in as you've suggested it is returning a type error: "generate_map() takes 0 positional arguments but 1 was given". I'm relatively new to python, could you please clarify what this means? – LEJ2474 Jun 02 '21 at 23:56
  • 1
    That means that `on_click` is expecting to be able to give your function some data (like an event object), but your function doesn't expect any arguments. Your function needs to have a parameter to accept the passed argument. – Carcigenicate Jun 02 '21 at 23:57
  • If you're new to Python, you might want to take a step back and work on a simpler project first. UI programming without a good knowledge base of the language will likely be painful. – Carcigenicate Jun 02 '21 at 23:58
  • Ok great, thank you for the help. I'll work on that and see if I can get it up and running. Cheers – LEJ2474 Jun 03 '21 at 00:01
  • Ok, so I've now added a parameter, self, to the function and it is running without any error. However, Only the text that tells you the time of the next pass over is returned and not the map. I have tested the generate_map function on it's own and it returns a map. Do you know why this isn't working when I pass it through the on_click function? – LEJ2474 Jun 03 '21 at 00:26

1 Answers1

1

Remove the parentheses after generate_map where you call button.on_click; i.e.:

button.on_click(generate_map)

The code you have now calls generate_map, so you're actually passing its return value (the map) into button.on_click. If you don't call it (leave out the parentheses), you'll pass the generate_map function itself to button.on_click, which is callable (and is what you're trying to do here).

JonathonW
  • 857
  • 7
  • 17
  • Great! Thank you very much! That certainly fixes the initial error but I'm now getting another type of error, "generate_map() takes 0 positional arguments but 1 was given". I'm not sure what this means, do you have any suggestion? – LEJ2474 Jun 02 '21 at 23:58