Mapping NYC subway stations

January 21st, 2012

I previously wrote about showing the transit layer with the Google Maps API, this is somewhat of a continuation, but narrower in scope; here I’ll talk about showing custom markers for New York City subway stations, making use of data from NYC Open Data (formerly the NYC Data Mine).

The reason for doing this at all, given that a Google Map already shows subway stations, is that the default indicators are fairly inflexible:

  • You can’t use a custom icon to change how they look
  • You can’t fire off custom event handlers when the user interacts with them

NYC subway stations near city hall

(this is true for all of the point of interest indicators: parks, schools, etc.)

Replacing the point of interest indications with markers turned out to be fairly simple and the data from NYC Open Data was (relatively) clean and readily usable, a pleasant surprise given my previous experience. For this little project, I exported the Subway Stations dataset; it can be exported in a number of formats, but JSON is probably the easiest to work client-side. With the data readily available as a JSON file, it can be loaded simply with an AJAX call to get the file and, once loaded, the subway stations can be plotted on the map by iterating through the list of stations in the JSON data.

It’s worth taking a look at the format of the JSON data, as the indexing of the nodes isn’t all that clear. There’s a meta element and data element at the root, the data element contains a zero-indexed array of subway stations, and each subway station contains a zero-indexed array of attributes, notably:

  • 10 = station name
  • 12 = dash-delimited list of train lines
  • 9 = object with latitude, longitude, and geometry field
    (Note that these values are referenced by the field name, not a numeric index).

NYC Open Data, Subway Station, JSON format

The code to get the JSON data (using jQuery’s .ajax), iterate through the array of subway stations, extract the relevant pieces of information about the stations, and create map markers for them is shown below. A label is attached to the marker by making use of Marc Ridey’s Label class.

$.ajax({
url:
'http://whatever.com/subway-stops.json',
success:
function (ret)
{
for(var i=0; i<ret.data.length; i++)
{
// extract station name, latitude, longitude, and dash-delimited list of train lines at station
var stationName = ret.data[i][10];
var lat = ret.data[i][9]['latitude'];
var lon = ret.data[i][9]['longitude'];
var trainLines = (ret.data[i][12]).split('-');

// make comma-delimited list of train lines
var trainLinesLbl = '';
for(var k=0; k<trainLines.length; k++)
{
trainLinesLbl += trainLines[k];
if(k < trainLines.length-1)
{
trainLinesLbl +=
',';
}                                    
}

// create marker
marker = new google.maps.Marker({
"position": new google.maps.LatLng(lat, lon),
"map": map,
"title": stationName + " [" + trainLinesLbl + "]",
"icon": "http://whatever.com/marker-subway.png"
});

// create label for marker
// uses Label created by Marc Ridey
var label = new Label({ map: map });
label.bindTo(
'position', marker, 'position');
label.bindTo(
'text', marker, 'title');                                                     
}
}                    
});

With some minor styling to the label and an icon from Map Icons Collection, here’s my result:

NYC subway stations with custom markers

Arch Enemies

January 2nd, 2012

Arch Enemies by Jason Bergsieker,

Arch Enemies

Paintings @ Bright Lyons

December 26th, 2011

Passed by Bright Lyons on Atlantic Avenue in Brooklyn and saw this awesomeness,

Bright Lyons, Homer and Bart

Batching, a basis for optimization

December 18th, 2011

It’s interesting that in 3 distinct domains I’ve run across the same underlying basis for optimization:

  • Graphics: Modern GPUs depend heavily on batching primitives, typically triangles. Instead of rendering triangles individually, you get much better performance by batching primitives together in a list, sending it to the GPU via a single call, then letting the GPU pipelines to do their thing.

    Even before modern GPUs, 2D pixel graphics exploited the embarrassingly parallel nature of computer graphics through operations like BitBlt which, in essence, batched together blocks of pixels.
  • Relational Databases: Issuing lots of small queries can kill performance. A better strategy is usually to make fewer queries, joining and returning as much data as possible with each query. Even if these queries becomes complex and costly, the cost of a complex query will usually still be less than the aggregate cost of numerous simpler queries.
  • Networking: The speed of light sucks… server and packet switching latencies make things worse. I usually assume ~50ms baseline latency to send a request packet + get a reply packet back from an internet server (I use the term “packet” loosely, referring to programmer-defined, application-level “packets” or messages, or whatever you like to call them, not necessarily TCP/IP packets). Note that this baseline is regardless of the amount of information in a packet and is bound by the travel time between server and client.

    So, to optimize communication and bandwidth, a good strategy is to transfer as much as possible per-packet instead of depending upon numerous requests/responses to/from a server, which would mean lots of packets and and lots of wasted time.

