Category Archives: mapping

How I styled polygons in mapbox.js from an external geojson file

so, this blog post had come a lot later than I expected
because a bit of yak shaving and I explain why at the end of this post.
This post is also the followup to How I learned a 3rd way to link external GEOJSON files in mapbox.js and leaflet.

How to style polygons, based on their properties, that were stored in an external geojson file, using mapbox.js

The Code referenced in this post is based on this commit and is viewable here .

To see the most updated of the Downtown Cleveland public parking map, which may include changes that were made after this blog post, go to http://skorasaurus.github.io/dtparking/

I’ll go through a couple things of what the code is doing and hopefully clarify a couple things for you:

First, at Line 52, I create a featureLayer method that will be used to
load the geojson file
.

Then, load your geojson file using loadURL() . In this example, it’s in the same directory as the index.html file.

Line 63 is a function will return the color based on the argument of the function. myargument is just a placeholder of sorts. This function is later called on lines 82 and 83 with to read the value of parking, which describes what kind of parking lot it is – surface, a multi-storey, or a underground one (written as polygon.feature.properties.parking)

Why polygon is there, I honestly can’t explain at the moment.
feature is there to represent each feature in our featLayer. I did not name it feature, but
properties is there to reference the properties of each feature,
and parking is to select the parking property.

There’s likely many different ways to write this function that begins at line 63 but this one that works for me. I’m interested to hear if there’s any disadvantages to what I did here.

The eachLayer method is confusing. This method is being used to say “hey, I want this code (in lines 77-83) to act on every object (all of the parking areas) that’s in featLayer. Layers have different meanings depending on context in geospatial/GIS.

Line 82
getMyColor is just an arbitrary name that I made to name the function that I made.I still catch myself once in a while of what is function and what is a method….
In several past commits, I didn’t include the ‘feature’ part of the object
because I had mistaken assumed that eachLayer method would go through each object within the layer and that adding ‘feature’ wasn’t necessary.

Beginning at line 63, is the function that will return a different color depending on what is the value of parking. For example, for this polygon parking has a value of ‘surface’ so ‘#679967’ is used as the fillColor for that particular polygon.

polygon and myargument are both arbitrary names that are selected by the coder. If you were to copy and paste this page into as your own, (as well as the dtparking.geojson file at the github repo ), you could rename polygon to
blob and myargument to judgejudy in each place and it’ll work.

Some helpful reminders/refreshers:

‘what’s a method versus a function?’ (unfortunately, I couldn’t find a nice, succinct answer for people on the web);
eachLayer (and all of the functions within mapbox.js, actually) is asynchronous – if you don’t know what this means, it can be explained better than I can by Michael Vollmer here

All methods in mapbox.js will begin with “l.mapbox.” ; you can still use leaflet methods which begin with “l.”

Interestingly, l.geojson is NOT asynchronous, I understand this better after this project. (I don’t know if there’s a way to determine if a class or its methods are asynchronous or not).

Mozilla’s javascript guide and reference are great.

=====

Cause for the delay of posting this blog post; one of my features in the geojson file was missing the parking property and caused the following error in the javascript console for the dtparking html page even though the html code was otherwise working. I added it to here in case someone else would have the same problem and search for the solution.

it was returning the following in the console:

Uncaught TypeError: undefined is not a function 945fae4e059fb12090a8dc22c6cd22e665ebeea2.html:51
(anonymous function) 945fae4e059fb12090a8dc22c6cd22e665ebeea2.html:51
s.LayerGroup.s.Class.extend.eachLayer mapbox.js:2
(anonymous function) 945fae4e059fb12090a8dc22c6cd22e665ebeea2.html:50
s.Mixin.Events.fireEvent mapbox.js:1
(anonymous function) mapbox.js:6
(anonymous function) mapbox.js:1
a mapbox.js:6

I fixed it in
this commit

How I learned a 3rd way to link external GEOJSON files in mapbox.js and leaflet.

How I learned a 3rd way to link to External GEOJSON files in mapbox.js and leaflet.

Do you have a geojson file and want to load it up in leaflet?

All it takes are two lines.

var featLayer = L.mapbox.featureLayer().addTo(mizzap);
featLayer.loadURL('dtparking.geojson');

