data have;
input id $3. mean_arm mean_leg diff_arm diff_leg upper_arm upper_leg lower_arm lower_leg reader_arm reader_leg;
cards;
ABC 878 787 2 1 8 9 -4 -3 872 788
DEF 600 500 7 4 10 11 -8 -7 590 501
GHI 300 200 12 4 11 8 -11 -10 299 202
;
run;
Using a data set like the one above with several body measurements (body part specified in the suffix of the variable name), I made a macro for PROC SGPLOT which plots DIFF_&thissuffix against MEAN_&thissuffix for each body part:
%macro graph(suffixes= );
%let nsuffix=%sysfunc(countw(&suffixes));
%do i= 1 %to &nsuffix;
%let thissuffix=%scan(&suffixes,&i,%str( ));
proc sgplot data=have;
scatter x=mean_&thissuffix y=diff_&thissuffix;
run; quit;
%end;
%mend;
%graph (suffixes= arm leg);
How do I add a REFLINE statement that makes horizontal lines at LOWER_&thissuffix and UPPER_&this.suffix? For a particular body part, the values of LOWER_&thissuffix are the same for all records, as are those for UPPER_&thissuffix.
Hi @bkq32 ,
Could you please provide more information about what does lower_&thissuffix and upper_&thissuffix represent?
I think you should explore the following options in the SCATTER statement of your PROC SGPLOT
proc sgplot data=have;
scatter x=mean_&thissuffix y=diff_&thissuffix / yerrorlower=lower_&thissuffix yerrorupper=upper_&thissuffix;
run; quit;
"yerrorlower" specifies a variable that contains the lower endpoints for the Y error bars
"yerrorupper" specifies a variable that contains the upper endpoints for the Y error bars.
in the same way, you have also xerrorupper and yerrorupper
Best,
Hi @ed_sas_member ,
I'm making a Bland-Altman plot where I compare a reader's values with a gold standard. LOWER_&THISSUFFIX and UPPER_&THISSUFFIX represent the lower/upper limits of agreement between the two, calculated as:
[(mean difference between reader and gold for a body part) - 1.96(standard deviation of the differences for a body part)]
[(mean difference between reader and gold for a body part) + 1.96(standard deviation of the differences for a body part)]
Since LOWER_ARM (as an example) has the same value for all records, I'd like one horizontal line rather than error bars for each of my observations.
@bkq32 wrote:
data have;
input id $3. mean_arm mean_leg diff_arm diff_leg upper_arm upper_leg lower_arm lower_leg reader_arm reader_leg;
cards;
ABC 878 787 2 1 8 9 -4 -3 872 788
DEF 600 500 7 4 10 11 -8 -7 590 501
GHI 300 200 12 4 11 8 -11 -10 299 202
;
run;Using a data set like the one above with several body measurements (body part specified in the suffix of the variable name), I made a macro for PROC SGPLOT which plots DIFF_&thissuffix against MEAN_&thissuffix for each body part:
%macro graph(suffixes= ); %let nsuffix=%sysfunc(countw(&suffixes)); %do i= 1 %to &nsuffix; %let thissuffix=%scan(&suffixes,&i,%str( )); proc sgplot data=have; scatter x=mean_&thissuffix y=diff_&thissuffix; run; quit; %end; %mend; %graph (suffixes= arm leg);
How do I add a REFLINE statement that makes horizontal lines at LOWER_&thissuffix and UPPER_&this.suffix? For a particular body part, the values of LOWER_&thissuffix are the same for all records, as are those for UPPER_&thissuffix.
Somewhere, you have to calculate LOWER_&thissuffix and UPPER_&thissuffix before your run PROC SGPLOT.
In fact, this is a common mistake. First, you have to figure out how to do this calculation and create a working REFLINE statement without using macros, for one plot. You haven't done this. Once you create such a working version of SAS code without macros, then creating a working macro which includes the desired REFLINE statement inside PROC SGPLOT ought to be easy enough.
So, task number 1, create code that does the desired SGPLOT with REFLINEs without macros, for a single instance of the plot.
Thanks, Paige. I did that here and it created the desired plot for ARM.
data have2;
set have;
upper_arm=meandiff_arm+1.96*stddiff_arm;
lower_arm=meandiff_arm-1.96*stddiff_arm;
upper_leg=meandiff_leg+1.96*stddiff_leg;
lower_leg=meandiff_leg-1.96*stddiff_leg;
run;
proc sgplot data=have2;
scatter x=mean_arm y=diff_arm;
refline 0 -7.592 2.992;
needle x=reader_arm
y=diff_arm / baseline=0;
yaxis values=(-8 to 8 by 2);
title "Bland-Altman Plot (arm)";
run; quit;
I'm thinking the next step is to use CALL SYMPUT to store the values of UPPER_: and LOWER_:, and then call it in the REFLINE statement? I'm not too familiar with CALL SYMPUT yet.
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 16. Read more here about why you should contribute and what is in it for you!
SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.
Find more tutorials on the SAS Users YouTube channel.