Home » Tutorials » How to Get Geolocation in Python

How to Get Geolocation in Python

Have you ever wondered how apps figure out exactly where you are or where you need to go? That’s geocoding at work, it transforms addresses into geographic coordinates and vice versa, which is fundamental in modern mapping technologies and location-based services. Learning to implement geocoding in Python is not just a great skill for developers; it also opens up a world of possibilities for anyone interested in exploring how digital maps function and interact with real-world locations.

In today’s tutorial, you’ll learn how to get geolocation in Python by building your own geocoding application. You’ll get to choose whether to input an address and fetch its latitude and longitude, or do the opposite; Start with geographic coordinates to discover the corresponding address. It’s a fantastic way to see coding in action and to understand how everyday technologies manage location data.

Let’s get started!

Table of Contents

Necessary Libraries

For the code to function properly, make sure to install the tkinter and geopy libraries via the terminal or your command prompt by running these commands:

$ pip install tk 
$ pip install geopy 

Imports

We aim to make this app user-friendly. So, we import the tkinter library for its graphical user interface (GUI). Additionally, to ensure the app is interactive with the user, we import the messagebox module from tkinter.

Finally, since the script’s goal is to convert addresses into coordinates and vice versa, we import Nominatim from geopy.geocoders.

import tkinter as tk
from tkinter import messagebox
from geopy.geocoders import Nominatim

GeocodingApp Class

Next, we define a class named GeocodingApp that inherits from tk.Tk in the tkinter library. This inheritance allows it to utilize Tkinter’s properties, such as widgets and GUI elements.

After that, we create a subclass of GeocodingApp and initialize it using super().__init__() to access the inherited functionality.

class GeocodingApp(tk.Tk):
   def __init__(self):
       super().__init__()

Initializing the Geocoding Application

Now, we set up our application:

  • First, we create an instance of the Nominatim class, which we will call geocoder.
  • Second, we set the title for our app and define its geometry.
       self.geocoder = Nominatim(user_agent="geoapp")
       self.title("Geocoding Application - The Pycodes")
       self.geometry("660x300")

Creating Labels, Entry Fields and Buttons

Creating Labels

Following that, we create labels to inform the user where to enter the address and coordinates, and we place them in the main window using the grid layout.

       # Labels for user instruction
       tk.Label(self, text="Enter address for geocoding:").grid(row=0, column=0, padx=10, pady=10, sticky="w")
       tk.Label(self, text="Enter latitude and longitude for reverse geocoding:").grid(row=2, column=0, padx=10, pady=10, sticky="w")
       tk.Label(self, text="Latitude:").grid(row=3, column=0, padx=10, pady=5)
       tk.Label(self, text="Longitude:").grid(row=3, column=2, padx=10, pady=5)

Entry Fields

For this step, we create entry fields where users can enter their address and coordinates. We place these fields on the main window using the grid layout.

       # Entry for Forward Geocoding
       self.address_entry = tk.Entry(self, width=40)
       self.address_entry.grid(row=1, column=0, columnspan=3, padx=10, sticky="we")


       # Entries for Reverse Geocoding
       self.latitude_entry = tk.Entry(self, width=20)
       self.latitude_entry.grid(row=4, column=0, padx=10, pady=5)
       self.longitude_entry = tk.Entry(self, width=20)
       self.longitude_entry.grid(row=4, column=2, padx=10, pady=5, sticky="we")

Buttons

In this part, we create two buttons, each calling a different function. The first button, called “Geocode Address“, triggers the geocode_address function. The second button, named “Reverse Geocode“, calls the reverse_geocode function. As with the previous elements, we place these buttons on the main window using the grid layout.

       # Buttons
       self.geocode_button = tk.Button(self, text="Geocode Address", command=self.geocode_address)
       self.geocode_button.grid(row=1, column=3, padx=10, pady=5)
       self.reverse_geocode_button = tk.Button(self, text="Reverse Geocode", command=self.reverse_geocode)
       self.reverse_geocode_button.grid(row=4, column=3, padx=10, pady=5)

Result Text Widget

Here, we create a text widget to display the results of the geocoding functions. We define its height and word wrapping to improve readability and position it on the main window using the grid layout.

       # Result Text Widget
       self.result_text = tk.Text(self, height=4, wrap='word')
       self.result_text.grid(row=5, column=0, columnspan=4, padx=10, pady=10, sticky="we")

Geocoding Functions

Let’s define our functions—the heart of our script:

geocode_address Function

The geocode_address function starts by retrieving the address entered by the user and then uses geocoder.geocode to locate the address. If the location is found, it clears the result_text widget, constructs a string with the address, its latitude, and longitude coordinates, and displays it on the result_text widget.

