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 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
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
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.
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.
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!).
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.
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!
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.
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.
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.
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.
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.
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.
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?
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
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?
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.
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.
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:
Calculate the slope of the land.
Calculate the aspect of the land (the direction it faces).
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.
privatefunction 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):
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.
From the x and y slopes follows an overall slope:
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.
To get an azimuth (0º to 360º, where north is 0º, east 90º, etc.), this table is provided:
Code, then. Remember that AS3 works in radians, not degrees.
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.
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.
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];
varmatrix:Matrix = newMatrix();
matrix.createGradientBox(255,5);
var gradientShape :Shape = newShape();
gradientShape.graphics.beginGradientFill("linear",gradientColors,gradientAlphas,gradientRatios,matrix);
gradientShape.graphics.drawRect(0,0,255,5);
gradientShape.graphics.endFill();
gradBmp = newBitmapData(255,5);
gradBmp.draw(gradientShape);
varcolors:Array = [];
for(var n :int = 0; n <256; n ++){colors.push( gradBmp.getPixel32(n,2));
}// ARGB againcolors[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:
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.
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.
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.
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.
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.
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.