Indiemapper is here

Two weeks ago our five-man team/jug band at Axis Maps finally launched indiemapper, the fabulous web-based thematic mapping application. Born more than two years ago, it’s come a long way. Have a gander at Zachary Johnson’s blog for the story of how it came to be and how it was made. (And yes, the “indiemapper” name is originally derived from the name of Zach’s site.)

The best way to get to know indiemapper is to head over to indiemapper.com, sign up, and try it for yourself. Nevertheless, in the interest of spreading the gospel of indiemapper, I present here a basic tour of its cartographic features.

indiemapper overview

Indiemapper is in part a reaction to the frustration, confusion, and difficulty we (as cartography students, teachers, and practitioners) have encountered in using GIS for thematic mapping. Our most important principle, which I hope is visible in the image above, is simple clarity—being easy to learn, easy to understand, and easy to use. Ben Sheesley and Mark Harrower have worked tirelessly to design an interface that fits that bill. Notice that the whole thing consists of only a half dozen or so components, the most complicated of which is the layers panel on the left side (which is a real feat of Flex/AS3 wizardry by Zach, I must add), and even that can be mastered with minimal effort.


GEOGRAPHIC DATA

indiemapper data libraries

We expect that most people want to map their own data, which can be uploaded from shapefiles, KML, and GPX files. To help you get started or to augment your own data, indiemapper is also stocked with reference data from Natural Earth vector and some pre-styled world reference base maps designed by Ben in indiemapper itself.


MAP PROJECTIONS

indiemapper projection panel

Map projections. Such pain they have caused me. But that’s a tale for another day. We ended up with fourteen projections that are a good selection of map projections suitable for most purposes. You have control over centering and standard parallels, and importantly the options are presented along with guidance and detailed information on what geometric properties each projection preserves and for what purposes the projection is appropriate.


MAP TYPES

Indiemapper has twelve basic types of thematic and reference map types, with more to come in the future. Here’s a quick rundown.

indiemapper reference layers
Reference points, lines, and areas. Any data source can have one or more layers depicting the base geography, and these can be combined to make some pretty nice reference maps, as you can see above in one of Ben’s base maps.



indiemapper choropleth maps
Choropleth. The bread and butter of thematic cartography. Indiemapper provides the excellent ColorBrewer color schemes and equal interval, quantile, and optimal breaks classification presets (or unclassed maps!).



indiemapper proportional symbol maps
Proportional symbols. These can be created for point features or on area feature centroids. They can either be unclassed (i.e. truly proportional), or classed, a.k.a. “range-graded” or “graduated.” Proportional symbol maps can get messy, but don’t worry, you can move the symbols around on the map so they don’t overlap.



indiemapper dot density maps
Dot density. Our dot density maps simply place dots at random within polygons. Be careful with dot density maps—they’re not effective with all arrangements of enumeration units, and remember to always use an equal-area map projection!



indiemapper cartograms
Cartogram. Here we get into pretty interesting territory. Zach built in his code for non-contiguous cartograms, and I’m not aware of any similarly easy implementation of cartograms in mapping software. Contiguous cartograms are a challenge we may take on some day, but you can make some pretty sweet (and easier to read, I’d say) maps with non-contiguous cartograms. As with proportional symbols, you can move the cartogram polygons around, and usually you’ll want to do so. Zach has gone experimental and allowed for classed cartograms here, too.



indiemapper map labels
Map labels. Any cartographer will agree that labeling is a huge part of the work that goes into a map and that automated label placement is a beast that has only recently been tamed. Indiemapper gets you started with basic labeling using any attribute you choose, and then allows you to move and rotate labels as desired. You have access to all the fonts installed on your computer, as well as a selection of embedded free fonts. Ben, whose PhD is practically in map typography, has made some templates based on his TypeBrewer work, making it easy to select effective and harmonious styles.



indiemapper bivariate choropleth maps
Bivariate choropleth. This is kind of a big deal. As far as I know, indiemapper makes creating bivariate choropleth way easier than ever before. It offers several sequential and diverging color schemes, automatic or manual (or no) classification, and a scatterplot to view the relationship between attributes.