Multi-faceted online identities

December 12th, 2011

Incredibly insightful insights by Christopher Poole (“moot”, founder of 4chan and Canvas)

From SXSW earlier this year

Zuckerberg’s totally wrong on anonymity being total cowardice. Anonymity is authenticity. It allows you to share in an unvarnished, unfiltered, raw and real way.

The cost of failure is really high when you’re contributing as yourself, to fail in an environment where you’re contributing with your real name is costly.

As for how anonymity connects to identity, he spoke to this at Web 2.0

It’s not who you share with, it’s who you share as… We all have multiple identities, it’s part of being human, identity is prismatic. Google and Facebook would have you believe you are a mirror, but in fact we’re more like diamonds, you can look at people from any angle and see something totally different and yet they’re still the same

Showing the transit layer with the Google Maps API

December 8th, 2011

While Google Maps has a very useful transit layer (showing subway lines, bus stops, etc.) available when zoomed in on a city, this layer is unfortunately not exposed via the Google Maps API. However, as demonstrated on BlinkTag Inc. by Brendan Nee, it’s possible to load the transit layer as a custom tile layers, pulling the transit layer images directly from Google’s servers.

// add transit overlay
var transitOptions = {
getTileUrl:
function (coord, zoom)
{
return "http://mt1.google.com/vt/lyrs=m@155076273,transit:comp|vm:&" + "hl=en&opts=r&s=Galil&z=" + zoom + "&x=" + coord.x + "&y=" + coord.y;
},

tileSize:
new google.maps.Size(256, 256),
isPng:
true
};

var transitMapType = new google.maps.ImageMapType(transitOptions);
map.overlayMapTypes.insertAt(0, transitMapType);    

Google Maps, Transit Layer, Subway - NYC, City Hall


However, there are 2 issues you may quickly notice:

1. Custom styling applied to the base layer is lost.
This is because full image tiles are loaded, which completely obscures the lower layer. A solution to this is to find and copy the apistyle and style URL parameters when the base layer is loaded (you can do this by looking at the GET requests with a tool like Firebug). You then simply add these paremeters to the URL returned by the getTileUrl() function.

getTileUrl: function (coord, zoom)
{
return "http://mt1.google.com/vt/lyrs=m@155076273,transit:comp|vm:&" + "hl=en&opts=r&s=Galil&z=" + zoom + "&x=" + coord.x + "&y=" + coord.y + "&apistyle=s.t%3A3%7Cp.h%3A%23C5C5C5%7Cp.s%3A-100%7Cp.l%3A37%7Cp.v%3Aon%2Cs.t%3A35%7Cp.h%3A%23F284FF%7Cp.s%3A100%7Cp.l%3A-9%7Cp.v%3Aon%2Cs.t%3A81%7Cp.v%3Aoff&s=Gal&style=api%7Csmartmaps";
},

Google Maps, Transit Layer, Subway - NYC, City Hall

2. The large subway stop markers are useless
In New York City at least, it’s impossible to identify train lines by color alone, so it’s fairly important to see the letter or number identifier for trains at the different stations. The map has both large and small markers for each station, but only the small markers shows this information. I couldn’t figure out a way to get the larger marker to show the letters/numbers, but by changing “vm:” to “vm:1” you can completely remove the large markers from the map. However, this also shrinks the size of the lines indicating the train routes.

getTileUrl: function (coord, zoom)
{
return "http://mt1.google.com/vt/lyrs=m@155076273,transit:comp|vm:1&" + "hl=en&opts=r&s=Galil&z=" + zoom + "&x=" + coord.x + "&y=" + coord.y + "&apistyle=s.t%3A3%7Cp.h%3A%23C5C5C5%7Cp.s%3A-100%7Cp.l%3A37%7Cp.v%3Aon%2Cs.t%3A35%7Cp.h%3A%23F284FF%7Cp.s%3A100%7Cp.l%3A-9%7Cp.v%3Aon%2Cs.t%3A81%7Cp.v%3Aoff&s=Gal&style=api%7Csmartmaps";
},

