GitSpatial – A Spatial API for your GitHub-hosted GeoJSON

GitHub supports rendering GeoJSON files directly in their website. And with help from geojson.io you can easily create, update and edit your GeoJSON features right in the browser.

I thought it would be fun to create a spatial API that fronts and syncs your GeoJSON hosted by GitHub. So, I built GitSpatial.

How it Works

When you first visit the site, you can log in with your GitHub account. You’ll be asked to allow GitSpatial access to your public repos (maybe private ones later?). When you grant access, we’ll get a list of your repos. Since you might have many repos, and many of those won’t have any GeoJSON, you are responsible for syncing any repos that do. Syncing is a one-time process that lets our service know that we should keep track of changes in this repo. When you sync we add a post-receieve hook to your repo settings so GitSpatial is notified when changes are made.

Once your repo is synced, the final step is to sync individual feature sets (files) that you want GitSpatial to keep track of. Again, you could have many GeoJSON files in a repo that you just don’t care about syncing, so we don’t want to bother tracking updates to those. As with repo syncing, this is a one-time process, so you won’t have to worry about it again.

When your feature set is done syncing, you’ll have immediate API access to it.

Using the API

Each feature set is shared as a separate resource like:

http://gitspatial.com/api/v1/JasonSanford/mecklenburg-gis-opendata/parks

or:

http://gitspatial.com/api/v1/JasonSanford/cambridgegis_data/utility_poles

GETing these resources will simply return a paginated set of data.

You can also search for features near a certain point. Suppose you wanted to find parks near a certain area. Simply specify a lat, lon and distance to search:

http://gitspatial.com/api/v1/JasonSanford/mecklenburg-gis-opendata/parks?lat=35.256&lon=-80.809&distance=2000

What if you’re creating a web mapping application and you want to show all utility poles in the map window. Just add a bbox URL parameter:

http://gitspatial.com/api/v1/JasonSanford/cambridgegis_data/utility_poles?&bbox=-71.1168622970581,42.36897629762196,-71.11066102981567,42.37254320340071

I’ve also added GitSpatial support in Leaflet Vector Layers. There are a couple of demos to check out out too. Below, you can see how updates to the data, in this case with geojson.io are almost immediately available in Leaflet Vector Layers.

What’s Next

  • Private Repos – For now every repo/feature set you sync is publicly available. I’d really like to add support for OAuth API access for private repos.
  • Attribute Searching – For GeoJSON feature properties I’m just dumbly storing the JSON as a string in a properties field. Ideally I’d like to use something like HStore to allow indexing and searching of this data.
  • Support non-*.geojson Files – Maybe you store your files as *.json or even *.topojson. We currently don’t look at these, but maybe soon.

You can view the site live at http://gitspatial.com. The source code is also available. As always, feature requests and bug fixes are welcome.

Collaborative Route Mapping with GitHub

A few weeks back GitHub announced rendering of geographic data in your repos via GeoJSON. It’s easier than ever to create, maintain, share and even style your geographic data. But more importantly this reduces the effort required to collaborate using geographic data.

After only a few weeks a number of interesting geo applications have surfaced using the new visualization capabilities GitHub offers. DC WiFi Social, from Ben Balter, is an effort to map locations in DC that serve alcolhol and offer WiFi – a great idea where a few residents with great local knowledge can make life much easier for visitors.

While my knowledge of Denver area bars that offer WiFi is rather limited, I thought it’d be fun to create something to gather bike routes in the Denver area based on distance and difficulty.

So, I forked DC WiFi Social which already had a great framework set up for collaborating: an informative readme, continuous integration (testing) via Travis CI, GeoJSON validation instructions, etc. With very little work of my own I was able to create a collaborative route mapping framework. You can view existing routes, filter by distance or difficulty, and add your own routes. Check it out with the links below.

Future Work

  • Expand beyond Denver – Someone else could fork this project in a different city, or expand the scope beyond just the Denver metro area
  • Maybe add running or hiking routes too?
  • Route POIs – It would be helpful to know about water stops, restrooms or other interesting places along your route
  • Photos – Add a photos property to the route. Maybe it has its own set of GeoJSON points to display photos at specific places along the route

More Fun Geo Things on GitHub

A Quick Hack with Google Fusion Tables and Geolocation

My wife was recently tasked with putting out signs for a consignment sale at our son’s preschool. Lots of them.

She showed me what they’d used in the past – A document with step-by-step directions from one location to the next and what kind of sign to place there. While this would have worked fine, it made it very hard to split up groups of folks to go and place specific types of signs.

So, thinking there had to be a better way, I sat down to see what I could to do make this easier for her. In just an hour or so I was able to come up with what seemed like a much better solution.