indiemapper bivariate proportional symbol maps
Bivariate proportional symbols. Thanks to the flexible architecture that Zach programmed, it is very easy for us to combine symbology types, so a bivariate proportional symbol map is as simple as combining a proportional symbols with a choropleth-like color scheme. Note that the styling panel essentially places the two individual style panels into two tabs.



indiemapper bivariate cartograms
Bivariate cartograms. Again, we just combine two existing symbologies. These colored cartograms are really the best use of cartograms, showing some attribute on a perfectly equalized base map. We’ve all seen them following elections.



indiemapper value-by-alpha maps
Value-by-alpha. This is an Axis Maps original. It’s a bivariate technique that I kind of made up in reaction to election cartograms, that was presented in our alternative election map, and was more fully developed by Robert Roth, me, and Zach in a forthcoming paper in the Cartographic Journal. One attribute is displayed by color, and another standardizing attribute by transparency. Some day I’ll finally write a post describing our work on the value-by-alpha technique.



indiemapper proportional label maps
Proportional labels. You see this kind of map occasionally, where labels are scaled according to some attribute value, a bit like in a word cloud. It was easy to implement, so why not?



indiemapper colored proportional label maps
Colored proportional labels. That’s right, we have a trivariate map symbology! It says one thing, is scaled by another thing, and colored by a third.


MAP LAYOUT

indiemapper layout controls

The goal of using indiemapper is to generate some sort of output image such as this Cartography 101-style map of Michigan (as vector SVG or raster JPEG and PNG), so layout controls are always available. At the center of the stage is a page that contains what will be exported in the end, and which has some style options of its own. On top of the map are several layers in a “Layout Objects” group: legends, north arrow, and annotations. Legends are generated automatically when you create a thematic layer, and they can be toggled on or off. North arrow options are, I’m sad to say, lacking dozens of garish styles. The annotation layer allows you to manually enter text for titles, labels, or what have you.


EXPERT GUIDANCE

As with the map above, there is additional information behind “learn more” buttons all over the place in indiemapper. There’s more to learn about every map type and many other features. Mark Harrower, building on his experience teaching and studying cartography as a professor at the University of Wisconsin-Madison, has written an extensive set of these “learn more” articles that teach users about cartography topics while providing guidance on best practices and how to achieve them in indiemapper. Among other things, this is one reason we think that indiemapper can be a very useful tool for students and teachers.


MAP MANAGEMENT

Save your maps online (unlimited storage), roll back to previous versions so you don’t have to worry about accidentally destroying your work, share your maps with other indiemapper users if you want to collaborate, and attach comments to map versions. Dave Heyman has built a fantastic web site and database back end to indiemapper that allows all this and so much more. It’s easy to manage all your maps from the “My Indie” page. Mark has recorded a nice video tour of all these features.


GET YOUR FACE IN THERE

Indiemapper.com. Get in there! You’ll get a 30 day free trial, and then it’s $30/month ($20 if you’re a student) with no lengthier commitments. Or you can stick to a weaker free version like a loser. You’re not a loser, are you?

Tagged , | 1 comment

Shaded relief in AS3

Shaded relief map of Molokai generated in AS3

Did you know that basic relief shading is fairly simple to accomplish? I didn’t until a few days ago when I was flipping through the Slocum et al. cartography textbook, Thematic Cartography and Geographic Visualization, wherein a four-step process is presented. It sounded easy, so it was time for further adventures in raster-based cartography in Flash! I swore off code projects outside my day job because they tend to be more headache- and hair-loss-inducing than enjoyable, but an easy one that produces pretty pictures is worth an exception.

I previously tried raster map projection in AS3, and the same caveats apply. Flash shouldn’t be your first choice for hill-shading, but it’s good to demonstrate that it can be done on the fly in AS3, which could occasionally come in handy. Here follows a tutorial-like explanation of how simple shaded relief can be achieved in AS3. Code is only shown in bits and pieces, so to see it all in one place (or if you want to skip the details), you can download the source AS3 file and the source image file.


