Can someone kindly help me? I am trying to construct four different graphs as one figure instead of having four different graphs.
Thank you
Sample data:
data texas_state;
set mapsgfk.us_counties;
where ID1='US-48';
if county in (43 109 141 229 243 377) then phr='10';
else
if county in (7 25 47 61 131 215 247 249 261 273 297 311 355
391 409 427 479 489 505) then phr='11';
else
if county in (11 17 45 65 69 75 79 87 107 111 117 125 129 153 169 179 189 191
195 205 211 219 233 269 279 295 303 305 341 345 357 359 369 375 381 393 421
437 445 483 501) then phr='1';
else
if county in (9 23 49 59 77 83 93 101 133 151 155 197 207 237 253 263 275
335 337 353 399 415 417 429 433 441 447 485 487 503) then phr='2';
else
if county in (85 97 113 121 139 143 147 181 221 231 251 257 349 363 367
397 425 439 497) then phr='3';
else
if county in (1 37 63 67 73 119 159 183 203 213 223 277 315 343 365 379
387 401 423 449 459 467 499) then phr='4';
else
if county in (5 199 225 241 245 347 351 361 373 403 405 407 419 455 457) then phr='5';
else
if county in (15 39 71 89 157 167 201 291 321 339 471 473 481) then phr='6';
else
if county in (21 27 31 35 41 51 53 55 99 145 149 161 185 193 209 217 281 287
289 293 299 309 313 331 333 395 411 453 477 491) then phr='7';
else
if county in (13 19 29 57 91 123 127 137 163 171 175 177 187 239 255 259 265 271 283 285
323 325 385 463 465 469 493 507) then phr='8';
else
if county in (3 33 81 95 103 105 115 135 165 173 227 235 267 301 307 317 319 327 329 371
383 389 413 431 435 443 451 461 475 495) then phr='9';
run;
*check contents;
PROC CONTENTS DATA=texas_state;RUN;
* sort map data set in order by new geographic designation;
proc sort data= mydata1.texas_state;
by phr;
run;
* eliminate county boundaries with HSA areas using PROC GREMOVE;
proc gremove
data= mydata1.texas_state
out= mydata1.texas_state_map;
by phr;
id county;run;
*year 2;
data WORK.YEAR2_REG;
infile datalines truncover;
input phr:$2. COUNT;
label COUNT="Frequency Count";
datalines;
1 752
2 1470
3 673
4 1336
5 1483
6 676
7 814
8 1285
9 521
10 611
11 733
;
pattern1 value=solid color=CXE5E0EC;
pattern3 value=solid color=CXB2A1C7;
pattern5 value=solid color=CX3F3151;
legend1 label=(position= TOP 'Rate per 100,000 people')
shape=bar(.1in,.1in) value=(justify=right '500 to 600'
'601 to 900' '1201 to 1500')
across=1 origin=(35,12) mode=reserve;
title1 lspace= 5 "YEAR2_DATA";
%ANNOMAC;
%MAPLABEL (MYDATA1.texas_state_map, YEAR2_REG, anno_phr_label, phr,
phr,font=Arial Black,color=red, size=2, hsys=3);
PROC FORMAT;
VALUE count
100 - 600 = '= 600'
601 - 900 = '601 to 900'
1201- 1500 = '1201 to 1500';run;
PROC GMAP DATA = YEAR2_REG MAP = MYDATA1.texas_state_map ALL;
ID phr;
FORMAT count count.;
CHORO count / DISCRETE ANNOTATE = anno_phr_label
legend=legend1;
TITLE 'YEAR2_DATA';
RUN;
Looks like ballardw and I had the same thought (use greplay), and were working on it simultaneously!
Here's what I came up with. Note that when using greplay, you'll need to delete the grsegs between each run, or start a fresh SAS session each time (which is what I do), if you want to make changes/improvements between 2 runs.
%annomac;
/* Find the x/y centroid of each phr area */
%centroid(texas_state_map,anno_phr_label,phr,segonly=1);
/* Merge in the response data */
proc sql noprint;
create table anno_phr_label as
select unique anno_phr_label.*, all.*
from anno_phr_label left join all
on anno_phr_label.phr = all.phr
order by year;
quit; run;
/* Add the annotate commands */
data anno_phr_label; set anno_phr_label;
length function $8 style $35 text $50;
xsys='2'; ysys='2'; hsys='3'; when='a';
function='label'; color='red'; position='5'; style='albany amt/bold'; size=4.5;
text=trim(left(put(count,comma10.0)));
run;
proc format;
value count
100 - 600 = '100 to 600'
601 - 900 = '601 to 900'
901- high = '901 and higher';
run;
/* Create the individual graphs, but don't display them (yet) */
goptions nodisplay;
/* First, create the legend using annotate */
data anno_legend;
length function $8 color $12 style $35;
xsys='3'; ysys='3'; hsys='3'; when='a';
color='gray33';
function='label'; size=3.0;
position='>';
y=4;
x=5; text='Rate per 100,000 people:'; output;
x=38; text='100 to 600'; output;
x=60; text='601 to 900'; output;
x=80; text='901 and higher'; output;
style='albany amt/unicode'; size=4.0; y=y+.3;
x=38-2.5; text='25a0'x; color="CXE5E0EC"; output;
x=60-2.5; text='25a0'x; color="CXB2A1C7"; output;
x=80-2.5; text='25a0'x; color="CX3F3151"; output;
color='gray55';
x=38-2.5; text='25a1'x; output;
x=60-2.5; text='25a1'x; output;
x=80-2.5; text='25a1'x; output;
run;
title;
goptions xpixels=800 ypixels=600;
proc gslide anno=anno_legend des='' name="legend";
run;
/* Next, create the 4 individual (visible) maps */
options nobyline;
title1 h=7pct ls=1. ls=1.55 f='albany amt/bold' '#byval(year) data';
pattern1 value=solid color=CXE5E0EC;
pattern3 value=solid color=CXB2A1C7;
pattern5 value=solid color=CX3F3151;
/* 48%x800=384 43%*600=258 */
goptions xpixels=384 ypixels=258;
goptions htext=4pct;
proc gmap data=all map=texas_state_map all;
by year;
id phr;
format count count.;
choro count / discrete anno=anno_phr_label
nolegend coutline=gray55
des='' name="#byval(year)";
run;
/*
turn on display again, and replay all the individual graphs
into a custom greplay template layout.
*/
goptions display;
%let border=gray44;
goptions xpixels=800 ypixels=600;
proc greplay nofs igout=work.gseg tc=tempcat;
tdef four des='Four Maps'
0/ llx=0 lly=0
ulx=0 uly=100
urx=100 ury=100
lrx=100 lry=0
color=gray55
1/ llx=0 lly=57
ulx=0 uly=100
urx=48 ury=100
lrx=48 lry=57
color=gray55
2/ llx=52 lly=57
ulx=52 uly=100
urx=100 ury=100
lrx=100 lry=57
color=gray55
3/ llx=0 lly=10
ulx=0 uly=53
urx=48 ury=53
lrx=48 lry=10
color=gray55
4/ llx=52 lly=10
ulx=52 uly=53
urx=100 ury=53
lrx=100 lry=10
color=gray55
;
template four;
treplay
0:legend
1:year1
2:year2
3:year3
4:year4;
run;
What output destination do you want to send this to?
And must the result be a single image or is it sufficient to place the 4 graphs in a 2 by 2 layout on a page or screen?
What output destination do you want to send this to? Jpeg or any format that would allow me copy and paste in a doc or powerpoint
And must the result be a single image or is it sufficient to place the 4 graphs in a 2 by 2 layout on a page or screen? Either is fine, I just want the four graphs to count as one figure for publication purposes.
Thank you so much.
Here is one way using the Proc Greplay. This will NOT be a complete solution because there will be things that you need to do for your desired display but it will show the main pieces.
The first is that you should specify where the graphics output catalog will be with the GOUT option for each Proc GMAP call.
Second the Choro (or which ever plot statement) should have the NAME= option so you can later identify which map you want to reference.
Then use Proc Greplay and a template to place each graph into a cell of a template. This will use a 2 by 2 layout supplied by SAS.
proc sql; create table demographics(rename=(iso=oiso newiso=iso id=oldid newid=ID)) as select demo.*, put(demo.iso,z3.) as newiso format=$3., put(demo.iso,ison2a.) as newid from sashelp.demographics as demo ; alter table demographics modify ID char(15) label='Alpha2 Country Code'; quit; title1 "Population in Europe MAP 1"; proc gmap map=mapsgfk.europe(where=(id not in:('SJ' 'TR'))) data=demographics(where=(cont=93)) all gout=work.dmap /*<= know where the output goes*/ ; id id; choro pop / cdefault=yellow stat=first name="Map1" nolegend ; run; quit; title1 "Population in Europe MAP 2"; proc gmap map=mapsgfk.europe(where=(id not in:('SJ' 'TR'))) data=demographics(where=(cont=93)) all gout=work.dmap /*<= know where the output goes*/ ; id id; choro pop / cdefault=yellow stat=first name="Map2" nolegend ; run; quit; title1 "Population in Europe MAP 3"; proc gmap map=mapsgfk.europe(where=(id not in:('SJ' 'TR'))) data=demographics(where=(cont=93)) all gout=work.dmap /*<= know where the output goes*/ ; id id; choro pop / cdefault=yellow stat=first name="Map3" nolegend ; run; quit; title1 "Population in Europe MAP 4"; proc gmap map=mapsgfk.europe(where=(id not in:('SJ' 'TR'))) data=demographics(where=(cont=93)) all gout=work.dmap /*<= know where the output goes*/ ; id id; choro pop / cdefault=yellow stat=first name="Map4" nolegend ; run; quit; proc greplay igout=work.dmap /*catalog with source maps created*/ gout=work.replay /* destination for replayed images*/ tc=sashelp.templt /* template source, should be available*/ template=l2r2 /* template with 2 left and 2 right boxes of same size*/ nofs ; /* each template when created has a region number the following tells which created graph goes into which region number. The names are entries in the IGOUT catalog */ treplay 1: map1 2: map2 3: map3 4: map4 ; quit; /* log will show the location of the created (default) png file*/
If you run this you will get a demonstration of some changes that will likely need to be made to your GMAP code.
The replayed template divides your current graphics page size, so the settings will affect the size of things like fonts when shrunk to fit into the displayed area. And this is trial and error depending on your text and desired resulting size.
If you have a legend in each graph that needs to be displayed then you need to adjust settings for legibility, as well as for footnotes and annotate graphics (map label). The font face can be pretty important as well as some "shrink" better.
You would likely need to create a custom template so that the 4 boxes do not quite take up all of the space and has a fifth cell that is 100% of the page to display annotate graphics for the legend. The annotate macros to place colored bars and text work for this.
Proc Template is used to create templates for this and aren't that difficult. You can examine the contents of the sashelp.templt items for some details. Basically you provide coordinates for the 4 corners of a rectangle as percentage of page space and a panel number for reference.
I suspect if you google Proc Greplay you'll get some other examples.
The log will show where the default output image file was created, likely in the Work library. Or you can use an ODS RTF or ODS POWERPOINT sandwich to create a document with the image(s) replayed.
ods rtf file="c:\path\file.rtf"; <entire proc replay code goes here> ods rtf close;
Options in your Gmap code and the template definitions come into play for border/ noborder appearance.
Looks like ballardw and I had the same thought (use greplay), and were working on it simultaneously!
Here's what I came up with. Note that when using greplay, you'll need to delete the grsegs between each run, or start a fresh SAS session each time (which is what I do), if you want to make changes/improvements between 2 runs.
%annomac;
/* Find the x/y centroid of each phr area */
%centroid(texas_state_map,anno_phr_label,phr,segonly=1);
/* Merge in the response data */
proc sql noprint;
create table anno_phr_label as
select unique anno_phr_label.*, all.*
from anno_phr_label left join all
on anno_phr_label.phr = all.phr
order by year;
quit; run;
/* Add the annotate commands */
data anno_phr_label; set anno_phr_label;
length function $8 style $35 text $50;
xsys='2'; ysys='2'; hsys='3'; when='a';
function='label'; color='red'; position='5'; style='albany amt/bold'; size=4.5;
text=trim(left(put(count,comma10.0)));
run;
proc format;
value count
100 - 600 = '100 to 600'
601 - 900 = '601 to 900'
901- high = '901 and higher';
run;
/* Create the individual graphs, but don't display them (yet) */
goptions nodisplay;
/* First, create the legend using annotate */
data anno_legend;
length function $8 color $12 style $35;
xsys='3'; ysys='3'; hsys='3'; when='a';
color='gray33';
function='label'; size=3.0;
position='>';
y=4;
x=5; text='Rate per 100,000 people:'; output;
x=38; text='100 to 600'; output;
x=60; text='601 to 900'; output;
x=80; text='901 and higher'; output;
style='albany amt/unicode'; size=4.0; y=y+.3;
x=38-2.5; text='25a0'x; color="CXE5E0EC"; output;
x=60-2.5; text='25a0'x; color="CXB2A1C7"; output;
x=80-2.5; text='25a0'x; color="CX3F3151"; output;
color='gray55';
x=38-2.5; text='25a1'x; output;
x=60-2.5; text='25a1'x; output;
x=80-2.5; text='25a1'x; output;
run;
title;
goptions xpixels=800 ypixels=600;
proc gslide anno=anno_legend des='' name="legend";
run;
/* Next, create the 4 individual (visible) maps */
options nobyline;
title1 h=7pct ls=1. ls=1.55 f='albany amt/bold' '#byval(year) data';
pattern1 value=solid color=CXE5E0EC;
pattern3 value=solid color=CXB2A1C7;
pattern5 value=solid color=CX3F3151;
/* 48%x800=384 43%*600=258 */
goptions xpixels=384 ypixels=258;
goptions htext=4pct;
proc gmap data=all map=texas_state_map all;
by year;
id phr;
format count count.;
choro count / discrete anno=anno_phr_label
nolegend coutline=gray55
des='' name="#byval(year)";
run;
/*
turn on display again, and replay all the individual graphs
into a custom greplay template layout.
*/
goptions display;
%let border=gray44;
goptions xpixels=800 ypixels=600;
proc greplay nofs igout=work.gseg tc=tempcat;
tdef four des='Four Maps'
0/ llx=0 lly=0
ulx=0 uly=100
urx=100 ury=100
lrx=100 lry=0
color=gray55
1/ llx=0 lly=57
ulx=0 uly=100
urx=48 ury=100
lrx=48 lry=57
color=gray55
2/ llx=52 lly=57
ulx=52 uly=100
urx=100 ury=100
lrx=100 lry=57
color=gray55
3/ llx=0 lly=10
ulx=0 uly=53
urx=48 ury=53
lrx=48 lry=10
color=gray55
4/ llx=52 lly=10
ulx=52 uly=53
urx=100 ury=53
lrx=100 lry=10
color=gray55
;
template four;
treplay
0:legend
1:year1
2:year2
3:year3
4:year4;
run;
Thank you so much for your help. Your solution and Ballardw's worked. But the legend appeared small by using Ballardw's soln.
I tried tweaking your code a little but I can't seem to get it right.
First, I want the annotation on the map to show the phr (1 to 11) and not the frequency counts for each region like the sample map below. I tried using the code below but did not work.
%ANNOMAC;
%MAPLABEL (texas_state_map, all, anno_phr_label, phr,
phr,font=Arial Black,color=black, size=2, hsys=3);
Second, I changed the proc format to six categories but the legend doesn't seem quite right.
proc format;
value count
400 - 600 = '400 to 600'
601 - 800 = '601 to 800'
801- 1000 = '801 to 1000'
1001- 1200 ='1001 to 1200'
1201 -1500 ='1201 -1500'
1501- 1700 = '>=1500';
run;
Thank you once again
I'm not really familiar with the %maplabel macro. If it gives you what you want, that's great ... but if it doesn't then I'd recommend using my code that creates the annotate step-by-step (that way you can tell exactly what it's doing).
When you say "the legend doesn't seem quite right" - note that I am annotating a 'fake' legend, rather than using the legend that would be generated with each map. Therefore you'll need to modify the code that creates the annotated legend to annotate the color-chips and text of the legend you want.
Once you get into the realm of creating a custom graph or map, you will find that you have to do a lot of extra coding & 'trickery' to get things exactly like you want them. (In this case, it would be easy to have a legend with each map, but since you want what "looks like" a legend for all 4 maps, then it requires a lot of extra effort.)
Wonder how to use Proc SGmap to achieve the similar result.
With appreciation,
Ethan
Hi Ethan, I am not that well versed in the sgmap procedure. Consider asking your question in a new post.
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.