OpenShift: Leaflet.js, MongoDB, and Flask

28 Nov
Leaflet Map

My simple application on OpenShift. Pulling data from MongoDB and presented using Leaflet.js

PaaS: Platform as a Service

I write a lot of small applications and scripts to improve my programming skills and to hopefully use in my work. Unfortunately, I cannot share most of them because  I don’t have access to a server – almost all of my apps run on a WAMP stack using localhost:8080.  Recenlty, I saw a tweet about a service by Red Hat – I remembered them from my Linux club days in college – called OpenShift. OpenShift is a Platform as a Service (PaaS) that “manages the stack so you can focus on your code.” It promised a way to for me to run all the new technologies my web host won’t allow. I had to try it out.

What I Want to Build

I make a lot of maps. Just simple point maps with a polygon here or there. No real geoprocessing or analysis. Just for displaying data. My application needed to display a map. My front-end of choice is Leaflet.js – a JavaScript library- and I have to be able to use it.

I am not a programmer but dabble in a few languages. Python is the one I am most comfortable with and I am more fluent in it than any other language. It is also a language I enjoy and having an interactive shell makes my coding go much faster. I can test solutions before they ever go in my program. If I am going to have a chance at success, I have to use Python.

All of my Python programming on the web has been using CherryPy. It is a minimal framework that was easy to install and to learn. I only need to do simple things like route and pass data so why go Django or Pylons – Pyramid now?

I really like  MongoDB. You may think spatial is special and get all PostGIS on me, but for what I need and what I like to do, I am all about MongoDB right now. So I need to be able to install it.

To summarize, I need – or want:

  1. Leaflet.js
  2. Python
  3. CherryPy
  4. MongoDB

Getting Started

Go to OpenShift and setup an account.

I am not a reader of manuals – OpenShift has a good one – but more of an experimenter and skimmer.  I used the OpenShift getting started and a blog post – REST web services with Python, MongoDB, and Spatial data in the Cloud – to get up and running. The blog used Flask, which I have never used before, but it does the same thing I was using CherryPy for, so I used it. In reading more about Flask, I found that it has a templating engine called Jinja2 available. When pushing my code to GIT, I saw that Jinja was already on OpenShift. I will admit, I am bad about templating and put all my HTML in a variable and have a function ‘return HTML.’ With this application, I wanted to break that bad habit.

After getting the Ruby Installer and Git, I followed all the instructions in the getting started and the blog and was left looking at a folder on my computer with some stuff inside of it. Now it’s time to play.

Coding the Application

The stuff in my folder is an application using Flask that I grabbed from GIT.  The important part is in the WSGI folder. The MyFlaskApp file has code that grabs data from a MongoDB and dumps it out to a webpage. This is the file I will edit to make my app.

Before I do anything else, I want to write my webpage. It will be nothing more than a simple Leaflet map with one marker at a point retrieved from MongoDB. It will also be a Jinja Template.

Here is the code for my webpage.

<!doctype html>
<head><title>OpenShift: Leaflet, MongoDB, Python. Jinja2</title>
<link rel=’stylesheet’ href=’http://cdn.leafletjs.com/leaflet-0.4/leaflet.css&#8217; />
</head>
<div id=’map’ style=’width: 900px; height: 350px’></div>
<script src=’http://cdn.leafletjs.com/leaflet-0.4/leaflet.js’></script&gt;
<script>
var map = L.map(‘map’).setView([40.71367, -73.99364 ], 13);
L.tileLayer(‘http://{s}.tile.cloudmade.com/API-KEY/997/256/{z}/{x}/{y}.png’,{attribution:’Paul Crickard’, maxZoom: 18 }).addTo(map);
L.marker({{ coord["pos"] }}).addTo(map)
</script>

This file needs to be put in a folder in WSGI called TEMPLATES. You will notice another folder in the directory called STATIC. This is where you can put CSS and JS files.

The code is straight HTML and JavaScript with the exception of   {{ coord[“pos’ }}. This is the Jinja part of the template. In the Flask Application, I will pass coord to the template.

Let’s take a look at a simple Flask application that will grab the point from MongoDB and send it to my Jinja Template. Here it is:

from flask import render_template

@app.route(“/ws/albuquerque”)
def albuquerque():
conn = pymongo.Connection(os.environ['OPENSHIFT_MONGODB_DB_URL'])
db = conn.parks
for z in db.location.find():
q=z
return render_template(‘map2.html’,coord=q)

The file I modified already has several import statements but you will need to add render_template to use Jinja. I changed the route to /albuquerque – I was going to use some local data but decided for a test I would use the parks JSON file so now the Albuquerque doesn’t make much sense. Then I grab a cursor and pass a point to q. Lastly, I call the render_template and hand it q as coord. Now in my HTML/Jinja Template, I can call coord. For the future, I would run a loop in the Template that grabbed all the points. A loop in Jinja looks like this:

{% for x in json %}
   Do something with X: 
   L.marker({{ x }}).addTo(map) 
{% endfor %}

Now go to my RHCloud.com and see it in action. It seems rather simple – I need to add some popups – but there is some powerful technology behind this. MongoDB has some spatial features like $near, $box or $within $center of a circle. This should somewhat please the spatial is special crowd. One of the things I love is that I can have an object {“pos”:[35,-106],”name”:”ABQ”} and I can have another {“pos”:[33,-106],”name”:”LL”, “visitors”: 50}. In a table, every record has the same fields – I don’t have to do that in MongoDB. I see MongoDB as much more flexible for my needs.

Next Steps

What functionality would I like to add to this?

  1. A form that allows the user to select either all the data or a subset using simple radio buttons or combo boxes.
  2. A way to download a report of the data selected.
  3. A form for users to enter new data.
  4. Popups with additional data. This should only require adding .bindPopup( {{coord["popupContent']}} )

One last thing: It runs on mobile. My HTML is not very good, but a mobile Leaflet app is simple. I have one that uses your phone’s current location on my website.

My App Running on Mobile

Flask App Running on iPhone 4S

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 36 other followers

%d bloggers like this: