Skip to content

Vagrant based Expanded Install Process

Andrew Thompson edited this page Mar 5, 2014 · 18 revisions

This install process uses Vagrant to manage the Virtual Machine, which introduces some particularities (specifically around Postgres) to the install. But you don't have to use Vagrant with OpenTreeMap if you don't want to - feel free to use VirtualBox, another VM host, or install OTM right on your webserver.

In addition to using vagrant, this install guide adds value over the "Install Process on Ubuntu 12.04" wiki page because it is newer and reflects v1.3 changes (like the addition of a default template); includes/combines tricky steps like configuration of Geoserver and Tilecache that were spread over many separate wiki pages; and begins to set up a robust virtualenv and nginx based environment similar to how Azavea deploys production OpenTreeMap instances.

##Step 1 (optional): Install Vagrant

If you want to use the Vagrant to manage your OpenTreeMap VM, download and install it for your platform: http://downloads.vagrantup.com/

vagrant box add base http://files.vagrantup.com/precise32.box   
vagrant init   
vagrant up   
vagrant ssh   

##Step 2: Git clone!

Many of the commands in this installation require root privileges; only switch to the root user prompt with the command below if you're comfortable with what you're doing and have room to experiment. (It's a virtual machine with nothing else on it, so there's pretty low risk.) We will, so we don't have to add "sudo" to many of the following commands. You could use "sudo" independently each time, or change the folder permissions for your user instead.

sudo su  

Make a directory for OpenTreeMap and its main components. We'll use /var/projects/otm, but yours could be anything.

mkdir /var/projects/otm  
cd /var/projects/otm  

