In today’s tutorial, we are going to write a code that builds a weather app using a GUI Framework. Specifically the tkinter library, and an API method. This app will allow users to search for weather information by entering the name of any city.
Let’s get started!
Table of Contents
- Necessary Libraries
- Imports
- Get Weather Function
- Creating the Main Window
- Creating Search Box and Button
- Creating Labels
- Creating Time Labels
- Main Loop
- Open Weather Map API Key
- Example
- Full Code
Necessary Libraries
Make sure to install these libraries via the terminal or your command prompt for the code to function properly.
$ pip install tk
$ pip install geopy
$ pip install timezonefinder
$ pip install requests
$ pip install pytz
Learn also: How to Build a Weather App with Flask in Python
Imports
from tkinter import *
from geopy.geocoders import Nominatim
from tkinter import messagebox
from timezonefinder import TimezoneFinder
from datetime import datetime
import requests
import pytz
We start by importing:
- First, the
tkinter
library, which allows us to create a graphical user interface (GUI). - Second,
Nominatim
from geopy, used for geocoding and retrieving location information. - Third,
messagebox
fromtkinter
to display dialogs as message boxes. - Our fourth import is
TimezoneFinder
library, which, as the name suggests, retrieves the timezone based on geographical coordinates. - Fifth, we import the
datetime
library to utilize time functions. - Sixth,
requests
library to communicate with the OpenWeatherMap server. - Lastly,
pytz
library which provides accurate access to time-related information.
Get Weather Function
Next, we create a function that gets the city name and then retrieves the city’s geographical coordinates. If it’s unable to find the coordinates, an error message appears. Otherwise, it determines the timezone of the location and obtains the current local time in the specified timezone.
Using the API key, it extracts important information (such as temperature, wind speed, etc.) of the searched city. If any error occurs during this operation, an error message pops up.
def get_weather():
try:
city = textfield.get()
geolocator = Nominatim(user_agent="weather_app")
location = geolocator.geocode(city)
if not location:
raise ValueError("City Not Found")
timezone_finder = TimezoneFinder()
result = timezone_finder.timezone_at(lng=location.longitude, lat=location.latitude)
home_timezone = pytz.timezone(result)
local_time = datetime.now(home_timezone)
current_time = local_time.strftime("%I:%M %p")
clock.config(text=current_time)
name.config(text=f"CURRENT WEATHER in {city}, {location.address.split(',')[-1].strip()}")
# Weather API
api_key = "Enter YOUR_OPENWEATHERMAP_API_KEY"
api = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"
json_data = requests.get(api).json()
weather_info = json_data.get('weather', [{}])[0]
main_info = json_data.get('main', {})
wind_info = json_data.get('wind', {})
sys_info = json_data.get('sys', {})
condition = weather_info.get('main', '')
description = weather_info.get('description', '')
temp = int(main_info.get('temp', 0) - 273.15)
pressure = main_info.get('pressure', 0)
humidity = main_info.get('humidity', 0)
wind_speed = wind_info.get('speed', 0)
country = sys_info.get('country', '')
sunrise_time = datetime.utcfromtimestamp(sys_info.get('sunrise', 0)).strftime('%H:%M:%S')
sunset_time = datetime.utcfromtimestamp(sys_info.get('sunset', 0)).strftime('%H:%M:%S')
temperature_label.config(text=f"{temp} °C")
condition_label.config(text=f"{condition} | Temperature is {temp} °C")
wind_label.config(text=f"Wind: {wind_speed} m/s")
humidity_label.config(text=f"Humidity: {humidity}%")
description_label.config(text=f"{description.capitalize()}")
pressure_label.config(text=f"Pressure: {pressure} hPa")
country_label.config(text=f"Country: {country}")
sunrise_label.config(text=f"Sunrise: {sunrise_time}")
sunset_label.config(text=f"Sunset: {sunset_time}")
except Exception as e:
messagebox.showerror("Weather App", str(e))
Creating the Main Window
Now, we create the main window, give it a title, define its geometry then disable its resizing.
# Creating the main window
root = Tk()
root.title("Weather App - The Pycodes")
root.geometry("900x600")
root.resizable(False, False)
Creating Search Box and Button
After that we create a search box where the user can input the city name, then we make a “Search” button that once clicked triggers the get_weather
function.
# Creating search box
textfield = Entry(root, justify="center", width=17, font=("poppins", 25, "bold"), bg="#404040", border=0, fg="white")
textfield.place(x=50, y=40)
textfield.focus()
search_button = Button(text="Search", font=("Arial", 12, 'bold'), command=get_weather)
search_button.place(x=400, y=34)
Creating Labels
Following that, we create labels that display the names of the important information retrieved by the API such as wind speed, pressure,…. etc, as well as the Labels that will display them by being Updated from the get_weather
function.
# Creating labels
label1 = Label(root, text="WIND", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label1.place(x=120, y=400)
label2 = Label(root, text="HUMIDITY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label2.place(x=250, y=400)
label3 = Label(root, text="DESCRIPTION", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label3.place(x=430, y=400)
label4 = Label(root, text="PRESSURE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label4.place(x=650, y=400)
label5 = Label(root, text="COUNTRY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label5.place(x=120, y=500)
label6 = Label(root, text="SUNRISE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label6.place(x=250, y=500)
label7 = Label(root, text="SUNSET", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label7.place(x=430, y=500)
temperature_label = Label(font=("arial", 70, "bold"), fg="#ee666d")
temperature_label.place(x=400, y=150)
condition_label = Label(font=("arial", 15, 'bold'))
condition_label.place(x=400, y=250)
wind_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
wind_label.place(x=120, y=430)
humidity_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
humidity_label.place(x=280, y=430)
description_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
description_label.place(x=450, y=430)
pressure_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
pressure_label.place(x=650, y=430)
country_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
country_label.place(x=120, y=530)
sunrise_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunrise_label.place(x=250, y=530)
sunset_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunset_label.place(x=430, y=530)
Creating Time Labels
# Time
name = Label(root, font=("arial", 15, 'bold'))
name.place(x=30, y=100)
clock = Label(root, font=("Helvetica", 20,))
clock.place(x=30, y=130)
Here, we created labels that will display the location and current time.
Main Loop
root.mainloop()
To wrap things up, the script kicks off the Tkinter main event loop with root.mainloop()
. This loop is like the heart of the GUI application, constantly listening for what the user does and keeping the app up and running.
Open Weather Map API Key
This is basically a digital key that allows our program to access specific weather information such as temperature, humidity, …., etc. To obtain the API key you need to follow these steps :
- First access this site https://openweathermap.org
- Second, you need to click sign up and if you don’t have an account then create one.
- Third, after you have successfully created an account, confirmed it, and signed in. Click API Keys.
- Fourth and last generate an API key.
Example
Once you hit run after following the code this is the result that you should be getting.
Full Code
from tkinter import *
from geopy.geocoders import Nominatim
from tkinter import messagebox
from timezonefinder import TimezoneFinder
from datetime import datetime
import requests
import pytz
def get_weather():
try:
city = textfield.get()
geolocator = Nominatim(user_agent="weather_app")
location = geolocator.geocode(city)
if not location:
raise ValueError("City Not Found")
timezone_finder = TimezoneFinder()
result = timezone_finder.timezone_at(lng=location.longitude, lat=location.latitude)
home_timezone = pytz.timezone(result)
local_time = datetime.now(home_timezone)
current_time = local_time.strftime("%I:%M %p")
clock.config(text=current_time)
name.config(text=f"CURRENT WEATHER in {city}, {location.address.split(',')[-1].strip()}")
# Weather API
api_key = "Enter YOUR_OPENWEATHERMAP_API_KEY"
api = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"
json_data = requests.get(api).json()
weather_info = json_data.get('weather', [{}])[0]
main_info = json_data.get('main', {})
wind_info = json_data.get('wind', {})
sys_info = json_data.get('sys', {})
condition = weather_info.get('main', '')
description = weather_info.get('description', '')
temp = int(main_info.get('temp', 0) - 273.15)
pressure = main_info.get('pressure', 0)
humidity = main_info.get('humidity', 0)
wind_speed = wind_info.get('speed', 0)
country = sys_info.get('country', '')
sunrise_time = datetime.utcfromtimestamp(sys_info.get('sunrise', 0)).strftime('%H:%M:%S')
sunset_time = datetime.utcfromtimestamp(sys_info.get('sunset', 0)).strftime('%H:%M:%S')
temperature_label.config(text=f"{temp} °C")
condition_label.config(text=f"{condition} | Temperature is {temp} °C")
wind_label.config(text=f"Wind: {wind_speed} m/s")
humidity_label.config(text=f"Humidity: {humidity}%")
description_label.config(text=f"{description.capitalize()}")
pressure_label.config(text=f"Pressure: {pressure} hPa")
country_label.config(text=f"Country: {country}")
sunrise_label.config(text=f"Sunrise: {sunrise_time}")
sunset_label.config(text=f"Sunset: {sunset_time}")
except Exception as e:
messagebox.showerror("Weather App", str(e))
# Creating the main window
root = Tk()
root.title("Weather App - The Pycodes")
root.geometry("900x600")
root.resizable(False, False)
# Creating search box
textfield = Entry(root, justify="center", width=17, font=("poppins", 25, "bold"), bg="#404040", border=0, fg="white")
textfield.place(x=50, y=40)
textfield.focus()
search_button = Button(text="Search", font=("Arial", 12, 'bold'), command=get_weather)
search_button.place(x=400, y=34)
# Creating labels
label1 = Label(root, text="WIND", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label1.place(x=120, y=400)
label2 = Label(root, text="HUMIDITY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label2.place(x=250, y=400)
label3 = Label(root, text="DESCRIPTION", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label3.place(x=430, y=400)
label4 = Label(root, text="PRESSURE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label4.place(x=650, y=400)
label5 = Label(root, text="COUNTRY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label5.place(x=120, y=500)
label6 = Label(root, text="SUNRISE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label6.place(x=250, y=500)
label7 = Label(root, text="SUNSET", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label7.place(x=430, y=500)
temperature_label = Label(font=("arial", 70, "bold"), fg="#ee666d")
temperature_label.place(x=400, y=150)
condition_label = Label(font=("arial", 15, 'bold'))
condition_label.place(x=400, y=250)
wind_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
wind_label.place(x=120, y=430)
humidity_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
humidity_label.place(x=280, y=430)
description_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
description_label.place(x=450, y=430)
pressure_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
pressure_label.place(x=650, y=430)
country_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
country_label.place(x=120, y=530)
sunrise_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunrise_label.place(x=250, y=530)
sunset_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunset_label.place(x=430, y=530)
# Time
name = Label(root, font=("arial", 15, 'bold'))
name.place(x=30, y=100)
clock = Label(root, font=("Helvetica", 20,))
clock.place(x=30, y=130)
root.mainloop()
Happy Coding!