1) THE DATA SOURCE

Any shaded relief map is born of elevation data, typically from a digital elevation model (DEM), a.k.a. digital terrain model. Ideally the relief map would be generated from the actual elevation values in the DEM, but a DEM is often visually displayed as a grayscale image, which is what my example uses as a source. (See the bottom of this post for a bit more info on DEM data.) Darker means lower elevation; lighter means higher. The price of using the image as a starting point is precision, as there are only 256 different gray values (elevations) in the image.

My source, an elevation map of the Hawaiian island of Moloka’i, is below.

Molokai DEM


2) LOADING AND PREPARING DATA

To generate the shaded relief it’s necessary to go through the DEM image pixel-by-pixel, calculate a result pixel for the relief, and draw that pixel to an an output image. So the setup for this whole thing is to load the image using a Loader, draw it to a BitmapData, and create another BitmapData for the relief map.

public class ShadedRelief extends Sprite
{
	private var loader : Loader = new Loader();
	private var sourceBitmap : BitmapData;
	private var reliefBitmap : BitmapData;
	public function ShadedRelief()
	{
		loader.load( new URLRequest("molokai.png") );
		loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
	}
	private function onLoaded( event : Event ) : void
	{
		sourceBitmap = new BitmapData( loader.width, loader.height );
		sourceBitmap.draw( loader );
		reliefBitmap = new BitmapData( loader.width, loader.height,true, 0 );
	}
}


3) GET YOUR MATH ON

Now I start following the mathematical steps laid out in the Slocum et al. text, which are three. For each pixel in the grid:

  1. Calculate the slope of the land.
  2. Calculate the aspect of the land (the direction it faces).
  3. Calculate a reflectance value.

These calculations are made by observing the data in a 3×3 pixel window, at the center of which is the pixel of interest. So to start, loop through the rows and columns of the source image. There are, I think, more efficient ways to do pixel-level manipulation than what I spell out below, but I’m keeping it simple here.

private function drawMap() : void
{
	for ( var i : int = 0; i < sourceBitmap.width; i ++ ) {
		for ( var j : int = 0; j < sourceBitmap.height; j ++ ) {
			// magic will occur here
		}	
	}
}

For reference, here’s a diagram of the 3×3 window for any given pixel (i,j):

3x3 window of elevation values

The Z values represent elevation values for each pixel. To find the slope of the cell, do a simple rise over run division in both the x and y directions.

x slope equation
y slope equation

From the x and y slopes follows an overall slope:

overall slope equation

The grayscale image no longer has any real elevation values, so the 0-255 gray value will stand in. That can be obtained with the BitmapData.getPixel method and from that grabbing just one of the RGB channels, e.g. source.getPixel(i+1,j) & 0xFF. The D value (the distance between pixels) isn’t known in meaningful units anymore either, so D could just be 1. However, for some reason I found that using a slightly larger number produced a nicer result. My slope code looks like this:

var topValue : Number = sourceBitmap.getPixel( i, Math.max(j-1,0) ) & 0xff;
var leftValue : Number = sourceBitmap.getPixel( Math.max(i-1,0), j ) & 0xff;
var rightValue : Number = sourceBitmap.getPixel( Math.min(i+1,sourceBitmap.width-1), j ) & 0xff;
var bottomValue : Number = sourceBitmap.getPixel( i, Math.min(j+1,sourceBitmap.height-1) ) & 0xff;
 
var slx : Number = (rightValue - leftValue)/3;
var sly : Number = ( bottomValue - topValue )/3;
var sl0 : Number = Math.sqrt( slx*slx + sly*sly );

Next, the aspect. First, get a local angle between the x slope and the overall slope.

facet angle

To get an azimuth (0º to 360º, where north is 0º, east 90º, etc.), this table is provided:

Converting angle to azimuth

Code, then. Remember that AS3 works in radians, not degrees.

