BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
fanwayne
Fluorite | Level 6

I am currently drawing a forest plot and I found a macro can do what I needed.

However, the template provided in this macro has one limitation (The paper was writtern by Janette Garner, title: An Enhanced Forest Plot Macro Using SAS).

The plot looks like as below. As I want to separate the header part and main contents of the plot, I do not know how to fix this. The default option for the header is to paint it with grey color, however I only need a bottom line for the header and make it looks a bit fomal for printing.

屏幕快照 2019-03-15 11.26.06.png

Does anyone who knows any solution for this purpose.

Thanks in advance!

proc import datafile="Y:\tab1.csv" dbms=csv out=tab1(where=(^missing(STATORD))) replace;
	getnames=yes;
run;


data forest;
		set tab1;
		by sortord statord;
		retain y y1 y2 y3 0;
		if first.sortord then do;
			y = y2 + 1;
			y1 = y - 1.5;
			y2 = y - 0.5;
		end;
		/* Adding 2.5 to each y1 and y2 will insert a small space (of size 0.5) between each subgroup chunk */
		y1 = y1 + 2.5;
		y2 = y2 + 2.5;
		y3 = mean(y1,y2);
run;

data plot;
	set forest;
	by y; /* Y-values associated with the header are only plotted once */
	if not first.y then y = .; /* We assign the variables "zero" and "one" as dummy variables to allow for
	plotting of text in some of the columns, in particular the labels. */
	zero = 0;
	one = 0.1;
	/* For alternating groups, add variables so that a reference band can be
	generated to aid in visualization */
	/* NOTE: To "disable" the reference bands, the user can set the color to
	white (cxffffff) in the PROC SGRENDER in Step 3 */
	if mod(sortord,2) = 0 then do;
		ref1=y1;
		ref2=y2;
		/* Third reference line to fill in any whitespace that may appear */
		if y ^ = . then ref3 = y;
		else if y = . then ref3 = ref1 - 0.5;
	end;
	*** Shift the "Overall" label down ***;
	if group = "Overall" then y = y3;
run;


