Retrieve Neighbourhoods

Retrieve Neighbourhoods

The Mapzen Places API allows you to query and retrieve Who’s On First data including neighbourhood data via a REST-ish interface.

In this tutorial, you will use the API to retrieve San Francisco's neighbourhoods and display them on a map. To do this, you will:

  1. Create a Map
  2. Find Info With Spelunker
  3. Retrieve Data using the API
  4. Display the data

Step 1: Create a Map

We are going to utilize mapzen.js to make our initial map.

To do this, we need to create an html page. Use the code below to create the map.

<!DOCTYPE html>
<html lang="en">
  <head>
  <title>San Francisco Neighbourhoods</title>
  <meta charset="utf-8">
  <link rel="stylesheet" href="https://mapzen.com/js/mapzen.css">
  <script src="https://mapzen.com/js/mapzen.min.js"></script>
  style>
    #map {
      height: 100%;
      width: 100%;
      position: absolute;
    }
    html,body{margin: 0; padding: 0;}
  </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
    // Get an API key from https://mapzen.com/dashboard
    L.Mapzen.apiKey = 'your-mapzen-api-key';
    var map = L.Mapzen.map('map', {
      tangramOptions: {
        scene: {
          import: [
            'https://mapzen.com/carto/refill-style/8/refill-style.zip',
            'https://mapzen.com/carto/refill-style/8/themes/color-gray.zip',
            'https://mapzen.com/carto/refill-style/8/themes/label-1.zip'
          ]
        }
      }
    });
    map.setView([37.77493, -122.41942], 14);
    </script>
  </body>
</html>

To learn more about mapzen.js, check out its Get Started tutorial.

Step 2: Find Info With Spelunker

Now, we need some background info (WOF ID, latitude, longitude, etc...) to best utilize the API. To do this, we are going to take a look at the Spelunker.

Search for San Francisco in the Spelunker. Find the one that is the locality in the United States. You should find the page below.

Note the WOF ID. You can find it if you scroll down, it also the number located near the top of the page preceded by / and followed by .geojson. For San Francisco, this is 85922583.

Also, verify that you map is centered on the the right coordinates and the level is set correctly. For our purposes, we are going to level 14.

<script>
// Get an API key from https://mapzen.com/dashboard
L.Mapzen.apiKey = 'your-mapzen-api-key';
var map = L.Mapzen.map('map', {
  tangramOptions: {
    scene: {
      import: [
        'https://mapzen.com/carto/refill-style/8/refill-style.zip',
        'https://mapzen.com/carto/refill-style/8/themes/color-purple-green.zip',
        'https://mapzen.com/carto/refill-style/8/themes/label-1.zip'
      ]
    }
  }
});
map.setView([37.77493, -122.41942], 14);
</script>

Step 3: Retrieve Data using the API

To retrieve data using the API, we are going to utilize the mapzen.places.api.js file.

Download a local copy and then add the script to your html file.

<script src="mapzen.places.api.js"></script>

Also add jQuery, we are going to use that later.

<script src="jquery.min.js"></script>

This script will allow you to make the queries available by the Mapzen Places API.

Add the following helper function to make those calls from your html file. Note that we are using the mapzen.places.getDescendants API method. We include mz:uri as an extra so we are able to retrieve a neighbourhood's geometry. Also note that we only want neighbourhood descendants.

function init() {

  // See: https://mapzen.com/documentation/places/methods/#mapzen.places.getDescendants
  // San Francisco's WOF ID
  var parent_id = 85922583;
  var method = 'mapzen.places.getDescendants';
  var data = {
    id: parent_id,
    per_page: 500,
    extras: 'mz:uri',
    placetype: 'neighbourhood'
  };

  // Ok now we actually call the API
  mapzen.places.api.call_paginated(method, data, onpage, onerror, oncomplete);
}

Add the following helper functions. Not that the show_place function has not yet been created.

// Take all the API results and show them on the map
var onpage = function(rsp) {
  //console.log(rsp);
  for (var i = 0; i < rsp.places.length; i++) {
    var place = rsp.places[i];
    show_place(place);
  }
};

// Just log errors to the JS console
var onerror = function(rsp) {
  console.error(rsp);
};

// NOOP (we are using onpage instead)
var oncomplete = function() { return; };

Step 4: Display the Data

Now we are going to display the data. To do this, we are going to write a show_place function. The show_place function takes a place's geometry and styles it with a fill and stroke. For our purposes, we are selecting random shades of gray.

var show_place = function(place) {
  $.get(place['mz:uri'], function(result) {
    var layer = L.geoJSON(result, {style: function (feature) {
      randomNumber1 = 86+Math.ceil(Math.random()*100);
      color = "rgb("+randomNumber1+","+randomNumber1+","+randomNumber1+")"
      return {color: '#888888', weight: 1, opacity: '.7', fillColor: color, fillOpacity: .5};
    }}).addTo(map);
    layer.bindPopup(place['wof:name']);
  });
}

Your code should now resemble:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>San Francisco Neighbourhoods</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="https://mapzen.com/js/mapzen.css">
    <script src="https://mapzen.com/js/mapzen.min.js"></script>
    <style>
      #map {
        height: 100%;
        width: 100%;
        position: absolute;
      }
      html,body{margin: 0; padding: 0;}
    </style>
  </head>
  <body onload="init()">
    <div id="map"></div>
    <script src="mapzen.places.api.js"></script>
    <script src="jquery.min.js"></script>
    <script>
    // Get an API key from https://mapzen.com/dashboard
    L.Mapzen.apiKey = 'your-mapzen-api-key';
    var map = L.Mapzen.map('map', {
      tangramOptions: {
        scene: {
          import: [
            'https://mapzen.com/carto/refill-style/8/refill-style.zip',
            'https://mapzen.com/carto/refill-style/8/themes/color-gray.zip',
            'https://mapzen.com/carto/refill-style/8/themes/label-1.zip'
          ]
        }
      }
    });
    map.setView([37.77493, -122.41942], 14);

    // How we should handle each API result
    var show_place = function(place) {
      $.get(place['mz:uri'], function(result) {
        var layer = L.geoJSON(result, {style: function (feature) {
          randomNumber1 = 86+Math.ceil(Math.random()*100);
          color = "rgb("+randomNumber1+","+randomNumber1+","+randomNumber1+")"
          return {color: '#888888', weight: 1, opacity: '.7', fillColor: color, fillOpacity: .5};
        }}).addTo(map);
        layer.bindPopup(place['wof:name']);
      });
    }

    // Incrementally show API results on the map
    var onpage = function(rsp) {
      //console.log(rsp);
      for (var i = 0; i < rsp.places.length; i++) {
        var place = rsp.places[i];
        show_place(place);
      }
    };

    // Just log errors to the JS console
    var onerror = function(rsp) {
      console.error(rsp);
    };

    // NOOP (we are using onpage instead)
    var oncomplete = function() { return; };

    function init() {

      // See: https://mapzen.com/documentation/places/methods/#mapzen.places.getDescendants
      // San Francisco's WOF ID
      var parent_id = 85922583;
      var method = 'mapzen.places.getDescendants';
      var data = {
        id: parent_id,
        per_page: 500,
        extras: 'mz:uri',
        placetype: 'neighbourhood'
      };

      // Ok now we actually call the API
      mapzen.places.api.call_paginated(method, data, onpage, onerror, oncomplete);
    }
  </script>
  </body>
</html>

When you refresh your html page, you should see this.

Congrats, you just made a map of San Francisco's neighbourhoods using the Mapzen Places API.