var phi : Number = Math.acos( slx/sl0 );
if ( sl0 == 0 ) { // account for division by zero trouble
	phi = 0;
}
var azimuth : Number;
if ( slx > 0 ) {
	if ( sly > 0 ) azimuth = phi + 1.5*Math.PI;
	else if ( sly < 0 ) azimuth = 1.5*Math.PI - phi;
	else phi = 1.5*Math.PI;
} else if ( slx < 0 ){
	if ( sly < 0 ) azimuth = phi + .5*Math.PI;
	else if ( sly > 0 ) azimuth = .5*Math.PI - phi;
	else azimuth = .5*Math.PI;
} else {
	if ( sly < 0 ) azimuth = Math.PI;
	else if ( sly > 0 ) azimuth = 0;
}

And now, a reflectance value, which will be the brightness of the final output pixel. A Lambertian reflectance is suggested, and the formula provided ends up looking like this in code:

var sunElev : Number = Math.PI*.25;
var sunAzimuth : Number = 1.75*Math.PI;
 
var L : Number = Math.cos( azimuth - sunAzimuth )*Math.cos( Math.PI*.5 - Math.atan(sl0) )*Math.cos( sunElev ) + Math.sin( Math.PI*.5 - Math.atan(sl0) )*Math.sin( sunElev );

The sunAzimuth and sunElevation values can be freely chosen and will affect the final appearance of shadows. 315º (northwest) and 45º respectively are pretty typical values. For some reason that I haven’t figured out, I ended up with some negative reflectance values, which I guess indicate black holes on the surface of the earth. I don’t understand the math going on here, but setting those to zero seemed to make the result look okay. (If anyone can explain or help me here, it’d be greatly appreciated!)


4) DRAW THE RELIEF

The reflectance value just needs to be translated into a shade of gray. The reflectance is basically a proportion of white, so to get RGB values it needs to be multiplied by 255 and assigned to each of the three channels. Finally, the pixel can be drawn on the output image.

var grayValue : Number = int(255 * L);
 
if ( grayValue < 0 ) {
	grayValue = 0;
}
// doing ARGB instead of RGB because transparency comes in handy elsewhere
reliefBitmap.setPixel32(i,j,0xff << 24 | grayValue << 16 | grayValue << 8 | grayValue);

Running through all that gets me the following Moloka’i map.

Molokai shaded relief grayscale


5) HYPSOMETRIC TINTING

The gray relief map wowed me enough the first time because I was amazed at how simple it was to produce (despite my lengthy explanation above). But it’s not a nice map without colors! Hypsometric tinting, in which colors are mapped to elevation ranges, is a common and aesthetically pleasing technique on relief maps. To get hypsometric tints on my relief map, another BitmapData is drawn based on the grayscale source image, but this time the math is much simpler. All that needs to be done is to match the gray value of each source pixel to a color class or a point in a continuous gradient of colors. I settled on the following gradient for elevation colors. It stays mostly in the greens to reflect the tropical setting, and moves a bit toward warmer colors at just the highest elevations.

Colors for hypsometric tints

I won’t explain all the code in detail, but basically I drew a vector gradient 256 pixels wide, then sampled the color at each x location and saved it in an array. Thus each 0-255 gray value can be matched to an index in that array. Then, in the loop where all that reflectance math is taking place, I added a couple of lines to draw that color to another BitmapData.

Note there is some additional funny business involving the first couple of values in the array. This is to deal with the ocean in my map. I had trouble getting the blues to look good in the gradient, so after creating the array I set those blues using brute force. I also didn’t want the ocean to show up as gray in the relief image, so if a pixel has a value at that low end that indicates it as water, it isn’t drawn to the relief map.

var gradientColors : Array = [0x0000ff,0x004000,0x679167, 0x81b279, 0xbfdfa8, 0xd0b8aa];
var gradientRatios : Array = [1,3,1*255/4,2*255/4,3*255/4,4*255/4];
var gradientAlphas : Array = [0,1,1,1,1,1];
var matrix : Matrix = new Matrix();
matrix.createGradientBox(255,5);
var gradientShape : Shape = new Shape();
gradientShape.graphics.beginGradientFill("linear",gradientColors,gradientAlphas,gradientRatios,matrix);
gradientShape.graphics.drawRect(0,0,255,5);
gradientShape.graphics.endFill();
 
