Data visualization with SAS programming

Basic Choro/Annotate Question

Accepted Solution Solved
Reply
Frequent Contributor
Posts: 84
Accepted Solution

Basic Choro/Annotate Question

Is it possible to add multiple annotations to a map?  For example, I would like to include a percentage by state on a basic map of the US, but can I also add the numerator and denominator that make up the percentage?  I have also noticed that although I format my percentage in my data set as percent9.2, it shows up as a decimal when the map is generated.  Is it possible for it to show up as a percentage in the xx.x% format?  Thanks.


Accepted Solutions
Solution
‎05-30-2012 08:18 AM
SAS Employee
Posts: 963

Re: Basic Choro/Annotate Question

The easiest way of adding multiple lines of text annotation is to use the 'positions' to place the text at various locations in relation to the x/y point ...

http://support.sas.com/documentation/cdl/en/graphref/63022/HTML/default/viewer.htm#annotate_position...

And in order for your format to show up in the annotated 'text' variable, you can use a 'put()' statement, and specify the format there.

I'm including a small sample that shows both of these things:

data anno_stuff; set maps.uscenter (where=(fipstate(state) in ('NC' 'SC' 'GA' 'FL')));
xsys='2'; ysys='2'; hsys='3'; when='a';
function='label';
length text $20;
position='2'; text=fipstate(state); output;
position='5'; text=fipnamel(state); output;
position='8'; text='Lat.='||trim(left(put(lat,comma5.2))); output;
run;

pattern1 v=solid color=white;

proc gmap data=maps.us map=maps.us (where=(fipstate(state) in ('NC' 'SC' 'GA' 'FL')));
id state;
choro state / levels=1 anno=anno_stuff;
run;

View solution in original post


All Replies
Solution
‎05-30-2012 08:18 AM
SAS Employee
Posts: 963

Re: Basic Choro/Annotate Question

The easiest way of adding multiple lines of text annotation is to use the 'positions' to place the text at various locations in relation to the x/y point ...

http://support.sas.com/documentation/cdl/en/graphref/63022/HTML/default/viewer.htm#annotate_position...

And in order for your format to show up in the annotated 'text' variable, you can use a 'put()' statement, and specify the format there.

I'm including a small sample that shows both of these things:

data anno_stuff; set maps.uscenter (where=(fipstate(state) in ('NC' 'SC' 'GA' 'FL')));
xsys='2'; ysys='2'; hsys='3'; when='a';
function='label';
length text $20;
position='2'; text=fipstate(state); output;
position='5'; text=fipnamel(state); output;
position='8'; text='Lat.='||trim(left(put(lat,comma5.2))); output;
run;

pattern1 v=solid color=white;

proc gmap data=maps.us map=maps.us (where=(fipstate(state) in ('NC' 'SC' 'GA' 'FL')));
id state;
choro state / levels=1 anno=anno_stuff;
run;

Frequent Contributor
Posts: 84

Re: Basic Choro/Annotate Question

Thank you very much for the response.  When I try to translate the coding you provided to use my data, it appears that the values are present, but in a single line across the map, rather than by state.  Do I need to take an extra step since I am not trying to map data from the maps.us table, but rather from my data, linked by statecode?

Here is the code I am using, in case that is needed.

data anno_stuff;

set Mods_by_State;

xsys='2'; ysys='2'; hsys='3'; size=3; when='a';

function='label';

length text $20;

position='2'; text=ModPercent; output;

position='5'; text=TotWOCount; output;

run;

pattern1 v=solid color=vligb;

proc gmap data=Mods_by_State map=maps.us;

  id StateCode;

  choro ModPercent / levels=6 anno=anno_stuff;

run;

SAS Employee
Posts: 963

Re: Basic Choro/Annotate Question

Are you setting an X and Y value for the position of the text labels somewhere?

You could use the X and Y from maps.uscenter (for example, merge that with your data set that has the labels).

Frequent Contributor
Posts: 84

Re: Basic Choro/Annotate Question

I was not including X & Y variables at first, but even though I am now including them, I still get the same result.  The code I am using is below.

data counts;

set hspdata.counts_2011(where=(resolvedte ge '01Oct2011'd)) hspdata.counts_2012;

length StateCode  $2.;

StateCode = substr(SRV_REGN,1,2);

run;

%let Beg_MTD = '01Apr12'd;

%let End_MTD = '30Apr12'd;

proc summary data = WO_Counts(where=(evt_stat_cd in ("Closed") and

  &beg_mtd. le Resolvedte le &end_mtd.)) missing nway;

  class  StateCode;

  var Change;

  output out =  Temp_by_State(rename=(_freq_=TotCnt) drop = _type_) sum=;

run;

proc sql;

create table tempUSmap as

select t1.statecode, t2.*

from maps.us as t1 left join maps.uscenter as t2 on t1.state = t2.state;

quit;

proc sort data= tempUSmap nodupkey;

  by StateCode;

Run;

proc sql;

create table tempUSmap_withmods as

select t1.*, t2.*

from tempUSmap as t1 left join Temp_by_State as t2 on t1.statecode = t2.statecode;

quit;

data Mods_by_State; 

  Set tempUSmap_withmods;

  length Group $8.; 

  APercent=round(Change/TotWOCnt,0.0001); 

  format APercent percent9.2; 

  if APercent <0.4 then Group = "<40%"; 

  if APercent >=0.4 and APercent <0.5 then Group = "40%-49%"; 

  if APercent >=0.5 and APercent <0.6 then Group = "50%-59%"; 

  if APercent >=0.6 and APercent <0.7 then Group = "60%-69%"; 

  if APercent >=0.7 then Group = ">70%";

  xsys='2'; ysys='2'; hsys='3'; size=3; when='a';

  function='label';

  length text $20;

  position='2'; text=put(APercent, percent9.1); output;