%macro forest(	showcol2=Y,
				showcol3=Y,
				showcol4=Y,
				showcol5=Y,
				colwghts=%str(0.15 0.32 0.10 0.35 0.08),
				barval=%str(0 10 20 30 40 50 60 70 80 90 100),
				xlabbar=%bquote(Responders (%)),
				showpct=N,
				pctfmt=5.1,
				frsttype=DIFF/*RATIO*/,
				frstval=%str(-30 -20 -10 0 10 20 30)/*%str(0 0.5 1 2)*/,
				frstlabl=Y,
				xlabfrst=%bquote(Difference (%)),
				legtitle=%str(Treatment Group),
				ci_col=N,
				statlabl=%str(P-value)
				);
	
	
	data plot;
		set plot;
		%if &frsttype=DIFF %then %do;
			ci_txt = strip(put(est,5.1))||"% ("||strip(put(low,5.1))||"% to"||strip(put(high,5.1))||"%)";
		%end;
		%if &frsttype=RATIO %then %do;
			ci_txt = strip(put(est,5.1))||" ("||strip(put(low,5.1))||" to"||strip(put(high,5.1))||")";
		%end;
		n_txt1p = strip(n_txt1)||" ("||strip(put(percent1,&pctfmt))||"%)";
		n_txt2p = strip(n_txt2)||" ("||strip(put(percent2,&pctfmt))||"%)";
	run;

	proc sql noprint;
		select max(y2) into :ymax from plot;
	quit;

	%let colcnt = %eval(%sysfunc(count(&showcol2&showcol3&showcol4&showcol5,Y))+1);


	proc template;
		define statgraph ForestPlot;

		*** Assign dynamic variables, where the options are specified in the SGRENDER procedure ***;
		dynamic _headercolor _trt1labl _trt1color _trt2labl _trt2color _refcolor
			_refsize _barsize _ymin _ymax _title _footnote;
		begingraph;

		*** Add a title, if one is specified in the SGRENDER procedure ***;
		EntryTitle _title /;
		layout lattice / columns=&colcnt columnweights=(&colwghts);
			*** Specify column headers ***;
		sidebar / align=top;
			layout lattice / rows=1 columns=&colcnt columnweights=(&colwghts)
				backgroundcolor=_headercolor opaque=true;
			entry halign=center textattrs=(size=8 weight=bold) "";

			%if &showcol2=Y %then %do; 
				entry halign=center textattrs=(size=8 weight=bold) ""; 
			%end;

			%if &showcol3=Y %then %do; 
				entry halign=center textattrs=(size=8 weight=bold) 
				%if &showpct=N %then %do; 
					"n/N" %end; %else %do; "n/N (%)" 
				%end;
				; 
			%end;

			%if &showcol4=Y %then %do; 
				entry halign=center textattrs=(size=8 weight=bold) ""; 
			%end;

			%if &showcol5=Y %then %do; 
				entry halign=center textattrs=(size=8 weight=bold) "&statlabl" ; 
			%end;

		endlayout;
		endsidebar;

		*** Column 1: Labels of the comparisons ***;
		layout overlay / walldisplay=none xaxisopts=(display=none) yaxisopts=(reverse=true display=none 
			tickvalueattrs=(weight=bold) linearopts=(viewmin=_ymin viewmax=_ymax));
			referenceline y=ref1 / lineattrs=(thickness=_refsize color=_refcolor);
			referenceline y=ref2 / lineattrs=(thickness=_refsize color=_refcolor);
			referenceline y=ref3 / lineattrs=(thickness=_refsize color=_refcolor);

			*** Header, using "y" variable ***;
			highlowplot y=y low=zero high=zero / highlabel=group lineattrs=(thickness=0) labelattrs=(size=7 weight=bold);

			*** Subgroup, using "y3" variable ***;
			highlowplot y=y3 low=one high=one / highlabel=level lineattrs=(thickness=0) labelattrs=(size=7 weight=bold);
		endlayout;

		%if &showcol2=Y %then %do;
		*** Column 2: Barplots of the proportion of successes in each treatment group ***;
			layout overlay / xaxisopts=(label="&xlabbar" labelattrs=(size=7 weight=bold) 
				linearopts=(tickvaluepriority=true tickvaluelist=(&barval))
				/*display=(tickvalues)*/) /* This hides the x-axis label */
			yaxisopts=(reverse=true display=none linearopts=(viewmin=_ymin viewmax=_ymax)) walldisplay=none;

			referenceline y=ref1 / lineattrs=(thickness=_refsize color=_refcolor);
			referenceline y=ref2 / lineattrs=(thickness=_refsize color=_refcolor);
			referenceline y=ref3 / lineattrs=(thickness=_refsize color=_refcolor);

			*** The barplots are created using a HIGHLOW plot, where the thickness of the line is 
			controlled by user. Tweaking is required based on the number of rows, height of the 
			output and spacing between bars. ***;

			highlowplot y=y1 low=zero high=percent1 /lineattrs=(thickness=_barsize color=_trt1color)
			labelattrs=(size=7 weight=bold) name='trt1' legendlabel=_trt1labl;

			highlowplot y=y2 low=zero high=percent2 /lineattrs=(thickness=_barsize color=_trt2color)
			labelattrs=(size=7 weight=bold) name='trt2' legendlabel=_trt2labl;
			referenceline x=0;
			endlayout;
		%end;

		%if &showcol3=Y %then %do;
			*** Column 3: Column of values that support the barplots, n/N ***;
			layout overlay / walldisplay=none xaxisopts=(display=none) yaxisopts=(reverse=true display=none
				tickvalueattrs=(weight=bold) linearopts=(viewmin=_ymin viewmax=_ymax));

			referenceline y=ref1 / lineattrs=(thickness=_refsize color=_refcolor);
			referenceline y=ref2 / lineattrs=(thickness=_refsize color=_refcolor);
			referenceline y=ref3 / lineattrs=(thickness=_refsize color=_refcolor);

			highlowplot y=y1 low=zero high=zero / 
				%if &showpct=N %then %do;
					highlabel=n_txt1 
				%end; 
				%if &showpct=Y %then %do; 
					highlabel=n_txt1p 
				%end;
				lineattrs=(thickness=0) labelattrs=(size=7 color=_trt1color);

				highlowplot y=y2 low=zero high=zero / 
					%if &showpct=N %then %do;
						highlabel=n_txt2 
					%end; 
					%if &showpct=Y %then %do; 
						highlabel=n_txt2p 
					%end;

				lineattrs=(thickness=0) labelattrs=(size=7 color=_trt2color);
			endlayout;
		%end;

		%if &showcol4=Y %then %do;
			*** Column 4: Plot the CI for the difference (and include the point estimate) ***;

			layout overlay / xaxisopts=(label="&xlabfrst" labelattrs=(size=7 weight=bold)
				linearopts=(tickvaluepriority=true tickvaluelist=(&frstval)))
				yaxisopts=(reverse=true display=none linearopts=(viewmin=_ymin
				viewmax=_ymax)) walldisplay=none;

				referenceline y=ref1 / lineattrs=(thickness=_refsize color=_refcolor);
				referenceline y=ref2 / lineattrs=(thickness=_refsize color=_refcolor);
				referenceline y=ref3 / lineattrs=(thickness=_refsize color=_refcolor);

				%if &frsttype=DIFF %then %do;
					referenceline x=0 / lineattrs=(pattern=shortdash);
				%end;

				%if &frsttype=RATIO %then %do;
					referenceline x=1 / lineattrs=(pattern=shortdash);
				%end;

				highlowplot y=y3 low=low high=high / lineattrs=(thickness=1 color=black) 
				%if &frstlabl=Y %then %do; 
					lowlabel=low highlabel=high 
				%end; 
				;

				scatterplot y=y3 x=est / markerattrs=(symbol=circlefilled size=10 color=black) 
				datalabelposition=bottom 
				%if &frstlabl=Y %then %do;
					datalabel=est 
				%end; 
				;

				*** Insert labels that explain the plot, namely that the right
				side favors Treatment 1 and the left side favors Treatment 2. The labels for
				these are defined in the SGRENDER procedure. ***;
				layout gridded / rows=2 border=false autoalign=(topright);
					entry textattrs=(size=7) halign=right 'Favors';
					entry textattrs=(size=7 color=_trt1color) halign=right _trt1labl;
				endlayout;

				layout gridded / rows=2 border=false autoalign=(topleft);
					entry textattrs=(size=7) halign=left 'Favors';
					entry textattrs=(size=7 color=_trt2color) halign=left _trt2labl;
				endlayout;
			endlayout;
		%end;

		%if &showcol5=Y %then %do;
			*** Column 5: Statistics (Numerical Values) columns ***;
			layout overlay / walldisplay=none xaxisopts=(display=none)
				yaxisopts=(reverse=true display=none linearopts=(viewmin=_ymin viewmax=_ymax));
				referenceline y=ref1 / lineattrs=(thickness=_refsize color=_refcolor);
				referenceline y=ref2 / lineattrs=(thickness=_refsize color=_refcolor);
				referenceline y=ref3 / lineattrs=(thickness=_refsize color=_refcolor);
				highlowplot y=y3 low=zero high=zero / 
					%if &ci_col=Y %then %do;
						highlabel=ci_txt 
					%end; 
					%if &ci_col=N %then %do; 
						highlabel=stat_txt 
					%end;
				lineattrs=(thickness=0) labelattrs=(size=7);
			endlayout;
		%end;

		endlayout;

		%if &showcol2=Y %then %do; /* Only display legend if barplot shown */
			*** Add legend to bottom of the graph to explain colored bars ***;
			layout globallegend / type=row weights=preferred legendtitleposition=left;
			discretelegend 'trt1' 'trt2' / title="&legtitle" titleattrs=(size=8 weight=bold) 
			across=2 displayclipped=true;
			endlayout;

		%end;

		*** Add footnote text, if specified in the SGRENDER procedure ***;
		entryfootnote halign=left textattrs=(size=7) _footnote;
		endgraph;
	end;
	run;


	proc sgrender data=plot template=ForestPlot;
		dynamic _refcolor='cxf0f0f0' /* Set _refcolor='cxffffff' (white) to "hide" the reference bars */
		_refsize=15
		_headercolor='cxd0d0d0'
		_trt1labl='Switch group'
		_trt1color='cxb30437'
		_trt2labl='No-switch group'
		_trt2color='cx009fc3'
		_barsize=11.5
		_ymin=2
		_ymax=&ymax.
		_title=''
		_footnote='';
	run;