Otherwise, a message indicating that the address wasn’t found will be displayed. Additionally, if any error occurs during the process, an error message will also be displayed.

   def geocode_address(self):
       address = self.address_entry.get()
       try:
           location = self.geocoder.geocode(address)
           if location:
               result = f"Address: {address}\nLatitude: {location.latitude}, Longitude: {location.longitude}"
               self.result_text.delete('1.0', tk.END)
               self.result_text.insert(tk.END, result)
           else:
               messagebox.showinfo("Result", "Address not found")
       except Exception as e:
           messagebox.showerror("Error", f"An error occurred: {e}")

reverse_geocode Function

This one does the opposite of the previous function. It starts by getting the latitude and longitude coordinates entered by the user. It then tries to find the address that matches these coordinates:

  • If it finds an address, the function displays the coordinates along with the address in the result_text widget, just like the previous function displayed its results.
  • If no address is found, it lets the user know by showing a message that says “No address found for these coordinates“. If something goes wrong during this process, it also shows an error message to explain what happened.
   def reverse_geocode(self):
       latitude = self.latitude_entry.get()
       longitude = self.longitude_entry.get()
       try:
           location = self.geocoder.reverse(f"{latitude}, {longitude}")
           if location:
               result = f"Coordinates: {latitude}, {longitude}\nAddress: {location.address}"
               self.result_text.delete('1.0', tk.END)
               self.result_text.insert(tk.END, result)
           else:
               messagebox.showinfo("Result", "No address found for these coordinates")
       except Exception as e:
           messagebox.showerror("Error", f"An error occurred: {e}")

Running the Application

This part ensures that the app runs directly and is not imported as a module. It also keeps the main window running and responsive to user actions until the user decides to exit.

if __name__ == "__main__":
   app = GeocodingApp()
   app.mainloop()

Example

As you can see here, our program takes the address as input and gives the coordinates as a result:

Here our program takes the coordinates as inputs and gives the address as a result:

Full Code

import tkinter as tk
from tkinter import messagebox
from geopy.geocoders import Nominatim


class GeocodingApp(tk.Tk):
   def __init__(self):
       super().__init__()


       self.geocoder = Nominatim(user_agent="geoapp")
       self.title("Geocoding Application - The Pycodes")
       self.geometry("660x300")


       # Labels for user instruction
       tk.Label(self, text="Enter address for geocoding:").grid(row=0, column=0, padx=10, pady=10, sticky="w")
       tk.Label(self, text="Enter latitude and longitude for reverse geocoding:").grid(row=2, column=0, padx=10, pady=10, sticky="w")
       tk.Label(self, text="Latitude:").grid(row=3, column=0, padx=10, pady=5)
       tk.Label(self, text="Longitude:").grid(row=3, column=2, padx=10, pady=5)


       # Entry for Forward Geocoding
       self.address_entry = tk.Entry(self, width=40)
       self.address_entry.grid(row=1, column=0, columnspan=3, padx=10, sticky="we")


       # Entries for Reverse Geocoding
       self.latitude_entry = tk.Entry(self, width=20)
       self.latitude_entry.grid(row=4, column=0, padx=10, pady=5)
       self.longitude_entry = tk.Entry(self, width=20)
       self.longitude_entry.grid(row=4, column=2, padx=10, pady=5, sticky="we")


       # Buttons
       self.geocode_button = tk.Button(self, text="Geocode Address", command=self.geocode_address)
       self.geocode_button.grid(row=1, column=3, padx=10, pady=5)
       self.reverse_geocode_button = tk.Button(self, text="Reverse Geocode", command=self.reverse_geocode)
       self.reverse_geocode_button.grid(row=4, column=3, padx=10, pady=5)


       # Result Text Widget
       self.result_text = tk.Text(self, height=4, wrap='word')
       self.result_text.grid(row=5, column=0, columnspan=4, padx=10, pady=10, sticky="we")


   def geocode_address(self):
       address = self.address_entry.get()
       try:
           location = self.geocoder.geocode(address)
           if location:
               result = f"Address: {address}\nLatitude: {location.latitude}, Longitude: {location.longitude}"
               self.result_text.delete('1.0', tk.END)
               self.result_text.insert(tk.END, result)
           else:
               messagebox.showinfo("Result", "Address not found")
       except Exception as e:
           messagebox.showerror("Error", f"An error occurred: {e}")


   def reverse_geocode(self):
       latitude = self.latitude_entry.get()
       longitude = self.longitude_entry.get()
       try:
           location = self.geocoder.reverse(f"{latitude}, {longitude}")
           if location:
               result = f"Coordinates: {latitude}, {longitude}\nAddress: {location.address}"
               self.result_text.delete('1.0', tk.END)
               self.result_text.insert(tk.END, result)
           else:
               messagebox.showinfo("Result", "No address found for these coordinates")
       except Exception as e:
           messagebox.showerror("Error", f"An error occurred: {e}")


if __name__ == "__main__":
   app = GeocodingApp()
   app.mainloop()

Happy Coding!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top