In a tile grid map of the U.S., NPR explains, states are reduced to a uniform size and shape to avoid the visual imbalances inherent to traditional choropleths, and the tiles are arranged to roughly approximate their real-world geographic locations.
So, inspired by hexagon tile map examples created in other languages by Nathan Weatherly and Matt Chambers, and with the help of some code snippets purloined from Rick Wicklin and Sanjay Matange, here's my stab at a SAS version of the United Polygons of America (code/data below).
*==> US tile map coordinates from Matt Chambers drive.google.com/file/d/0B24QRdfcy_JJZFRKLUZzMHZYbG8/view; data StateGrid; input statecode : $2. row column@@; row=-row; * Flip map's y-coordinates (FL at bottom, ME at top!); row=.85*row; * Tighten up line spacing; cards; AK 0 0.5 ME 0 11.5 VT 1 10 NH 1 11 WA 2 1.5 MT 2 2.5 ND 2 3.5 MN 2 4.5 WI 2 5.5 MI 2 7.5 NY 2 9.5 MA 2 10.5 RI 2 11.5 ID 3 2 WY 3 3 SD 3 4 IA 3 5 IL 3 6 IN 3 7 OH 3 8 PA 3 9 NJ 3 10 CT 3 11 OR 4 1.5 NV 4 2.5 CO 4 3.5 NE 4 4.5 MO 4 5.5 KY 4 6.5 WV 4 7.5 MD 4 8.5 DE 4 9.5 CA 5 2 AZ 5 3 UT 5 4 KS 5 5 AR 5 6 TN 5 7 VA 5 8 NC 5 9 DC 5 12 NM 6 3.5 OK 6 4.5 LA 6 5.5 MS 6 6.5 AL 6 7.5 SC 6 8.5 TX 7 4 GA 7 8 HI 8 0.5 FL 8 8.5 ; *==> Calc x, y points of hexagons for each state (stackoverflow.com/questions/3436453/calculate-coordinates-of-a-regular-polygons-vertices); data StatePolygons; set StateGrid; radius=.54; id+1; angle = 2 * constant("PI") / 6; do i = 0 to 6; x = column + radius * sin(i * angle); y = row + radius * cos(i * angle); output; end; *==> Per pupil public elementary/HS spending (https://www.census.gov/govs/school/); data EdSpending; input statecode : $2. percapitaspend@@; cards; AK 10105 AL 5031 AR 5319 AZ 4016 CA 5507 CO 5036 CT 10285 DC 10771 DE 8637 FL 5162 GA 5616 HI 6949 IA 6356 ID 4092 IL 7291 IN 5517 KS 6072 KY 5348 LA 5905 MA 8916 MD 8499 ME 6970 MI 6433 MN 7261 MO 5728 MS 4615 MT 6352 NC 5232 ND 7117 NE 7646 NH 8660 NJ 10102 NM 5225 NV 4768 NY 13756 OH 6220 OK 4170 OR 5517 PA 8557 RI 8415 SC 5349 SD 5019 TN 4943 TX 4947 UT 4199 VA 6673 VT 9849 WA 5625 WI 6527 WV 6476 WY 9252 ; *==> Merge map coordinates and state spending; proc sql; create table statespend as select sp.*, percapitaspend format=dollar7.0 from StatePolygons sp, edspending es where sp.statecode=es.statecode; *==> Draw the map; proc template; define statgraph ustemplate; begingraph; entrytitle "Per Pupil Public Elementary/HS Spending By State (2013)"; layout overlayequated / border=false xaxisopts=(display=none) yaxisopts=(display=none); polygonplot id=id x=x y=y / colorresponse=percapitaspend colormodel=(red blue green) dataskin=matte name="spend" display=(FILL); continuouslegend "spend"; textplot x=column y=row text=statecode / textattrs=(color=white size=10pt weight=bold); endlayout; endgraph; end; run;
proc sgrender data=statespend template=ustemplate;
run;
This is awesome!!!
Well done.
Check out Sanjay Matange's Micro Maps post for an explanation of LAYOUT OVERLAYEQUATED (and a neat PolygonPlot visualization!).
Fabulous data visualization! Love your work @tc... I noticed you have a SAS Global Forum 2016 presenter badge. What's your presentation?
Kind Regards,
Michelle
Thanks for the shameless plug opportunity. 🙂
10180 - Creating and Sharing SAS® ODS Graphics with a Code Playground Based on Microsoft Office
Thursday, Apr 21, 11:30 AM - 11:50 AM – Veronese 2403/2404
Absolutely!!!! Not shameless at all... you deserve to get a huge crowd!
I've added it to my agenda and hope to see it and meet you in person.
Thanks!
Michelle
The YouTube trailer / teaser is awesome. Great idea.
Very cool indeed! It is good to see the POLYGON plot getting some attention. I do believe it is one of the most flexible statements in the list that allows you to do things beyond the obvious plots.
Brilliant! @tc, I love how you sourced and cited work from others (public sharing from Google drive, Stack Overflow). That's how community forums work best together!
BY the way @tc, anyone who wants to try your code will just need to add two more lines:
proc sgrender template=ustemplate;
run;
To actually render the template that you defined. Works perfectly with that!
Good catch-thanks! Made correction to post. Those bad cut-and-pastes can kill you! 🙂
This example was featured in the April 2016 edition of SAS Tech Report: Tips Extra. An alert reader points out that TEXTPLOT is a SAS 9.4 Maint 2 addition. If you're testing with a release earlier than that, you'll find the TEXTPLOT statement generates an error and, if you remove it, of course you won't see the state name abbreviations.
There's more than one way to "skin" a polygon with ODS Graphics. 🙂
Using the label and labelattrs options to display the state labels eliminates the need for a TEXTPLOT statement:
proc template;
define statgraph ustemplate;
begingraph;
entrytitle "Per Pupil Public Elementary/HS Spending By State (2013)";
layout overlayequated / border=false xaxisopts=(display=none) yaxisopts=(display=none);
polygonplot id=id x=x y=y /
colorresponse=percapitaspend colormodel=(red blue green)
dataskin=matte name="spend" display=(FILL)
labelattrs=(color=white size=10pt weight=bold) label=statecode;
continuouslegend "spend";
endlayout;
endgraph;
end;
run;
proc sgrender data=statespend template=ustemplate;
run;
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.