%mend forest;

%forest;








1 ACCEPTED SOLUTION

Accepted Solutions
JeffMeyers
Barite | Level 11

I would use the DRAWLINE statement (see it added to the sidebar below)

sidebar / align=top;
            layout lattice / rows=1 columns=&colcnt columnweights=(&colwghts)
                backgroundcolor=_headercolor opaque=true;


            drawline x1=0 x2=100 y1=0 y2=0  /drawspace=layoutpercent lineattrs=(thickness=1pt color=black pattern=1);



            entry halign=center textattrs=(size=8 weight=bold) "";

            %if &showcol2=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) ""; 
            %end;

            %if &showcol3=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) 
                %if &showpct=N %then %do; 
                    "n/N" %end; %else %do; "n/N (%)" 
                %end;
                ; 
            %end;

            %if &showcol4=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) ""; 
            %end;

            %if &showcol5=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) "&statlabl" ; 
            %end;

        endlayout;
        endsidebar;

SGRender.png

View solution in original post

2 REPLIES 2
JeffMeyers
Barite | Level 11

I would use the DRAWLINE statement (see it added to the sidebar below)

sidebar / align=top;
            layout lattice / rows=1 columns=&colcnt columnweights=(&colwghts)
                backgroundcolor=_headercolor opaque=true;


            drawline x1=0 x2=100 y1=0 y2=0  /drawspace=layoutpercent lineattrs=(thickness=1pt color=black pattern=1);



            entry halign=center textattrs=(size=8 weight=bold) "";

            %if &showcol2=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) ""; 
            %end;

            %if &showcol3=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) 
                %if &showpct=N %then %do; 
                    "n/N" %end; %else %do; "n/N (%)" 
                %end;
                ; 
            %end;

            %if &showcol4=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) ""; 
            %end;

            %if &showcol5=Y %then %do; 
                entry halign=center textattrs=(size=8 weight=bold) "&statlabl" ; 
            %end;

        endlayout;
        endsidebar;

SGRender.png

fanwayne
Fluorite | Level 6
This looks perfect! Thank you so much!

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 2 replies
  • 1470 views
  • 1 like
  • 2 in conversation