nc-state logo
Summer 2 Python Assignment: OpenWeatherMap Weather Forecast
Christopher G. Healey

Due Date

Monday, July 17, 5:00pm via Moodle. Look for the "Python Programming: OpenWeatherMap Moodle Submission" link.

Introduction

The assignment for this year's Summer Session 2 Python module involves using the OpenWeatherMap weather API and simple analytics on forecast weather data. You will be asked to:

  1. Use the OpenWeatherMap API to query future-day forecasts containing expected daily weather conditions for 16 different cities.
  2. Parse the Python variables returned by the API to extract the the minimum and maximum forecast temperature temperatureMini and temperatureMaxi in Celsius for each of the upcoming four (4) days.
  3. Compute the average minimum and maximum forecast temperatures Minavg and Maxavg for the upcoming four (4) days.
  4. Write the location description loc we provide below, the four minimum and maximum forecast temperatures, and the overall minimum and maximum forecast temperatures to a CSV file named temp.csv, one line per city.

OpenWeatherMap API

In order to use the OpenWeatherMap API, you must first register with the site to obtain a free developer's API key. This key is required for every query you make, to track your use of the site.

  1. Go to the OpenWeatherMap sign-up page.
  2. Enter a username, your NCSU email, and choose a password in the appropriate fields.
  3. Click "I am 16 years old and over", "I agree with Privacy Policy, Terms and conditions of sale and Websites terms and conditions of use", and "I'm not a robot."
  4. Click "Create Account."
  5. In the pop-up window that appears, enter NCSU as the Company and choose Education/Science in the Purpose pop-up dialog, then click Save.
  6. Look for a verification email from the OpenWeather Team and click the "Verify your email" button to activate your account.
  7. Click the Billing plans link near the top of the page and you will be taken to the billing plan page, where you can confirm that by default you have been given a Free plan with 60 calls per minute.
  8. Click on the API keys link and you will see the default API key created for you. You will need this key to make calls to the Open Weather Map API.

It may take a few hours for your API key to activate. Wait at least a day before checking on API calls returning code 401 (Invalid API key.)

Take careful note of the query restrictions placed on free accounts. You are only allowed to make 60 queries per minute, after which queries will be blocked. You should plan your development accordingly.

As an example, here is some simple Python code that gets the four-day forecast for Peterhead, Scotland. You will want to focus on the forecase API call, since this will contain the information you need to build your 4-day forecasts. I've obfuscated my API key, so you would insert your own key as a string for the api_key variable.

Code: import pprint import requests import sys api_key = 'XXXXX' # Geolocate Peterhead, Scotland to get it's latitude and longitude URL = 'http://api.openweathermap.org/geo/1.0/direct' city = 'Peterhead,Scotland' geo = f'{URL}?q={city}&limit=5&appid={api_key}' resp = requests.get( geo ) if resp.status_code != 200: # Failure? print( f'Error geocoding {city}: {resp.status_code}' ) sys.exit( 1 ) # OpenWeatherMap returns a list of matching cities, up to the limit specified # in the API call; even if you only ask for one city (limit=5), it's still # returned as a 1-element list if len( resp.json() ) == 0: # No such city? print( f'Error locating city {city}; {resp.status_code}' ) sys.exit( 2 ) json = resp.json() if type( json ) == list: # List of cities? lat = json[ 0 ][ 'lat' ] lon = json[ 0 ][ 'lon' ] else: # Unknown city? print( f'Error, invalid data returned for city {city}, {resp.status_code}' ) sys.exit( 3 ) # Use Peterhead's latitude and longitude to get it's 5-day forecast in 3-hour # blocks URL = 'http://api.openweathermap.org/data/2.5/forecast' forecast = f'{URL}?lat={lat}&lon={lon}&appid={api_key}' resp = requests.get( forecast ) if resp.status_code != 200: # Failure? print( f'Error retrieving data: {resp.status_code}' ) sys.exit( 4 ) # Pretty-print the resulting JSON forecast for the first 3 hour block print( f'{city}:' ) data = resp.json() printer = pprint.PrettyPrinter( width=80, compact=True ) printer.pprint( data[ 'list' ][ 0 ] ) Result: Peterhead,Scotland: {'clouds': {'all': 65}, 'dt': 16294716000 'dt_txt': '2021-08-20 15:00:00', 'main': {'feels_like': 285.58, 'grnd_level': 1013, 'humidity': 81, 'pressure': 1016, 'sea_level': 1016, 'temp': 286.11, 'temp_kf': -0.18, 'temp_max': 286.29, 'temp_min': 286.11}, 'pop': 0, 'sys': {'pod': 'd'}, 'visibility': 10000, 'weather': [{'description': 'broken clouds', 'icon': '04d', 'id': 803, 'main': 'Clouds'}], 'wind': {'deg': 123, 'gust': 5.45,'speed': 5.06}}