gradBmp = new BitmapData(255,5);
gradBmp.draw(gradientShape);
 
var colors : Array = [];
 
for ( var n : int = 0; n < 256; n ++ ) {
	colors.push( gradBmp.getPixel32(n,2) );
}
// ARGB again
colors[0] = 0xffccccff;
colors[1] = 0xffccccff;
 
[...]
 
for ( var i : int = 0; i < sourceBitmap.width; i ++ ) {
	for ( var j : int = 0; j < sourceBitmap.height; j ++ ) {
		[...]
		var centerValue : Number = sourceBitmap.getPixel( i,j ) & 0xff;
		tintBitmap.setPixel32( i,j,colors[int(centerValue)] );
		[...]
		if ( centerValue >= 3 ) reliefBitmap.setPixel32(i,j,0xff << 24 | grayValue << 16 | grayValue << 8 | grayValue);
	}	
}

The hypsometric tinting by itself looks like this:

Molokai hypsometric tints


6) PUTTING IT ALL TOGETHER

The final map is a matter of combining the relief and tint images. I found that overlaying the relief map at 30% opacity looked pretty good. A blur filter on both the tint and relief maps helps to smooth out the pixelated coastline and some noise, respectively. And a glow filter on the relief map provides a nice coastal effect, even if I haven’t quite perfected it here.

tintBitmap.applyFilter( tintBitmap, new Rectangle(0,0,tintBitmap.width,tintBitmap.height), new Point(), new BlurFilter(1.2,1.2) );
var tintMap : Bitmap = new Bitmap(tintBitmap);
addChild(tintMap);
 
reliefBitmap.applyFilter( reliefBitmap, new Rectangle(0,0,reliefBitmap.width,reliefBitmap.height), new Point(), new BlurFilter(2,2) );
reliefBitmap.applyFilter( reliefBitmap, new Rectangle(0,0,reliefBitmap.width,reliefBitmap.height), new Point(), new GlowFilter(0xffffff,.75,45,45,3,2) );
var reliefMap : Bitmap = new Bitmap( reliefBitmap );
addChild( reliefMap );
reliefMap.alpha = .3;

Pow. And pau.

Shaded relief map of Molokai generated in AS3


7) ADDITIONAL RESOURCES

The formulas in the Slocum et al. textbook are derived from:
Eyton, J.R. (1991) “Rate-of-change-maps.” Cartography and Geographic Information Systems 18, no. 2:87–103.
As for the textbook itself, I’m looking at the second edition, pages 300-301.

It’s been a while since I actually sought out DEM data, but at least for the United States the best source remains the USGS. You can download data for anywhere in the country at http://seamless.usgs.gov/. The USGS also has some worldwide data with GTOPO30. A bit of Googling will likely lead you to additional sources of DEMs.

DEM data may not always come in a format suitable for this particular tutorial. (But remember that this is not the way to go most of the time anyway.) It may come in the actual DEM file format, or perhaps a GeoTIFF that you may have trouble opening in ordinary image editing software. Unfortunately I’m not up on the best ways to convert DEMs to grayscale images. I grew to like MicroDEM, a Windows program from several years ago, for all kinds of DEM manipulation. I’m a Mac user but have fired up Windows on my machine more than once to use this program. Anyway, again the best I can suggest is to use your Google-fu.

Finally, there is no avoiding mentioning the man who is barely short of a deity of relief shading: Tom Patterson. Mr. Patterson, who is known to and revered by all cartographers, does mind-blowing work for the National Park Service, and he has been kind enough to impart some of his wisdom through shadedrelief.com. Do check out that site for a lot of good information and tutorials. He also has created the wonderful Natural Earth I, II, and III maps and has co-spearheaded the Natural Earth vector effort.

Tagged , , , | 7 comments

Footprints