The first line initializes the feature layer to your map.
In my example, mizzap is the variable of the object that I created to initialize my map.. (I hate that ‘map’ is used all the time as a variable), you don’t know what’s it is referring to). Mizzap can be refer to an object directed through l.mapbox.map or l.map :)

The second line loads my geojson file which is in the same directory as my html file. I can now use it later on simply as ‘featLayer’.
.

For context, here is the finished product as html .

I loosely called it ‘the 3rd way’ as fellow Maptime organizer and all-around kickass person Lyzi Diamond described 2 other ways ( (1) and (2) ) ways to load Geojson files and I aspire that this post compliments her posts..

Why did I use this way to load my geojson (And you can too)?

Now, how I learned to use this 3rd way was because I wanted to load and style polygons in leaflet or mapbox.js based on properties within the geojson file AND I didn’t want to include styling properties in the geojson file.

Also, I’m still learning javascript and I was quite admittedly a little frustrated (and surprised) to find plenty of examples online of loading geojson and styling it but none of them fit my use case.

There were numerous examples of how to load and customize points…
https://github.com/maptime/maptime-bites/blob/gh-pages/00004/index.html
https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-from-csv-custom-style/
https://www.mapbox.com/foundations/building-a-store-locator/
https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-as-links/
http://bl.ocks.org/geografa/8743008
http://ebrelsford.github.io/jekyll-map/
http://lyzidiamond.com/posts/osgeo-august-meeting/

or

They were loading GEOJSON within the browser itself and not to an external file.
https://www.mapbox.com/mapbox.js/example/v1.0.0/geojson-simplestyle/

or
referring to a GEOJSON File (example) which isn’t a true geojson file, but has its variable in it, as mapbox did in this choropleth example.
This last point is problematic if you’re sharing this data set as Lyzi Diamond concisely explains:

If you tried to show the file in GitHub, for example, the points would not be interpreted and a map would not be rendered. Additionally, you don’t always have direct control over the GeoJSON file itself, especially if it’s a shared dataset or if it’s being returned from some other process. Adding a variable definition could also potentially mess up the work of anyone else trying to use your dataset, if it is indeed a dataset you constructed.

OR in some instances, the authors did a combination of these.

I admit, I wasn’t familiar with AJAX at all and didn’t want to touch it. Looking back, I was probably too intimidated by it and at the same time I was reading the mapbox.js documentation and thought: ‘wow, using Mapbox.js will save me some time and not have to use the Leaflet-Ajax plugin ,
I had used mapbox.js a couple times before and knew it includes the functionality of leaflet, also has many other methods and classes that are designed to add more functionality, and offers easier integration with map tiles from mapbox.com

I told myself:”I could just load my geojson file using loadurl(), and mapbox will have an example to show me!”

I learn code by reading examples and modifying them.

Below, I go through several commits where I learned to use loadURL(), load and style all polygons in a geojson file, and then point out my mistakes along the way where I used the wrong code.
=======
Commit one:

