<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mikejcorey.com &#187; Tutorials</title>
	<atom:link href="http://www.mikejcorey.com/wordpress/category/tutorials/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mikejcorey.com/wordpress</link>
	<description>Online mapping, data visualization, and the future of journalism.</description>
	<lastBuildDate>Fri, 25 Feb 2011 21:53:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Tutorial part 2: Create beautiful hillshade maps from digital elevation models with GDAL and Mapnik</title>
		<link>http://www.mikejcorey.com/wordpress/2011/02/25/tutorial-part-2-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/</link>
		<comments>http://www.mikejcorey.com/wordpress/2011/02/25/tutorial-part-2-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/#comments</comments>
		<pubDate>Fri, 25 Feb 2011 21:31:44 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[digital elevation model]]></category>
		<category><![CDATA[gdal]]></category>
		<category><![CDATA[GeoTIFF]]></category>
		<category><![CDATA[gis]]></category>
		<category><![CDATA[Mapnik]]></category>
		<category><![CDATA[open-source]]></category>

		<guid isPermaLink="false">http://www.mikejcorey.com/wordpress/?p=389</guid>
		<description><![CDATA[In part 1 of our GDAL and Mapnik hillshade map tutorial, we used GDAL to convert tiled USGS digital elevation models to a merged GeoTIFF. When also reprojected the map to Mercator and used a California border shapefile to cut...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.mikejcorey.com/wordpress/2011/02/05/tutorial-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/">In part 1 of our GDAL and Mapnik hillshade map tutorial</a>, we used GDAL to convert tiled USGS digital elevation models to a merged GeoTIFF. When also reprojected the map to Mercator and used a California border shapefile to cut out just the state of California.</p>
<p>In this installment, we&#8217;ll use the result as a Mapnik layer, and check out some different options for using raster data in your Mapnik maps.</p>
<p>Before we dive in, a note about versions. In this tutorial I&#8217;m using Mapnik2, which is now in beta release. I&#8217;m doing this both because Mapnik2 adds some exciting new capabilities, and so this tutorial is worth anything for more than a few weeks. Even though Mapnik2 is still beta, I&#8217;ve been running it for several weeks now and so far haven&#8217;t run into any serious difficulties, so especially if you&#8217;re on Mac OS X, I&#8217;d recommend giving version 2 a shot.</p>
<p>Even if you do run into problems, <a href="http://www.mail-archive.com/mapnik-users@lists.berlios.de/info.html">the Mapnik listserv is very active</a>, and the developers themselves are very quick to respond with help and to fix bugs. If only every open-source project was so well-maintained!</p>
<p>If you&#8217;re not running version 2, a lot of this will still work, though you might need to tweak syntax a little bit. I&#8217;ll note anything you just can&#8217;t do in Mapnik before version 2.</p>
<p><strong>Data mis en place</strong></p>
<p>Here&#8217;s the data we&#8217;ll use for this part of the tutorial:</p>
<ul>
<li><a href="http://www.mikejcorey.com/download/ca-mercator.tar.gz">A California border shapefile in Mercator projection (SRID 3395)</a></li>
<li><a href="http://www.mikejcorey.com/download/california_county_shortline.tar.gz">A California county/shorelines shapefile (SRID 4326)</a></li>
<li><a href="http://www.mikejcorey.com/download/california_water.tar.gz">A California water shapefile (SRID 4269)</a></li>
<li><a href="http://www.mikejcorey.com/download/ca-dem-combined-merc-cutout.tif.gz">The final GeoTIFF cutout from part 1</a> (This is an 88 MB file, so don&#8217;t download if you don&#8217;t have to!)</li>
</ul>
<p>Now on to the fun!</p>
<p>First, let&#8217;s do a basic Mapnik map with our GeoTIFF layer. For many Mapnik maps, <a href="https://github.com/mapnik/Cascadenik/wiki/Cascadenik">Cascadenik makes styling much simpler for anyone familiar with CSS syntax</a>, but currently (February 2011) Cascadenik doesn&#8217;t support raster layers. So we&#8217;ll start with this XML:</p>
<p><code>&lt;Map srs="+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="hillshade style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;RasterSymbolizer opacity="1" scaling="bilinear" mode="normal" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="hillshade"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;hillshade style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;gdal&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/yourname/Documents/gdaltutorial/ca-dem-combined-merc-cutout.tif&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;<br />
&lt;/Map&gt;</code></p>
<p>Let&#8217;s break this down in stages. First, the overall <strong>&lt;Map&gt;</strong> wrapper:</p>
<p><code>&lt;Map srs="+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"&gt;<br />
&lt;/Map&gt;</code></p>
<p>This is where we set the projection of the overall map. Don&#8217;t worry, you don&#8217;t need to understand what all of it means (although it&#8217;s fun to find out!). As you no doubt noticed, this is the same srs data we used to reproject our GeoTIFF in part 1.</p>
<p>One of the great features of Mapnik is that even if the data for separate layers are in different projections, in most cases Mapnik can simply reproject that data on the fly. You can&#8217;t reproject raster data within Mapnik, however, so you&#8217;ll always want to be sure that you get your GeoTIFF into the projection you want your final map to use before you get to Mapnik (as we did in part 1).</p>
<p>Now let&#8217;s drop down a bit to the layer data:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="hillshade"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;hillshade style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;gdal&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/yourname/Documents/gdaltutorial/ca-dem-combined-merc-cutout.tif&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;</code></p>
<p>This is where we tell Mapnik what type of data we&#8217;re using for this layer. Inside the <strong>&lt;Datasource&gt;&lt;/Datasource&gt;</strong> tags, we specify the data type (<strong>gdal</strong>), and point to the location of our GeoTIFF file. It&#8217;s good practice to use the absolute path to your files so if you move your Mapnik files you won&#8217;t break the script.</p>
<p>The remaining line inside our <strong>&lt;Layer&gt;&lt;/Layer&gt;</strong> tags is the <strong>&lt;StyleName&gt;&lt;/StyleName&gt;</strong>. This tells Mapnik which style definition to use for this layer. So let&#8217;s take a look at that style definition.</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="hillshade style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;RasterSymbolizer opacity="1" scaling="bilinear" mode="normal" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;</code><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
There&#8217;s a lot you can do with raster data, especially in Mapnik2. This style definiton is pretty basic, though. We&#8217;re saying that we want the GeoTIFF to be rendered at 100% opacity. Scaling controls how Mapnik renders the image when scaling it down from its original size, and the mode controls how the raster layer is blended with layers below it. Since there&#8217;s nothing currently behind the layer, mode is somewhat moot at the moment. <a href="http://trac.mapnik.org/wiki/RasterSymbolizer#Usage"</a>Feel free to play with different values for both scaling and mode.</a></p>
<p>That&#8217;s about it. Just make sure your style name matches the <strong>&lt;StyleName&gt;&lt;/StyleName&gt;</strong> tag in your layer.</p>
<p>That&#8217;s it for our first, pretty basic GeoTIFF Mapnik map. Save this file as <strong>ca-map.xml</strong>.</p>
<p>Now we&#8217;ll use Python to compile this XML into an image. I highly recommend that once you get the basics down, you simplify your life and download <a href="https://github.com/mapnik/Cascadenik/wiki/Cascadenik">Cascadenik</a> and <a href="http://code.google.com/p/mapnik-utils/wiki/Nik2Img">nik2img</a> to do a little of this coding for you, but at this point you&#8217;ve installed enough for one tutorial. So we&#8217;ll stick to a basic Python script. Even if you&#8217;ve never used Python before, now&#8217;s the time to start. Trust me, if you have any programming experience this will make sense.</p>
<p>Open a new text file, and save the following code as <strong>ca-stuff-compile.py</strong> into the same directory as your XML document:</p>
<p><code>#!/usr/bin/env python<br />
import mapnik2<br />
mapfile = 'ca-stuff.xml'<br />
map_output = 'ca-map.png'<br />
m = mapnik2.Map(1200, 800)<br />
mapnik2.load_map(m, mapfile)<br />
bbox = mapnik2.Box2d(mapnik2.Coord(-14000000, 3700000), mapnik2.Coord(-12500000, 5200000))<br />
m.zoom_to_box(bbox)<br />
mapnik2.render_to_file(m, map_output)</code></p>
<p>Right off the bat, if you&#8217;re not using Mapnik2 for this, you&#8217;ll need to change everthing that says <strong>mapnik2</strong> to simply <strong>mapnik</strong>.</p>
<p>Next we assign some variables. We specify our XML file for Mapnik to chew on, and tell Mapnik what filename to use for the final image.</p>
<p><code>mapfile = 'ca-stuff.xml'<br />
map_output = 'ca-map.png'</code></p>
<p>Next we instantiate a new mapnik map, and pass our XML to Mapnik&#8217;s load_map() function. We also specify the pixel dimensions we want to give our final map, 800 pixels wide by 600 pixels deep.</p>
<p><code>m = mapnik2.Map(800, 600)<br />
mapnik2.load_map(m, mapfile)</code></p>
<p>Now we tell Mapnik what bounding box we want the map to use. We&#8217;ll use this to control how much space will show up around our map content, but you could also specify only a section of the map or any other arbitrary bounding box. But how do we know what to use?</p>
<p>Remember back in part 1 when we used <strong>ogrinfo</strong> to get the bounding box of our California shapefile that we used to cut out the GeoTIFF? Here&#8217;s what that returned:</p>
<p><code>Extent: (-13849389.898804, 3810165.061203) - (-12704836.275367, 5133847.169980)</code></p>
<p>So if you want to clip your map at California&#8217;s exact boundaries, you can use that extent exactly. But generally we want our maps to have a little padding, so we&#8217;ll round up and down a bit:</p>
<p><code>bbox = mapnik2.Box2d(mapnik2.Coord(-14000000, 3700000), mapnik2.Coord(-12500000, 5200000))<br />
m.zoom_to_box(bbox)</code></p>
<p>Note that, mercifully, Mapnik uses the same format for its bounding box as <strong>ogrinfo</strong>. The points represent the lower left and upper right corners of our image.</p>
<p>Finally, the script renders the map to our file:</p>
<p><code>mapnik2.render_to_file(m, map_output)</code></p>
<p>If you haven&#8217;t already save this file into the same directory as your XML document as <strong>ca-stuff-compile.py</strong>.</p>
<p>Now, in a terminal window, change into this directory, and let&#8217;s build that map:</p>
<p><code>$ python ca-stuff-compile.py</code></p>
<p>If you don&#8217;t get any error messages, check your directory. You should see a new file called ca-map.png, and hopefully your hillshade map is in the middle.</p>
<p><img src="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-mapnik-1.jpg" alt="" title="ca-mapnik-1" width="610" height="406" class="aligncenter size-full wp-image-400" /></p>
<p>Neato! Well, sort of &#8211; it&#8217;s pretty boring, right? Not much different from our original GeoTIFF. Let&#8217;s change that now by adding more styles and more map layers to our XML. We&#8217;ll add a lot at once here, but not so much conceptually:</p>
<p><code>&lt;Map background-color="rgb(51,122,207)" srs="+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="hillshade style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;RasterSymbolizer opacity="0.8" scaling="bilinear" mode="multiply" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="polygon style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;PolygonSymbolizer fill="rgb(255,204,102)" fill-opacity="1" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="county style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;LineSymbolizer stroke="#CCCCCC" stroke-width="0.4" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="water style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;PolygonSymbolizer fill="rgb(51,122,207)" fill-opacity="1" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="stateborder"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;polygon style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/ca-mercator/ca-mercator.shp&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;shape&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="hillshade"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;hillshade style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;gdal&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/ca-dem-combined-merc-cutout.tif&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="water" srs="+proj=longlat +ellps=WGS84 +no_defs"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;water style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/california_water/california_water.shp&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;shape&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="counties" srs="+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;county style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/california_county_shoreline/california_county_shoreline.shp&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;shape&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;<br />
&lt;/Map&gt;</code></p>
<p>We&#8217;ve added 3 shapefile layers: one in Mercator projection that you may recognize as the state border shapefile we used to cutout the GeoTIFF in part 1:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="stateborder"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;polygon style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/ca-mercator/ca-mercator.shp&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;shape&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;</code></p>
<p>You&#8217;ll also notice that we&#8217;ve put this layer before the GeoTIFF in our XML. This is because we want the state border to be behind the GeoTIFF in the rendered image.</p>
<p>We&#8217;ve specified that this layer uses <strong>&lt;StyleName&gt;polygon style&lt;/StyleName&gt;</strong>, so let&#8217;s take a look at the <strong>polygon style</strong> style, defined above the layers:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="polygon style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;PolygonSymbolizer fill="rgb(255,204,102)" fill-opacity="1" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;</code><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
This one&#8217;s pretty simple. We set a fill color for features in this layer using standard Web RGB syntax and Mapnik&#8217;s <a href="http://trac.mapnik.org/wiki/PolygonSymbolizer"><strong>PolygonSymbolizer</strong></a>, and specify that we want 100% opacity for this layer.</p>
<p>Next let&#8217;s turn to the style for the GeoTIFF, which we&#8217;ve now changed so it will blend with our state border background layer:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="hillshade style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;RasterSymbolizer opacity="0.8" scaling="bilinear" mode="multiply" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;</code></p>
<p>We&#8217;ve changed the opacity of the GeoTIFF layer to 80%, to keep the level of gray down, and we&#8217;ve changed the blend mode to <strong>multiply</strong>. This tells Mapnik how to blend the GeoTIFF with the underlying layers. There are <a href="http://trac.mapnik.org/wiki/RasterSymbolizer#Usage">several other modes you can experiment with</a>, but in most cases you&#8217;ll probably want multiply.</p>
<p>Now we&#8217;ll add a water layer so we can see some of California&#8217;s major lakes, and then county borders. Here&#8217;s another great thing about Mapnik: You can use many types of data as layers: shapefiles, PostGIS tables and many other ogr types.</p>
<p>Here&#8217;s the top 2 layers:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="water" srs="+proj=longlat +ellps=WGS84 +no_defs"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;water style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/california_water/california_water.shp&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;shape&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Layer name="counties" srs="+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;StyleName&gt;county style&lt;/StyleName&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="file"&gt;/Users/youruser/Documents/gdaltutorial/california_county_shoreline/california_county_shoreline.shp&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Parameter name="type"&gt;shape&lt;/Parameter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Datasource&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Layer&gt;</code><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
The main thing to notice about these layers is that we&#8217;ve specified an additional parameter in the <strong>&lt;Layer&gt;&lt;/Layer&gt;</strong> tag: <strong>srs</strong>. We&#8217;re doing this because each of these layers is in a different spatial reference system than our main map. The water layer is in SRID 4326, or standard latitude/longitude pairs. The county layer is in SRID 4269, otherwise known as NAD83. As long as you specify the correct srs, Mapnik will do any reprojection needed on the fly (though not on raster layers, remember), so there&#8217;s no need to reproject everything into the same projection on your own.</p>
<p>All that&#8217;s left is the style definitions for those two layers:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="county style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;LineSymbolizer stroke="#CCCCCC" stroke-width="0.4" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Style name="water style"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Rule name="rule 1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;PolygonSymbolizer fill="rgb(51,122,207)" fill-opacity="1" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Rule&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Style&gt;</code></p>
<p>Nothing too fancy here. The county style is using a <a href="http://trac.mapnik.org/wiki/LineSymbolizer"><strong>LineSymbolizer</strong></a> instead of the PolygonSymbolizer we saw earlier. Look &#8211; we can use hexadecimal color codes too! And we set the stroke width to 0.4 pixels. The water style colors the water blue &#8212; not much more to say than that.</p>
<p>OK, time to render this map. In your Terminal:</p>
<p><code>$ python ca-stuff-compile.py</code></p>
<p>If you did everything right, you should have a simple but pretty nice multi-layer Mapnik map.</p>
<p><a href="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-mapnik-2.jpg"><img src="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-mapnik-2.jpg" alt="" title="ca-mapnik-2" width="610" height="407" class="aligncenter size-full wp-image-402" /></a></p>
<p>Since we used a fairly high-resolution GeoTIFF, you should be able to change the image dimensions in ca-stuff-compile.py to make the image quite large for print, HD video, or a poster for your bedroom. But even I don&#8217;t do that with my maps!</p>
<p>Unless you want to <a href="http://www.axismaps.com/typographic.php">send me this one</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikejcorey.com/wordpress/2011/02/25/tutorial-part-2-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tutorial: Create beautiful hillshade maps from digital elevation models with GDAL and Mapnik</title>
		<link>http://www.mikejcorey.com/wordpress/2011/02/05/tutorial-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/</link>
		<comments>http://www.mikejcorey.com/wordpress/2011/02/05/tutorial-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/#comments</comments>
		<pubDate>Sat, 05 Feb 2011 06:59:37 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[digital elevation model]]></category>
		<category><![CDATA[gdal]]></category>
		<category><![CDATA[GeoTIFF]]></category>
		<category><![CDATA[gis]]></category>
		<category><![CDATA[Mapnik]]></category>
		<category><![CDATA[open-source]]></category>

		<guid isPermaLink="false">http://www.mikejcorey.com/wordpress/?p=368</guid>
		<description><![CDATA[Mapnik is your best friend if you want to create map tiles for a slippy map or just want an open-source way to output high-quality printed maps for a wide variety of uses. Though for your first project I might...]]></description>
			<content:encoded><![CDATA[<p>Mapnik is your best friend if you want to create map tiles for a slippy map or just want an open-source way to output high-quality printed maps for a wide variety of uses.</p>
<p>Though for your first project I might recommend a somewhat lower-priority project, <a href="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/SaveTheDate3-5x5.jpg">I like to think I&#8217;m the only person to ever use Mapnik to make wedding invitations</a>.</p>
<p>(If I&#8217;m wrong, I&#8217;d love to see more examples!)</p>
<p>One of Mapnik&#8217;s greatest strengths is its ability to combine multiple types of data into a single map: shapefiles, PostGIS data and raster data are all easy to combine.</p>
<p>When I began working with GIS data I started with exclusively vector data, because vector data are so easily scaled to any size and don&#8217;t take up much storage space. Vector layers are also easy to color and style, and are great at keeping your thematic maps clean and easy to read.</p>
<p>But sooner or later you&#8217;ll want to add some texture to your maps, and it&#8217;s time to add elevation models with raster data.</p>
<p>Luckily, there&#8217;s lots of raster data available to get started. The <a href="http://edc2.usgs.gov/geodata/index.php">USGS publishes digital elevation models (.DEM) of most of the United States</a> (everywhere except Alaska, I believe). This is definitely high-enough resolution for adding texture to a state-level visualization.</p>
<p>Less luckily, the digital elevation models are sliced up into small pieces. This can be nice because it cuts down on file sizes, but if you want a statewide elevation map, you&#8217;ll have to put many pieces together.</p>
<p>A statewide elevation model of California, for example, requires <a href="http://www.brenorbrophy.com/California-DEM.htm">merging 70 .dem files at the 2 arc-second resolution</a>.</p>
<p><a href="http://www.brenorbrophy.com/California-DEM.htm"><img class="aligncenter size-full wp-image-374" title="ca-components" src="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-components.jpg" alt="" width="610" height="610" /></a></p>
<p>However, never fear! GDAL is here to help.</p>
<p><a href="http://www.gdal.org/">GDAL is a powerful, open-source library of translation scripts</a> for raster geographic data.</p>
<p>So with GDAL, a shapefile of California&#8217;s border and a set of digital elevation models and Mapnik, it&#8217;s straightforward to make a seamless high-resolution .PNG map of California with nice elevation hillshades.</p>
<p>This tutorial isn&#8217;t for people without any GIS or programming experience, but if you have a little of both you&#8217;ll be fine. This tutorial is for Mac OS X Snow Leopard users, but will probably work for Linux users with a few OS-related tweaks.</p>
<p>Using GDAL requires knowledge of basic GIS concepts and basic command-line programming. I&#8217;ve had good luck installing the <a href="http://www.kyngchaos.com/software/frameworks">GDAL Complete package from kyngchaos.com</a>. Scroll down to the &#8220;GDAL 1.8 Complete&#8221; .dmg installer.</p>
<p>To get started with raster data, you mostly just need to know what a TIF image is.</p>
<p>To do any Mapnik work, you should feel comfortable with:</p>
<ul>
<li> GIS concepts like map projections</li>
<li> Shapefiles and/or PostGIS</li>
<li> XML</li>
<li> Basic command-line programming</li>
</ul>
<p>The Mapnik website has detailed <a href="http://trac.mapnik.org/wiki/MacInstallation">installation guides</a> and  <a href="http://trac.mapnik.org/wiki/MapnikTutorials">tutorials on how to use it</a>. There&#8217;s an excellent <a href="http://mojodna.net/2009/12/05/the-os-x-spatial-stack.html">OS X-specific guide to installing Mapnik and dependencies (including GDAL and many other useful spacial libraries) here</a>. There&#8217;s many ways to do it and I won&#8217;t get into that here. Just make sure you have Mapnik running with GDAL support.</p>
<p>The tutorial is divided into two parts. Part 1, this post, will focus on merging, converting, projecting and clipping the digital elevation models so they can be used with Mapnik. We&#8217;ll handle the Mapnik process in part 2.</p>
<h2>Data mis en place</h2>
<p>Here&#8217;s the data we&#8217;ll use for this tutorial:<a href="http://www.mikejcorey.com/download/ca-mercator.tar.gz"></a></p>
<ul>
<li><a href="http://www.mikejcorey.com/download/ca-mercator.tar.gz">A California border shapefile in Mercator projection (SRID 3395)</a></li>
<li> <a href="http://www.mikejcorey.com/download/raw-ca-dems.tar.gz">A g-zipped archive of all the digital elevation models you&#8217;ll need for California</a></li>
</ul>
<h2>Fun with GDAL</h2>
<p>Download and upzip the shapefile and the .dem folder. Then open a terminal window and navigate to wherever you downloaded the shapefile and dem folders.</p>
<p>Then, in the terminal:</p>
<p><code>$ cd raw-ca-dems</code></p>
<p>First we&#8217;ll merge the digital elevation model tiles into a single .dem file using <strong>gdal_merge</strong>. We need to specify that we want any areas without data to be white by specifying <strong>-init &#8220;255&#8243;</strong>. Then we specify our desired output filename with <strong>-o (filename)</strong> and then list the files we want to merge together. Like so:</p>
<p><code>$ gdal_merge.py -init "255" -o ca-dem-combined.dem alturas-e.dem alturas-w.dem bakersfield-e.dem bakersfield-w.dem chico-e.dem chico-w.dem crescent_city-e.dem death_valley-e.dem death_valley-w.dem el_centro-e.dem el_centro-w.dem eureka-e.dem fresno-e.dem fresno-w.dem goldfield-w.dem kingman-e.dem kingman-w.dem klamath_falls-w.dem las_vegas-w.dem long_beach-e.dem long_beach-w.dem los_angeles-e.dem los_angeles-w.dem lovelock-w.dem mariposa-e.dem mariposa-w.dem medford-e.dem medford-w.dem monterey-e.dem monterey-w.dem needles-e.dem needles-w.dem noyo_canyon-e.dem redding-e.dem redding-w.dem reno-e.dem reno-w.dem sacramento-e.dem sacramento-w.dem salton_sea-e.dem salton_sea-w.dem san_bernardino-e.dem san_bernardino-w.dem san_clemente_island-e.dem san_diego-e.dem san_diego-w.dem san_francisco-e.dem san_francisco-w.dem san_jose-e.dem san_jose-w.dem san_luis_obispo-e.dem san_luis_obispo-w.dem santa_ana-e.dem santa_ana-w.dem santa_cruz-e.dem santa_maria-e.dem santa_rosa_island-e.dem santa_rosa-e.dem santa_rosa-w.dem susanville-e.dem susanville-w.dem trona-e.dem trona-w.dem ukiah-e.dem ukiah-w.dem vya-w.dem walker_lake-e.dem walker_lake-w.dem weed-e.dem weed-w.dem</code></p>
<p>As long as you don&#8217;t get any errors, you should now have a new file in your folder called ca-dem-combined.dem. If you have GIS software like Quantum GIS you should be able to add this as a raster layer. If you do open it up, you shouldn&#8217;t see any seams between the former tiles &#8212; that&#8217;s what we want for a good-looking Mapnik layer.</p>
<p>But for this to work in Mapnik, we need a GeoTIFF. To convert the merged .dem to a GeoTIFF, we&#8217;ll use <a href="http://www.gdal.org/gdaldem.html"><strong>gdaldem</strong></a>. The gdaldem command has several modes; we&#8217;ll use hillshade to create a shaded relief map, the most common way to visualize texture. We also need to specify the ratio of vertical units to horizontal. Since right now the .dem is in WGS84 projection (standard latitude/longitude), we&#8217;ll use degrees, so <strong>-s 111120</strong>. Then we specify the input file and the output file. Here&#8217;s the full command:</p>
<p><code>$ gdaldem hillshade -s 111120 ca-dem-combined.dem ca-dem-combined.tif</code></p>
<p>Even if you don&#8217;t have a GIS viewer, you should be able to open the .tif file in any image browser like Preview or Photoshop. (Be careful you don&#8217;t resave the file, though &#8212; most image editors will remove necessary geometric data from the file if you re-save it.) You&#8217;ll see a few thin black lines around the outside edge of the old tile data, but don&#8217;t worry &#8212; we&#8217;ll cut this out later.</p>
<p><img class="aligncenter size-full wp-image-378" title="ca-combined" src="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-combined.jpg" alt="" width="620" height="620" /></p>
<p>So now we have a combined .tif, but most of the time we want to display our finished project in Mercator projection &#8212; most non-GIS types will think non-Mercator maps look a bit strange. We need to reproject our .tif to Mercator with <a href="http://www.gdal.org/gdalwarp.html"><strong>gdalwarp</strong></a>. We&#8217;ll use the <strong>-t_srs</strong> option to set the target projection, and use the projection specification for the version of Mercator that&#8217;s also used by Google Maps and OpenLayers.</p>
<p><code>$ gdalwarp -t_srs '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs' ca-dem-combined.tif ca-dem-combined-merc.tif</code></p>
<p>If you open up the resulting file, you should see that the projection has changed.</p>
<p><img class="aligncenter size-full wp-image-379" title="ca-merc" src="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-merc.jpg" alt="" width="620" height="781" /></p>
<p>Now we have our final hillshade data, but we want to only show California &#8212; not all the extra stuff outside the border. We&#8217;ll use our California border shapefile as a mask to cut out just the hillshade data inside the boundary. This is a three-step process.</p>
<p>First, we determine the bounding box, or extent, of our clipping mask &#8212; the California border shapefile in this case. We use <strong>ogrinfo</strong> for this, which comes along with GDAL Complete.</p>
<p><code>$ ogrinfo -al ../ca-mercator/ca-mercator.shp</code></p>
<p>This will return a lot of details about the shapefile. But if you scroll back to the top of the output you&#8217;ll see:</p>
<p><code>Extent: (-13849389.898804, 3810165.061203) - (-12704836.275367, 5133847.169980)</code></p>
<p>These represent the longitude and latitude points (in Mercator projection) of the southwest and northeast corners of our shapefile data.</p>
<p>Next, we trim our merged Mercator .tif to those exact boundaries with <a href="http://www.gdal.org/gdal_translate.html"><strong>gdal_translate</strong></a>.</p>
<p><code>$ gdal_translate -projwin -13849389.898804 5133847.169980 -12704836.275367 3810165.061203 ca-dem-combined-merc.tif ca-dem-combined-merc-box.tif</code></p>
<p><strong>Warning:</strong> Notice that in the above command we reversed the order of the two y-axis values (5133847.169980 and 3810165.061203) from how they appeared in our ogrinfo query. This is because gdal_translate&#8217;s <strong>-projwin</strong> option is looking for the upper left and lower right coordinates &#8212; exactly the opposite of the extent we got from ogrinfo. Annoying, but that&#8217;s just the way it is.</p>
<p>Finally, we&#8217;ll use the shapefile&#8217;s polygon boundaries as a clipping mask on the merged, projected and trimmed .tif, which is now trimmed to show the same area as the shapefile. We&#8217;ll use <a><strong>gdalwarp</strong></a> for this, using some different options than before. The <strong>-co COMPRESS=DEFLATE</strong> option is a generic &#8220;creation option&#8221; that can have many values. We specify <strong>-dstalpha</strong> to create a &#8220;nodata&#8221; band in our resulting .tif, so we are left with a transparent background. And finally we use <strong>-cutline</strong> to specify a file to use as the clipping mask. As before we then specify our input file and desired output filename.</p>
<p><code>$ gdalwarp -co COMPRESS=DEFLATE -dstalpha -cutline ../ca-mercator/ca-mercator.shp ca-dem-combined-merc-box.tif ca-dem-combined-merc-cutout.tif</code></p>
<p>And there&#8217;s our textured California border. If you open <strong>ca-dem-combined-merc-cutout.tif</strong> in an image viewer, you should see a beautifully clipped grayscale image.</p>
<p><img class="aligncenter size-full wp-image-380" title="ca-cutout" src="http://www.mikejcorey.com/wordpress/wp-content/uploads/2011/02/ca-cutout.jpg" alt="" width="620" height="717" /></p>
<p><a href="http://www.mikejcorey.com/wordpress/2011/02/25/tutorial-part-2-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/">In the second half of our tutorial, we&#8217;ll use this cutout .tif as a layer in Mapnik</a>. We&#8217;re more than halfway there!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikejcorey.com/wordpress/2011/02/05/tutorial-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps API hands-on training, part 2</title>
		<link>http://www.mikejcorey.com/wordpress/2010/03/09/google-maps-api-hands-on-training-part-2/</link>
		<comments>http://www.mikejcorey.com/wordpress/2010/03/09/google-maps-api-hands-on-training-part-2/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 04:39:58 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://www.mikejcorey.com/wordpress/?p=235</guid>
		<description><![CDATA[The notes from a hands-on class I'm helping teach at NICAR 2010 in Phoenix this week.]]></description>
			<content:encoded><![CDATA[<style type="text/css">
.level1 {
	list-style-type : decimal ;
	margin-left : 10px ;
}
.level2 {
	list-style-type : upper-alpha ;
	margin-left : 10px ;
}
</style>
<p><a href="http://www.mikejcorey.com/wordpress/2010/03/07/google-maps-api-hands-on-training-part-1/">Go back to part one of the training</a>.<br />
<b>Assumed knowledge:</b><br />
	HTML<br />
	Moderate to advanced Javascript understanding<br />
	CSS<br />
	XML<br />
	Google Maps API basic skills:
<ul>
<li>Initialization of map</li>
<li>Adding map controls</li>
<li>Basic adding of points, click event listeners</li>
<li>Display of map points from flat XML</li>
</ul>
<p><b>Supporting files:</b></p>
<ul>
<li class="level1">Starter file, with a basic map, for you to follow along: <a href="http://mikejcorey.com/nicar2010/googlemapstartfile2.html" target="_new">googlemapstartfile2.html</a></li>
<li class="level1">XML file, which you will want to have locally so you can modify it: <a href="http://mikejcorey.com/nicar2010/basicmapxml.xml" target="_new">basicmapxml.xml</a></li>
<li class="level1">Completed file, if you&#8217;re stuck or just want to skip ahead: <a href="http://mikejcorey.com/nicar2010/googlemapspart2-complete.html" target="_new">googlemapspart2-complete.html</a></li>
</ul>
<p>		</p>
<ol>
<li class="level1"><B>Dynamic geocoding</b><br/><br />
Users often will want to figure out how your data relates to their own geographic location. They want to search against an address or by clicking on a point on the map. To do this kind of functionality you&#8217;ll need to use Google&#8217;s gecoder function.</p>
<ol>
<li class="level2">Create an instance of the geocoder to use for your searches. This should be placed in the code outside of the function that you use to create your map so you can use it anywhere on the page.<br/>
<pre class="brush: jscript; light: true;">var objGeocoder = new GClientGeocoder();</pre>
</li>
<p><br/></p>
<li class="level2">Now let&#8217;s put the geocoder to use. Whereas most of our actions are called against the map instance (objMap), in this case we use the geocoder. Lets do a really basic manual address query that in any real situation you&#8217;d probably collect from an HTML form. You&#8217;ll see that Google takes the address and returns a point &#8212; formatted as a lat,long pair &#8212; if it finds something, and returns as undefined if it can&#8217;t geocode the address. In this case, if it does find an address, we&#8217;ll center the map on that point at zoom level 10. This code goes INSIDE the loadMap function, after the map has been instantiated.<br/>
<pre class="brush: jscript; light: true;">var strTestAddress = &quot;Your address here&quot;;
objGeocoder.getLatLng(strTestAddress, function(objPoint) {
	if (!objPoint) {
		alert(strTestAddress + &quot; not found&quot;);
	} else {
		objMap.panTo(objPoint,10);
	}
});
</pre>
</li>
<p><br/></p>
<li class="level2">Another way to react to user activity is to ask Google for a lat-long pair based on a user&#8217;s click. This allows a user who doesn&#8217;t know the address for their desired location to still use a proximity feature. This involves applying an event listener to the entire map. When a user clicks on the map, we first make sure they&#8217;re not clicking on a marker. If they are, we let that marker&#8217;s earlier set click handler do its work and do nothing in our function. If it&#8217;s not a marker, we re-center the map and do whatever else we might want to. Often we&#8217;ll want to pass the geocoded point to another function.<br/>
<pre class="brush: jscript; light: true;">GEvent.addListener(objMap, 'click', function(objMarker,objPoint) {
	if (objMarker) {
	}
	else {
		objMap.panTo(objPoint,10);
		var objNewMarker = new GMarker(objPoint);
		objMap.addOverlay(objNewMarker);
		objNewMarker.openInfoWindowHtml(&quot;Pssst, pass it on: &quot; + objPoint);
	}
});</pre>
</li>
<p><br/>
	</ol>
</li>
<p><br/></p>
<li class="level1"><B>Polylines and polygons</b><br/><br />
Markers are the most commonly used overlays in the Google Maps API, but polylines and polygons are next. Polylines are familar to most Google Maps users from the driving directions feature, but you can use them for other applications. Polygons are useful for showing regions and other non-point data.<br/><br />
I know what you&#8217;re thinking: STOP! Please don&#8217;t think you can throw up a Google map showing all the counties in your state. It will be slow, slow slow &#8212; this is a major failing of the Javascript API to me, and is one of the main reasons we use Google Maps for Flash for complex polygon data.<br/><br />
That said, polygons used one at a time or a few at a time work well. Let&#8217;s start by drawing a basic line:<br/></p>
<ol>
<li class="level2">We&#8217;ll start by putting some points into an array:<br/>
<pre class="brush: jscript; light: true;">var arrLinePoints = new Array();
arrLinePoints.push(new GLatLng(33.5081, -112.2047));
arrLinePoints.push(new GLatLng(33.5642, -112.1154));
arrLinePoints.push(new GLatLng(33.5608, -112.0042));
arrLinePoints.push(new GLatLng(33.5116, -111.9211));</pre>
</li>
<p><br/></p>
<li class="level2">Then we&#8217;ll spit those points back out as a line. We specify an array that&#8217;s the source of the points, the color of the line, the line width, and the opacity of the line (0.1 to 1):<br/>
<pre class="brush: jscript; light: true;">var objMyLine = new GPolyline(arrLinePoints, &quot;#446891&quot;, 3, 1);
objMap.addOverlay(objMyLine);</pre>
</li>
<p><br/></p>
<li class="level2">Polygons work much the same, except that the last point in the array should be the same as the first one to close the polygon, and you specify a color and opacity for the fill color in addition to the stroke color and opacity:<br/>
<pre class="brush: jscript; light: true;">var arrShapePoints = new Array();
arrShapePoints.push(new GLatLng(33.4623, -112.1086));
arrShapePoints.push(new GLatLng(33.4632, -112.0382));
arrShapePoints.push(new GLatLng(33.4280, -112.0375));
arrShapePoints.push(new GLatLng(33.4285, -112.1075));
arrShapePoints.push(new GLatLng(33.4623, -112.1086));
var objMyPolygon = new GPolygon(arrShapePoints, &quot;#446891&quot;, 3, 1, &quot;#99C1D8&quot;, 0.2);
objMap.addOverlay(objMyPolygon);</pre>
</li>
<p>
	</ol>
</li>
<li class="level1"><B>Clustering markers</b><br/><br />
Many times you&#8217;ll have a lot of points that at wide zoom levels are too close together to distinguish. Using marker clustering is generally the best way to get around this. Google has built-in clustering functions, but we like one called ClusterMarker better because it has more flexibility. The approach works so well that we use ClusterMarker even when we&#8217;re not clustering icons because it makes it easy to trigger clicks to a particular point.<br/><br />
You can download the plugin here:<br/><br />
<a href="http://googlemapsapi.martinpearman.co.uk/downloads.php?cat_id=1" target="_new">http://googlemapsapi.martinpearman.co.uk/downloads.php?cat_id=1</a><br/><br />
And read more about using it here:<br/><br/></p>
<p>	<a href="http://googlemapsapi.martinpearman.co.uk/articles.php?cat_id=1" target="_new">http://googlemapsapi.martinpearman.co.uk/articles.php?cat_id=1</a><br/><br/></p>
<ol>
<li class="level2">For today&#8217;s example, in your HTML document&#8217;s &lt;HEAD&gt;, import the Javascript file that contains the clustering functions.<br/>
<pre class="brush: jscript; html-script: true; light: true;">&lt;script type=&quot;text/javascript&quot; src=&quot;http://www.mikejcorey.com/nicar2010/ClusterMarker.js&quot;&gt;&lt;/script&gt;
</pre>
</li>
<li class="level2">Create a custom icon to be used as your clustering icon. Since this icon has a different size and shape from the other icons from part one, we won&#8217;t base this on the baseIcon we created earlier. This should be defined with your other markers, outside the loadMap function<br/>
<pre class="brush: jscript; light: true;">var objGroupIcon = new GIcon();
objGroupIcon.image = &quot;http://www.mikejcorey.com/nicar2010/images/severalicons-brown.png&quot;;
objGroupIcon.shadow = &quot;http://www.mikejcorey.com/nicar2010/images/severalicons-brown-shadow.png&quot;;
objGroupIcon.iconSize = new GSize(41.0, 36.0);
objGroupIcon.shadowSize = new GSize(57.0, 34.0);
objGroupIcon.iconAnchor = new GPoint(20.5, 18.0);
objGroupIcon.infoWindowAnchor = new GPoint(20.5, 18.0);
</pre>
</li>
<p><br/></p>
<li class="level2">Create a new ClusterMarker instance for your map. We&#8217;ll also tell ClusterMarker what icon to use to mark a cluster. We can also easily turn the clustering on and off by setting the second line to true or false. <b>Note: For some reason my code display tags are freaking out after this point, so delete any backslashes in the code</b><br/>
<pre class="brush: jscript; light: true;">var objMyCluster;
var arrMarkerStorage = new Array();

objMyCluster = new ClusterMarker(objMap, { clusterMarkerIcon: objGroupIcon });
objMyCluster.clusteringEnabled = true;</pre>
</li>
<p><br/></p>
<li class="level2">Instead of manually adding a marker using map.addOverlay, when our marker function runs each time we&#8217;ll push each marker into the array we just created.<br/>
<pre class="brush: jscript; light: true;">function createMarker(objPoint,strHTML,strIconName) {
	var objMarker = new GMarker(objPoint,{ icon:strIconName });
	GEvent.addListener(objMarker, 'click', function() {
		objMarker.openInfoWindowHtml(strHTML);
	});
	arrMarkerStorage.push(objMarker);
	return objMarker;
</pre>
</li>
<p></p>
<li class="level2">Since the ClusterMarker is now going to handle the placement of markers, we can delete or comment out the line inside loadMyLocations that actually places the marker.<br/>
<pre class="brush: jscript; light: true;">
//objMap.addOverlay(objMarker);
</pre>
</li>
<p><br/></p>
<li class="level2">Once our XML loop has finished running, we&#8217;ll tell cluster marker to go to work on the array of points we&#8217;ve stored up. Make sure this is outside and after your loop but still inside the loadLocations function.<br/>
<pre class="brush: jscript; light: true;">
objMyCluster.addMarkers(arrMarkerStorage);
objMyCluster.refresh();
</pre>
</li>
</ol>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.mikejcorey.com/wordpress/2010/03/09/google-maps-api-hands-on-training-part-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Google Maps API hands-on training, part 1</title>
		<link>http://www.mikejcorey.com/wordpress/2010/03/07/google-maps-api-hands-on-training-part-1/</link>
		<comments>http://www.mikejcorey.com/wordpress/2010/03/07/google-maps-api-hands-on-training-part-1/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 03:01:23 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://www.mikejcorey.com/wordpress/?p=197</guid>
		<description><![CDATA[The notes from a hands-on class I'm helping teach at NICAR 2010 in Phoenix this week.]]></description>
			<content:encoded><![CDATA[<style type="text/css">.level1 {
	list-style-type : decimal ;
	margin-left : 10px ;
}
.level2 {
	list-style-type : upper-alpha ;
	margin-left : 10px ;
}</style>
<p><a href="http://www.mikejcorey.com/wordpress/2010/03/09/google-maps-api-hands-on-training-part-2/">Go to part two of the training</a><br />
<b>Presumed knowledge:</b><br />
	HTML<br />
	Moderate Javascript understanding<br />
	CSS<br />
	Basic XML<br />
<b>What you&#8217;ll need:</b></p>
<ul>
<li class="level1">A Google Maps API key (one per server, make an include)</li>
<li class="level1">A text editor</li>
<li class="level1">Some addresses or Lat-Long coordinates<br />
		<b>Where to geocode points:</b></p>
<ul>
<li class="level2">geocoder.us</li>
<li class="level2">batchgeocode.com (feed it a tab-delimited file of addresses, get one back)</li>
</ul>
</li>
<li class="level1">A browser</li>
<li class="level1">Firebug is very helpful</li>
</ul>
<p>
<b>Supporting files:</b></p>
<ul>
<li class="level1">Starter file, with a basic map, for you to follow along: <a href="http://mikejcorey.com/nicar2010/googlemapstartfile.html" target="_new">googlemapstartfile.html</a></li>
<li class="level1">Completed file, if you&#8217;re stuck or just want to skip ahead: <a href="http://mikejcorey.com/nicar2010/googlemapspart1-complete.html" target="_new">googlemapspart1-complete.html</a></li>
</ul>
<p>
<b>Getting started:</b></p>
<ol>
<li class="level1">Make sure you&#8217;re using the API appropriately. The good news is that Google has very open terms, but be sure you understand the advertising caveat</li>
<p></p>
<li class="level1">Create a basic HTML page</li>
<p></p>
<li class="level1">Sign up for an API key at <a href="http://code.google.com/apis/maps/signup.html" target="_new">http://code.google.com/apis/maps/signup.html</a></li>
<p></p>
<li class="level1">Keep a tab open for the API reference at <a href="http://code.google.com/apis/maps/documentation/reference.html" target="_new">http://code.google.com/apis/maps/documentation/reference.html</a></li>
<p></p>
<li class="level1">Load your API key inside the &lt;HEAD&gt; of the HTML document
<pre class="brush: jscript; light: true;">&lt;!--mikejcorey.com key (will work offline, but not if you upload it to another site)--&gt;
&lt;script src=&quot;http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAnXJbcYra5cIfy6uPpLTD6hQ5QqU9rgaQFdjDVk398i-rXfaBgBTE1-zdxRWaL7MjmfClkvNiI-i4KA&amp;sensor=false&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
</li>
<p></p>
<li class="level1">Inside your HTML body, create a target &lt;DIV&gt; for your map
<pre class="brush: jscript; light: true;">&lt;div id=&quot;map&quot; style=&quot;width:500px;height:400px;border:1px solid #000;&quot;&gt;&lt;/div&gt;</pre>
</li>
<p></p>
<li class="level1">Inside your document&#8217;s &lt;/HEAD&gt; tag, write Javascript to initialize your map after the entire body of the document has loaded
<pre class="brush: jscript; light: true;">var objMap; //A variable we declare early so our map is accessible outside the function that creates it.
//A function that loads when the HTML page is finished loading, which creates the map
function loadMap() {
	if (GBrowserIsCompatible()) {
		objMap = new GMap2(document.getElementById(&quot;map&quot;));
	} else {
		document.getElementById(&quot;map&quot;).innerHTML = &quot;There's supposed to be a Google Map here, but your browser isn't capable of showing it.&quot;;
	}
}</pre>
</li>
<p></p>
<li class="level1">Set a center point (lat-long pair) and zoom level for the map
<pre class="brush: jscript; light: true;">objMap.setCenter(new GLatLng(33.453814, -112.073239), 12);</pre>
</li>
<p></p>
<li class="level1">Add this code to the &lt;BODY&gt; tag of your HTML document to initialize the map once the body has finished loading, and to prevent memory leaks
<pre class="brush: jscript; light: true;">&lt;body onload=&quot;loadMap()&quot; onunload=&quot;GUnload()&quot;&gt;</pre>
</li>
<p></p>
<li class="level1">Add a different map type, set the map to use that type
<pre class="brush: jscript; light: true;">objMap.addMapType(G_PHYSICAL_MAP);
objMap.setMapType(G_PHYSICAL_MAP);</pre>
</li>
<p></p>
<li class="level1">Add some controls to the map for zooming and changing the map type
<pre class="brush: jscript; light: true;">objMap.addControl(new GLargeMapControl());
objMap.addControl(new GMapTypeControl());</pre>
</li>
<p></p>
<li class="level1">A marker is one type of overlay. Other overlays include lines, polygons, and ground overlays. There&#8217;s several ways to add markers to the map. Let&#8217;s start with the simplest method, and add a marker to the map using the default icon.
<pre class="brush: jscript; light: true;">//The simplest way to add a marker
var objBasicPoint = new GLatLng(33.453814, -112.073239);
var objBasicMarker = new GMarker(objBasicPoint);
objMap.addOverlay(objBasicMarker);</pre>
</li>
<p></p>
<li class="level1">That&#8217;s fine if we don&#8217;t want too many markers and we don&#8217;t want them to do much, but as soon as you get over about 5 markers, this approach becomes impractical. <b>Writing a function</b> that can be called over and over is a good way to handle multiple markers. Inside the function we&#8217;ll also add an <b>event listener</b> to pop up a label (called an InfoWindow) when the user clicks on the icon.
<pre class="brush: jscript; light: true;">//Our function for creating markers with event listeners
function createMarker(objPoint,strHTML,strIconName) {
	var objMarker = new GMarker(objPoint,{ icon:strIconName });
	GEvent.addListener(objMarker, 'click', function() {
		objMarker.openInfoWindowHtml(strHTML);
	});
	return objMarker;
}

//Adding a marker the more useful way, using a function
var objPoint = new GLatLng(33.479035, -112.047882);
var strWindowContent = &quot;&lt;div style='color:#CC0000;width:200px;'&gt;&lt;b&gt;Barrio Cafe\&lt;/b&gt;&lt;br/&gt;Azcentral.com raves: Superb Mexican food in a funky setting.\&lt;/div&gt;&quot;;
var objTestMarker = createMarker(objPoint,strWindowContent);
objMap.addOverlay(objTestMarker);</pre>
</li>
<p></p>
<li class="level1">If you have more than one type of data you want to show on the map, you&#8217;ll want to use a different color or shape of icon. You can make custom markers with any .PNG image file with a transparent background. Photoshop will work fine, but Adobe Fireworks is even better for this. We won&#8217;t cover creating the icon image here, so we&#8217;re starting with an image that we know the pixel dimensions of. For this map we&#8217;re going to use two icons that are the same shape, but are different sizes. First we&#8217;ll tell Google some key information about both icons. We&#8217;ll declare these variables before our other functions and outside of those functions, so we can access the markers from anywhere in the script.
<pre class="brush: jscript; light: true;">//marker definitions
var objBaseIcon = new GIcon();
objBaseIcon.shadow = &quot;http://www.mikejcorey.com/nicar2010/images/shadow-stop.png&quot;;
objBaseIcon.iconSize = new GSize(19, 25);
objBaseIcon.shadowSize = new GSize(32, 25);
objBaseIcon.iconAnchor = new GPoint(9, 25);
objBaseIcon.infoWindowAnchor = new GPoint(9, 1);</pre>
</li>
<p></p>
<li class="level1">Now we&#8217;ll define the different icons, which will be based on our baseicon, and put the icons into an array for easy reference later.
<pre class="brush: jscript; light: true;">var objRedIcon = new GIcon(objBaseIcon);
objRedIcon.image = &quot;http://www.mikejcorey.com/nicar2010/images/stop.png&quot;;

var objGreenIcon = new GIcon(objBaseIcon);
objGreenIcon.image = &quot;http://www.mikejcorey.com/nicar2010/images/start.png&quot;;

var arrMapIcons = [objRedIcon,objGreenIcon];</pre>
</li>
<p></p>
<li class="level1">If you want to load marker data from a database, or if you&#8217;d like to be able to easily change the markers, you&#8217;ll want to load markers dynamically from XML or JSON. In this example we&#8217;ll load multiple points from a flat XML file. This process uses a custom <b>asynchronous request</b> from Google called <b>GDownloadUrl</b>.
<pre class="brush: jscript; light: true;">//function for retrieving list of points from XML
function loadMyLocations(strWhichXML) {
	GDownloadUrl(strWhichXML, function(data) {
		var objXML = GXml.parse(data);
		var objLocations = objXML.documentElement.getElementsByTagName(&quot;location&quot;);

	});
}</pre>
</li>
<p></p>
<li class="level1">Set up a basic Javascript loop to get each XML row
<pre class="brush: jscript; light: true;">for (var numI = 0; numI &lt; objLocations.length; numI++) {
}</pre>
</li>
<p></p>
<li class="level1">For each row, get the attributes you need and run our marker function as before
<pre class="brush: jscript; light: true;">var objLocationItem = objLocations[numI];
var numMarkerLabel = objLocationItem.getAttribute(&quot;label&quot;);
var numMarkerIcon = objLocationItem.getAttribute(&quot;markertype&quot;);
var numMarkerLat = parseFloat(objLocationItem.getAttribute(&quot;lat&quot;));
var numMarkerLng = parseFloat(objLocationItem.getAttribute(&quot;lng&quot;));
var objPoint = new GLatLng(numMarkerLat, numMarkerLng);
var strWindowContent = &quot;&lt;div style='color:#CC0000;'&gt;&quot; + numMarkerLabel + &quot;\&lt;/div&gt;&quot;;
var objMarker = createMarker(objPoint,strWindowContent,arrMapIcons[numMarkerIcon]);
objMap.addOverlay(objMarker);</pre>
</li>
<p></p>
<li class="level1">That&#8217;s all for part one. Here&#8217;s the code for the entire page:</li>
<pre class="brush: jscript; light: true;">
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
	&lt;title&gt;My awesome first Google map&lt;/title&gt;
	&lt;!--mikejcorey.com key (will work offline, but not if you upload it to another site)--&gt;
	&lt;script src=&quot;http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAnXJbcYra5cIfy6uPpLTD6hQ5QqU9rgaQFdjDVk398i-rXfaBgBTE1-zdxRWaL7MjmfClkvNiI-i4KA&amp;sensor=false&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	&lt;script language=&quot;Javascript&quot;&gt;
	//&lt;![CDATA[
		var objMap; //A variable we declare early so our map is accessible outside the function that creates it.

		//marker definitions
		var objBaseIcon = new GIcon();
		objBaseIcon.shadow = &quot;http://www.mikejcorey.com/nicar2010/images/shadow-stop.png&quot;;
		objBaseIcon.iconSize = new GSize(19, 25);
		objBaseIcon.shadowSize = new GSize(32, 25);
		objBaseIcon.iconAnchor = new GPoint(9, 25);
		objBaseIcon.infoWindowAnchor = new GPoint(9, 1);
		var objRedIcon = new GIcon(objBaseIcon);
		objRedIcon.image = &quot;http://www.mikejcorey.com/nicar2010/images/stop.png&quot;;

		var objGreenIcon = new GIcon(objBaseIcon);
		objGreenIcon.image = &quot;http://www.mikejcorey.com/nicar2010/images/start.png&quot;;

		var arrMapIcons = [objRedIcon,objGreenIcon];
		//A function that loads when the HTML page is finished loading, which creates the map
		function loadMap() {
			if (GBrowserIsCompatible()) {

				objMap = new GMap2(document.getElementById(&quot;map&quot;));
				objMap.setCenter(new GLatLng(33.453814, -112.073239), 12);

				objMap.addMapType(G_PHYSICAL_MAP);
				objMap.setMapType(G_PHYSICAL_MAP);

				objMap.addControl(new GLargeMapControl());
				objMap.addControl(new GMapTypeControl());

				//The simplest way to add a marker
				var objBasicPoint = new GLatLng(33.453814, -112.073239);
				var objBasicMarker = new GMarker(objBasicPoint);
				objMap.addOverlay(objBasicMarker);

				//Adding a marker the more useful way, using a function
    			var objPoint = new GLatLng(33.479035, -112.047882);
    			var strWindowContent = &quot;&lt;div style='color:#CC0000;width:200px;'&gt;&lt;b&gt;Barrio Cafe\&lt;/b&gt;&lt;br/&gt;Azcentral.com raves: Superb Mexican food in a funky setting.\&lt;/div&gt;&quot;;
				var objTestMarker = createMarker(objPoint,strWindowContent);
				objMap.addOverlay(objTestMarker);

				//Or we can just load a bunch of points from an XML file
				loadMyLocations(&quot;basicmapxml.xml&quot;);
			} else {
				document.getElementById(&quot;map&quot;).innerHTML = &quot;There's supposed to be a Google Map here, but your browser isn't capable of showing it.&quot;;
			}
		}

		//Our function for creating markers with event listeners
		function createMarker(objPoint,strHTML,strIconName) {
			var objMarker = new GMarker(objPoint,{ icon:strIconName });
			GEvent.addListener(objMarker, 'click', function() {
				objMarker.openInfoWindowHtml(strHTML);
			});
			return objMarker;
		}

		//function for retrieving list of points from XML
		function loadMyLocations(strWhichXML) {
			GDownloadUrl(strWhichXML, function(data) {

				var objXML = GXml.parse(data);
				var objLocations = objXML.documentElement.getElementsByTagName(&quot;location&quot;);

				for (var numI = 0; numI &lt; objLocations.length; numI++) {
					var objLocationItem = objLocations[numI];

					var numMarkerLabel = objLocationItem.getAttribute(&quot;label&quot;);
					var numMarkerIcon = objLocationItem.getAttribute(&quot;markertype&quot;);
					var numMarkerLat = parseFloat(objLocationItem.getAttribute(&quot;lat&quot;));
					var numMarkerLng = parseFloat(objLocationItem.getAttribute(&quot;lng&quot;));

					var objPoint = new GLatLng(numMarkerLat, numMarkerLng);
					var strWindowContent = &quot;&lt;div style='color:#CC0000;'&gt;&quot; + numMarkerLabel + &quot;\&lt;/div&gt;&quot;;
					var objMarker = createMarker(objPoint,strWindowContent,arrMapIcons[numMarkerIcon]);
					objMap.addOverlay(objMarker);
				}
			});
		}
	//]]&gt;
	&lt;/script&gt;
&lt;/head&gt;
&lt;body onload=&quot;loadMap()&quot; onunload=&quot;GUnload()&quot;&gt;
	&lt;div id=&quot;map&quot; style=&quot;width:500px;height:400px;border:1px solid #000;&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
</li>
</ol>
<p><a href="http://www.mikejcorey.com/wordpress/2010/03/09/google-maps-api-hands-on-training-part-2/">Go to part two of the training</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikejcorey.com/wordpress/2010/03/07/google-maps-api-hands-on-training-part-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

