Python + Folium + Oracle REST APIs (aka ORDS)

Willkommen

I stumbled upon a new [to me] python library called Folium. It’s a mapping tool that enables python developers (or is it programmers, which is less offensive?) to visualize data on a Leaflet map.

About folium

Folium makes it easy to visualize data that’s been manipulated in Python on an interactive leaflet map. It enables both the binding of data to a map for choropleth visualizations as well as passing rich vector/raster/HTML visualizations as markers on the map.

The library has a number of built-in tilesets from OpenStreetMap, Mapbox, and Stamen, and supports custom tilesets with Mapbox or Cloudmade API keys. Folium supports Image/Video, GeoJSON and TopoJSON overlays.

Folium docs

…but what about leaflet.js?

Leaflet.js is the leading open-source JavaScript library for mobile-friendly interactive maps. Out-of-the-box features include: tile layers/WMS, markers/popups, vector layers (polylines, polygons, circles, rectangles), image overlays, and GeoJSON

Leaflet.js “Features” page

Tilesets

I highlighted the tilesets above, and I’m not sure if this is a GIS or a leaflet term, but it seems that tilesets refer to different map renderings. Folium includes the following:

  • OpenStreetMap
  • Stamen Terrain
  • Stamen Toner
  • Stamen Watercolor

At the time of writing, I didn’t have API credentials for Mapbox Bright or Mapbox Control Room. But I’m assuming they still work if you have the appropriate API credentials.

Excluding the Mapbox tiles, those packaged by default are more than sufficient:

Tip: Read more on Stamen here, s'il vous plaît. They seem to be the original creators of these Stamen tiles. 

Python + Folium + ORDS = Happiness

Folium installation and quick start pages are straightforward – requiring minimal steps and effort. The same goes for installing the Live Server extension too. Once installed, you can right-click on a .html file to load it onto a local development server (so it displays in a new browser window).

Let me jump right into how I set up Folium to work with ORDS. If you recall, most of the tables I have in my Autonomous Databases are REST-enabled (previous post working with ORDS).

An ORDS Review

Step 1 REST Enabling your table with ORDS in Database Actions Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
1. Once in Database Actions, right-click on an object and select REST > Enable.
Step 2 REST Enabling your table with ORDS in Database Actions Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
2. Choose an alias (good security measure) along with Authentication (also good practice).
Step 3 REST Enabling your table with ORDS in Database Actions Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
3. If you forget the URI, you can review the cURL command.
Step 4 REST Enabling your table with ORDS in Database Actions Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
4. There you can copy/paste directly into a Command-Line or copy the URI portion and place into your browser’s address bar.

…and now back to your regularly scheduled blog post

Since I needed latitude and longitude coordinates for Folium, I decided to work with my Restaurant table. Put the REST endpoint (URI) directly into the browser; and you’ll see this:

ORDS REST URI Endpoint from Oracle Autonomous Database, Chris Hoina Senior Product Manager Database Tools

Afterward, I looked at the JSON object to see how it was structured (there are too many lists, dictionaries, arrays, etc. to remember amirite?!) because I’d need to iterate through all the items in the GET Response – to tease out what Folium needs.

The play-by-play

Printing the response (to see what it looks like)

Walkthrough 1 Folium Python VS Code ORDS API GET Requests Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
  • I’m covering all my bases here; reviewing the ORDS-provided request/object from a table in my Autonomous Database
  • Using json.() to “decode” it into a python dictionary
  • Please pay attention to line 10, where I actually create the base map

Review of what Folium needs

Walkthrough 2 Folium Python VS Code ORDS API GET Requests Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
  • Looping through the python dictionary, pulling out what I need for the next step
  • Including lines 25-29 to create the pop-up markers.
  • The ('<i>{}</i>'.format(Resty)) allows me to pass the names to the string (stuff in quotes, plus the {}). The HTML for italics is optional.
  • In this case, ‘x’ and ‘y’ are the coordinates
  • Line 31 saves a .html file (which uses Bootstrap!)

Newly rendered .HTML

Walkthrough 3 Folium Python VS Code ORDS API GET Requests Oracle Autonomous Database Chris Hoina Senior Product Manager Database Tools
  • Using the Live Server extension, I can review the Folium map plus the pop-up markers!
NOTE: This isn't the focus, but spoiler alert, I'll be putting this into a Flask application. I'll also build this out, so the individual markers/popups have charts/graphs for each restaurant. Again, all of which will be provided by ORDS-enabled tables (not so shameless plug).

Summary

After it is all said and done, it took me less than an afternoon to figure out how to make this work. So if you have a table with latitude and longitude, what are you waiting for?! REST-enable it with ORDS, and you can come up with a very quick demo on your own!

Also, I didn’t have to create any database models, the dependencies are minimal (a few python libraries), and an Always Free OCI account is really all you need to get started.

Code

import json
import requests
import folium

m = folium.Map(location=[35.78742648626059, -78.78122033558192], zoom_start=12, tiles="Stamen Watercolor")

response = requests.get('your ORDS enpoint/URI').json()

# print(type(response))
# print(response)

for entry in response['items']:
    Resty = entry['name']
    Lat = entry['y']
    Long = entry['x']
    
    folium.Marker(

        location=[Lat, Long], 
        popup = folium.Popup('<i>{}</i>'.format(Resty))
#this line is optional/an alternative to the above line
        # popup = folium.Popup('<i>{}</i>'.format(entry['name']))

                ).add_to(m)
        
    m.save("index.html")

[I did not] reinvent the wheel

Lastly, much of what I learned about Folium came from the following two videos (I recommend bookmarking them for reference):

Leave a Comment