I tried to use the style option (from l.geojson) and a switch to customize the styling of the geojson file as on show on leaflet’s geojson example page .
which has the follow example.
===
L.geoJson(states, {
style: function(feature) {
switch (feature.properties.party) {
case ‘Republican’: return {color: “#ff0000”};
case ‘Democrat’: return {color: “#0000ff”};
}
}
}).addTo(map);

I adapted it in this commit (on github) and as html here
Unfortunately this didn’t work…
the console displayed:

“Uncaught Error: Invalid GeoJSON object. mapbox.js:3
s.extend.geometryToLayer mapbox.js:3
s.GeoJSON.s.FeatureGroup.extend.addData mapbox.js:3
s.GeoJSON.s.FeatureGroup.extend.initialize mapbox.js:3
e mapbox.js:1
s.geoJson mapbox.js:3
(anonymous function) index.html:36″

I thought..”
maybe I can’t style within loadURL… maybe I have to use l.geojson
and call it again?””

=======
Then, I was still confused and as I was continuing to find examples of what I was looking for and eventually asked Bill Morris, a longtime leaflet/mapbox.js/tilemill user.

He showed me several maps he recently made of Burlington
where he styled styled polygons in leaflet based on the properties of the geojson file but.

So, in this commit and
(as html),

I used 2 functions to style the polygons but no styling was happening. Still stumped.
I wanted to make sure that my 2nd function (to determines which color is being used in the style based on the property of parking) was being called/run. so I first used the show method inside the getColor function.

There was no error in the javascript console or information to find out why the functions were being called, I thought.

I tried again with replacing show with console.log and same result: the polygons would display , but
I couldn’t figure out why my getColor function wasn’t calling the property in my geojson file.

Throughout the day, I found a couple more examples (from maptime and mapbox’s store locator – that were similar to what I was looking for – customizing a feature based on the feature’s properties
(for reference, a feature is a geographic object that represents a point or a polygon) – but neither were for customizing polygons, but they offered a couple ideas of other things I tried, with no success..

I had wondered if should I first use the loadurl method and then use the filter option/method to not loading any styling; then use another function to add the data again and style it?”

Then <a href="http://twitter.com/geografa"Rafa Gutierrez from MapBox helped me out, and gave me an example of applying a style to all polygons in a geojson file (code).

Thanks to Rafa’s example and the reading documents for the upteenth time, reading the
I finally figured out a couple REALLY IMPORTANT concepts and learned where I went wrong:

I was using ‘style’ as a method in my previous commits. Again, THIS IS WRONG!
Only looking after his example,

style is not a method, but an OPTION in leaflet.

L.mapbox.featureLayer() is based upon and ‘extends’ the l.featureGroup. You can use a few more methods that are listed in L.mapbox.featureLayer() as well as all of the methods that are in l.featureGroup with l.mapbox.featureLayer.

I didn’t immediately realize that I could use the setStyle method to style my polygon since my object (which I named ‘featLayer’ in all of my examples) was constructed from l.mapbox.featureLayer because all of the examples I had found online (at the time) had constructed their object using l.geojson and used the style option of l.geojson.

But, now how do I style based on the properties of the feature in the geojson file, I wondered!
Part 2 of how I learned this, coming up.

How I tried to overlay a mask over multiple layers except for a specific region in Tilemill (and left with a buffalo tint)(and I liked it)

One thing about designing maps, you want to draw people to what they see (yes, ultimately the viewer will have their own subjective interpretation, but I digress…).
So, when designing a map to highlight the locations of 125 items that were to be photographed in the 2012 CPS Cleveland Photo Scavenger hunt, I wanted to focus on the contest area while giving viewers (likely participants who may have forgotten the exact boundaries or may not have done the scavenger hunt but would be at least familiar with downtown Cleveland) a little context of the surroundings.

How to accomplish this ? Well, I’m guessing it can be accomplished through a couple different ways: one, by, fading the surrounding features (this known as the buffalo tint) as shown in this demo by Bill Morris, wboykinm (he does inspiring works using Tilemill, pushes it to its capabilities, and blogs about it who does this buffalo tint over a separate base map, or by laying a gray mask over the surrounding area outside the border, on the same map.

Either of these techniques – Decreasing the opacity of the outside area or giving it a gray mask to make it a bit harder to read, drawing the viewer to the easier part to read and having the non-grayed part pop-out.

So, I started experimented in my project (based off originally osm-bright written by mapbox)

with map {
background-color: #999;
}

which would provide the gray mask, and one of the polygon comp-op function that allows you to do different effects on features in tilemill (using the gray mask)

#border {
opacity: 0.5;
polygon-comp-op: hard-light;
line-width: 4;
line-opacity: .65;
}

Unfortunately, all of the polygon-comp-op options that I tried including dst-in which had no effect or colored inside of the border. I uad only been able to lay the mask over the rest of the features inside of my polygon, (labels, roads, water, land), but not outside – what I’m intending to do.

So, hours later, I stepped away and thought how else to tackle this,
I came back, noticed, silly me, that

map {
background-color @water;
}

was called again in base.mss to provide Lake Erie with its blue sheen. I figured that might have something to do with it but that was a red harring. I eliminated that line and it left me with a gray lake.

Meanwhile, I hadn’t figured out yet or found anyone else who had done anything like this – overlay a mask over multiple layers except for a specific region in Tilemill.

(written on Nov. 28, 2012)
Flash forward 24 hours. This is why I love Tilemill. Yes, it’s free, open-source, supports linux (as well as win and osx). What you see is what you get – allowing you to code on one side while showing what your map looks like on the other. I’ve been a fan for a while, and I’m finally starting to make progress learning its intracies and operations 15 months later as its capabilities increase. It’s getting kudos by cartographers (Dane Springmeyer, lead developer of Tilemill, had the most attended presentation, by far at this year’s NACIS, the biggest annual mapping conference in North America).

I was a bit frustrated, and after a day of trying to understand the comp-op and wondering why all of the comp-op operations that I was trying had no visible effect or achieved the opposite of what I was intending to do, coloring inside the polygon, as shown above.

Only a few hours after I posted my query in TM support, Dane clarified some new tools that became available in mapnik 2.1 (just released 2 months ago) and how to go about doing it in Tilemill.

As of now, my code ended up as:
#border {
::outline {
line-color: #999;
line-width: 4;
line-opacity: .47;
line-join: round;
line-comp-op:multiply;
}
line-opacity: .95;
polygon-opacity:1;
opacity:.83;
image-filters:agg-stack-blur(10,10);
comp-op:dst-atop;
}

(for future reference, note: In this code, as opacity gets closer to zero, you are able to see more and more of the area outside of the border.

Resulting in:

As of now, I didn’t use the gray mask that I first intended to do (nor have I figured it out yet) but I’m really liking the results and I’m encouraged by my progress, to be able to do something that I hadn’t before.

Work on this isn’t done (I’d like to customize the colors a little more, maybe add interactivity) and you can follow the progress at its github repo and view the map.

Downtown Cleveland Parking Map

Upon hearing about the (ill-fated) proposed parking garage for the May Company building a couple weeks ago, I wanted to highlight the existing amount of parking that already exists downtown.

So, here’s a map of Downtown Cleveland’s parking,
here’s a map of Downtown Cleveland parking broken down by garage, underground, and surface, hosted by mapbox. The map design is based on osm-bright and the source is available on my github page.

(Update: There are still a handful of lots that are exclusively for some downtown apartment complexes – particularly on West 9th, that are unmapped at the moment).

Cleveland neighborhood map update – Extracting Cleveland OSM data

Quick update to the Cleveland Neighborhood map:

Last week, I figured out how to extract the Cleveland area that I use for the map from the osm data for Ohio.

Extracting a selected area from a larger source of OSM data is a task that happens more often for OSM users and there’s an application that does this – osmosis

Shown in the commands below, the area is selected by Lat/Long points.
bzcat /file/path/ohio.osm.bz2 | osmosis\
--read-xml enableDateParsing=no file=-\
--bounding-box top=41.6000 left=-81.85 bottom=41.4173 right=-81.5323 --write-xml file=-\
| bzip2 > extracted.osm.bz2

(Your top is the northern most point, left is western, bottom is south, and right is east).
First time around, I received an error stating the osmosis command couldn’t be found.. though I had chmod u+x osmosis.

So, I figured to add ./ infront of osmosis (as shown below)

bzcat /file/path/ohio.osm.bz2 | ./osmosis\
--read-xml enableDateParsing=no file=-\
--bounding-box top=41.6000 left=-81.85 bottom=41.4173 right=-81.5323 --write-xml file=-\
| bzip2 > extracted.osm.bz2
and voila, it worked, leaving me with the .OSM data to work with.

An updated version 4.1 is on the way, hopefully by tomorrow. 4.1 will include Hough and North Collinwood.

Cleveland neighborhoo map – Hiccup!

It’s been longer than I anticipated for an update to v4 of the Cleveland neighborhood map because of an unexpected hiccup.

I was attempting to download the OpenStreetMap XML Data of Cleveland through OSM’s API. (see: this image).
Alas, I cannot download it this way, as I had in the past because OSM’s API limits requests to 50,000 nodes. Since I last downloaded the data in December, the number of nodes as increased to over 50,000 thanks in part to mostly me and a few others adding buildings, some roads, cemeteries, and parks to OSM.

Instead, I’m thinking that I’ll have to download the the state of Ohio and then somehow separate the Cleveland data from it.