Skip to content

Instantly share code, notes, and snippets.

@andy-esch
Created June 16, 2015 17:44
Show Gist options
  • Save andy-esch/b7d4b41457b3eef2f9a9 to your computer and use it in GitHub Desktop.
Save andy-esch/b7d4b41457b3eef2f9a9 to your computer and use it in GitHub Desktop.
Code for America -- Brief Workshop

Code for America -- brief deep dive

Andy Eschbacher, Map Scientist, CartoDB

06/16/15

You can find this page at:

bit.ly/cdb-cfa

Getting started

Our goal today

Use CartoDB's JavaScript Library and Data API to create a basic geospatial app

Our full working example is here.

Setting us up for accounts

If you don't have an account, go here to sign up: https://cartodb.com/signup?plan=academy

These are academic accounts that are better than the normal free accounts. If you have a free account already but don't have the academic one, send me an email (eschbacher@cartodb.com) and I'll bump you up. For now they have 50% more storage, but soon they'll have 100% more and table syncing.

Import a dataset

Today we'll be making maps and interacting with a dataset of DC Tax lots. The original dataset is available here: DC tax lots. No need to download that though!

We'll use a slightly cleaned up version of the dataset that you can access through a public table I have in my account.

Let's save the Wi-Fi a bit though, instead of downloading the dataset, copy this URL (which is an API call to grab the data from my CartoDB account -- notice that it's SQL in a URL):

http://eschbacher.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20dc_tax_lots&format=geojson&filename=dc_tax_lots

And paste it into the CartoDB import menu:

import data

Making our first maps

Let's take a second to tour the interface in case some of you haven't used the tool before.

Imgur

Transforming data types

Some SQL we hide for you. For example, there's no need to use SQL to change datatypes. But you can use SQL if you want, or need more than the four for which we provide easy casting!

Imgur

Using SQL in CartoDB

CartoDB is built on PostgreSQL and gives you access to the full relational database model, plus geospatial functions based on PostGIS, a geospatial extension.

SELECT superhero.name, city.name, city.geom
FROM city, superhero
WHERE ST_Contains(city.geom, superhero.geom)
AND city.name = 'Gotham'

Example: calculating tax lot elevation based on DC contour lines.

In this example, I'm using a second dataset from opendata.dc.gov for elevation data.

<iframe width='100%' height='520' frameborder='0' src='https://team.cartodb.com/u/eschbacher/viz/7a778c92-f9f0-11e4-9479-0e018d66dc29/embed_map' allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen></iframe>

Filtering on the map

Say we're only interested in the properties that have elevations between 50 and 150 feet, we could execute the following query to get the properties returned.

SELECT 
  *
FROM 
  dc_tax_lots
WHERE
  elevation > 50 AND elevation < 150

filtering

Aside: how I added the elevation column

The tax lots data didn't include the elevation data originally. To get it, I had to do some geospatial analysis.

First, I added a new column, called elevation of type number.

Next, I ran a relational SQL statement that measures the elevation by finding the closest contour line in the contour lines table to each property in the DC Tax Lots table (no interpolation here!).

UPDATE
  dc_tax_lots_t dt
SET
  elevation = (
  SELECT
    c.elevation
  FROM
   dc_20_foot_contours c
  ORDER BY
   c.the_geom <-> dt.the_geom
  LIMIT 1
 )

Choropleth on elevation

Let's create a choropleth from the elevation column.

Imgur

Transforming data type

In CartoDB, you can move between points, lines, and polygons fairly easily using the PostGIS geospatial functionality. For example, you can join a group of points into a linestring. In this case, let me show you how to extract the centroid of each building so that we can use Torque to animate it.

First, navigate back to your dashboard, go to your datasets, and click on dc_tax_lots to directly enter the data table (instead of working on visualizing the data).

SELECT
  ST_Centroid(the_geom_webmercator) the_geom_webmercator, 
  elevation, 
  creation_d
FROM 
  dc_tax_lots

We can capture a snapshot of this by using the options->table from query functionality.

centroid

A quick look at Torque

Point torque

Imgur

Categorical torque

