Plotting API Results on a Map using Flask and LeafletJS

Mateusz Wiza
6 min readJun 28, 2021

It is a frequent use-case to include a map in dashboards, websites or web applications. But how do we go from a list of coordinates, or a Python code that retrieves these coordinates from an API, to an interactive JavaScript-based map on our website? I will explain this in an example of a simple web app, which displays all the shops around the entered location.

Input page

Let’s start by talking about the input page. I made it very simple, without any unnecessary elements and without even a gram of styling with CSS. Just a good, old HTML, obviously in the Flask edition. And because we’re using Flask here, to be able to fetch the data using Python eventually, we actually need two files, one in HTML and another one in Python.

Everything is very simple so far. In Python, we initialize our Flask application and create the method for our (only) subpage. The if statement handles the request received from the form when a user clicks the ‘submit’ button, this is where our map will appear. For now, it can be skipped and the most important element is this render_template() function, which will take the input.html file and simply show it in the browser. As you can see in the <head> section of the HTML, I added the CSS stylesheet because you can use this file to make the input form look better. In my case though, there is no CSS code concerning the form, so after running Flask, we can see the following page:

As you can see, it’s nothing fancy indeed. Normally, in dashboards like this, you wouldn’t deal with geographic coordinates as they aren’t very user-friendly. Instead, you can use a single input field for an address. However, for the API I’m using here (and for most APIs out there), we’ll need the coordinates so if you only gather the address, you’ll need to geocode it. There are many ways of geocoding but my favourite is the free API called OpenCage.

API Call

Before we can show any data on the map, we first need to acquire them using an API. In other words, we’re going to program our backend now. There are many APIs providing the locations of all sorts of things and places. In real life, I made Flask dashboards that showed parking locations or the company’s competitors. In this case, to keep it simple, I decided that we’ll display all shops in a 500 meters radius from the input location and we’ll use the OpenStreetMap data for it.

In particular, I’m using the OverPass Turbo API that is used for querying OpenStreetMap data and even more, in particular, I’m using its Python interface through a library called overpy. I covered this API and the very query for returning the list of shops in this article:

The Map

We have the results from the API: the list of coordinates of all the shops around the entered coordinates. How to present them in form of a map? For this, I’m using a JavaScript library called LeafletJS. To use it, we need to add several elements to the HTML file, so let’s create the results.html file.

Firstly, we can follow LefletJS’s quick start guide and add the following two lines to the <head> section:

Secondly, in the <body> section of the same HTML file, we need to create a div that will contain the map. Then, we can add a script in which we initialize the map and set its tile. It’s important that the ID in L.map() is the same as the div that will contain the map.

Before moving any further, let’s examine the code from above. When initializing the map, we use the setView() function that determines what will be shown to the user when they open the page. We can choose which coordinates the map will be centred at and what will be the initial zoom. I didn’t specify the coordinates because they will depend on the user’s input. That’s why I put the variables ‘lat’ and ‘lon’ in double squirely brackets — this means they’ll be passed from the Python script. I set the zoom to 16 but feel free to experiment with this.

Then the map tile is its background. Remember that we only mark our shop locations but we still need a map with other features such as roads or buildings. This is what tiles are for. There are many sources of map tiles, you can use the one from Google to make your map look the same as Google Maps, there’s also a website called mapbox that has a large collection of advanced tiles. I decided to use the tile from OpenStreetMap. For once, because we’re using the data from OpenStreetMap, but also because these tiles are very easy to use without the need to registering anywhere and always free.

Having all of this, we still need to define the markers corresponding to shop locations and add them to a map. To do it, we need to return to our main Python file (app.py) and add the code which executes the get_shops() function from the backend. We get the list of all the shops in a collection with attribute .nodes where each node is a single shop. Each node then has attributes such as .lat and .lon for the coordinates and .tags using which we can get more details such as the name.

To create the markers we need to iterate all the nodes and for each one create the variable for a marker using L.marker([lat,lon]) function. To add this to the map, we use the addTo() function. In theory, we could use the same variable name for each marker and simply reset it in each iteration — we’d still see all the markers on the map. But I prefer to make the variable names different (here they are in form ‘shopX’ where X is the next number) because it makes life easier if we need to do anything with these markers later.

LeafletJS also allows us to add a little pop-up window for each marker that appears when a user clicks a marker. We can define what the pop-up will say using a bindPopup() function. In this case, I decided to have the name of the shop in one line and its website in the second line. However, I don’t think all the shops in OpenStreetMap have these details, so it’ll say ‘null’ if they’re missing.

Remember that we’re still in the Python file and we’ll need to pass the JavaScript code for all the markers to the HTML template. Therefore, we need to store this markers’ code as a string. Then we simply make this string longer in each iteration of the loop. In the end, we can render the template again passing the string markers and the coordinates (to centre the map).

But wait a minute, when we pass the string with code for all the markers to our template, where will this code appear? That’s a very good question and the answer is — nowhere. At least for now. This is because we still need to add one piece of code to results.html. A little command {{markers|safe}} within the <script> tags. You may remember that the double squirely brackets mean that something is passed from Python. Here, we need to add this |safe marker. Without it, Flask would consider our string plain text and would just print it out on the page. The string, however, is a code that needs to be executed and this marker makes it possible.

Now the application is ready. When the user enters the coordinates and clicks the ‘Display shops’ button, they will see the map like that:

The complete code for this example can be found in this GitHub repository: https://github.com/mateuszwiza/mapping-api-results

--

--