Rest API / String Formatting in Python

How did this adventure begin?

My girlfriend has gone on a research trip recently! Normally I wouldn't start my blog posts out that way, however, it's relevant. Her research vessel actually has some data available, publicly, here: http://webcam.oregonstate.edu/tracker/.

There's some cool data there:

  • Temperatures
  • Depth
  • Wind
  • Latitude
  • Longitude

I initially thought this was going to be an endeavor in web parsing, but then I looked at the source of the website. I eventually came across this nifty javascript function they are using:

Particularly handy is the URL: https://app.uhds.oregonstate.edu/api/webcam/ship. I am more familiar with PowerShell than Python, so just to test it out before I learned how to get the data in Python, I used PowerShell to see what data was available.

Initial Data Grab Via PowerShell

This was an extremely simple, yet validating part of the equation.

$url = 'https://app.uhds.oregonstate.edu/api/webcam/ship'
$data = Invoke-RestMethod -Uri $url
$data.count
$data[0]

Sweet! That's what we want. Well, what I was looking for.

Making it work in Python

To make this work in Python, I needed to do a few things.

  • Get the data, preferably as JSON/a dictionary in Python
  • Convert Celsius to Fahrenheit
  • Convert Knots to Mph
  • Format the data and print it out

Getting the Data

For this to work, we need to use the requests library in Python. So the very first line we'll need is:

import requests

To get the data , I built out this function:

def get_data():
    ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"
    request_data = requests.get(ship_api_url)
    return request_data.json()

First, I start out by storing the URL we used earlier in the variable ship_api_url:

ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"

Then, I make the request and store the results:

request_data = requests.get(ship_api_url)

And finally, I return the results as a dictionary from the request converted to JSON:

return request_data.json()

I wanted to test out what I had so far, so our script looks like this:

import requests

def get_data():
    ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"
    request_data = requests.get(ship_api_url)
    return request_data.json()

data = get_data()
print(data[0])

Annnd the results:

Now to get to work!

Converting Values

Now it was time to start converting some of the values. 

I made a function that converts Celsius to Fahrenheit, and then one that converts knots to mph.

First I needed the math:

C to F conversion:

9.0 / 5.0 * temp_in_c + 32

Knots to Mph conversion:

1.1507 * knot

With that in mind, here is the code for the two functions I made:

def convert_c_to_f(temp):
    "Converts Celsius to Fahrenheit."
    conversion = round(9.0 / 5.0 * temp + 32, 2)
    return conversion

def convert_knot_to_mph(knot):
    "Converts wind from knots to mph"
    conversion = round(1.1507 * knot, 2)
    return conversion

I added in some rounding there to ensure we only get up to two decimal places.

String Formatting

The last step for me was to format all of the data, and present it how I wanted it to be presented. To do this I created a function that takes the data and formats it.
It uses a multi line string plus the string format method at the end so I could insert the values that I wanted. 

Here's the function I created for that:

def format_data(data_to_format):
    "Formats the data how we want it"
    formatted = """
    Air Temp [{0} F] Water Temp [{1} F]
    Wind [{2} mph] Depth [{3} meters]
    Lat [{4}] Long [{5}]    
    Current Location: https://www.google.com/maps/place/{4},{5}
    *note* You may need to zoom out on the map to see the relative location!
    """.format(convert_c_to_f(data_to_format['air_temp']),
               convert_c_to_f(data_to_format['water_temp']),
               convert_knot_to_mph(data_to_format['wind']),
               data_to_format['depth'], data_to_format['lat'], data_to_format['lng'])
    return formatted

You can see in the above code snippet that I used the first value of the data array, and for some of the values used the appropriate conversion functions we created earlier.

So what's it look like, now?

Here's all of the current code:

import requests

def get_data():
    "Gets api data"
    ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"
    request_data = requests.get(ship_api_url)
    return request_data.json()

def convert_c_to_f(temp):
    "Converts Celsius to Fahrenheit."
    conversion = round(9.0 / 5.0 * temp + 32, 2)
    return conversion

def convert_knot_to_mph(knot):
    "Converts wind from knots to mph"
    conversion = round(1.1507 * knot, 2)
    return conversion

def format_data(data_to_format):
    "Formats the data how we want it"
    formatted = """
    Air Temp [{0} F] Water Temp [{1} F]
    Wind [{2} mph] Depth [{3} meters]
    Lat [{4}] Long [{5}]    
    Current Location: https://www.google.com/maps/place/{4},{5}
    *note* You may need to zoom out on the map to see the relative location!
    """.format(convert_c_to_f(data_to_format['air_temp']),
               convert_c_to_f(data_to_format['water_temp']),
               convert_knot_to_mph(data_to_format['wind']),
               data_to_format['depth'], data_to_format['lat'], data_to_format['lng'])
    return formatted

data = get_data()
latest_dataset = data[0]
print(format_data(latest_dataset))

And after running it, here are the results:

Conclusion

I had two goals in doing this. 

  1. Learn a little bit more Python
  2. Make a command for my Python Discord bot that displays the ship's data, as well as the current web cam image (as the website only displayed one OR the other)

I used what we created above, and added a command to my bot which displays the data and the image! Here is the result of that:

Have a question, or know of a different way to achieve the same results? Leave a comment and say hi!