Imgur

Temporal bubbles

Imgur

Cumulative bubbles

Imgur

Method for creating the last two

CartoDB.js

Creating maps in the Editor is all well and good, but using JavaScript you can make custom applications.

Our goal is to make a simple app that shows all building footprints within a given elevation range.

Let's all start with the same template, you can view, copy, and paste an template HTML file here: index.html

The simplest CartoDB.js map

A map in one line of JavaScript. Paste the following piece of code into the <script> tags in the HTML template.

cartodb.createVis('map','https://team.cartodb.com/u/eschbacher/api/v2_1/viz/5f709a68-f9e3-11e4-abb5-0e4fddd5de28/viz.json');

Open the HTML file in your browser and you'll see the choropleth we made. Swap out the URL above with the one from your map if you prefer.

Adding to an existing map object

To add more customization, we will lean on the Leaflet.js map library to visualize our data.

First, make sure you delete the line we added above and create a Leaflet map object in its place:

var map = new L.Map('map', {
    zoomControl: false,
    center: [38.893, -77.03],
    zoom: 13
});

Next, add a basemap. You can use one of the freely available CartoDB basemaps.

var layer = L.tileLayer(
    'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png',
    {
        attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>'
  })
  .addTo(map);

If you reload your map you'll see a basemap without data visualized on it -- which is what we're adding next!

The createLayer method

The createLayer method is a really powerful way to use CartoDB in your front end applications. It allows you to add your own map object using Leaflet or Google Maps, and add your layers from CartoDB. Here we're using Leaflet.

cartodb.createLayer(map, 'https://team.cartodb.com/u/eschbacher/api/v2_1/viz/5f709a68-f9e3-11e4-abb5-0e4fddd5de28/viz.json')
    .addTo(map)
    .done(function(layer) {
        // Do further things here
    })
    .error(function(err) {
        console.log('error error');
    });

Again, you can replace my map data link with yours.

Add interactivity

You can add interactivity in the Editor very easily, but for maps you are creating on the fly in CartoDB.js, you can also add custom interactivity.

var lots = layer.getSubLayer(0);
lots.setInteractivity('cartodb_id, elevation');
lots.setInteraction(true);

Add custom interaction

You can use cursor events on your polygons (e.g. featureClick, featureOver, featureOut) to create your own actions on your webpage. Let's log the elevation value to the console for any lot we hover over:

lots.on('featureOver', function(e, pos, pixel, data) {
    console.log("Elevation: " + data.elevation + " feet.");
});

It's also easy to create custom infowindows from the callback objects on these types of events. I made one here.

Map lot similarity

Let's build a simple app that let's you click a lot and see all lots within a 30 foot elevation envelope. We can do this by combining the click event and the ability to define a new SQL statement on our map tiles.

First, let's construct our new SQL string from the click input,

lots.on('featureClick', function(e, pos, pixel, data) {
    var newSql = "SELECT * FROM dc_tax_lots WHERE elevation >= "+(data.elevation - 30)+" AND elevation <= "+(data.elevation + 30);
    console.log("SQL: " + newSql);
});

Updating layer parameters

Using the layer object returned by createLayer, we can actually update our SQL, CartoCSS, and interactivity on the fly. Let's use setSQL to run our new statement:

lots.setSQL(newSql);

Add a button

Let's add a simple button to reset the map. I've already added the HTML to the webpage, we just need to remove the class hidden when we set the SQL filter and then wire up the button using jQuery.

$('button').removeClass('hidden');

Wire a button to a setSQL

Finally, make the button do something! In this case, we reset the SQL to select all rows and columns in the data table.

$('button').click(function(){
    $('button').addClass('hidden');
    lots.setSQL("SELECT * FROM dc_tax_lots");
});

To checkout a full working example, you can see one here.

Resources to help you make maps

  1. Map Academy is a site I run
  2. CartoDB Tutorials
  3. CartoDB Editor Documentation
  4. CartoDB APIs
  5. Community help on StackExchange
  6. CartoDB Map Gallery
  7. Me: eschbacher@cartodb.com

Thanks!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment