This demonstration is heavily inspired by NeuralNine’s video.
You need a free account from here.
The VS Code extension JSON viewer is recommended for viewing downloaded JSON content.
Set your maximum API calls to 1000 per day to make sure you are under the limit for billing.
To run the examples, download your API key, save it in the right folder (see below) in a file called api_key_OpenWeather, containing only the key (no spaces or “enters”).
# Imports
import datetime as dt
import requests
import jsonBASE_URL = "http://api.openweathermap.org/data/2.5/weather?"
API_KEY = open('../../../No_sync/api_key_OpenWeather','r').read()
CITY = "Ski" # Implicit geocoding is deprecated.
url = BASE_URL + "q=" + CITY + "&appid=" + API_KEYRequest current weather in chosen city¶
response = requests.get(url).json()
print(response){'coord': {'lon': 10.8358, 'lat': 59.7195}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'base': 'stations', 'main': {'temp': 291.92, 'feels_like': 291.24, 'temp_min': 291.92, 'temp_max': 292.77, 'pressure': 1003, 'humidity': 53, 'sea_level': 1003, 'grnd_level': 988}, 'visibility': 10000, 'wind': {'speed': 1.12, 'deg': 255, 'gust': 1.53}, 'clouds': {'all': 16}, 'dt': 1787055586, 'sys': {'type': 2, 'id': 2006772, 'country': 'NO', 'sunrise': 1787024344, 'sunset': 1787079742}, 'timezone': 7200, 'id': 3139081, 'name': 'Ski', 'cod': 200}
# Write JSON to file for viewing
with open('downloads/weather.json', 'w') as f:
json.dump(response, f, indent=4)Conversion functions¶
Changing scales can make results more interpretable
# Kelvin to Celsius
def kelvin_to_celsius(temp):
return temp - 273.15
# Meters per second to knots
def mps_to_knots(speed):
return speed * 1.943844Print some weather properties¶
# Current temperature
temp_kelvin = response['main']['temp']
temp_celsius = kelvin_to_celsius(temp_kelvin)
print(f"The current temperature in {CITY} is {temp_celsius:.1f} °C")The current temperature in Ski is 18.8 °C
# Sunrise and sunset today in local time
sunrise = dt.datetime.fromtimestamp(response['sys']['sunrise'])
sunset = dt.datetime.fromtimestamp(response['sys']['sunset'])
print(f"Sunrise today is at {sunrise:%H:%M} and sunset is at {sunset:%H:%M}")Sunrise today is at 05:39 and sunset is at 21:02
# Wind direction and speed
wind_knots = mps_to_knots(response['wind']['speed'])
print(f"Wind today is from {response['wind']['deg']}° at {round(wind_knots,1)} knots")Wind today is from 255° at 2.2 knots
BASE_URL = "https://api.openweathermap.org/data/2.5/forecast?"
CITY = "Agadir"
urlF = BASE_URL + "q=" + CITY + "&appid=" + API_KEYRequest forecasted weather in chosen city¶
responseF = requests.get(urlF).json()
#print(json.dumps(responseF, indent=4))
print(responseF){'cod': '200', 'message': 0, 'cnt': 40, 'list': [{'dt': 1787065200, 'main': {'temp': 301.14, 'feels_like': 302.06, 'temp_min': 298.61, 'temp_max': 301.14, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 999, 'humidity': 55, 'temp_kf': 2.53, 'dew_point': 291.26}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 4}, 'wind': {'speed': 5.02, 'deg': 278, 'gust': 5.42}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-18 15:00:00'}, {'dt': 1787076000, 'main': {'temp': 299.57, 'feels_like': 299.57, 'temp_min': 298.15, 'temp_max': 299.57, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 999, 'humidity': 55, 'temp_kf': 1.42, 'dew_point': 289.81}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'clouds': {'all': 14}, 'wind': {'speed': 4.07, 'deg': 271, 'gust': 4.68}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-18 18:00:00'}, {'dt': 1787086800, 'main': {'temp': 296.04, 'feels_like': 296.16, 'temp_min': 296.04, 'temp_max': 296.04, 'pressure': 1018, 'sea_level': 1018, 'grnd_level': 1001, 'humidity': 68, 'temp_kf': 0, 'dew_point': 289.75}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.11, 'deg': 175, 'gust': 2.02}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-18 21:00:00'}, {'dt': 1787097600, 'main': {'temp': 296.18, 'feels_like': 296.26, 'temp_min': 296.18, 'temp_max': 296.18, 'pressure': 1017, 'sea_level': 1017, 'grnd_level': 1000, 'humidity': 66, 'temp_kf': 0, 'dew_point': 289.55}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 3.15, 'deg': 112, 'gust': 3.43}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-19 00:00:00'}, {'dt': 1787108400, 'main': {'temp': 295.72, 'feels_like': 295.76, 'temp_min': 295.72, 'temp_max': 295.72, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 999, 'humidity': 66, 'temp_kf': 0, 'dew_point': 289.03}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.47, 'deg': 313, 'gust': 1.49}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-19 03:00:00'}, {'dt': 1787119200, 'main': {'temp': 295.25, 'feels_like': 295.29, 'temp_min': 295.25, 'temp_max': 295.25, 'pressure': 1017, 'sea_level': 1017, 'grnd_level': 1000, 'humidity': 68, 'temp_kf': 0, 'dew_point': 289.13}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 0.99, 'deg': 109, 'gust': 0.7}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-19 06:00:00'}, {'dt': 1787130000, 'main': {'temp': 295.37, 'feels_like': 295.48, 'temp_min': 295.37, 'temp_max': 295.37, 'pressure': 1018, 'sea_level': 1018, 'grnd_level': 1001, 'humidity': 70, 'temp_kf': 0, 'dew_point': 289.54}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 4.25, 'deg': 189, 'gust': 3.99}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-19 09:00:00'}, {'dt': 1787140800, 'main': {'temp': 300.1, 'feels_like': 300.35, 'temp_min': 300.1, 'temp_max': 300.1, 'pressure': 1017, 'sea_level': 1017, 'grnd_level': 1000, 'humidity': 47, 'temp_kf': 0, 'dew_point': 286.62}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 2.58, 'deg': 233, 'gust': 1.13}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-19 12:00:00'}, {'dt': 1787151600, 'main': {'temp': 300.93, 'feels_like': 301.27, 'temp_min': 300.93, 'temp_max': 300.93, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 998, 'humidity': 49, 'temp_kf': 0, 'dew_point': 287.95}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 90}, 'wind': {'speed': 2.93, 'deg': 284, 'gust': 4.24}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-19 15:00:00'}, {'dt': 1787162400, 'main': {'temp': 299.52, 'feels_like': 299.52, 'temp_min': 299.52, 'temp_max': 299.52, 'pressure': 1015, 'sea_level': 1015, 'grnd_level': 998, 'humidity': 54, 'temp_kf': 0, 'dew_point': 288.87}, 'weather': [{'id': 803, 'main': 'Clouds', 'description': 'broken clouds', 'icon': '04d'}], 'clouds': {'all': 69}, 'wind': {'speed': 3.32, 'deg': 285, 'gust': 4.53}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-19 18:00:00'}, {'dt': 1787173200, 'main': {'temp': 295.92, 'feels_like': 296.13, 'temp_min': 295.92, 'temp_max': 295.92, 'pressure': 1017, 'sea_level': 1017, 'grnd_level': 1000, 'humidity': 72, 'temp_kf': 0, 'dew_point': 290.64}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 4}, 'wind': {'speed': 0.57, 'deg': 126, 'gust': 3.55}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-19 21:00:00'}, {'dt': 1787184000, 'main': {'temp': 294.11, 'feels_like': 294.45, 'temp_min': 294.11, 'temp_max': 294.11, 'pressure': 1018, 'sea_level': 1018, 'grnd_level': 1001, 'humidity': 84, 'temp_kf': 0, 'dew_point': 291.5}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 4}, 'wind': {'speed': 2.79, 'deg': 111, 'gust': 3.04}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-20 00:00:00'}, {'dt': 1787194800, 'main': {'temp': 293.52, 'feels_like': 293.83, 'temp_min': 293.52, 'temp_max': 293.52, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 1000, 'humidity': 85, 'temp_kf': 0, 'dew_point': 291.07}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 5}, 'wind': {'speed': 1.27, 'deg': 96, 'gust': 1.89}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-20 03:00:00'}, {'dt': 1787205600, 'main': {'temp': 292.41, 'feels_like': 292.74, 'temp_min': 292.41, 'temp_max': 292.41, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 999, 'humidity': 90, 'temp_kf': 0, 'dew_point': 290.95}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 2}, 'wind': {'speed': 0.73, 'deg': 224, 'gust': 0.15}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-20 06:00:00'}, {'dt': 1787216400, 'main': {'temp': 295.47, 'feels_like': 295.64, 'temp_min': 295.47, 'temp_max': 295.47, 'pressure': 1017, 'sea_level': 1017, 'grnd_level': 1000, 'humidity': 72, 'temp_kf': 0, 'dew_point': 290.1}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 0}, 'wind': {'speed': 2.04, 'deg': 233, 'gust': 0.72}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-20 09:00:00'}, {'dt': 1787227200, 'main': {'temp': 298.35, 'feels_like': 298.52, 'temp_min': 298.35, 'temp_max': 298.35, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 1000, 'humidity': 61, 'temp_kf': 0, 'dew_point': 289.52}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 2}, 'wind': {'speed': 4.46, 'deg': 252, 'gust': 3.36}, 'visibility': 9552, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-20 12:00:00'}, {'dt': 1787238000, 'main': {'temp': 301.93, 'feels_like': 302.31, 'temp_min': 301.93, 'temp_max': 301.93, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 996, 'humidity': 48, 'temp_kf': 0, 'dew_point': 288.18}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'clouds': {'all': 14}, 'wind': {'speed': 7.21, 'deg': 303, 'gust': 8.3}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-20 15:00:00'}, {'dt': 1787248800, 'main': {'temp': 300.38, 'feels_like': 301, 'temp_min': 300.38, 'temp_max': 300.38, 'pressure': 1012, 'sea_level': 1012, 'grnd_level': 995, 'humidity': 53, 'temp_kf': 0, 'dew_point': 289.24}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 7}, 'wind': {'speed': 5.05, 'deg': 340, 'gust': 9.39}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-20 18:00:00'}, {'dt': 1787259600, 'main': {'temp': 295.39, 'feels_like': 295.58, 'temp_min': 295.39, 'temp_max': 295.39, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 998, 'humidity': 73, 'temp_kf': 0, 'dew_point': 290.62}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 1}, 'wind': {'speed': 4.2, 'deg': 120, 'gust': 3.04}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-20 21:00:00'}, {'dt': 1787270400, 'main': {'temp': 294.03, 'feels_like': 294.29, 'temp_min': 294.03, 'temp_max': 294.03, 'pressure': 1015, 'sea_level': 1015, 'grnd_level': 998, 'humidity': 81, 'temp_kf': 0, 'dew_point': 290.83}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 2.27, 'deg': 132, 'gust': 1.64}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-21 00:00:00'}, {'dt': 1787281200, 'main': {'temp': 292.99, 'feels_like': 293.3, 'temp_min': 292.99, 'temp_max': 292.99, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 997, 'humidity': 87, 'temp_kf': 0, 'dew_point': 291}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 1.56, 'deg': 158, 'gust': 1.56}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-21 03:00:00'}, {'dt': 1787292000, 'main': {'temp': 292.21, 'feels_like': 292.55, 'temp_min': 292.21, 'temp_max': 292.21, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 996, 'humidity': 91, 'temp_kf': 0, 'dew_point': 291.04}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 1.27, 'deg': 167, 'gust': 0.96}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-21 06:00:00'}, {'dt': 1787302800, 'main': {'temp': 294.71, 'feels_like': 294.93, 'temp_min': 294.71, 'temp_max': 294.71, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 997, 'humidity': 77, 'temp_kf': 0, 'dew_point': 290.47}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 0}, 'wind': {'speed': 2.31, 'deg': 190, 'gust': 0.9}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-21 09:00:00'}, {'dt': 1787313600, 'main': {'temp': 297.99, 'feels_like': 298.17, 'temp_min': 297.99, 'temp_max': 297.99, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 997, 'humidity': 63, 'temp_kf': 0, 'dew_point': 289.94}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 2}, 'wind': {'speed': 4.56, 'deg': 252, 'gust': 3.65}, 'visibility': 8998, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-21 12:00:00'}, {'dt': 1787324400, 'main': {'temp': 300.31, 'feels_like': 301.06, 'temp_min': 300.31, 'temp_max': 300.31, 'pressure': 1011, 'sea_level': 1011, 'grnd_level': 994, 'humidity': 55, 'temp_kf': 0, 'dew_point': 289.64}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'clouds': {'all': 11}, 'wind': {'speed': 5.57, 'deg': 300, 'gust': 6.8}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-21 15:00:00'}, {'dt': 1787335200, 'main': {'temp': 299.62, 'feels_like': 299.62, 'temp_min': 299.62, 'temp_max': 299.62, 'pressure': 1010, 'sea_level': 1010, 'grnd_level': 993, 'humidity': 58, 'temp_kf': 0, 'dew_point': 290.23}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 7}, 'wind': {'speed': 6.78, 'deg': 328, 'gust': 7.75}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-21 18:00:00'}, {'dt': 1787346000, 'main': {'temp': 295.09, 'feels_like': 295.38, 'temp_min': 295.09, 'temp_max': 295.09, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 996, 'humidity': 78, 'temp_kf': 0, 'dew_point': 291.16}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 4.01, 'deg': 96, 'gust': 4.45}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-21 21:00:00'}, {'dt': 1787356800, 'main': {'temp': 294.23, 'feels_like': 294.53, 'temp_min': 294.23, 'temp_max': 294.23, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 997, 'humidity': 82, 'temp_kf': 0, 'dew_point': 291.25}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 3.56, 'deg': 125, 'gust': 3.1}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-22 00:00:00'}, {'dt': 1787367600, 'main': {'temp': 293.32, 'feels_like': 293.69, 'temp_min': 293.32, 'temp_max': 293.32, 'pressure': 1012, 'sea_level': 1012, 'grnd_level': 995, 'humidity': 88, 'temp_kf': 0, 'dew_point': 291.46}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 5}, 'wind': {'speed': 1.55, 'deg': 140, 'gust': 1}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-22 03:00:00'}, {'dt': 1787378400, 'main': {'temp': 292.62, 'feels_like': 293.05, 'temp_min': 292.62, 'temp_max': 292.62, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 996, 'humidity': 93, 'temp_kf': 0, 'dew_point': 291.67}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 1}, 'wind': {'speed': 1.54, 'deg': 165, 'gust': 1.12}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-22 06:00:00'}, {'dt': 1787389200, 'main': {'temp': 294.39, 'feels_like': 294.74, 'temp_min': 294.39, 'temp_max': 294.39, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 997, 'humidity': 83, 'temp_kf': 0, 'dew_point': 291.58}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'clouds': {'all': 18}, 'wind': {'speed': 2.71, 'deg': 165, 'gust': 1.12}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-22 09:00:00'}, {'dt': 1787400000, 'main': {'temp': 297.12, 'feels_like': 297.43, 'temp_min': 297.12, 'temp_max': 297.12, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 997, 'humidity': 71, 'temp_kf': 0, 'dew_point': 291.32}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'clouds': {'all': 19}, 'wind': {'speed': 3.98, 'deg': 255, 'gust': 2.62}, 'visibility': 9627, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-22 12:00:00'}, {'dt': 1787410800, 'main': {'temp': 299.26, 'feels_like': 299.26, 'temp_min': 299.26, 'temp_max': 299.26, 'pressure': 1011, 'sea_level': 1011, 'grnd_level': 995, 'humidity': 57, 'temp_kf': 0, 'dew_point': 289.67}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02d'}], 'clouds': {'all': 12}, 'wind': {'speed': 3.97, 'deg': 278, 'gust': 4.75}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-22 15:00:00'}, {'dt': 1787421600, 'main': {'temp': 298.27, 'feels_like': 298.35, 'temp_min': 298.27, 'temp_max': 298.27, 'pressure': 1011, 'sea_level': 1011, 'grnd_level': 995, 'humidity': 58, 'temp_kf': 0, 'dew_point': 289.29}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 6}, 'wind': {'speed': 1.32, 'deg': 301, 'gust': 3.71}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-22 18:00:00'}, {'dt': 1787432400, 'main': {'temp': 294, 'feels_like': 294.15, 'temp_min': 294, 'temp_max': 294, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 997, 'humidity': 77, 'temp_kf': 0, 'dew_point': 289.98}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 4.75, 'deg': 131, 'gust': 3.57}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-22 21:00:00'}, {'dt': 1787443200, 'main': {'temp': 292.59, 'feels_like': 292.76, 'temp_min': 292.59, 'temp_max': 292.59, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 998, 'humidity': 83, 'temp_kf': 0, 'dew_point': 289.91}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 4.45, 'deg': 113, 'gust': 4.91}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-23 00:00:00'}, {'dt': 1787454000, 'main': {'temp': 292.43, 'feels_like': 292.58, 'temp_min': 292.43, 'temp_max': 292.43, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 996, 'humidity': 83, 'temp_kf': 0, 'dew_point': 289.71}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 3.08, 'deg': 110, 'gust': 3.18}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-23 03:00:00'}, {'dt': 1787464800, 'main': {'temp': 291.91, 'feels_like': 292.09, 'temp_min': 291.91, 'temp_max': 291.91, 'pressure': 1014, 'sea_level': 1014, 'grnd_level': 997, 'humidity': 86, 'temp_kf': 0, 'dew_point': 289.85}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01n'}], 'clouds': {'all': 0}, 'wind': {'speed': 1.26, 'deg': 97, 'gust': 1.81}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2026-08-23 06:00:00'}, {'dt': 1787475600, 'main': {'temp': 293.9, 'feels_like': 294.02, 'temp_min': 293.9, 'temp_max': 293.9, 'pressure': 1015, 'sea_level': 1015, 'grnd_level': 999, 'humidity': 76, 'temp_kf': 0, 'dew_point': 289.73}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 0}, 'wind': {'speed': 1.16, 'deg': 215, 'gust': 1.51}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-23 09:00:00'}, {'dt': 1787486400, 'main': {'temp': 295.64, 'feels_like': 295.72, 'temp_min': 295.64, 'temp_max': 295.64, 'pressure': 1015, 'sea_level': 1015, 'grnd_level': 999, 'humidity': 68, 'temp_kf': 0, 'dew_point': 289.04}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'clouds': {'all': 4}, 'wind': {'speed': 4.47, 'deg': 251, 'gust': 3.49}, 'visibility': 9224, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2026-08-23 12:00:00'}], 'city': {'id': 2561668, 'name': 'Agadir', 'coord': {'lat': 30.4202, 'lon': -9.5982}, 'country': 'MA', 'population': 698310, 'timezone': 3600, 'sunrise': 1787033220, 'sunset': 1787080673}}
# Write JSON to file for viewing
with open('downloads/forecast.json', 'w') as f:
json.dump(responseF, f, indent=4)When and what?¶
Check contents and time stamps
# Content of responseF
responseF.keys()dict_keys(['cod', 'message', 'cnt', 'list', 'city'])# Number of forecasts
print(len(responseF["list"]))40
# Print forecast times
for forecast in responseF["list"]:
print(forecast["dt_txt"])2026-08-18 15:00:00
2026-08-18 18:00:00
2026-08-18 21:00:00
2026-08-19 00:00:00
2026-08-19 03:00:00
2026-08-19 06:00:00
2026-08-19 09:00:00
2026-08-19 12:00:00
2026-08-19 15:00:00
2026-08-19 18:00:00
2026-08-19 21:00:00
2026-08-20 00:00:00
2026-08-20 03:00:00
2026-08-20 06:00:00
2026-08-20 09:00:00
2026-08-20 12:00:00
2026-08-20 15:00:00
2026-08-20 18:00:00
2026-08-20 21:00:00
2026-08-21 00:00:00
2026-08-21 03:00:00
2026-08-21 06:00:00
2026-08-21 09:00:00
2026-08-21 12:00:00
2026-08-21 15:00:00
2026-08-21 18:00:00
2026-08-21 21:00:00
2026-08-22 00:00:00
2026-08-22 03:00:00
2026-08-22 06:00:00
2026-08-22 09:00:00
2026-08-22 12:00:00
2026-08-22 15:00:00
2026-08-22 18:00:00
2026-08-22 21:00:00
2026-08-23 00:00:00
2026-08-23 03:00:00
2026-08-23 06:00:00
2026-08-23 09:00:00
2026-08-23 12:00:00
Make plots of omnipresent measurements and events¶
We will later look at missing data, data only sporadically appearing and so on.
# Air pressure per period
pressures = []
timestamps = []
for forecast in responseF["list"]:
pressures.append(forecast["main"]["pressure"])
timestamps.append(dt.datetime.fromtimestamp(forecast["dt"]))import matplotlib.pyplot as plt
plt.bar(timestamps, pressures)
plt.xticks(rotation=45)
plt.ylim(960, 1050)
plt.grid()
plt.ylabel("Air pressure (hPa)")
plt.title(f"Forecasted air pressure in {CITY}")
plt.show()
Exercise¶
Make a new forecast request for your own hometown. Call your response something else than responseF.
If available, plot the humidity like we did with air pressure.
Precipitation¶
... comes in two main flavours: rain and snow.
We need to check which is present and set to zero if it is abscent.
rain = []
snow = []
for forecast in responseF["list"]:
try: # Check if rain is present in forecast
rain.append(forecast["rain"]["3h"])
except KeyError:
rain.append(0)
try: # Check if snow is present in forecast
snow.append(forecast["snow"]["3h"])
except KeyError:
snow.append(0)# Stacked bar chart with rain and snow
plt.bar(timestamps, rain, label="Rain")
plt.bar(timestamps, snow, label="Snow")
plt.xticks(rotation=45)
plt.grid()
plt.ylabel("Precipitation (mm)")
plt.title(f"Forecasted precipitation in {CITY}")
plt.legend()
plt.show()

Live coding¶
Create a Streamlit app with these elements:
City selector (can we make use og the Geocoding API?)
Property selector
Print selected data