{"id":2250,"date":"2015-02-25T13:47:41","date_gmt":"2015-02-25T18:47:41","guid":{"rendered":"http:\/\/andywoodruff.com\/blog\/?p=2250"},"modified":"2019-01-17T21:14:18","modified_gmt":"2019-01-18T02:14:18","slug":"how-to-make-a-value-by-alpha-map","status":"publish","type":"post","link":"https:\/\/andywoodruff.com\/blog\/how-to-make-a-value-by-alpha-map\/","title":{"rendered":"How to make a value-by-alpha map"},"content":{"rendered":"<p>Last week, Josh Stevens published a <a href=\"http:\/\/www.joshuastevens.net\/cartography\/make-a-bivariate-choropleth-map\/\" target=\"_blank\">superb how-to guide for making bivariate choropleth maps<\/a>, something not directly supported in most GIS applications. Go read it. I&#8217;ll wait here.<\/p>\n<p>Josh included a mention of <a href=\"http:\/\/andywoodruff.com\/blog\/value-by-alpha-maps\/\" target=\"_blank\">value-by-alpha maps<\/a>, a pet technique of some colleagues and me. It boils down to a specific type of bivariate choropleth map, in which one variable is intended as a weight for the other and is symbolized by opacity. The idea is offered as an alternative to cartograms\u2014a way to give more visual weight to more significant entities, and suppress less significant ones. Recent examples of the technique include <a href=\"http:\/\/www.thecartofish.com\/blog\/2015\/02\/18\/mapping-wind-and-population-using-raster-algebra-and-value-by-alpha-mapping\/\" target=\"_blank\">wind energy mapping<\/a> and <a href=\"http:\/\/www.nytimes.com\/interactive\/2014\/11\/04\/upshot\/senate-maps.html?_r=0\" target=\"_blank\">midterm election maps<\/a>.<\/p>\n<p>Anyway, Josh&#8217;s post inspired me to write a quick and dirty how-to for value-by-alpha maps. (Dirty because I&#8217;m skipping nice things like legends and labels.) So here are a couple of ways to make one. I&#8217;m making a map of 2008 US presidential election results, just like our <a href=\"http:\/\/www.axismaps.com\/blog\/2008\/11\/a-new-kind-of-election-map\/\" target=\"_blank\">first attempt<\/a> at this. (Example data <a href=\"http:\/\/andywoodruff.com\/data\/election2008.zip\">here<\/a>.)<\/p>\n<h3>Using GIS and graphics software<\/h3>\n<p>First, a method for making static maps using GIS (QGIS in this example) and graphics programs like Illustrator and Photoshop.<\/p>\n<p><strong>1. Make a choropleth map of the &#8220;variable of interest&#8221;<\/strong><\/p>\n<p>Here, it&#8217;s the percent of votes won by Obama.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/gis_election1.jpg\" alt=\"\" title=\"2008 election map in QGIS\" width=\"800\" height=\"521\" class=\"alignnone size-full wp-image-2252\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/gis_election1.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/gis_election1-300x195.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Don&#8217;t use too many classes. For a diverging color map like this, use at most four to six colors. For a sequential scheme, use two or three. When thinking about data classification, remember that a lot of the map will fade away in the final product. My first thought with this map was to limit the dark colors to more extreme values than this, but I found that the end map became a sea of <em>meh<\/em> and failed to tell much of a story, so I expanded those outer classes.<\/p>\n<p><strong>2. Duplicate the layer and make a grayscale map of the &#8220;equalizing variable&#8221;<\/strong><\/p>\n<p>The &#8220;equalizing variable&#8221; is the one that will be used to give more or less visual weight to units on the map. In this example it&#8217;s population\u2014counties with more population are more significant in the election&#8217;s outcome than counties with few people. (Yeah, it really should be total votes, but population is a decent proxy for that.)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/gis_population.jpg\" alt=\"\" title=\"Population map in QGIS\" width=\"800\" height=\"521\" class=\"alignnone size-full wp-image-2256\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/gis_population.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/gis_population-300x195.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Brightness in this map will correspond to opacity in the final map. Don&#8217;t use a straight black-to-white scheme here. Bottom out at 10\u201315% brightness so that units don&#8217;t totally disappear from the map. On the other end, don&#8217;t let the gap between pure white and the second-brightest color be too large, or else the map may look like only a few points of color. The middle colors of my map differ in brightness by 30% and go up to 90% white, with the top color being pure white. It doesn&#8217;t sound like much of a difference between 90% and 100%, but the visible difference is more than you might expect.<\/p>\n<p>Depending on the data, default classification schemes may not serve you well. County population is such a case; most defaults would group far too many counties into the low or high ends. In other cases, something like quantiles might work well. If you use a classification that groups too many units into similar ranges, you may as well stick with a standard univariate choropleth map.<\/p>\n<p><strong>3a. Export to vector and combine<\/strong><\/p>\n<p><em>tl;dr \u2014 use the grayscale layer as an opacity mask on the color layer<\/em><\/p>\n<p>I exported my QGIS map to SVG with two choropleth layers. Here&#8217;s a procedure in Illustrator.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy1.jpg\" alt=\"\" title=\"VBA Illustrator 1\" width=\"800\" height=\"441\" class=\"alignnone size-full wp-image-2258\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy1.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy1-300x165.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Select the grayscale layer, then <strong>cut<\/strong> it.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy2.jpg\" alt=\"\" title=\"VBA Illustrator 2\" width=\"800\" height=\"441\" class=\"alignnone size-full wp-image-2259\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy2.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy2-300x165.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Select the color layer, find the <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy_transparency.jpg\" alt=\"\" title=\"Illustrator transparency panel button\" width=\"30\" height=\"26\" class=\"alignnone size-full wp-image-2298\" style=\"display:inline\"\/> <strong>transparency<\/strong> panel, and click the <strong>Make Mask<\/strong> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy3.jpg\" alt=\"\" title=\"VBA Illustrator 3\" width=\"800\" height=\"441\" class=\"alignnone size-full wp-image-2260\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy3.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy3-300x165.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Activate the square on the right if it&#8217;s not already active. You&#8217;ll probably see a blank artboard at this point.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy4.jpg\" alt=\"\" title=\"VBA Illustrator 4\" width=\"800\" height=\"441\" class=\"alignnone size-full wp-image-2262\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy4.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy4-300x165.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Now paste the grayscale map that you cut a minute ago. Use <strong>paste in front<\/strong> so that it stays in the right place. At this point you&#8217;ll see some colors again.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy5.jpg\" alt=\"\" title=\"VBA Illustrator 5\" width=\"800\" height=\"441\" class=\"alignnone size-full wp-image-2264\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy5.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy5-300x165.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Click that left square in the transparency panel again, then deselect everything, and there you have it: a value-by-alpha map!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy6.jpg\" alt=\"\" title=\"VBA Illustrator 6\" width=\"800\" height=\"441\" class=\"alignnone size-full wp-image-2265\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy6.jpg 800w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/illy6-300x165.jpg 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p><strong>3b. Or do it as raster<\/strong><\/p>\n<p>You could do the same thing with raster graphics using Photoshop or similar. Export your two map layers to images and put them into Photoshop layers. Again select and cut the grayscale one. Create an opacity mask on the color layer, and paste the grayscale map into the mask. Below is the button to click to create an opacity mask on a layer.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/photoshop_mask.jpg\" alt=\"\" title=\"Photoshop opacity mask\" width=\"266\" height=\"171\" class=\"alignnone size-full wp-image-2267\" \/><\/p>\n<h3>Web maps<\/h3>\n<p>If you&#8217;re a web mapper, it&#8217;s just as easy to make a value-by-alpha map in the browser as with desktop software. Here&#8217;s the same map from above done with <a href=\"http:\/\/d3js.org\" target=\"_blank\">D3<\/a>, having exported the data to GeoJSON.<\/p>\n<p><strong>1. The typical D3 map setup.<\/strong><\/p>\n<p>Add an SVG element, create projection and path variables, blah blah blah.<\/p>\n<pre><code>var svg = d3.select(\"body\")\r\n  .append(\"svg\")\r\n  .attr(\"width\",800)\r\n  .attr(\"height\",500);\r\nvar projection = d3.geo.albersUsa()\r\n  .translate([400,250])\r\n  .scale(1000);\r\nvar path = d3.geo.path()\r\n  .projection( projection );<\/code><\/pre>\n<p><strong>2. Make a scale for the color layer.<\/strong><\/p>\n<p>D3&#8217;s <a href=\"https:\/\/github.com\/mbostock\/d3\/wiki\/Quantitative-Scales#threshold-scales\" target=\"_blank\">threshold scales<\/a> work well for customized data classifications. Here we have a domain of the interior class breaks for the election data (40%, 50%, and 60%), and a range of the four colors that go in between and outside them.<\/p>\n<pre><code>var colorScale = d3.scale.threshold()\r\n  .domain( [ .4, .5, .6 ] )\r\n  .range( [ \"#ca0020\", \"#f4a582\", \"#92c5de\", \"#0571b0\" ] );<\/code><\/pre>\n<p><strong>3. Make a scale for the grayscale layer.<\/strong><\/p>\n<p>With this scale, we don&#8217;t want to map the data classes to actual colors, but rather to numbers, because we&#8217;ll use these directly for opacity attributes. The numbers in the range below correspond to the brightness values of my grays (15%, 30%, etc.).<\/p>\n<pre><code>var grayScale = d3.scale.threshold()\r\n  .domain( [ 50000, 100000, 500000, 1000000 ] )\r\n  .range( [ .15, .30, .60, .90, 1 ] );<\/code><\/pre>\n<p><strong>4. Load the geodata and assign color and opacity according to the two data properties.<\/strong><\/p>\n<pre><code>d3.json( \"election.geojson\", function(json){\r\n  svg.selectAll( \"path\" )\r\n    .data( json.features )\r\n    .enter()\r\n    .append( \"path\" )\r\n    .attr( \"d\", path )\r\n    .attr( \"fill\", function(d){\r\n      return colorScale( d.properties.Obama_pct);\r\n    })\r\n    .attr( \"fill-opacity\", function(d){\r\n      return grayScale( d.properties.POP2010 );\r\n    });\r\n});<\/code><\/pre>\n<p>Run all that in a web page, and oh hey look at that, <a href=\"http:\/\/bl.ocks.org\/awoodruff\/857b5b0bf170b236787b\" target=\"_blank\">a value-by-alpha map<\/a>!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/vba_d3.jpg\" alt=\"\" title=\"Value by alpha made with D3\" width=\"758\" height=\"489\" class=\"alignnone size-full wp-image-2270\" srcset=\"https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/vba_d3.jpg 758w, https:\/\/andywoodruff.com\/blog\/wp-content\/uploads\/2015\/02\/vba_d3-300x193.jpg 300w\" sizes=\"auto, (max-width: 758px) 100vw, 758px\" \/><\/p>\n<p>So there you have it, two ways to make value-by-alpha maps! Alternatively, you could use good ol&#8217; <a href=\"http:\/\/indiemapper.io\">indiemapper<\/a>, which supports value-by-alpha and handful of ordinary and crazy multivariate symbols.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week, Josh Stevens published a superb how-to guide for making bivariate choropleth maps, something not directly supported in most GIS applications. Go read it. I&#8217;ll wait here. Josh included a mention of value-by-alpha maps, a pet technique of some colleagues and me. It boils down to a specific type of bivariate choropleth map, in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2250","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/posts\/2250","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/comments?post=2250"}],"version-history":[{"count":5,"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/posts\/2250\/revisions"}],"predecessor-version":[{"id":3009,"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/posts\/2250\/revisions\/3009"}],"wp:attachment":[{"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/media?parent=2250"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/categories?post=2250"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andywoodruff.com\/blog\/wp-json\/wp\/v2\/tags?post=2250"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}