I used Google Fusion Tables to create a row for each sign location. Fusion tables is great because it will automatically geocode most things you throw at it – in my case cross streets (Pierce & Chatfield).

With just a few lines of code I could easily see all of the places where signs needed to be.

That was good, but what she really needed was a way to show only certain types of signs on the map for a specific group to place. I added a simple select element that changed the query parameters sent to the Fusion Tables API which automatically updated the overly.

<select id="sign-select">
    <option value="arrow=1">Arrow</option>
    <option value="info_arrow=1">Info Arrow</option>
    <option value="info=1">Info</option>
    <option value="">All</option>
</select>

$('#sign-select').on('change', function () {
    var options = {
        query: {
            select: 'Location',
            from: '1hSKp4BbrAUikm8H5k_deWghrrmaYupYE4phdAks',
            where: $('#sign-select').val()
        }
    };
    my_fusion_tables_layer.setOptions(options);
});

Cool, now we know where the locations are and what we need to place there, but where am I? With the native geolocation capabilties now found on most mobile browsers I could easily tap in and get a very precise location and show it on the map.

Still, this could be better. Instead of using the getCurrentPosition method, I opted to use the lesser known watchPosition. This constantly polls the device for an accurate location (at the cost of battery life) so that a moving marker could be shown on the map to help the navigator.

watching = navigator.geolocation.watchPosition(locateSuccess, locateError, {
    enableHighAccuracy: true,
    timeout: 10000,
    maximumAge: 0
});

The final product is here. I’ve also made the source code available. It’s pretty sloppy and probably has a few bugs, but for a last minute project I was happy with the outcome.

Leaflet Vector Layers version 1.4.0 released

Thanks to contributions from Bryan McBride and others an updated version of Leaflet Vector Layers is out, 1.4.0.

Updates in this release:

  • Utilize the OOP capabilities from Leaflet itself rather than duplicating the code
  • Ability to use CircleMarkers, not just simple markers, to represent points
  • Ability to add clickEvent handlers to let you hook into when map objects are clicked
  • Fixed busted base maps on a couple of demos
  • Ability to pass a precision parameter to a PostGIS RESTful Web Service Framework endpoint
  • Ability to pass a title to vectorOptions so that a standard HTML title is shown when a map feature is hovered

Leaflet Vector Layers version 1.3.0 released

That took a really long time. Sorry.

But an updated version of Leaflet Vector Layers is out with support for Leaflet version 0.4.x.

Also in this release:

  • Fixed a bug where GeoIQ was returning JSON wrapped in single quotes, then they didn’t, then this layer type broke.
  • Reduce file size by 6k because I was dumb and duplicating some code. There’s probably still some room for improvement here.
  • Added code examples for GISCloud.

GeoJSON validation via geojsonlint.com

Here at MapMyFitness we’ve been increasing our usage of the GeoJSON format over the last few months. Whether it’s displaying routes on a Google Map or processing data between subsystems, GeoJSON has proven to be a simple dialect for describing various geo features in our systems.

One thing I’ve been wanting to do for quite some time is build a GeoJSON validator. While the spec is very simple, it’s easy to get tripped up when you’re first getting started with the format.

So, I built http://geojsonlint.com. It’s a very simple django app that validates your GeoJSON and shows your feature(s) on a map if everything checks out ok. It works by POSTing your data to the /validate endpoint and returning a JSON object that signifies success or an error.

Valid:

{"status": "ok"}

Invalid:

{"status": "error", "message": "Required field 'coordinates' is missing"}

There are still a few rough edges but the code is available at https://github.com/JasonSanford/geojsonlint.com if you want to check it out or fix something I could be doing better. I’m using the Validictory python library to do most of the heavy lifting.