Google Maps, Transit Layer, Subway - NYC, City Hall

There is a third issue that’s pretty noticeable as well: bus stops do not how the identifier of the buses that stop at them. I’ve yet to find a way to show them.

Gear

November 13th, 2011

Pulling some old photos from my phone.

Grand Canyon, pulley gear

This is a gear from a old pulley system that serviced a mine on the west side of the Grand Canyon.

… Guano Point, is named after an old guano (bat droppings) mine that operated in the 1950′s. Guano was used primarily as a fertilizer because it is extremely rich in minerals. Daring miners would hoist hundreds of pounds of guano across the Colorado River up to the present day Guano Point. The ruins of the mine and pulley system still remain, visitors can walk right up and touch them.

from grandcanyonwest.com

android.process.acore has stopped unexpectedly

October 1st, 2011

This started popping up in my existing AVD after I updated my Android SDK packages:

android.process.acore has stopped unexpectedly error message

Another reason to hate the Android emulator. *sigh*
Not sure what broke, but thankfully doesn’t it occur in newly created AVDs.

Aurora Australis

September 27th, 2011

Posted by @Favidat,

Aurora Australis from the International Space Station

Elegant <img> presentation

September 17th, 2011

While it’s easy to decry Flash and espouse the merits of HTML5, it’s worth taking a look at some of the positive elements found on many Flash sites and seeing what can be brought over to the HTML side. One very obvious aspect is the presentation of images. Flash sites almost never render an image in the way that an <img> tag is rendered by the browser. Flash sites will (typically) elegantly animate or fade an image in/out whereas the default browser behavior for HTML is to progressively render the image as it is received (sometimes images are 2D interlaced for a slightly better effect). Even worse, many HTML sites leave width and height as attributes to be determined dynamically for the <img> tag, resulting in page content shifting around as images are loaded.

Better image presentation is certainly possible with HTML + Javascript, and there are tons of beautiful JS image galleries on the web, but outside of such galleries most developers don’t attempt anything beyond the typical <img> presentation.

So, I did a little experiment with 2 goals in mind:

  • Elegant presentation of images with HTML + JS
  • Very simple markup, one iota above what’s necessary for a typical <img> tag

I’m pretty happy with the results.

elegant img loading

View the demo
(disable your browser cache so that loading latency is accurately taken into account)

Here’s what I did:

1. Make the <img> elements.

e.g.

<img
data-src="http://aautar.digital-radiation.com/elegant-img-loading/p1.jpg"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAQSURBVHjaYvj//z8DQIABAAj8Av7bok0WAAAAAElFTkSuQmCC"
width="200"
height="150"
alt="photo" />

Things to note:

  • The data-src attribute is an HTML 5 custom data attribute. It specifies the URL of the image to be loaded.
  • The src attribute uses the data URI scheme to load and set the initial image displayed in the img element. Leaving the src attribute blank is not desirable as it will collapse the img element and only show the alt tag (the same behavior occurs initially if a URL to an image is specified). Specifying a data URI allows the image to be loaded as part of the document itself. The data URI shown above is for a 1×1, transparent PNG. A GIF preloader would probably be a good idea here.
  • The width and height attributes are specified. This is not strictly necessary, but in keeping with the theme of elegance, this prevent other content on the page from shifting after images are loaded.

2. Write the Javascript code

<script src="jquery-1.6.2.min.js" type="text/javascript"></script>
<
script type="text/javascript">

window.onload = function ()
{
$(
'img').each(function ()
{
var imgElem = $(this);
var src = imgElem.attr('data-src');

var img = new Image();
img.src = src;
img.onload =
function ()
{

imgElem.fadeTo(
'fast', 0.0001, function ()
{
imgElem.attr(
'src', src);
imgElem.fadeTo(
'slow', 1)
});

}

});
}

</script>

For simplicity, jQuery is used.

After the page is loaded, the data-src attribute of every <img> element is read. The image, specified by the data-src attribute, is loaded via a Javascript Image object and, once loaded (Image.onload event fires):

  • The <img> element is faded out (actually faded to an alpha of 0.0001 because a total fadeOut to 0 will effectively remove the element from the document rendering).
  • The src attribute is changed to the the URL of the loaded image.
  • The <img> element is faded in.

The important bit is changing the src attribute; the effect itself, whether it’s fading, sliding, etc. is not terribly important.