Hi,
I'm trying to represent a subset of counties but need to have both couny labels & outlines as well as a state outline. I haven't been able to come up with the state-level boundary annotate file that would work.
What I have so far is:
data ohiomap;
set mapsgfk.us_counties(where=(statecode='OH'));
run;
%annomac;
%centroid(ohiomap,centroids,state county);
proc sql;
create table anno_centroids as
select a.*, trim(left(b.idname)) as text,
'2' as xsys, '2' as ysys, '3' as hsys, 'a' as when, 'label' as function,
'5' as position, 2 as size, 'black' as color
from centroids a left join mapsgfk.us_counties_attr b
on a.state = b.state and a.county = b.county;
create table ohiodata as
select distinct county, 39 as state
from anno_centroids
where text like 'A%';
run;
quit;
pattern1 v=s c=white;
proc gmap data=ohiodata map=ohiomap;* anno=anno_state;
id state county;
choro state / levels=1 nolegend anno=anno_centroids(where=(text=:'A'));
run;
quit;
This gives me counties that start with 'A' but I also need the state outline. If I use the 'all' keyword on the gmap statement, that works but includes all county boundaries, which I don't need. I've tried several approaches to generating the anno_state file but haven't gotten it right yet.
Thanks!
--Ben
The basic approach is to get a map data set of the boundary points you want. Since you want to have county, or combinations thereof, start with a county map subsetted to the state of interest. It sounds like already have that.
Then use Proc Gremove to create a new map set with the internal (county) boundaries removed. There is an example in the online help for creating districts from the US State map data.
After you create a boundary set that maps successfully then you trace boundaries to create an annotate set. Here's an example from a project I did.
data distanno; length function color $8; retain xsys ysys '2' when 'a' color 'black' size 2 xsave ysave; drop xsave ysave; set idmap.districtmap ; by district segment; /* Move to the first coordinate */ if first.segment then do; function='move'; xsave=x; ysave=y; output; end; /* Draw to each successive coordinate */ else do; function='draw'; line=1 ; output; /* Connect the last coordinate to the first */ if last.segment then do; x=xsave; y=ysave; output; end; end; run;
This uses an input map that has already combined counties into districts in my state and then creates a boundary annotate set to outline them. The trace the boundary approach should work for any map boundary set. If the map data when sorted doesn't display correctly you might try the BY with the notsorted option.
A key part of this is to start with a relatively high resolution base county set and use that for to make all of the annotates from that so that you don't get odd artifacts when you use county, county groups, and/or state boundaries together.
Good morning,
I added the following prior to the proc gmap call:
proc gremove data=ohiomap out=stateonly;
by state;
id county;
run;
data anno_state;
set stateonly;
by segment;
length function $8 color $8;
if first.segment then function='poly'; else function='polycont';
color='black'; style='mempty'; when='b'; xsys='2'; ysys='2'; line=3; size=1;
run;
data map;
set ohiomap stateonly;
run;
And then added that to the proc gmap call per:
proc gmap data=ohiodata map=map anno=anno_state;
That gave me the map I was looking for (state boundary with dashed lines and labeled county boundaries).
I'm now getting a bunch of:
NOTE: PROBLEM IN OBSERVATION 1 -
DATA SYSTEM REQUESTED, BUT VALUE IS NOT ON GRAPH 'X'
NOTE: PROBLEM IN OBSERVATION 2 -
DATA SYSTEM REQUESTED, BUT VALUE IS NOT ON GRAPH 'X'
NOTE: PROBLEM IN OBSERVATION 3 -
DATA SYSTEM REQUESTED, BUT VALUE IS NOT ON GRAPH 'X'
This is referring to the anno_state file. The x value in Obs 1 is 25827.864786. I see 2 observations with that value: one with a county FIPS code and one with it missing from the state boundary file. So I'm not sure why these are getting flagged. ?
--Ben
You don't want to add the annotate set back to the MAP data. Annotate is to add to an existing graphics output. The variables on the records for the Annotate set would likely
Try
proc gmap data=ohiodata map=ohipmap anno=anno_state;
I think you may want the WHEN in you state to be 'A'. Gmap doesn't really do transparencies (or I haven't tried lately any way) and if you have 'B' then the state boundary will be drawn before the Map and data and overwritten. 'A' adds it after the county level map is drawn.
Was able to get this put together eventually, using:
proc gmap data=ohiodata map=map all anno=anno_state;
id county;
choro ptbpct / discrete legend=legend1 anno=anno_centroids(where=(county in (&county))) xsize=4.75in;
format ptbpct pctlabels.;
label ptbpct='Map Measure Ranges';
run;
quit;
The map file did need the state outline boundary added to it to suppress errors in the log similar to:
DATA SYSTEM REQUESTED, BUT VALUE IS NOT ON GRAPH 'Y'
And the resulting map had the bottom portion of the state outline truncated.
Normally the 'B' value for the when variable would indeed result in the lines being covered; in this case though they were outside the polygons being drawn in most cases, and where the county boundaries and state boundary were identical, the user wanted to see the solid county boundary.
Thanks for the guidance on this one! At times simple things just aren't as obvious as it would appear.
--Ben
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9.
Early bird rate extended! Save $200 when you sign up by March 31.
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.