Oh, there's no place like SAS ODS Graphics for the Holidays. 🙂
So, with Halloween coming up, here's a states-as-jack-o-lanterns makeover of CNN's 2016 Electoral Map. It's kind of a remix of The United Polygons of America, but using SYMBOLIMAGE instead of polygons.
In the immortal words of Count Floyd, "Oooh, wasn't that scary, kids?"
*==> Tile Map of 2016 Presidential Election w/States as Pumpkins!; *==> 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=.95*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 ; *==> Get state predictions (cnn.com/election/interactive-electoral-college-map, updated oct 19, 2016 4:00 pm et); data StateDR(keep=prediction statecode); length statecode $ 2; input prediction $char17.; do s=1 to 51; statecode=scan(substr(_infile_,18),s); if statecode^='' then output; end; cards; Leans Democrat CO FL MI NH NV PA VA WI Solid Democrat CA CT DC DE HI IL MA MD ME MN NJ NM NY OR RI VT WA Leans Republican GA IA Solid Republican AK AL AR ID IN KS KY LA MO MS MT ND NE OK SC SD TN TX WV WY Battleground AZ NC OH UT ; *==> Merge map coordinates and CNN predictions; proc sql; create table stategridDR as select sg.*, sd.prediction from stategrid sg, statedr sd where sg.statecode=sd.statecode; *==> Draw the map (map predictions to colored pumpkins); ods listing image_dpi=300 gpath='/folders/myfolders'; ods graphics on / reset antialias width=11in height=8.5in imagename="PresidentialElection"; proc template; define statgraph ustemplate; begingraph; symbolimage name=symPLD image="/folders/myfolders/PumpkinLightBlue.png"; symbolimage name=symPSD image="/folders/myfolders/PumpkinBlue.png"; symbolimage name=symPLR image="/folders/myfolders/PumpkinLightRed.png"; symbolimage name=symPSR image="/folders/myfolders/PumpkinRed.png"; symbolimage name=symPBG image="/folders/myfolders/PumpkinOrange.png"; discreteattrmap name="symbols" / ignorecase=true trimleading=true; value "Leans Democrat" / markerattrs=(symbol=symPLD size=47pt); value "Solid Democrat" / markerattrs=(symbol=symPSD size=47pt); value "Leans Republican" / markerattrs=(symbol=symPLR size=47pt); value "Solid Republican" / markerattrs=(symbol=symPSR size=47pt); value "Battleground" / markerattrs=(symbol=symPBG size=47pt); enddiscreteattrmap; discreteattrvar attrvar=groupmarkers var=prediction attrmap="symbols"; legendItem type=marker name="psd" / markerattrs=(symbol=symPSD size=24pt) label="SOLID (D)" labelattrs=(size=9pt weight=bold); legendItem type=marker name="pld" / markerattrs=(symbol=symPLD size=24pt) label="LEANS (D)" labelattrs=(size=9pt weight=bold); legendItem type=marker name="pbg" / markerattrs=(symbol=symPBG size=24pt) label="BATTLEGROUND" labelattrs=(size=9pt weight=bold); legendItem type=marker name="plr" / markerattrs=(symbol=symPLR size=24pt) label="LEANS (R)" labelattrs=(size=9pt weight=bold); legendItem type=marker name="psr" / markerattrs=(symbol=symPSR size=24pt) label="SOLID (R)" labelattrs=(size=9pt weight=bold); layout overlayequated / border=false xaxisopts=(display=none) yaxisopts=(display=none); entry "2016 Electoral Map (Source: CNN, 10-22-2016)" / valign= top textattrs=(size=16pt weight=bold); scatterplot x=column y=row / group=groupmarkers; textplot x=column y=row text=statecode / position=top textattrs=(color=black size=9.5pt weight=bold); discretelegend "psd" "pld" "pbg" "plr" "psr" / location=inside border=true valign=bottom; endlayout; endgraph; end; run; proc sgrender data=stategridDR template=ustemplate;
Very cool, TC.
Just wondering if you could have used STYLEATTRS DATASYMBOLS=(sympld sympsd ...) to make the pumplins into group symbols and also get these in the legend automatically? If I had your full code (with images), I could have tried it out.
As things turn out, yes I could have, and it indeed greatly simplifies things! I wasn't aware of this feature, but a quick google turned up a blog post of yours on the subject (Infographics Using SAS), which I followed to come up with the below look-Ma-no-GTL solution. Always learn something from these SAS Communities "code reviews"!
REVISED IMAGE
SIMPLIFIED CODE
*==> Tile Map of 2016 Presidential Election w/States as Pumpkins!;
*==> 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=.95*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
;
*==> Get state predictions (cnn.com/election/interactive-electoral-college-map, updated oct 19, 2016 4:00 pm et);
data StateDR(keep=prediction statecode);
length statecode $ 2;
input prediction $char17.;
do s=1 to 51;
statecode=scan(substr(_infile_,18),s);
if statecode^='' then output;
end;
cards;
BATTLEGROUND AZ NC OH UT
LEANS (D) CO FL MI NH NV PA VA WI
LEANS (R) GA IA
SOLID (D) CA CT DC DE HI IL MA MD ME MN NJ NM NY OR RI VT WA
SOLID (R) AK AL AR ID IN KS KY LA MO MS MT ND NE OK SC SD TN TX WV WY
;
*==> Merge map coordinates and CNN predictions;
proc sql;
create table stategridDR as
select sg.*, sd.prediction
from stategrid sg, statedr sd where sg.statecode=sd.statecode order by sd.prediction;
*==> Draw the map (map predictions to colored pumpkins);
ods listing image_dpi=300 gpath='/folders/myfolders';
ods graphics on / reset antialias width=11in height=8.5in attrpriority=none imagename="ElectoralMap";
proc sgplot data=stategridDR noborder;
symbolimage name=symPLD image="/folders/myfolders/PumpkinLightBlue.png";
symbolimage name=symPSD image="/folders/myfolders/PumpkinBlue.png";
symbolimage name=symPLR image="/folders/myfolders/PumpkinLightRed.png";
symbolimage name=symPSR image="/folders/myfolders/PumpkinRed.png";
symbolimage name=symPBG image="/folders/myfolders/PumpkinOrange.png";
styleattrs datasymbols=(symPBG symPLD symPLR symPSD symPSR);
xaxis display=none; yaxis display=none;
title height=16pt bold "2016 Electoral Map (Source: CNN, 10-22-2016)";
scatter x=column y=row / group=prediction markerattrs=(size=47pt) name="SCATTER";
text x=column y=row text=statecode / position=top textattrs=(color=black size=9.5pt weight=bold);
keylegend "SCATTER" / valueattrs=(size=11) autoitemsize;
TRANSPARENT .PNG IMAGES (COLORIZED MS-OFFICE CLIPART, REDUCED SIZE FROM ORIGINALS)
Cool! Though I liked the icon sizes in the legend of your previous plot.
I am concerned about the small size of the icons in the legend. I see you are using AutoItemSize. They could get bigger if you make the value font in the legend bigger. But I am not sure if there is any other ways to scale up just the legend symbols. I will check.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.