Replace XXXXX with the API key you were issued by the OpenWeatherMap site. The variable data will contain Python-encoded representations of numerous fields with information on Peterhead and its forecasted weather. data[ 'list' ] is just one of the fields available. You can print data to view the different dictionary entries available. Note that OpenWeatherMap returns a 40-element array data[ 'list' ] with entry 0 corresponding to the first three-hour block, and entry 39 corresponding to the last three-hour block. Also note that the default temperature units are Kelvin, which is why the values seem high (286.11 Kelvin is 55.33 Fahrenheit or 12.96 Celsius.) More information about the 5-day/3-hour forecast call is available on OpenWeatherMap's API reference. Finally, note that we use the geo API to convert a city's name and country into a latitude and longitude needed to identify the location were we want to query a weather forecast.

http://api.openweathermap.org/geo/1.0/direct?q=Nanaimo,British Columbia&limit=1&appid=XXXXX

Cities to Query

Below is a list of the 16 cities to query. We have tested the name and country of each city to ensure OpenWeatherMap's API will return proper data if you specify use the geo API to convert the city to a latitude and longitude, then use the latitude and longitude to retrieve the 5 day/3 hour forecast data.

  1. Guilin, China
  2. Dissen, Germany
  3. Guatemala City, Guatemala
  4. Kandukur, India
  5. Nanaimo, British Columbia
  6. Uijeongbu-si, South Korea
  7. Yangon, Myanmar
  8. Jalpa de Mendez, Mexico
  9. Enugu, Nigeria
  10. Peterhead, Scotland
  11. Lima, Peru
  12. Singapore, Singapore
  13. Kaohsiung, Taiwan
  14. Grimesland, North Carolina
  15. Visalia, California
  16. Colonia del Sacramento, Uruguay

You can hard-code these city and country names directly into your program. There is no requirement that you provide any mechanism to enter them into the program as it runs. We will modify your code as needed if we want to run it on cities that are different than the ones we gave you to test with.

loc = [
  'Guilin,China',
  'Dissen,Germany',
  'Guatemala City,Guatemala',
...
  'Visalia,California',
  "Colonia del Sacramento,Uruguay'
]

Locating "Tomorrow"

The 4-day forecast you build starts at midnight tomorrow, and includes tomorrow plus the three days following tomorrow. For example, if the date when you run your program is August 23, you would provide a 4-day forecast for August 24 through August 28.

OpenWeatherMap always returns dates and times in UTC (Coordinated Universal Time or Greenwich Mean Time.) This means that, technically, to get the proper forecast for a general location, you would first need to convert all dates and times from UTC to the timezone of the location, then use these to identify the first three-hour block corresponding to 12am-3am in the target city's timezone.

Unfortunately, this is non-trivial for a variety of reasons: certain countries define non-standard time zones, daylight savings time is used in some countries (or parts of countries) but not others, and so on. Because of this, we will allow you to use the date and time OpenWeatherMap returns as though it were properly corrected for the timezone of the city you query. This means the 4-day forecast will most likely be offset forward some number of three-hour multiples, but for the purpose of the assignment, this is not critical.

To find the first block that corresponds to the beginning of "tomorrow", start at block data[ 'list' ][ 0 ] and look at the dt_txt field. If it contains the time 00:00:00, this is the first block for tomorrow. If it does not contain 00:00:00, move to the next block data[ 'list' ][ 1 ] and see if that block's dt_txt contains 00:00:00. Continue searching forward one block at a time until you find the first occurrence of midnight (00:00:00). This identifies the block at the beginning of tomorrow. Each day is eight blocks long (eight 3-hour blocks spans 24 hours). For example, if you determine block 3 is the start of tomorrow, you now know that blocks 3–10 cover all of tomorrow, blocks 11–18 cover all of the day after tomorrow, and so on.

Determining a Day's Minimum and Maximum Temperature

Once you have the eight forecasts for minimum temperatures and the eight forecasts for maximum temperatures for a given day, the minimum you need to extract is the smallest of the eight forecast minimum temperatures. Similarly, the maximum you need to extract is the largest of the eight forecast maximum temperatures. These are the values you should write as \(min_{i}\) and \(max_{i}\) for day \(i\).