Future Work

  • Break it down into its own python library
  • Allow for pasting a URL to a GeoJSON resource to validate
  • Better error messages – Give the exact line number for something that didn’t validate (kind of like http://jsonlint.com)

Denver Open Data

A few weeks back Brian Timoney tweeted about some recent Denver/Colorado open data efforts. OpenColorado hosts over 400 data sets from DRCOG, the City and County of Denver, Boulder and a handful of others.

I decided to see what data was available and what I could do with it. The Public Art data set seemed interesting and small enough to do create something without too much effort.

I downloaded the shapefile and uploaded to my hosted geo service of choice, CartoDB. I use CartoDB because, with the exposed SQL API, my options are almost endless.

Within a few hours (over a few days) I put together a quick “Denver Art Finder” application. It uses Leaflet for the web mapping API and Handlebars as a simple templating engine. The application works by checking your location (you can fake it if you’re not in Denver) and searching for public art within 1km of you via CartoDB’s SQL API. If we find some, we throw some pins on the map that you can click (tap) to find the title of the piece, the artist’s name, and how far away it is. Very simple stuff.

You can grab the source code or view the application at the links below:

Fun with ScraperWiki and CartoDB

I’ve been trying to contain my excitement for the Great American Beer Festival until I successfully acquired tickets. Luckily, I was one of the few that actually got tickets.

I couldn’t help but wonder about the spatial distribution of all of the breweries attending the festival. Will there be a Colorado bias? I wonder who’s coming from my home state (North Carolina)? Anyone coming from Alaska, Hawaii? (yup)

So, being a geo geek, I headed to their website in hopes of finding a map. No luck. But there was a well-fomratted table of all 566 breweries. Nice.

I vaguely remembered some twitter chatter from a few months back about ScraperWiki, but didn’t know much about it. Within a few minutes, even with my marginal Python skills, I was able to write a recipe to scrape all of the names, cities and states for all of the breweries. The end product? A CSV.

Time to head to CartoDB. Importing my CSV was easy enough and geocoding these points through their interface was easy enough. You can even concatenate multiple columns to geocode against – in my case {city}, {state}, USA.

More exciting than the map itself is the fact that it took about 20 minutes to do all the things above. Thanks ScraperWiki and CartoDB!

The Map

The Recipe

Leaflet Vector Layers

A few weeks back I posted about Google Vector Layers which helps you create interactive layers with the Google Maps API and data from common providers like ArcGIS Server, Arc2Earth, CartoDB and GeoCommons. I’m a big fan of the Google Maps API but lately there have been lots of folks swtiching to web mapping alternatives, like Leaflet.

So, I made Leaflet Vector Layers.

Leaflet Vector Layers is Google Vector Layers’ twin brother. The API is nearly identical (new gvector.AGS({...}) vs. new lvector.AGS({...})) and the library works exactly the same — fetching features as the user pans and zooms the map, or fetching all features at once for smaller data sets.

It’s also great for use behind the firewall where the Google Maps terms or pricing can be prohibitive for some organizations.

Leaflet Vector Layers has all of the features of the Google Maps flavor like multi-provider support, popup (InfoWindow) templating, simple symbology definitions, support for dynamic data and scale dependent rendering.

So, check out the links below for an overview of the library, documentation and demos.


Links

  • The Main Page (Start Here) – This will link you to the source code, demos and documentation
  • The GitHub Repo – Please send issues, feature requests and code contributions here
  • Documentation – Go here when you get console errors
  • Demos – Some good code to get you started

Google Vector Layers

There’s no shortage of geo data providers these days. It’s quite easy to publish data and make it available to the world in minutes using software like ArcGIS Server, Geocommons, Arc2Earth and CartoDB.

What’s sometimes not easy as it could be, is taking data from these providers and showing them on your slippy map of choice, Google Maps.

For the past few months in my downtime I’ve been working on a library that makes it much easier to view and interact with your data in these services — Google Vector Layers.

With just a few lines of code you can view data from a number of geo web services, symbolize it based on property values and create highly customized InfoWindows using the feature data.

The library works by listening to map events (pan and zoom) and then fetching features within the map’s extent after each event. This method works great for data sets with lots of features that you want to interact with, but not load all at once. But you can also load all data initially if you’ve only got a handful of features and prefer a less chatty approach.

Features

There are number of things that make this library quite handy:

  • Multi-Provider Support – Current support for ArcGIS Server, Arc2Earth, Geocommons and CartoDB (with more in mind)
  • Easy InfoWindow Templating – Create InfoWindow templates with a simple string with property names {mustached} or with a function that gets passed feature properties, and should return valid HTML for the InfoWindow
  • Dynamic Data Support – Easily visualize live data that auto-updates at an interval that you set (and makes sense for your data’s update frequency)
  • Simple, Powerful Symbology – Style your layers with a single symbology, a unique symbol for specific attribute values or set symbols to display if a feature’s attibutes are within a specific range. Or …
  • Use Your Current Styles – If you’re using an ArcGIS Server layer you can use the styles you’ve already spent time creating in ArcMap
  • Scale Dependent Rendering – You wouldn’t want to show lots of features with complex geometries at lower zoom levels – Using scaleRange lets you set the minimum and maximum scales a layer should be visible

The documentation and demo pages have much more detail about all of these features.


Links

  • The Main Page (Start Here) – This will link you to the source code, demos and documentation
  • The GitHub Repo – Please send issues, feature requests and code contributions here
  • Documentation – Go here when you get console errors
  • Demos – Some good code to get you started