Displaying Zip Code Boundaries on Google Maps
February 25th, 2008Using GPolygons to overlay zip code boundaries on Google Maps is relatively straightforward. Finding a recent source for the associated geographical information is a little more challenging.
Not long ago the census bureau freely provided such boundary information because their summary statistics directly correlated with zip code. But as of the 2000 census, the bureau switched to using the ZCTA instead. ZCTA’s, or “zip code tabulation areas,” roughly correspond to zip codes, but there is no longer a one-to-one match.
Still, in many cases, ZCTA data is close enough to satisfy client requirements. It certainly provides an economical way to bridge a gap until a more expensive solution is warranted.
Generally, each zip code corresponds to a single ZCTA. Sometimes a zip code contains two or more ZCTA’s or vice-versa. Certain zip codes, for instance those that are exclusive to post office boxes, do not have a corresponding ZCTA.
Here is a Rails view snippet that displays one or more ZCTA’s:
<div id="gmap" style="width: 400px; height: 300px;"></div>
<script>
var map;
if( GBrowserIsCompatible() ) {
map = new GMap2( $( 'gmap' ) );
map.setCenter( new GLatLng( <%= @center %> ), @zoom );
<% @zctas.each do |zcta| %>
polylines = [ { color: '#888888',
weight: 4,
opacity: 0.85,
points: '<%= zcta.points %>',
zoomFactor: 32,
levels: '<%= zcta.levels %>',
numLevels: 4 } ]
<% zcta.zcta_masks.each do |mask| %>
// append masks
polylines.concat( [ { color: '#888888',
weight: 4,
opacity: 0.85,
points: '<%= mask.points %>',
zoomFactor: 32,
levels: '<%= mask.levels %>',
numLevels: 4 } ] )
<% end %>
map.addOverlay( new GPolygon.fromEncoded( {
polylines: polylines,
fill: true,
color: '#CC7700',
opacity: 0.25,
outline: true
} ) );
<% end %>
window.onunload = GUnload;
}
</script>
The above view snippet requires a controller action that loads the @center, @zoom, and @zctas instance variables. The @zctas instance variable references a collection of models created from the following schema:
ActiveRecord::Schema.define(:version => 1) do
create_table "zcta_masks", :force => true do |t|
t.integer "zcta_id", :null => false
t.text "points"
t.text "levels"
end
create_table "zctas", :force => true do |t|
t.integer "zcta", :null => false
t.integer "area", :null => false
t.integer "zipcode", :null => false
t.float "lat"
t.float "lng"
t.text "points"
t.text "levels"
end
end
The ‘zctas’ table holds the encoded points and levels for the polyline that describes the zcta exterior boundary. The ‘zcta_masks’ table holds the optional polylines used to subtract interior sections.
The required zcta dataset can be downloaded in raw form from the US Census Bureau and then processed using the Encoded Polyline Algorithm Format. Alternatively, a pre-encoded dataset with an example Rails app can be purchased for $199 from Austin Rail Yard.