- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I want to position some curvelabels at the end of my time-series lines. I'm trying different combinations of CURVELABELLOC and CURVELABELPOS.
For some reason, it keeps on putting the label for the top series on top of the figure. The first figure is with
OUTSIDE and MAX (same results with AUTO). The second is with INSIDE and MAX. (If I drop the top series, I some of the labels on the top and rotated!).
How can I force it to put all labels down the RHS of the figure?
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
You want this ?
* Curvelabel;
data dat;
input date var1 var2;
cards;
1 10 20
2 15 25
3 11 .
4 18 .
;
run;
data dat2;
set dat end=last;
retain retainvar1 retainvar2;
if not missing(var1) then retainvar1=var1;
if not missing(var2) then retainvar2=var2;
if last;
keep date retainvar1 retainvar2;
run;
%sganno
data sganno;
set dat2;
%SGTEXT(LABEL='var1',WIDTH=80, X1SPACE="GRAPHPERCENT",Y1SPACE="DATAVALUE" ,X1=96,Y1=retainvar1,TEXTCOLOR="blue")
%SGTEXT(LABEL='var2',WIDTH=80, X1SPACE="GRAPHPERCENT",Y1SPACE="DATAVALUE" ,X1=96,Y1=retainvar2,TEXTCOLOR="red")
run;
proc sgplot data=dat sganno=sganno ;
series x=date y=var1 /markers markerattrs=(symbol=circlefilled color=blue) lineattrs=(color=blue)
CURVELABELLOC=outside curvelabel curvelabelattrs=(color=white);
series x=date y=var2 /markers markerattrs=(symbol=circlefilled color=red) lineattrs=(color=red)
CURVELABELLOC=outside curvelabel curvelabelattrs=(color=white);
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
So could help to address where is problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
My code has lots of lines, but this simple code shows the problem. My preference would be to have all the labels on the outside at right.
data dat;
input date var1 var2;
cards;
1 10 20
2 10 20
3 10 .
4 10 .
;
run;
Title "Outside puts one series at top (I would prefer all the labels at right)";
proc sgplot;
series x=date y=var1 /curvelabel curvelabelloc=outside;
series x=date y=var2 /curvelabel curvelabelloc=outside;
run;
title "Inside, in this case, works OK";
title2 "Though the top label would be neater if it were to the right";
proc sgplot;
series x=date y=var1 /curvelabel curvelabelloc=inside curvelabelpos=max;
series x=date y=var2 /curvelabel curvelabelloc=inside curvelabelpos=max;
run;
title "However, if the lines are close together, one label gets put at the bottom";
proc sgplot;
series x=date y=var1 /curvelabel curvelabelloc=inside curvelabelpos=max;
series x=date y=var2 /curvelabel curvelabelloc=inside curvelabelpos=max;
yaxis values=(1 to 100);
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Here is a work-around. I create two dummy cases at the end. But this wouldn't work if I had data point markers.
* Curvelabel;
data dat;
input date var1 var2;
cards;
1 10 20
2 15 25
3 11 .
4 18 .
;
run;
data dat2;
retain retainvar1 retainvar2;
drop retainvar1 retainvar2;
set dat end=lastobs;
if not(missing(var1)) then retainvar1 = var1;
if not(missing(var2)) then retainvar2 = var2;
output;
nextdate = lag(date)+1;
nextdate2 = lag(date)+2;
drop nextdate nextdate2;
if lastobs then do;
date = nextdate;
var1 = .;
var2 = .;
output;
date = nextdate2;
var1 = retainvar1;
var2 = retainvar2;
output;
end;
run;
Title "Adding two dummy observations at end works if I don't have data point markers";
proc sgplot data=dat2;
series x=date y=var1 /curvelabel curvelabelloc=outside break;
series x=date y=var2 /curvelabel curvelabelloc=outside break;
run;
title;
proc sgplot data=dat2;
series x=date y=var1 /curvelabel curvelabelloc=inside curvelabelpos=max break;
series x=date y=var2 /curvelabel curvelabelloc=inside curvelabelpos=max break;
run;
proc sgplot data=dat2;
series x=date y=var1 /curvelabel curvelabelloc=inside curvelabelpos=max break;
series x=date y=var2 /curvelabel curvelabelloc=inside curvelabelpos=max break;
yaxis values=(1 to 100);
run;
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Agree this is odd - especially the ones that show up on the bottom when the lines are close together. At least for the ones that place the label on top, I think the algorithm is just trying to put it in the least ambiguous position possible, even if it doesn't look great. It's more obvious when you have a lot of lines, some of which (like in your plot) only extend part way down the x-axis:
You could play around with something like this instead -- labeling with the TEXT statement instead of the CURVELABEL options:
data test;
do grp=1 to 10;
ymean=rand('erlang',2)*5;
nwks=25;
if ranuni(0)<0.4 then nwks=rand('integer',5,25);
x=.; y=.;
do wk=1 to nwks;
yval=ymean+rand('normal')*10;
if wk=nwks then do;
put 'hello?';
x=wk;
y=yval;
end;
output;
end;
end;
run;
proc sgplot data=test noautolegend;
series x=wk y=yval / group=grp;
text x=x y=y text=grp / group=grp textattrs=(size=12pt) position=right backfill backlight;
scatter x=x y=y / group=grp markerattrs=(size=12pt);
run;
Looks a little silly as-is, but if you fiddle with the options, I would bet you can get something good.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Is there a reason you're writing separate SERIES statements instead of writing a single SERIES statement with the GROUP= option?
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
You want this ?
* Curvelabel;
data dat;
input date var1 var2;
cards;
1 10 20
2 15 25
3 11 .
4 18 .
;
run;
data dat2;
set dat end=last;
retain retainvar1 retainvar2;
if not missing(var1) then retainvar1=var1;
if not missing(var2) then retainvar2=var2;
if last;
keep date retainvar1 retainvar2;
run;
%sganno
data sganno;
set dat2;
%SGTEXT(LABEL='var1',WIDTH=80, X1SPACE="GRAPHPERCENT",Y1SPACE="DATAVALUE" ,X1=96,Y1=retainvar1,TEXTCOLOR="blue")
%SGTEXT(LABEL='var2',WIDTH=80, X1SPACE="GRAPHPERCENT",Y1SPACE="DATAVALUE" ,X1=96,Y1=retainvar2,TEXTCOLOR="red")
run;
proc sgplot data=dat sganno=sganno ;
series x=date y=var1 /markers markerattrs=(symbol=circlefilled color=blue) lineattrs=(color=blue)
CURVELABELLOC=outside curvelabel curvelabelattrs=(color=white);
series x=date y=var2 /markers markerattrs=(symbol=circlefilled color=red) lineattrs=(color=red)
CURVELABELLOC=outside curvelabel curvelabelattrs=(color=white);
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thanks everyone for all the suggestions. I'll have to learn how to do annotations. SAS is obviously looking at which axis is closest to the max point for each line and putting the label on that axis. Unfortunately this is often pretty ugly.
One simple enhancement for SAS would be to add an OUTSIDERIGHT choice to the CURVELABELLOC option to allow users to force output to the right hand side.
A very simple work-around (which is actually workable for my graph today) is to change the y axis to have more white space at top and bottom - then the right axis will always be closer.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I maybe END instead of max
data dat; input date var1 var2; cards; 1 10 20 2 15 25 3 11 . 4 18 . ; run; data dat2; retain retainvar1 retainvar2; drop retainvar1 retainvar2; set dat end=lastobs; if not(missing(var1)) then retainvar1 = var1; if not(missing(var2)) then retainvar2 = var2; output; nextdate = lag(date)+1; nextdate2 = lag(date)+2; drop nextdate nextdate2; if lastobs then do; date = nextdate; var1 = .; var2 = .; output; date = nextdate2; var1 = retainvar1; var2 = retainvar2; output; end; run; title "Curvelabelpos=END with outside"; proc sgplot data=dat2; series x=date y=var1 /curvelabel curvelabelloc=outside curvelabelpos=end break; series x=date y=var2 /curvelabel curvelabelloc=outside curvelabelpos=end break; run; title "Curvelabelpos=END with inside"; proc sgplot data=dat2; series x=date y=var1 /curvelabel curvelabelloc=inside curvelabelpos=end break; series x=date y=var2 /curvelabel curvelabelloc=inside curvelabelpos=end break; run; title;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
That looks promising. Can you make the dots disappear?
It might be easier to make them disappear if they were generated by separate statements. That will also make the data manipulation easier.
Like this:
data dat3;
retain retainvar1 retainvar2;
set dat end=lastobs;
if not(missing(var1)) then retainvar1 = var1;
if not(missing(var2)) then retainvar2 = var2;
output;
if lastobs then do;
var1 = .;
var2 = .;
var1e = retainvar1;
var2e = retainvar2;
output;
end;
drop retainvar1 retainvar2;
run;
title "Curvelabelpos=END with outside";
proc sgplot data=dat3;
series x=date y=var1 / ;
series x=date y=var2 / ;
series x=date y=var1e /curvelabel curvelabelloc=outside curvelabelpos=end ;
series x=date y=var2e /curvelabel curvelabelloc=outside curvelabelpos=end ;
run;