run;

goptions reset=all border;

pattern1 v=ms c=cxeff3ff;

pattern2 v=ms c=cxbdd7e7;

pattern3 v=ms c=cx6baed6;

pattern4 v=ms c=cx2171b5;

legend1

origin=(75,60)pct

across=1

mode=share

label=(position=top j=c 'Modification Rate')

shape=bar(3,4)pct

cborder=blue

;

title1 "Modifications by State";

footnote1 j=r &sysdate;

legend1 label=("Modifiation Percent");

pattern1 v=msolid color=vligb;

proc gmap

  map=maps.us

  data=Mods_by_State;

  id StateCode;

  choro Group / levels=6 annotate=anno_stuff;

run;

quit;

Frequent Contributor
Posts: 84

Re: Basic Choro/Annotate Question

Actually, I figured it out.  In addition to merging the maps.us and maps.uscenter so that I had the center values by StateCode, I had to change the data Mods_by_State statement into two data steps, one with the annotate example you provided and one with my data set.  Thanks again to both of you.

Robert, one further question.  i noticed on your website you have some examples where you have states that have data offset and connected by a leader line (i.e. the east coast data values are off to the right of the graph to avoid overlap).  How is that done?  I have been searching around for that code and have been unable to find it as of yet.  Thanks.

Valued Guide
Posts: 723

Re: Basic Choro/Annotate Question

hi ... the USCENTER data set has two observations for some states (extra X/Y coordinates for adding labels)

there's a variable named OCEAN and if that variable has a value of 'Y' the X/Y values are in the Atlantic Ocean while the X/Y values for the same state with OCEAN = 'N' are at the state center

* make a new data set ... place X/Y values for same state in one observation;

data new;

merge

maps.uscenter (where=(ocean eq 'N'))

maps.uscenter (where=(ocean eq 'Y') rename=(x=xo y=yo));

by state;

drop lat long;

run;

* if a state has only one set of X/Y values, draw a label;

* if a state has two sets of X/Y values, draw a line, then draw a label;

data anno;

retain xsys ysys '2' hsys '3' style '"calibri"' size 2 function 'label' cbox 'graydd' when 'a';

set new;

text = fipstate(state);

if ocean eq 'N' then output;

else do;

   size = 0.25;

   function = 'move';

   output;

   x = xo;

   y = yo;

   function = 'draw';

   output;

   size = 2;

   function = 'label';

   output;

end;

run;

goptions reset=all;

pattern1 v=msolid color=white;

proc gmap data=maps.us map=maps.us anno=anno;

id state;

choro state / levels=1 nolegend;

run;

quit;

Attachment
Frequent Contributor
Posts: 84

Re: Basic Choro/Annotate Question

I have a follow up question:  is the same thing possible using US county, even though there is no US county center map?  I would like to limit my results by state and county, and then display several pieces of information by county, one of which being COUNTYNM from the maps.cntyname table.  Thanks.

SAS Employee
Posts: 963

Re: Basic Choro/Annotate Question

We don't ship a data set with the pre-calculated center of each county, but we ship the %centroid macro that you can use to estimate the centers of the areas in any of your SAS maps.  Here's an example of how to run the centroid macro:

/* Find the center of each county */

%annomac;

%centroid( mymap, centers, state county );

And here is an example that I used the above code in:

http://robslink.com/SAS/democd31/church.htm

http://robslink.com/SAS/democd31/church_info.htm

Valued Guide
Posts: 723

Re: Basic Choro/Annotate Question

Hi ... a follow up to Robert's posting ... the %CENTROID macro requires a data set that's sorted according to the ID variable(s).  So, finding the center of each county would require ...

proc sort data=maps.counties out=mymap;

by state county;

run;

Frequent Contributor
Posts: 84

Re: Basic Choro/Annotate Question

But can you use the %annomac to annotate multiple items per county?

Valued Guide
Posts: 723

Re: Basic Choro/Annotate Question

hi ... %annomac just allows you to use the SAS-supplied macros, like %centroid

once you know the centroids, it's easy (sort of) to add multiple items

take a look at Faking ArcGIS maps in SAS ... http://www.nesug.org/Proceedings/nesug11/gr/gr08.pdf

Valued Guide
Posts: 723

Re: Basic Choro/Annotate Question

Hi ... Robert answered your multiple lines of text question.  Here's his example (modified a bit) to show how to get the percentages to appear properly ...

* data set with numeric variables NUM, DEN, Z formatted PRECENT9.2;

data x;

set maps.uscenter (where=(fipstate(state) in ('NC' 'SC' 'GA' 'FL')));

num = ceil(10000*ranuni(999));

den = ceil(100000*ranuni(999));

z = num / den;

format z percent9.2;

run;

* convert numeric variables to text with PUT statements ... FORMAT controls appearance;

data anno_stuff;

retain xsys ysys '2' hsys '3' when 'a' function 'label' style '"calibri"' size 2;

length text $50;

set x;

position='2'; text=catt(fipnamel(state), ':' , put(z,percent9.1)); output;

position='5'; text=put(num,comma10.); output;

position='8'; text=put(den,comma10.); output;

run;

pattern1 v=msolid color=white;

proc gmap data=maps.us map=maps.us (where=(fipstate(state) in ('NC' 'SC' 'GA' 'FL')));

id state;

choro state / levels=1 nolegend anno=anno_stuff;

run;

quit;

Attachment
Post a Question
Discussion Stats
  • 12 replies
  • 5230 views
  • 3 likes
  • 3 in conversation