Jeff Reifman

I’m a Seattle-based technology consultant. If you found this tutorial helpful, please share it on Twitter & follow me at @reifman.

Purchase a pre-installed image of this tutorial as a Digital Ocean droplet for just $15.

Back in 2008, Zillow released boundary shape files to more than 7,000 U.S. neighborhoods via a Creative Commons Attribution-Sharealike license. Zillow did so to encourage innovation although they are no longer actively maintaining the data.

My community startup Geogram actively combines the Zillow neighborhood data and HTML5 Geolocation to link new users to email groups associated with their local neighborhood.

If you haven’t used geographic shapefiles before, it can be a bit confusing as to how to integrate the Zillow map data into your own application.

I’ve built a free, open source demo application, MapApp, to demonstrate how to use the Zillow neighborhood boundaries and integrate them with Google Maps, geolocation and geocoding.

MapApp is built using the Yii Framework and can be run on any MySQL/PHP-capable server. MapApp also leverages Google Maps API, HTML5 Geolocation helper from estebanav, eGeocoder and egMap (the latter two are Yii extensions).

Setting up your server

To get started, you can find the MapApp code on Github. Follow the installation steps which are tested for the Rackspace Cloud with Ubuntu 12.04 but should work with any version of LAMP.

Follow the installation steps for getting the MapApp code from Github. You can either clone the repository or download a copy. Configure the Apache site (as described in the installation steps) and restart Apache.

Prepare the Zillow Neighborhood Data

Once you’ve created your MySQL database for MapApp, it’s time to get the Zillow data.

Install the Geospatial Data Abstraction Libraries and unzip:

sudo apt-get install gdal-bin
sudo apt-get install unzip

Make a directory to temporarily store the Zillow data and copy the download scripts.

mkdir ~/zillow
cp /var/www/mapapp/docs/wget-zillow.txt ~/zillow/wget-zillow

Customize the batch file to download the files for the states that you want (e.g. California, Oregon, Washington, or all). Then, run the download script. This will download all of the desired zip files from Zillow:

bash wget-zillow

Then, prepare the MySQL import scripts:

cp /var/www/mapapp/docs/import-zillow.txt ~/zillow/import-zillow
copy /docs/import-zillow.txt to ~/zillow/import-zillow

Customize the list of states whose shape files you would like to import into MySQL. You’ll also need to customize the database name, credentials and neighborhood table name in your local file and run the script. This will use the ogr2ogr tool to import the shape (.shp) files into MySQL:

bash import-zillow

Configuring MapApp

You’ll need to customize the /docs/mapapp-config.ini file with your own settings, especially the MySQL access settings:

mkdir /var/www/secure
cd /var/www/secure
cp /var/www/mapapp/docs/mapapp-config.ini /var/www/secure/mapapp-config.ini
sudo nano mapapp-config.ini

Then, run the database migration to initialize MapApp. Database migrations are part of the Yii Framework, and serve to create tables and schema in a programmatic way:

cd /var/www/mapapp
./app/protected/yiic migrate up

When prompted, enter a user name, email and password for your administrator account. This is what you’ll use to login in to MapApp’s home page.

Finally, you’ll need to run a script to reverse the geographic coordinates in the Zillow neighborhoods MySQL table. Visit http://yourdomain.com/mapapp/app/neighborhoods/reverse. Depending on the number of Zillow state files you imported, this could take a few minutes. I’ve found that ogr imports the Zillow latitude and longitude data in an opposite coordinate order than Google Maps requires.

Using MapApp

Visit your home page at http://mapapp.yourdomain.com. Login with the user name and password you created during the database migration.

mapapp-home
Browse your imported neighborhoods and click on any you wish to view.  The next neighborhood link makes it easy to see more than one. You can also search by neighborhood name, city, state or county.

mapapp-neighborhoods