In spite of everything that maps can do, the ones I enjoy most are the simplest of all, those that reveal geography by stripping away all but some particular phenomenon and showing little or nothing more than where it exists. It’s the challenge of interpretation, or the self-satisfaction of recognizing something, or the imagining of a world to fill in the gaps, or something.

Every building in Montgomery County, Ohio

And so it was nice to run across this map of every building footprint in Montgomery County (Dayton), Ohio while idly browsing the “Maps” folder on my computer. I cranked it out from GIS data some six years ago. Give it a click for a large version.

Granted this map is more interesting if you know the area, but nonetheless it’s fascinating how much something like this can indicate about the patterns of human settlement in a typical American city. It’s not too difficult to see where settlement has followed or been bounded by highways and rivers. Industrial areas are discernible from residential areas, and city from suburb from rural. (By the way, this map only shows a sliver of Greene County—including my hometown of Beavercreek—where a good chunk of additional suburbia is located.) Owing to its simplicity, I believe this map shows urban patterns much more clearly than a satellite image or a road map.

If you’re familiar with the Dayton area, check out the patterns that probably confirm what you already know. See how to the north, settlement extends in spokes between the Mad, Stillwater, and Miami Rivers. Notice how immediately south of west Dayton, there’s hardly anything on the west side of the river. And look at the difference in suburban density on the west and east sides of Far Hills Avenue through Oakwood and Kettering.

If you’re not familiar with the Dayton area, the wonderful thing is that despite being nothing more than polygons, this map can probably teach you a bit about it.

Tagged , , | 10 comments

Obligatory Valentine’s Day map

Even while under the knife as we do some final development work, indiemapper sends its love.

The Werner projection for Valentine's Day


Remember, the sweetest sentiment today and forever is:

Werner projection equation 1

Werner projection equation 2

Werner projection equation 3

Werner projection equation 4

Tagged , , | 4 comments

The “Pacific Islands” are actually just a myth

So when you map them, go ahead and omit most of the Pacific. It’s empty anyway.

Pacific Islands map

The same goes for Terra Australis, but it is customary to retain an “Antarctica” label as a joke.

Seen at Franklin Park Conservatory, Columbus, Ohio.

Tagged , , | 7 comments

Mapping a whole darn year

2009 travel in Cambridge and Boston

In the past I have mentioned here an ongoing project to trace my every movement on a map, using memory and mouse-clicking rather than technology that costs money. Well, the advent of 2010 marks a full calendar year of doing this and a good moment to show some results.

Obviously this is not a novel concept (to choose a single example, I must link to UrbanTick here), and nobody besides me cares about the particulars of my travels. Shut up, it’s fun anyway. There are two reasons why this originally sounded interesting. First, I work from home, and there is very little routine in my trips out of the house, both in timing and destination. Rather than a predictable daily grind, I could hope for a an unknown awesome-looking pattern. Second, I keep the tracks separated by mode of transportation (foot, car, train, bus, and bike so far). A portrait of urban mobility or some such. As I bonus I will add that for a urban geography and cartography nerd, this project works as motivation to get out and explore different parts of town. There are witnesses to my excitement over being able to add a new line to the map.

Anyway, below is a little Flash animation of daily travels, with some transparency to highlight hot spots. I gave up on trying to do this beyond the immediate local area (Cambridge, Massachusetts)*, so there are some noticeable pauses where I disappeared for weeks on various out-of-town trips.

Get Adobe Flash player

Goals for 2010:

  • Cover more ground! I still haven’t made it to half of Cambridge, and there is a lot of neighboring Boston and Somerville to explore.
  • Use a bicycle more than four times in a year. It is perhaps the best way to get around town and shouldn’t be collecting dust.
  • Collect more data, such as distance, for summary statistics. This may require more sophisticated techniques than simply drawing lines, though, which would conflict with my New Year’s resolution to be more technologically lazy.

* Sorry for making this an increasingly Boston-centric blog, but hey, for your own projects you start with what’s outside your front door too, right? Not that I actually have a front door.

Tagged , , , | 17 comments