Demonstration of API using OpenWeatherMap.org#

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 json

Current weather#

Common definitions to use for all requests#

BASE_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_KEY

Request 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': '02n'}], 'base': 'stations', 'main': {'temp': 280.25, 'feels_like': 278.88, 'temp_min': 280.25, 'temp_max': 281.66, 'pressure': 1032, 'humidity': 93, 'sea_level': 1032, 'grnd_level': 1016}, 'visibility': 10000, 'wind': {'speed': 2.09, 'deg': 164, 'gust': 6.2}, 'clouds': {'all': 18}, 'dt': 1759344384, 'sys': {'type': 2, 'id': 2006772, 'country': 'NO', 'sunrise': 1759296113, 'sunset': 1759337435}, '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.943844

Forecasted weather#

Common definitions to use for all requests#

BASE_URL = "https://api.openweathermap.org/data/2.5/forecast?"
CITY = "Mo i Rana"

urlF = BASE_URL + "q=" + CITY + "&appid=" + API_KEY

Request 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': 1759352400, 'main': {'temp': 281.61, 'feels_like': 280.62, 'temp_min': 280.39, 'temp_max': 281.61, 'pressure': 1027, 'sea_level': 1027, 'grnd_level': 975, 'humidity': 82, 'temp_kf': 1.22}, 'weather': [{'id': 802, 'main': 'Clouds', 'description': 'scattered clouds', 'icon': '03n'}], 'clouds': {'all': 28}, 'wind': {'speed': 1.92, 'deg': 122, 'gust': 1.74}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-01 21:00:00'}, {'dt': 1759363200, 'main': {'temp': 279.95, 'feels_like': 279.25, 'temp_min': 278.82, 'temp_max': 279.95, 'pressure': 1026, 'sea_level': 1026, 'grnd_level': 973, 'humidity': 83, 'temp_kf': 1.13}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02n'}], 'clouds': {'all': 17}, 'wind': {'speed': 1.42, 'deg': 100, 'gust': 1.45}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-02 00:00:00'}, {'dt': 1759374000, 'main': {'temp': 278.19, 'feels_like': 277.32, 'temp_min': 278.19, 'temp_max': 278.19, 'pressure': 1024, 'sea_level': 1024, 'grnd_level': 972, 'humidity': 82, 'temp_kf': 0}, 'weather': [{'id': 801, 'main': 'Clouds', 'description': 'few clouds', 'icon': '02n'}], 'clouds': {'all': 11}, 'wind': {'speed': 1.37, 'deg': 128, 'gust': 1.27}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-02 03:00:00'}, {'dt': 1759384800, 'main': {'temp': 278.28, 'feels_like': 276.56, 'temp_min': 278.28, 'temp_max': 278.28, 'pressure': 1024, 'sea_level': 1024, 'grnd_level': 972, 'humidity': 83, 'temp_kf': 0}, 'weather': [{'id': 803, 'main': 'Clouds', 'description': 'broken clouds', 'icon': '04d'}], 'clouds': {'all': 54}, 'wind': {'speed': 2.11, 'deg': 107, 'gust': 1.68}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-02 06:00:00'}, {'dt': 1759395600, 'main': {'temp': 282.13, 'feels_like': 281.44, 'temp_min': 282.13, 'temp_max': 282.13, 'pressure': 1022, 'sea_level': 1022, 'grnd_level': 970, 'humidity': 68, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.69, 'deg': 72, 'gust': 2.1}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-02 09:00:00'}, {'dt': 1759406400, 'main': {'temp': 284.78, 'feels_like': 283.49, 'temp_min': 284.78, 'temp_max': 284.78, 'pressure': 1020, 'sea_level': 1020, 'grnd_level': 969, 'humidity': 57, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.67, 'deg': 99, 'gust': 2.23}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-02 12:00:00'}, {'dt': 1759417200, 'main': {'temp': 283.64, 'feels_like': 282.47, 'temp_min': 283.64, 'temp_max': 283.64, 'pressure': 1019, 'sea_level': 1019, 'grnd_level': 968, 'humidity': 66, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.19, 'deg': 141, 'gust': 0.8}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-02 15:00:00'}, {'dt': 1759428000, 'main': {'temp': 282.49, 'feels_like': 281.75, 'temp_min': 282.49, 'temp_max': 282.49, 'pressure': 1019, 'sea_level': 1019, 'grnd_level': 968, 'humidity': 72, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.8, 'deg': 121, 'gust': 1.71}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-02 18:00:00'}, {'dt': 1759438800, 'main': {'temp': 282.44, 'feels_like': 282.12, 'temp_min': 282.44, 'temp_max': 282.44, 'pressure': 1019, 'sea_level': 1019, 'grnd_level': 967, 'humidity': 72, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.38, 'deg': 87, 'gust': 0.84}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-02 21:00:00'}, {'dt': 1759449600, 'main': {'temp': 282.72, 'feels_like': 282.72, 'temp_min': 282.72, 'temp_max': 282.72, 'pressure': 1018, 'sea_level': 1018, 'grnd_level': 967, 'humidity': 73, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.31, 'deg': 84, 'gust': 0.89}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-03 00:00:00'}, {'dt': 1759460400, 'main': {'temp': 282.81, 'feels_like': 282.26, 'temp_min': 282.81, 'temp_max': 282.81, 'pressure': 1017, 'sea_level': 1017, 'grnd_level': 966, 'humidity': 77, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.65, 'deg': 59, 'gust': 0.86}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-03 03:00:00'}, {'dt': 1759471200, 'main': {'temp': 283.15, 'feels_like': 282.4, 'temp_min': 283.15, 'temp_max': 283.15, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 965, 'humidity': 77, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.93, 'deg': 73, 'gust': 1.29}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-03 06:00:00'}, {'dt': 1759482000, 'main': {'temp': 284.53, 'feels_like': 283.55, 'temp_min': 284.53, 'temp_max': 284.53, 'pressure': 1016, 'sea_level': 1016, 'grnd_level': 965, 'humidity': 70, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.37, 'deg': 98, 'gust': 1.47}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-03 09:00:00'}, {'dt': 1759492800, 'main': {'temp': 285.84, 'feels_like': 284.94, 'temp_min': 285.84, 'temp_max': 285.84, 'pressure': 1015, 'sea_level': 1015, 'grnd_level': 964, 'humidity': 68, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 2.9, 'deg': 114, 'gust': 3.1}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-03 12:00:00'}, {'dt': 1759503600, 'main': {'temp': 284.82, 'feels_like': 283.9, 'temp_min': 284.82, 'temp_max': 284.82, 'pressure': 1013, 'sea_level': 1013, 'grnd_level': 963, 'humidity': 71, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 98}, 'wind': {'speed': 2.98, 'deg': 97, 'gust': 3.61}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-03 15:00:00'}, {'dt': 1759514400, 'main': {'temp': 283.54, 'feels_like': 282.65, 'temp_min': 283.54, 'temp_max': 283.54, 'pressure': 1012, 'sea_level': 1012, 'grnd_level': 962, 'humidity': 77, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 99}, 'wind': {'speed': 2.79, 'deg': 86, 'gust': 3.55}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-03 18:00:00'}, {'dt': 1759525200, 'main': {'temp': 282.97, 'feels_like': 281.37, 'temp_min': 282.97, 'temp_max': 282.97, 'pressure': 1010, 'sea_level': 1010, 'grnd_level': 960, 'humidity': 82, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 3.13, 'deg': 73, 'gust': 3.05}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-03 21:00:00'}, {'dt': 1759536000, 'main': {'temp': 282.19, 'feels_like': 280.1, 'temp_min': 282.19, 'temp_max': 282.19, 'pressure': 1008, 'sea_level': 1008, 'grnd_level': 957, 'humidity': 77, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 85}, 'wind': {'speed': 3.74, 'deg': 80, 'gust': 3.14}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-04 00:00:00'}, {'dt': 1759546800, 'main': {'temp': 282.25, 'feels_like': 280.02, 'temp_min': 282.25, 'temp_max': 282.25, 'pressure': 1004, 'sea_level': 1004, 'grnd_level': 954, 'humidity': 73, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04n'}], 'clouds': {'all': 99}, 'wind': {'speed': 4.06, 'deg': 80, 'gust': 4.22}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-04 03:00:00'}, {'dt': 1759557600, 'main': {'temp': 280.57, 'feels_like': 277.91, 'temp_min': 280.57, 'temp_max': 280.57, 'pressure': 1003, 'sea_level': 1003, 'grnd_level': 952, 'humidity': 75, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 4.15, 'deg': 72, 'gust': 3.86}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-04 06:00:00'}, {'dt': 1759568400, 'main': {'temp': 283.42, 'feels_like': 281.96, 'temp_min': 283.42, 'temp_max': 283.42, 'pressure': 998, 'sea_level': 998, 'grnd_level': 948, 'humidity': 56, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 4.51, 'deg': 78, 'gust': 11.4}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-04 09:00:00'}, {'dt': 1759579200, 'main': {'temp': 284.51, 'feels_like': 282.93, 'temp_min': 284.51, 'temp_max': 284.51, 'pressure': 994, 'sea_level': 994, 'grnd_level': 944, 'humidity': 47, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 100}, 'wind': {'speed': 5.63, 'deg': 118, 'gust': 16.28}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-04 12:00:00'}, {'dt': 1759590000, 'main': {'temp': 281.71, 'feels_like': 278.7, 'temp_min': 281.71, 'temp_max': 281.71, 'pressure': 989, 'sea_level': 989, 'grnd_level': 939, 'humidity': 71, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 5.61, 'deg': 114, 'gust': 13.93}, 'visibility': 8948, 'pop': 1, 'rain': {'3h': 1.36}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-04 15:00:00'}, {'dt': 1759600800, 'main': {'temp': 280.86, 'feels_like': 278.2, 'temp_min': 280.86, 'temp_max': 280.86, 'pressure': 986, 'sea_level': 986, 'grnd_level': 936, 'humidity': 86, 'temp_kf': 0}, 'weather': [{'id': 501, 'main': 'Rain', 'description': 'moderate rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 4.29, 'deg': 114, 'gust': 12.01}, 'visibility': 6575, 'pop': 1, 'rain': {'3h': 5.15}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-04 18:00:00'}, {'dt': 1759611600, 'main': {'temp': 280.37, 'feels_like': 277.3, 'temp_min': 280.37, 'temp_max': 280.37, 'pressure': 983, 'sea_level': 983, 'grnd_level': 933, 'humidity': 90, 'temp_kf': 0}, 'weather': [{'id': 501, 'main': 'Rain', 'description': 'moderate rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 4.91, 'deg': 97, 'gust': 11.35}, 'visibility': 8388, 'pop': 1, 'rain': {'3h': 4.77}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-04 21:00:00'}, {'dt': 1759622400, 'main': {'temp': 279.95, 'feels_like': 277.13, 'temp_min': 279.95, 'temp_max': 279.95, 'pressure': 981, 'sea_level': 981, 'grnd_level': 931, 'humidity': 92, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 4.17, 'deg': 86, 'gust': 6.67}, 'visibility': 9476, 'pop': 1, 'rain': {'3h': 0.61}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-05 00:00:00'}, {'dt': 1759633200, 'main': {'temp': 279.82, 'feels_like': 277.15, 'temp_min': 279.82, 'temp_max': 279.82, 'pressure': 980, 'sea_level': 980, 'grnd_level': 930, 'humidity': 96, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10n'}], 'clouds': {'all': 99}, 'wind': {'speed': 3.84, 'deg': 96, 'gust': 4.91}, 'visibility': 1834, 'pop': 0.2, 'rain': {'3h': 0.12}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-05 03:00:00'}, {'dt': 1759644000, 'main': {'temp': 279.99, 'feels_like': 277.47, 'temp_min': 279.99, 'temp_max': 279.99, 'pressure': 979, 'sea_level': 979, 'grnd_level': 929, 'humidity': 95, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 99}, 'wind': {'speed': 3.63, 'deg': 94, 'gust': 4.82}, 'visibility': 6356, 'pop': 0.2, 'rain': {'3h': 0.1}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-05 06:00:00'}, {'dt': 1759654800, 'main': {'temp': 280.39, 'feels_like': 277.88, 'temp_min': 280.39, 'temp_max': 280.39, 'pressure': 980, 'sea_level': 980, 'grnd_level': 930, 'humidity': 94, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 3.78, 'deg': 104, 'gust': 6.89}, 'visibility': 5433, 'pop': 1, 'rain': {'3h': 1}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-05 09:00:00'}, {'dt': 1759665600, 'main': {'temp': 281.66, 'feels_like': 280.26, 'temp_min': 281.66, 'temp_max': 281.66, 'pressure': 980, 'sea_level': 980, 'grnd_level': 931, 'humidity': 91, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 2.43, 'deg': 137, 'gust': 5.44}, 'visibility': 10000, 'pop': 1, 'rain': {'3h': 1.12}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-05 12:00:00'}, {'dt': 1759676400, 'main': {'temp': 280.42, 'feels_like': 279.38, 'temp_min': 280.42, 'temp_max': 280.42, 'pressure': 984, 'sea_level': 984, 'grnd_level': 934, 'humidity': 96, 'temp_kf': 0}, 'weather': [{'id': 502, 'main': 'Rain', 'description': 'heavy intensity rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.78, 'deg': 203, 'gust': 3.37}, 'visibility': 2494, 'pop': 1, 'rain': {'3h': 12.93}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-05 15:00:00'}, {'dt': 1759687200, 'main': {'temp': 282.41, 'feels_like': 278.62, 'temp_min': 282.41, 'temp_max': 282.41, 'pressure': 989, 'sea_level': 989, 'grnd_level': 939, 'humidity': 94, 'temp_kf': 0}, 'weather': [{'id': 502, 'main': 'Rain', 'description': 'heavy intensity rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 8.94, 'deg': 238, 'gust': 13}, 'visibility': 5569, 'pop': 1, 'rain': {'3h': 12.06}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-05 18:00:00'}, {'dt': 1759698000, 'main': {'temp': 281.6, 'feels_like': 277.7, 'temp_min': 281.6, 'temp_max': 281.6, 'pressure': 993, 'sea_level': 993, 'grnd_level': 943, 'humidity': 96, 'temp_kf': 0}, 'weather': [{'id': 501, 'main': 'Rain', 'description': 'moderate rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 8.39, 'deg': 235, 'gust': 15.27}, 'visibility': 2088, 'pop': 1, 'rain': {'3h': 4.12}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-05 21:00:00'}, {'dt': 1759708800, 'main': {'temp': 281.62, 'feels_like': 278.16, 'temp_min': 281.62, 'temp_max': 281.62, 'pressure': 996, 'sea_level': 996, 'grnd_level': 945, 'humidity': 85, 'temp_kf': 0}, 'weather': [{'id': 501, 'main': 'Rain', 'description': 'moderate rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 6.89, 'deg': 240, 'gust': 10.86}, 'visibility': 10000, 'pop': 1, 'rain': {'3h': 4.44}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-06 00:00:00'}, {'dt': 1759719600, 'main': {'temp': 281.45, 'feels_like': 280.26, 'temp_min': 281.45, 'temp_max': 281.45, 'pressure': 997, 'sea_level': 997, 'grnd_level': 946, 'humidity': 89, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10n'}], 'clouds': {'all': 99}, 'wind': {'speed': 2.12, 'deg': 183, 'gust': 2.46}, 'visibility': 10000, 'pop': 1, 'rain': {'3h': 0.68}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-06 03:00:00'}, {'dt': 1759730400, 'main': {'temp': 281.75, 'feels_like': 280.5, 'temp_min': 281.75, 'temp_max': 281.75, 'pressure': 997, 'sea_level': 997, 'grnd_level': 946, 'humidity': 88, 'temp_kf': 0}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': 'overcast clouds', 'icon': '04d'}], 'clouds': {'all': 99}, 'wind': {'speed': 2.26, 'deg': 170, 'gust': 2.53}, 'visibility': 10000, 'pop': 0.78, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-06 06:00:00'}, {'dt': 1759741200, 'main': {'temp': 282, 'feels_like': 281.14, 'temp_min': 282, 'temp_max': 282, 'pressure': 996, 'sea_level': 996, 'grnd_level': 946, 'humidity': 88, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.85, 'deg': 130, 'gust': 2.08}, 'visibility': 10000, 'pop': 0.79, 'rain': {'3h': 0.38}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-06 09:00:00'}, {'dt': 1759752000, 'main': {'temp': 283.62, 'feels_like': 282.86, 'temp_min': 283.62, 'temp_max': 283.62, 'pressure': 994, 'sea_level': 994, 'grnd_level': 944, 'humidity': 82, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 0.87, 'deg': 119, 'gust': 1.02}, 'visibility': 10000, 'pop': 0.94, 'rain': {'3h': 0.67}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-06 12:00:00'}, {'dt': 1759762800, 'main': {'temp': 283.62, 'feels_like': 282.89, 'temp_min': 283.62, 'temp_max': 283.62, 'pressure': 991, 'sea_level': 991, 'grnd_level': 941, 'humidity': 83, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 2.5, 'deg': 84, 'gust': 2.58}, 'visibility': 10000, 'pop': 1, 'rain': {'3h': 0.84}, 'sys': {'pod': 'd'}, 'dt_txt': '2025-10-06 15:00:00'}, {'dt': 1759773600, 'main': {'temp': 282.28, 'feels_like': 280.33, 'temp_min': 282.28, 'temp_max': 282.28, 'pressure': 988, 'sea_level': 988, 'grnd_level': 938, 'humidity': 88, 'temp_kf': 0}, 'weather': [{'id': 500, 'main': 'Rain', 'description': 'light rain', 'icon': '10n'}], 'clouds': {'all': 100}, 'wind': {'speed': 3.51, 'deg': 118, 'gust': 4.31}, 'visibility': 10000, 'pop': 1, 'rain': {'3h': 1.5}, 'sys': {'pod': 'n'}, 'dt_txt': '2025-10-06 18:00:00'}], 'city': {'id': 3145614, 'name': 'Mo i Rana', 'coord': {'lat': 66.3128, 'lon': 14.1428}, 'country': 'NO', 'population': 17853, 'timezone': 7200, 'sunrise': 1759295659, 'sunset': 1759336302}}
# 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"])
2025-10-01 21:00:00
2025-10-02 00:00:00
2025-10-02 03:00:00
2025-10-02 06:00:00
2025-10-02 09:00:00
2025-10-02 12:00:00
2025-10-02 15:00:00
2025-10-02 18:00:00
2025-10-02 21:00:00
2025-10-03 00:00:00
2025-10-03 03:00:00
2025-10-03 06:00:00
2025-10-03 09:00:00
2025-10-03 12:00:00
2025-10-03 15:00:00
2025-10-03 18:00:00
2025-10-03 21:00:00
2025-10-04 00:00:00
2025-10-04 03:00:00
2025-10-04 06:00:00
2025-10-04 09:00:00
2025-10-04 12:00:00
2025-10-04 15:00:00
2025-10-04 18:00:00
2025-10-04 21:00:00
2025-10-05 00:00:00
2025-10-05 03:00:00
2025-10-05 06:00:00
2025-10-05 09:00:00
2025-10-05 12:00:00
2025-10-05 15:00:00
2025-10-05 18:00:00
2025-10-05 21:00:00
2025-10-06 00:00:00
2025-10-06 03:00:00
2025-10-06 06:00:00
2025-10-06 09:00:00
2025-10-06 12:00:00
2025-10-06 15:00:00
2025-10-06 18: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(980, 1050)
plt.grid()
plt.ylabel("Air pressure (hPa)")
plt.title(f"Forecasted air pressure in {CITY}")
plt.show()
../../_images/259c59551d4df8203a53be99be4a9f718a99b0ea1cac8b24f1e92814083bed8f.png

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()
../../_images/0ae7b25bec756e3858a2326623f8436a19ab83c4fdb4438ec59da962783ef3a4.png

Live coding#

  • Create a Streamlit app with these elements:

    • City selector (can we make use og the Geocoding API?)

    • Property selector

    • Plot of selected data