Install git (if you don't have it yet) and clone the OpenTreeMap repository. As of June 2013, the most recent branch to clone off of is v1.3.

apt-get install git  
git clone -b v1.3 git://github.com/azavea/OpenTreeMap.git  

##Step 3: Set up Python environment and gather dependencies

OpenTreeMap is a Django application written mainly in Python, and requires specific versions of a number of other Python libraries to function. Conveniently, a "requirements.txt" file is included in the repository that can be used with the pip installer to download and install these dependencies easily.

Copy the requirements.txt file out into your main otm directory.

cp OpenTreeMap/requirements.txt requirements.txt 

Next, we'll install pip using Python's older "easy_install" feature.

apt-get -y install python-setuptools  
easy_install pip  

Now we'll use pip to install virtualenv, a tool used for creating isolated Python environments. Virtualenv is useful for keeping many different versions of dependencies installed on the same machine without having them conflict with one another. This means OpenTreeMap can have its own library versions, and any other Python applications you have running on your machine can have their separate versions too.

pip install virtualenv  

Create a virtual environment in your otm directory, so you know to what it belongs to.

cd /var/projects/otm #if you're not already here  
virtualenv env #you can call it something more distinctive than "env," but it's conveniently short  

Activate the environment. Notice an "(env)" indicator appears at the beginning of your command prompt line, signifying that you are using this particular environment.

source env/bin/activate  

Next, we'll use aptitude to get many non-Python libraries we need. It's a good idea to update your aptitude repositories so Ubuntu knows where to find the libraries we're going to install.

apt-get update  
sudo apt-get install sendmail  
apt-get install postgresql  
apt-get install python-dev build-essential postgresql-server-dev-all  
apt-get install libgdal1-1.7.0  
apt-get install libgdal1-dev  

Finally, we install the required Python dependencies into our virtual environment!

pip install -r requirements.txt  

Update October 7, 2013: The newest version of pip won't install "pre-release version numbers" of python libraries by default. The version number scheme used by the "pytz" timezone library (depended on by celery, an OTM dependency) conflicts with this new behavior and could cause your "pip install -r requirements.txt" step at this point to fail. If this happens, OpenTreeMap user Josh has posted a few workarounds to the problem on the mailing list. If you have any questions about this step we encourage you to post to that thread.

##Step 4: Install Python bindings for GDAL

GDAL is an open source geospatial data transformation library. Unfortunately, something went awry/missing in the packaging of the Python bindings for GDAL 1.7, so this step is a bit tricky. Just trust us.

pip install --no-install gdal==1.7.0  
cd /usr/lib && sudo ln -s libgdal1.7.0.so libgdal.so  
cd /usr/include/gdal  

Find the swq.h file in this directory (/usr/include/gdal). It (mistakenly) is probably empty. Delete this empty version and make sure it's gone.

rm swq.h  

Now we have to download the right, non-empty swq.h file to this folder from the Internet...

wget http://svn.osgeo.org/gdal/branches/1.7/gdal/ogr/swq.h > swq.h  

To finish the installation of the GDAL Python bindings, we'll run setup.py and pip install again, with the proper include directories.

cd /var/projects/otm/env/build/gdal  #where env is the name of the virtualenv you made
python setup.py build_ext --include-dirs=/usr/include/gdal  
pip install --no-download gdal  

##Step 5: Install PostGIS

cd /var/projects/otm/OpenTreeMap  
apt-get install postgresql-9.1-postgis postgis  

##Step 6: Install final set of Python dependencies that couldn't be installed easily through pypi

These include django-registration and django-reputation, which are only in bitbucket and Google Code repositories.

pip install https://bitbucket.org/ubernostrum/django-registration/downloads/django-registration-0.8-alpha-1.tar.gz

apt-get install subversion  
  
cd /var/projects/otm  
mkdir temp  
cd temp  

svn checkout http://django-reputation.googlecode.com/svn/trunk/ django-reputation  
  
cp -r django-reputation/django_reputation/ ../env/lib/python2.7/site-packages/  #where env is your virtualenv name

##Step 7: Apply patches to dependencies

fix proj, django-sorting, and django-reputation patches listed in README now

A few dependencies have bugs we'll need to fix. These patches we need to apply are also in the README file.

###Proj Fix proj to deal with spherical mercator

cd /var/projects/otm/temp # or other temp directory
wget http://download.osgeo.org/proj/proj-datumgrid-1.4.tar.gz
mkdir proj-datumgrid-1.4
tar -xzf proj-datumgrid-1.4.tar.gz -C proj-datumgrid-1.4
cd proj-datumgrid-1.4
nad2bin null < null.lla
sudo cp null /usr/share/proj

###django-sorting Apply patch to sorting_tags.py file within django-sorting:

cd /var/projects/otm/env/lib/python2.7/site-packages/django_sorting/templatetags

Edit sorting_tags.py file within that directory following: https://github.com/directeur/django-sorting/issues#issue/8 -including comment by Alsaihn

###django-shapes

cd /var/projects/otm/env/lib/python2.7/site-packages/shapes

Apply patch to shapes/views/export.py. In shapes/views/export.py - zip-response method - change:

            # Stick it all in a django HttpResponse
            #response = HttpResponse(zip_stream, mimetype=mimetype)
            #response['Content-Disposition'] = 'attachment; filename=%s.zip' % file_name.replace('.shp','')
            #response['Content-length'] = str(len(zip_stream))
            #response['Content-Type'] = mimetype
            #response.write(zip_stream)
            return zip_stream

###django-reputation

cd /var/projects/otm/env/lib/python2.7/site-packages/django_reputation

Change default config and user bug: (b/c it doesn't seem to accept values in settings.py)

In config.py, change values as needed.

In models.py - change:

                ....
                relevant_reputation_actions = UserReputationAction.objects.filter(user=user).filter........
                ....
                if expected_delta <= MAX_REPUTATION_GAIN_PER_DAY and expected_delta >= -1 * MAX_REPUTATION_LOSS_PER_DAY:
                    delta = action_value
                elif expected_delta > MAX_REPUTATION_GAIN_PER_DAY:
                    delta = 0
                elif expected_delta < MAX_REPUTATION_LOSS_PER_DAY:
                    delta = 0
                ...

##Step 8: Create PostGIS-enabled database template

To do this, we'll need to switch to the Postgres user prompt.

su postgres  

And run the psql prompt. This is where some of the particularities around using Vagrant (if you are using it) can come to bite if you're not careful. Vagrant's Ubuntu has its Locale set up differently than PostGIS is expecting.

For more information, see:

Ubuntu docs on Locale

Gist on installing Postgres in Vagrant

Article on installing Postgres in Vagrant

Article on changing locale of Postgres install

If you're using vagrant, do this:

psql  
CREATE DATABASE template_postgis OWNER postgres TEMPLATE template0 ENCODING 'UTF8' LC_CTYPE 'en_US.UTF8' LC_COLLATE 'en_US.UTF8';  
l\q

If you're NOT using Vagrant, you only need to do this:

psql  
CREATE DATABASE template_postgis OWNER postgres; 
l\q  

Now we need to load PostGIS' features into our PostGIS template database.

psql template_postgis -f /usr/share/postgresql/9.1/contrib/postgis-1.5/postgis.sql  

psql template_postgis -f /usr/share/postgresql/9.1/contrib/postgis-1.5/spatial_ref_sys.sql  

##Step 9: Create the OpenTreeMap database

We'll use a database "otm" accessed by a user "otm" with password "otm." If this was production, you might want different/descriptive/secure values for those.

psql  
CREATE USER otm ENCRYPTED PASSWORD 'otm';  
CREATE DATABASE otm OWNER otm TEMPLATE template_postgis;  
\c otm  
alter table geometry_columns OWNER TO otm;  
alter table spatial_ref_sys OWNER TO otm;
\q  
  
exit #from postgres user back to your own shell  

##Step 10: Modify OTM's local_settings.py file

It needs to have your database connection information, and other things.

cd /var/projects/otm/OpenTreeMap # if not already  

cp local_settings.example.py local_settings.py  

Edit your new local_settings.py with your database user and password like below:

DATABASES = {
    'default' : {  
        'NAME' : 'otm',  
        'ENGINE' : 'django.contrib.gis.db.backends.postgis',  
        'USER' : 'otm',  
        'PASSWORD' : 'otm',  
        'HOST' : '127.0.0.1',  
        'PORT' : '5432',  
    }  
}  

Other changes to make in local_settings.py include:

  • TEMPLATE_DIRS contains os.path.join(os.path.dirname(__file__), 'templates') (meaning - the templates directory in the same parent directory as this local_settings.py file), and that's where the templates folder from the repository is
  • STATICFILES_DIRS has the same thing (you will have to add it) os.path.join(os.path.dirname(__file__), 'static')
  • change the SECRET_KEY to something unique
  • change STATIC_ROOT, we suggest '/usr/local/otm/static'
  • change emails in ADMINS and DEFAULT_FROM_EMAIL

##Step 11: Create a choices.py file

Imported by the local_settings.py file, the choices.py file defines possible "choices" for various values and dropdown lists available in the OpenTreeMap user interface. For example, you might have particular kinds of plot types you want to track, stewardship activities, conditions, etc. There is a choices.example.py file already in the OpenTreeMap repository, which has several default values. If you just want to get started, simply rename this file to choices.py:

cp choices.example.py choices.py

Note, you may need to add a pests category at the end - you may run into errors later on without it:

'pests': [  
]  

##Step 12: Run syncdb and migrate

cd /var/projects/otm
source env/bin/activate #if not already
cd OpenTreeMap
python manage.py syncdb  

The syncdb command above should ask you to create a Django superuser. Please do, and remember the username and password you use. Next, run migrate:

python manage.py migrate  

##Step 13: Test! (Is it alive?)

Now we're at the point we can perform our first test and see if we get something that looks like a treemap!

###Using vagrant?

If you're using vagrant, you'll have to "halt" the machine and change the port forwarding in your VagrantFile. Something like this should do it:

config.vm.network :forwarded_port, guest: 8000, host: 8000

Next, you'll have to "vagrant up" and ssh again. With your virtualenv activated and in your /var/projects/otm/OpenTreeMap directory:

python manage.py runserver 0.0.0.0:8000

###Not using vagrant?

python manage.py runserver

###Both vagrant and not vagrant

Get a web browser on your host machine (or your VM/server if its not headless) and try http://localhost:8000/map/. Does a page come up? Yay!

Test http://localhost:8000/\_admin\_/ - if no CSS shows up, check your local_settings.py file and change/add:

ADMIN_MEDIA_ROOT = os.path.join(os.path.dirname(__file__), '..', 'admin_media/')
ADMIN_MEDIA_PREFIX = '/admin_media/'

Then, add a link to your django admin_media file:

ln -s /var/projects/otm/env/lib/python2.7/site-packages/django/contrib/admin/media /var/projects/otm/admin_media

##Step 14: Install and configure the nginx HTTP server

apt-get install nginx  

cd /etc/nginx/sites-available

touch otm

Modify the new "otm" file you just created in the sites-available directory to look something like this. We're adding a lot here, we'll eventually get to it all as we go through the next steps:

upstream otm {
    server localhost:12000;
}

server {
    listen 8000;

    location / {
        proxy_pass http://127.0.0.1:12000;
    }

    location /static/ {
        alias /var/projects/otm/OpenTreeMap/static/;
    }

    location /geoserver {
        proxy_pass http://127.0.0.1:8080/geoserver;
    }

    location /tilecache {
        proxy_pass http://127.0.0.1:8081/tilecache;
    }
}

Next, we need to symlink that nginx configuration file in sites-available to sites-enabled to enable it:

ln -s /etc/nginx/sites-available/otm /etc/nginx/sites-enabled/otm

Now, for the config to take effect, restart nginx with a:

service nginx restart

##Step 16: Add users and groups and permissions in Django

Read the wiki page on Users and Groups. With nginx configured, you should be able to access the Django admin interface by first running

python manage.py runserver 12000

remember the 12000 or other port you put into the nginx config, and to activate your virtualenv.

Now, go to http://localhost:8000/\_admin\_/ from a browser on your host machine. Log in with the Django superuser credentials you created in Step 12. Add the new Management group for Management users, and the new Reputation Actions for the Trusted Users in the Django admin.

##Step 17: Install Geoserver

Use your favorite app server, like Apache Tomcat.

apt-get install tomcat7

cd /var/projects/otm/temp
wget http://downloads.sourceforge.net/geoserver/geoserver-2.3.1-war.zip
unzip geoserver-2.3.1-war.zip  

cp geoserver.war /var/lib/tomcat7/webapps

For more information or tips about moving your data directory, you may want to read the Setting up Geoserver for OTM wiki page. Because we're using nginx as a proxy, the port change shouldn't be necessary, however. We'll also be covering most of that wiki page in the next few steps.

##Step 18: Wrangle your neighborhood data

You will need a set of "neighborhoods" or other geographical boundaries to use with OpenTreeMap. These could be states, counties, municipalities, actual neighborhoods within municipalities, or any combination thereof. Increasingly, you can get these from government open data catalogs, often in "shapefile" format. A shapefile often comes as a .zip file with a number of constituent files (.prj, .dbf, .shp, etc.)

Get your hands on a neighborhood shapefile, and unzip it to a directory. You can use a tool called "shp2pgsql" to turn the shapefile into SQL statements to build a table from in PostGIS.

A crucial point - many shapefiles from government data catalogs will use a special projection (denoted by EPSG codes), often specific to that area. It can be easier to work with spatial data if it's all of the same projection. Assuming that the tree locations you'll eventually import probably are already in latitude and longitude (and unprojected at that - they probably came directly from a GPS), it makes sense to import your neighborhoods into PostGIS as unprojected latitude and longitude too. That's EPSG code 4326.

Replace the "####" below with the EPSG code your shapefile came in. Also, when running this command, make sure the directory you're in has the .shp file as well as the .dbf, .prj, and any other files that were unzipped, and that they all have the same name (aside from the file extension). shp2pgsql will use them all, but it doesn't matter which file you run the command on. The .shp is a safe bet.

shp2pgsql -s ####:4326 YOURFILENAMEHERE.shp > YOURFILENAMEHERE.sql  

Now we can run this SQL file, which will create a table in our database with the same name as the file.

sudo su postgres

psql otm -f YOURFILENAMEHERE.sql  

##Step 19: Insert neighborhood SQL data into treemap_neighborhood table

Now, let's go into psql and select the relevant columns from our new YOURFILENAMEHERE table and insert them into the treemap_neighborhood table. Viewing the data in the table we created with PGAdmin on your host might be helpful to determining which columns you'll need and how to map them to treemap_neighborhood, but you can also view table data with the psql prompt and a SELECT * command. (If you're using Vagrant, you may need to go into your VagrantFile again and port-forward the Postgres port 5432 to your host, and then run PGAdmin on your host connecting to localhost:5432. You should be able to use user "postgres" and a blank password.)

Keep in mind the way OTM cycles through neighborhoods - you should import your neighborhoods with the smallest geographic areas first into the treemap_neighborhoods table, then municipalities, counties, states, so on and so forth.

Note, the table that shp2pgsql created for your shapefile may have radically different columns than the treemap_neighborhood table. For reference, here are the treemap_neighborhood table's columns and types:

id - serial primary key
name - varchar(255)
region_id - integer
county - varchar(255)
state - varchar(2)
geometry - geometry

###Here's the quick risky way to do the import:

sudo su postgres  
psql  
\c otm  
INSERT INTO treemap_neighborhood (id, name, region_id, city, county, state,
geometry) SELECT YOURTABLENAMEHERE.your_id_field, YOURTABLENAMEHERE.your_name_field, 42,
'Your County', 'Your State', YOURTABLENAMEHERE.the_geom FROM YOURTABLENAMEHERE;  

Notice in the above statement we combined some fields, with 'string constants', with an integer constant - useful if your shapefile doesn't have all this info but your treemap will only end up covering one county, or state, etc. The "region_id" can be any integer constant - it doesn't have an affect on eco-benefit calculations, but it's useful if your forestry organization separates various neighborhoods or geographic areas into different regions for management/admin purposes, etc.

###Here's the safe way to do the import: The alternative to trying to stuff all your data in wholesale, is to first create a temporary table, insert data into that, verify it's correct, then copy the temporary table's data over into treemap_neighborhood:

alternative is to create temporary table, insert, check, then select *

CREATE TABLE temp_nhood (id serial primary key, name varchar(255) NOT NULL,
region_id integer NOT NULL, city varchar(255) NOT NULL, county varchar(255)
NOT NULL, state varchar(2), geometry geometry);  

INSERT INTO temp_nhood... # same as quick-risky statement above.....  

# check the data using psql select *, or PGAdmin, once correct:

INSERT INTO treemap_neighborhood SELECT * FROM temp_nhood;  

##Step 19: Create tree_search view

There's a sql script in the OTM repository that must be run to create a database view:

cd /var/projects/otm/OpenTreeMap  
  
sudo su postgres  
  
psql -d otm -a -f scripts/db/create_search_view.sql  

##Step 20: Grant your OTM user permissions on said view

An easy way to run this is via the PGAdmin SQL query window on your host. You could also use the psql prompt within your VM.

GRANT SELECT ON tree_search TO otm;  

##Step 21: Import i-Tree data

The i-Tree importer section of the Importing Data wiki page gives a good overview of how to install the i-Tree suite, save the ResourceUnit CSV files, and import them with the import script. Remember, a good way to get files from your host machine to the Vagrant VM is to use the shared "/vagrant" folder.

python manage.py itree_import /vagrant/itree/Hydro_Interception.csv hydro_interception_dbh  
#....so on and so forth for all fields....

##Step 22: Import species data

Determine which species of tree you're going to allow in your OTM installation, and make a csv file with their information following the species_import_template.csv.

Then, use the manage.py command to import them.

python manage.py speciesimport /vagrant/itree/species_import_mycity.csv  

##Step 23: Import trees (if you have them yet!)

Following the uimport template, make a csv file of whatever beginning inventory you've done. Perhaps you can get this information from an open data catalog or a horticultural society in your area.

You may want to import this tree information in small chunks to start out if you have hundreds or thousands. The import process may take a long time - 10 seconds per tree is not unheard of.

python manage.py uimport /vagrant/itree/small_inventory.csv
# now run the following command to update aggregate eco benefit values
python manage.py update_aggregates

If you have a lot of trees, the following workaround was suggested on the opentreemap-user listserv:

By the time I had 20,000 trees or so in the database, each additional tree was taking minutes... when you have 10k more to go things got ugly... The problem is related to (treemap/models.py) Tree.quick_save --> Plot.save --> Tree.update_aggregate. I eventually replaced plot.save with plot.quick_save to make thing work After importing all tree sets, then I run python manage.py update_aggregates

##Step 22: Add Workspace, Store, and layers in Geoserver

Note, you'll need your nginx proxy configured as we discussed above to get into the Geoserver admin from your host machine at http://localhost:8000/geoserver. Default password is admin/geoserver.

First, create a new Workspace. To be simple, give it a name of "otm" with a Namespace URI also of "otm". Hit Save.

Next, add a new Store. Select the PostGIS option. Put it in the "otm" Workspace you just made. Give it a Data Source Name. This could be "otm- yourcity" or something like that. Give it the right connection parameters, specifying the "otm" database you created earlier and the "otm" user. Other defaults should be fine. Hit Save.

Next, go to the Layers tab, and click "Add a new resource". Add it from the "otm :otm-yourcity" Store you just created. In the list of possible layer names that pops up (based on the tables available in your Postgres/PostGIS database), search for the "treemap_neighborhood" layer name and hit "Publish." Default name and title should be fine, the important bits are the Coordinate Reference Systems and the Bounding Boxes.

If you imported your neighborhood shapefile as 4326, select that as the native and declared SRS. Next, you should be able to hit "compute from data" and "compute from native bounds" to get the two Bounding Boxes automatically. Save the treemap_neighborhood layer.

Now, we need to add a treemap_plot layer. Go through the same steps as you did for the treemap_neighborhood layer, except publish the "treemap_plot" layer. And, importantly, copy/paste the 8 bounding box coordinates from the treemap_neighborhood layer rather than computing them automatically. The treemap_plot layer defines where users are allowed to add plots (and thus trees). We want users to be able to add trees throughout the different neighborhoods, rather than limiting ourselves to where our original import of trees was!

Finally, add a new layer for the "tree_search" view. Assuming the tree data you'll be importing has unprojected latitude and longitude points, your Declared SRS can be "EPSG:4326" and SRS Handling can be "Force Declared". Next, for the two Bounding Boxes, you should be able to hit "Compute from data" and "Compute from native bounds." If you run into errors, go back to step 20 and check that the user you set up for your Store has proper permissions to view the tree_search view.
Hit Save.

##Step 23: Create a Geoserver Layer Group

Next, we'll create a "Layer group" to facilitate caching the map tiles. This group will have neighborhoods and plots combined. You could also add a treemap_trees layer and add it to the group too if you wish.

In the Geoserver admin, go to Data > Layer groups and add a new one.

Name otm
Title otm
Workspace otm

(of course, you can change these names [except the workspace] to anything you'd like)

Next, add the treemap_neighborhood layer and the treemap_plots layers. Ordering here does matter. Neighborhoods could be on top of trees, or vice versa depending on your preference. Just use the up and down arrows to switch order.

Hit the Generate Bounds button, and save.

##Step 24: Add the new tree_search layer to local_settings.py

Look for the GEOSERVER_GEO_LAYER parameter in local_settings.py. If you kept the defaults, you should set this to 'otm:tree_search'. IE, workspace:layer.

Next, change the GEOSERVER_URL to 'http://localhost:8000/geoserver/wms', assuming that's the port and location you configured with nginx.

##Step 25: Install TileCache

TileCache is our map tile server. This is so your users can view your data in Geoserver through the Openlayers map in their browsers.

cd /var/projects/  
mkdir tilecache  
cd tilecache  
deactivate # if needed to deactivate the current otm virtualenv that may be activated
virtualenv env # create new one  
source env/bin/activate  
pip install tilecache  
pip install paste  
cp env/TileCache/tilecache.cfg /etc/tilecache.cfg  

##Step 26: Configure TileCache

Edit the /etc/tilecache.cfg file you just created, like below. Comment out the [basic] configuration and put yours underneath it.

[OTM]  #name tilecache layers CAPITALS of geosever layer names, as a convention  
type=WMS
url=http://localhost:8080/geoserver/wms?transparent=true
extension=png
layers=otm:otm #the name of the layer group  
bbox=-20037508.34,-20037508.34,20037508.34,20037508.34 # bounding box of the world in [Web Mercator](https://en.wikipedia.org/wiki/Mercator_projection)
srs=EPSG:900913
reproject=true
levels=22  

##Step 27: Add tilecache to nginx config if you haven't already in step 14

cd /etc/nginx/sites-available/  

Edit the otm file here.

...
server {  
        listen 8000;  
        ...
        location /tilecache {  
                proxy_pass http:127.0.0.1:8081/tilecache;
        }  
}  

Restart nginx

sudo service nginx restart  

##Step 28: Fix TileCache TMS bug

cd /var/projects/tilecache/env/lib/python2.7/site-packages/TileCache/Services  

Edit the TMS.py file here, and add a missing line:

...  
elif len(parts) < 2:  
        return self.serviceCapabilities(host, self.service.layers)  
else:  
        parts = parts[-5:] # this is the line that needs to be added!!!  
        layer = self.getLayer(parts[1])  
        if len(parts) < 3:  
               ...

##Step 29: Add TileCache settings to local_settings.py

cd /var/projects/otm/OpenTreeMap/ 

Edit local_settings.py, and look for and change these tilecache settings:

TILECACHE_URL = "http://localhost:8000/tilecache"  
TILECACHE_LAYER = "OTM"  

##Step 30: Change Bounding Box in local_settings.py

The bounding box should be latitude and longitude centered around the area you want your treemap to focus on. For instance, the points for a treemap in Toronto, Canada might be:

BOUNDING_BOX = { # WKID 4326
    'left': -79.9167,
    'bottom': 43.5000,
    'right': -78.3600,
    'top': 43.5600
}

MAP_CENTER_LAT = 43.6481
MAP_CENTER_LON = -79.4042

##Step 31: Change restricted extent in static/js/map.js

In map.js, you'll find:

var restr = new OpenLayers.bounds(#a bunch of really long numbers here#)

Those really long numbers are Web Mercator meters. They define the maximum area users can pan the map, so you'll want to set those coordinates so they contain the full area where your treemap will cover. For instance, taking the Toronto, CA example again:

var restr = new OpenLayers.bounds(-8865393.302464582, 5400823.198323851, -8807062.507587653, 5443096.924338368)

If you're looking for a way to convert decimal latitude and longitude into Web mercator meters, this Github gist does the trick.

##Step 33: Add values to treemap_benefitvalues table

The treemap_benefitvalues table is where OpenTreeMap gets its information about the prices of various eco-benefits: KWH of electricity, natural gas savings, etc etc. This information varies from city to city and region to region. To get accurate information for your area, you'll have to do some research. The units of these values can be found on the External Data wiki page.

In addition to displaying the main eco-benefit sidebar on the main page, values in this table are needed to perform tree and neighborhood searches. If you leave it blank, many links (particularly to /search/) will result in 500 server errors. If you just want to get the map working, you can use the default values from phillytreemap.org:

id - 3
area - Philadelphia
stormwater - 0.0099
electricity - 0.1262
natural_gas - 1.5
co2 - 0.00334
ozone - 4.59
nox - 4.59
pm10 - 8.31
sox - 3.48
voc - 2.31
bvoc - 2.31

Once you change the values in this table, it is a good idea to run the "resave_trees" command in the treemap/management/commands directory. This is especially true if you already imported/have tree records in your database.

python manage.py resave_trees

##Step 34: Start TileCache

cd /var/projects/tilecache/  

source env/bin/activate
  
tilecache_http_server.py -p 8081 # or whichever port you put in nginx config  

##Step 35: Start Django runserver

cd /var/projects/otm

source env/bin/activate

python OpenTreeMap/manage.py runserver 12000

Visit your map from your host machine: http://localhost:8000/map/

With any luck, you should see your trees and neighborhoods you imported on the map, be able to pan and zoom, search by species, and other features. Huzzah!

##Things you might want to do now:

Change your Geoserver SLDs (Styled Layer Descriptors) to something better looking than solid gray neighborhoods with bright red tree square dots.

Instead of using Django's builtin runserver, get a more versatile solution like Gunicorn running before you deploy to production. Also take a look at how gunicorn and nginx can work together.