/* SAS program to accompany the blog post "Label multiple regression lines in SAS" https://blogs.sas.com/content/iml/2018/01/08/label-regression-lines-sas.html by Rick Wicklin, published 08JAN2018 Purpose: Show how to label regression curves that are produced by the REG statement with the GROUP= option in PROC SGPLOT in SAS. */ /* Motivation: The following attempt to label the curves does not work: proc sgplot data=sashelp.iris noautolegend; reg x=SepalLength y=PetalLength / group=Species CURVELABEL; run; WARNING: CURVELABEL not supported for fit plots when a group variable is used. The option will be ignored. */ /***************************************** Method 1: Label the regression line for each group: The LINEPARM statement ****************************************/ proc sort data=sashelp.iris out=iris; by Species; run; /* compute parameter estimates */ proc reg data=iris outest=PE noprint; by Species; model PetalLength = SepalLength; run; /* construct labels from the parameter estimates */ data Labels; length Label $30; set PE(rename=(SepalLength=Slope)); /* independent variable */ Label = catx(" ", put(Intercept, BestD5.), '+', /* separate by blank */ put(Slope, BestD5.), '* SepalLength'); keep Label Species Intercept Slope; run; proc print noobs; run; data Plot; set iris Labels; run; title "Regression Lines Labeled with Slope and Intercept"; proc sgplot data=Plot; scatter x=SepalLength y=PetalLength / group=Species; lineparm x=0 y=Intercept slope=Slope / group=Label curvelabel curvelabelloc=outside clip; run; /***************************************** Method 2: Label the regression line for each group: The TEXT statement ****************************************/ /* Use ODS output to find data coordinates of end of lines */ proc sgplot data=iris; ods output SGPLOT= RegPlot; reg x=SepalLength y=PetalLength / group=Species; run; proc contents short varnum; run; /* find names used by graph */ data Coords; set RegPlot( rename=(REGRESSION_SEPALLENGTH_PETAL___X = x REGRESSION_SEPALLENGTH_PETAL___Y = y REGRESSION_SEPALLENGTH_PETAL__GP = Group) where=(x ^=.)); by Group; if last.Group; keep x y Group; run; proc print noobs; run; /* combine the positions and labels with original data */ data A; merge Labels Coords(rename=(Group=Species)); by Species; run; data Plot; set iris A; /* optional: pad label with blanks on the left (if length is long enough) */ Label = " " || Label; run; proc sgplot data=Plot; reg x=SepalLength y=PetalLength / group=Species; text x=x y=y text=Label / position=right; run; proc sgplot data=Plot; reg x=SepalLength y=PetalLength / group=Species; text x=x y=y text=Label / position=right; run; /***************************************** Method 2 actually works for nonlinear curves, such as produced by the PBSPLINE statement ****************************************/ /* use ODS OUTPUT to find data coordinates of end of lines */ proc sgplot data=iris noautolegend; ods output SGPLOT= RegPlot; pbspline x=SepalLength y=PetalLength / group=Species; run; proc contents short varnum; run; data Coords; set RegPlot( rename=(PBSPLINE_SEPALLENGTH_PETALLE___X = x PBSPLINE_SEPALLENGTH_PETALLE___Y = y PBSPLINE_SEPALLENGTH_PETALLE__GP = Group) where=(x ^=.)); by Group; if last.Group; Label = " " || Group; /* no equation for sline; use group as label */ keep x y Group Label; run; data Plot; set iris Coords(rename=(Group=Species)); run; title "Penalized B-Splines Labeled with Species"; proc sgplot data=Plot noautolegend; pbspline x=SepalLength y=PetalLength / group=Species; text x=x y=y text=Label / position=right; run;