CSV Output

After you have completed retrieving data from the OpenWeatherMap site, write your results to an output file called temp.csv. Each line will correspond to a single city, and will contain the following entries

\(loc\),\(min_1\),\(max_1\), \(min_4\), \(max_4\),\(\ldots\),\(min_{\textrm{avg}}\),\(max_{\textrm{avg}}\)

where \(min_i\) corresponds to the minimum forecast temperature in Celsius for \(i\) days in the future, \(max_i\) corresponds to the maximum forecast temperature in Celsius for \(i\) days in the future, and \(min_{\textrm{avg}}\) and \(max_{\textrm{avg}}\) correspond to the average minimum and maximum temperature. In your case, \(i\) ranges from 1 to 4.

Your CSV file must also contain a header line as its first line, formatted as follows.

City,Min 1,Max 1, ... Min 4,Max 4,Min Avg,Max Avg

Below is an example of the output you should create in your CSV file. Note that these are just examples, and are not the ones your program will generate, since it will be run sometime in the future.

City,Min 1,Max 1,Min 2,Max 2,Min 3,Max 3,Min 4,Max 4,Min Avg,Max Avg
"Guilin, China",11.05,15.29,12.14,14.93,6.05,15.24,8.36,13.42,9.40,14.72
"Dissen, Germany",28.25,33.52,25.86,31.00,24.52,26.01,25.20,30.52,25.96,30.26
...
"Colonia del Sacramento, Uruguay",25.62,29.77,25.47,30.46,26.07,31.01,26.52,31.48,25.92,30.68

Note: Your CSV output must match ours EXACTLY. Pay special attention to the specific wording and order of items in the header line, the exact order of temperatures in the data lines, and the fact that the city and country are separated by comma and space (e.g., "City, Country", NOT "City,Country", with double quotes around the city name and country, NOT without them).

OpenWeatherMap returns temperatures with up to two decimal places of precision. You should ensure that your average minimum and maximum forecast temperatures Minavg and Maxavg are output with EXACTLY two decimal places of precision ("exactly" means if the temperature is 29.2, you would write 29.20 to your output file, NOT 29.2).

When you examine your file temp.csv to validate its content, DO NOT DO IT IN EXCEL. Excel will truncate decimal values. This means if the file contains 12.00, it will appear as 12 in Excel, and you will think your program is not generating two decimals of precision properly. If you load temp.csv into a text editor like Notepad, you will most likely see 12.00, exactly as expected. Lesson: Excel will screw you. Do not trust it.

Grading

Your completed program is due by 5:00pm EST on Monday, July 17. Each student must submit their Python code using Moodle. Look for "Python Programming: OpenWeatherMap API Assignment" in the Programming → Python section on Moodle's AA 500 (001) course page.

Although it might seem odd to specify these, here are things we DO NOT want you to submit.

  1. Do not submit a Jupyter Notebook (an .ipynb file). We want a Python source code file (a .py file) that we can run with Python directly from the command line. You can export a Python from from a Jupyter notebook, if needed.
  2. Do not submit any CSV files of temperature data. We will run your program to generate the temp.csv file. It would be useless to submit a CSV file, because the values it contains depends on when your program is run.

Your program will be graded on a 101-point scale from 0 to 100. Grading will be performed in two parts.

  1. We will run your program and examine its temp.csv output file to our known, correct answers.
  2. We will run your program on a small number of additional cities, to determine whether it can correctly parse and analyze a standard OpenWeatherMap forecast.

Please pay special attention to requirement 2. This means you cannot hard-code any temperature values into your program. Each result you write to the CSV file must be based on values parsed directly from OpenWeatherMap's results for the given city and day the program is run.

Collaboration

Because this is one of the first assignments where you will not be working in teams, I want to provide some guidelines on the types of collaboration that are considered acceptable and not acceptable for this assignment.

Acceptable collaboration would include:

When you sit down to code your assignment, you will do this by yourself. You cannot collaborate with your classmates when you write your code. It must be done individually, and without assistance from other students that include:

Submission of your code means you've implicitly agreed to these collaboration guidelines, and have not participated in any type of collaboration that would be considered inappropriate.

If you have any questions about whether a specific collaboration is allowed, please ask either myself or Andrea. We are happy to discuss where the lines lie with respect to how you can communicate with your classmates about the assignment.