I’m using the Yii extension egMap to display Google Maps using the Zillow neighborhood polygon data. However, any PHP library for Google Maps or Javascript will work just as well.

The prepareMap function in the Neighborhoods model requests the Zillow polygon data from the database as well as the center point of the neighborhood (called a centroid). We use the centroid to position the viewport of the map.

public function prepareMap($id) {
$pg = Yii::app()->db->createCommand()
->select('AsText(SHAPE) as region,ASTEXT(Centroid(SHAPE)) as center')
->from(Yii::app()->getDb()->tablePrefix.'neighborhoods')
->where('OGR_FID=:ogr_fid', array(':ogr_fid'=>$id))
->queryRow();
Yii::import('ext.gmap.*');
$gMap = new EGMap();
$gMap->setJsName('map_region');
$gMap->width = '500';
$gMap->height = '500';
$gMap->zoom = 13;
$center = new stdClass;
list($center->lat, $center->lon) = $this->string_to_lat_lon($pg['center']);
$gMap->setCenter($center->lat, $center->lon);
$coords = $this->string_to_coords($pg['region']);
$polygon = new EGMapPolygon($coords);
$gMap->addPolygon($polygon);
return $gMap;
}

The Neighborhoods controller view action renders the page with the map:

public function actionView($id)
{
$gMap = Neighborhoods::model()->prepareMap($id);
$this->render('view',array(
'model'=>$this->loadModel($id),
'gMap' => $gMap,
));
}

mapapp-neighborhood-view

Click on Geolocation in the Navigation bar to locate your neighborhood from your WiFi address. This will not work via cellular. You will likely need to grant permission to your browser for geolocation for this feature to work.

mapapp-locateme

 We’re using the geoposition script from estebanav to support HTML 5 Geolocation with the widest possible browser support.

Once your location is found, we’ll show your location on a map with your Zillow neighborhood as well as Geocoding information looked up independently.

We use the Yii eGeocoding extension to look up additional data about your location. This is mainly to show additional sources of data you can use beyond the Zillow boundary data.

public function actionIndex()
{
$model = new Geolocation();
if(isset($_POST['Geolocation']))
{
$info = Yii::app()->geocoder->reverse($_POST['Geolocation']['lat'],$_POST['Geolocation']['lon']);
$gps_for_sql = "Point(".$_POST['Geolocation']['lat']." ".$_POST['Geolocation']['lon'].")";
$neighborhood = Neighborhoods::model()->lookupFromLatLon($gps_for_sql);
$gMap = Neighborhoods::model()->prepareMap($neighborhood['OGR_FID']);
$marker = new EGMapMarkerWithLabel($_POST['Geolocation']['lat'],$_POST['Geolocation']['lon'], array('title' => 'You are here!'));
$gMap->addMarker($marker);
$gMap->width = '400';
$gMap->height = '400';
$this->render('view',array( 'data'=>$neighborhood,'info'=>$info,'gMap' => $gMap));
} else
$this->render('index',array( 'model'=>$model));
}

mapapp-youlivehere

Learning More

Free email groups for your block or small business.

I hope you’ve found this helpful. Please feel free to post corrections, questions or comments to this tutorial below. You can also reach me on Twitter @reifman or email me directly.

If you’d like to see more, try out Geogram for yourself. It has a number of extended mapping and email features.

If you’re interested in a tutorial on Geogram’s use of the Mailgun email API, read How Geogram built a free group email service using Yii for PHP with MySQL.

Please feel free to share this tutorial with others on Twitter and elsewhere.

Posted by Jeff Reifman

Jeff is a technology consultant based in the Pacific Northwest.

2 Comments

  1. Very cool. For Django developers, there’s also the django-zillow app: https://github.com/claymation/django-zillow

    Reply

  2. Nicely done! I’m looking for a ruby solution, but I may have to reverse what you did here if I can’t find one. Thx.

    Reply

Leave a reply

Your email address will not be published. Required fields are marked *