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

Updated: The following MWE better shows my situation.

data have;
	input id :$16. @@;
	f=compress("https://fred.stlouisfed.org/graph/fredgraph.csv?id="||id);
	infile _ url filevar=f firstobs=2 dsd truncover end=e;
	do until(e);
		input date yymmdd10. +1 value;
		if value>. then output;
	end;
cards;
will5000indfc indpro sp500 unrate dexuseu cpiaucsl gdp dgs10 fedfunds
;

data sganno(drop=v);
	display="fill";
	fillcolor="black";
	filltransparency=0.8;
	x1space="datavalue";
	y1space="wallpercent";
	function="polygon ";
	infile "https://fred.stlouisfed.org/graph/fredgraph.csv?id=usrecm" url firstobs=2 dsd truncover;
	input x1 yymmdd10. +1 v;
	if v then do;
		y1=0;
		output;
		function="polycont";
		y1+100;
		output;
		x1=intnx("month",x1,1);
		output;
		y1+-100;
		output;
	end;
run;

ods html close;
ods results=off;
ods listing gpath="!userprofile\desktop\";
ods graphics/reset;

proc sgplot data=have sganno=sganno;
	by notsorted id;
	series x=date y=value;
	xaxis valuesformat=year4.;
	yaxis valuesformat=best8. type=log;
run;

I cannot simply adjust the SGANNO data set. How can I avoid the overwhelming SGANNO shades automatically?

SGPlot8.pngSGPlot4.pngSGPlot7.pngSGPlot6.pngSGPlot5.pngSGPlot2.pngSGPlot3.pngSGPlot1.pngSGPlot.png

Original: This MWE draws a shaded SGPLOT SERIES.

data data;
do t=1 to 100;
x+rannor(1);
output;
end;
run;

data sganno;
display="fill";
fillcolor="black";
filltransparency=0.8;
x1space="datavalue";
y1space="wallpercent";
do x1=-10 to 90 by 10;
function="polygon ";
y1=0;
output;
function="polycont";
y1=100;
output;
x1+10;
output;
y1=0;
output;
end;
run;

ods html close;
ods results=off;
ods listing gpath="!userprofile\desktop\";
ods graphics/reset imagename="sgplot";

proc sgplot data=data sganno=sganno;
	series x=t y=x;
run;

SGANNO has six uniform shades starting at X1=-10, 10, 30, 50, 70, 90, so SGPLOT locates the first shade outside the box.

sgplot.png

I have manually used PROC SGPLOT DATA=DATA SGANNO=SGANNO(WHERE=(X1>=0)); to avoid this, but this requires too many micromanagements. How can I automatically limit SGANNO not to overwhelm the box?

1 ACCEPTED SOLUTION

Accepted Solutions
JeffMeyers
Barite | Level 11

I think the BLOCK plot will work for what you're trying to do.  I used your value of t to make a modular variable (1 or 0).  I use this to make different blocks in the block plot, then alternate between black and white for the two colors.

sgplot.png

 

data data;
do t=1 to 100;
x+rannor(1);
block=mod(floor(t/10),2);
output;
end;
run;


ods results;
ods graphics/reset imagename="sgplot";

proc sgplot data=data;
block x=t block=block / nooutline filltype=alternate
    fillattrs=(color=white) altfillattrs=(color=black transparency=0.8)
   nolabel novalues;
	series x=t y=x;
run;

View solution in original post

18 REPLIES 18
Reeza
Super User
Is there a particular reason to implement this using SGANNO?

Try using a Band or Polygon statement instead?
Or possibly even the colorbands option on the xaxis/yaxis statement? I feel like those would align better if your data changes..
Junyong
Pyrite | Level 9

No specific reason—I have been using SGANNO just following How to show recessions on your SGplot line graph.

Reeza
Super User
Well, annotation allows you to control your features but that means you lose some of the automatic options. More control means you have to specify the details....I'd suggest switching to a different approach that was more dynamic if you need to do it more than just as a single post.

I've moved the post to the Graphics forum, perhaps one of the SAS graphing guru's may have a better answer for you 🙂
JeffMeyers
Barite | Level 11

I think the BLOCK plot will work for what you're trying to do.  I used your value of t to make a modular variable (1 or 0).  I use this to make different blocks in the block plot, then alternate between black and white for the two colors.

sgplot.png

 

data data;
do t=1 to 100;
x+rannor(1);
block=mod(floor(t/10),2);
output;
end;
run;


ods results;
ods graphics/reset imagename="sgplot";

proc sgplot data=data;
block x=t block=block / nooutline filltype=alternate
    fillattrs=(color=white) altfillattrs=(color=black transparency=0.8)
   nolabel novalues;
	series x=t y=x;
run;
JeffMeyers
Barite | Level 11
@DanH_sas Not to hijack this thread, but is there a reason why there's no Y-axis variant of block plot? I've actually wanted something like that quite a few times.
DanH_sas
SAS Super FREQ

@JeffMeyers , we have not had a lot of call for it. There are workarounds (using Band plots, etc.); but, if you need this support, I would suggest putting in a request with Technical Support so that we can track it.

 

Thanks!

Dan

PGStats
Opal | Level 21

Adding two macro variables could provide some automation:

 

data data;
do t=1 to 100;
x+rannor(1);
output;
end;
run;

proc sql;
select 10*floor(min(t)/10), 10*ceil(max(t)/10) into :t0, :t1
from data;
quit;

data sganno;
display="fill";
fillcolor="black";
filltransparency=0.8;
x1space="datavalue";
y1space="wallpercent";
do x1=&t0 to &t1-10 by 10;
function="polygon ";
y1=0;
output;
function="polycont";
y1=100;
output;
x1+10;
output;
y1=0;
output;
end;
run;

proc sgplot data=data sganno=sganno;
    series x=t y=x;
run;

image.png

PG
Junyong
Pyrite | Level 9

The original code was just an MWE. I know that I can change the SGANNO data set to plot properly but, as described below, wondered if SGPLOT has an automatic solution to avoid the overwhelming shades.

GraphGuy
Meteorite | Level 14

Why are you starting your x1 values for the annotated shaded bars at -10?  

do x1=-10 to 90 by 10;

 Since your x axis starts at 0, then the -10 is going to be outside the axes. If you start at 0 or 10, I think you will get something more of what you're looking for!

Junyong
Pyrite | Level 9

That was just an MWE. My real data are more similar to this.

data have;
	input id :$16. @@;
	f=compress("https://fred.stlouisfed.org/graph/fredgraph.csv?id="||id);
	infile _ url filevar=f firstobs=2 dsd truncover end=e;
	do until(e);
		input date yymmdd10. +1 value;
		if value>. then output;
	end;
cards;
will5000indfc indpro sp500 unrate dexuseu cpiaucsl gdp dgs10 fedfunds
;

data sganno(drop=v);
	display="fill";
	fillcolor="black";
	filltransparency=0.8;
	x1space="datavalue";
	y1space="wallpercent";
	function="polygon ";
	infile "https://fred.stlouisfed.org/graph/fredgraph.csv?id=usrecm" url firstobs=2 dsd truncover;
	input x1 yymmdd10. +1 v;
	if v then do;
		y1=0;
		output;
		function="polycont";
		y1+100;
		output;
		x1=intnx("month",x1,1);
		output;
		y1+-100;
		output;
	end;
run;

ods html close;
ods results=off;
ods listing gpath="!userprofile\desktop\";
ods graphics/reset;

proc sgplot data=have sganno=sganno;
	by notsorted id;
	series x=date y=value;
	xaxis valuesformat=year4.;
	yaxis valuesformat=best8. type=log;
run;

I have multiple time series to plot with one SGANNO data set shared by the time series. That is why I cannot simply adjust X1 for each.

SGPlot.pngSGPlot1.pngSGPlot2.pngSGPlot3.pngSGPlot4.pngSGPlot5.pngSGPlot6.pngSGPlot7.pngSGPlot8.png

Hope this better explains.

JeffMeyers
Barite | Level 11

I'm a bit confused by what you're trying to do.  Do you want the shading to alternate along a specific length of time, or just every 10% of the graph?

If it's by a specific length of time then my solution would work.  If it's by 10% of the graph then you would want to annotate by wall percent instead of by data value on your x-axis.

Junyong
Pyrite | Level 9

I am not randomly shading 10% of each graph. NBER based Recession Indicators for the United States from the Peak through the Trough is a dummy time series that is 1 if the market is in recession.

This monthly series is from December 1854 to September 2020, and I am shading the plots of other multiple time series variables such as Industrial Production: Total Index (from January 1919) and Unemployment Rate (from January 1948) as follows.

The problem is that the time series variables I am plotting start later (for example, January 1919) than the recession series (December 1854) I am shading, and the SGPLOT SGANNO unexpectedly spans the ranges outside the plotting area. I don't want to apply the shades outside the box of the time series plots.

SGPlot3.png

This is the same Unemployment Rate series drawn by SGPLOT. The SGANNO shades 1937, 1938, and 1945 because the market was in recession, but the Unemployment Rate series starts in January 1948, so the two pre-1948 shades are making the outcome ugly.

JeffMeyers
Barite | Level 11

I would then suggest looking at my earlier example using the BLOCK plot.  If you have or can calculate a variable that is equal to 1 whenever you want it shaded and can make it 0 when you don't want it shaded, you can use the BLOCK plot to alternate the shading like in my example.  Then SGPLOT would automatically limit where the shading happens (it won't draw it outside the axes like annotation does).  I don't have your exact data to give a more specific example.

Junyong
Pyrite | Level 9

So the corresponding MWE will be this.

data have;
	n=_n_;
	input id :$16. @@;
	f=compress("https://fred.stlouisfed.org/graph/fredgraph.csv?id="||id);
	infile _ url filevar=f firstobs=2 dsd truncover end=e;
	do until(e);
		input date yymmdd10. +1 value;
		if value>. then output;
	end;
	format date yymmdd10.;
cards;
will5000indfc indpro sp500 unrate dexuseu cpiaucsl gdp dgs10 fedfunds usrecm
;

proc sql;
	create table want(drop=n) as
		select i.*,j.value as usrecm
		from have(where=(id^="usrecm")) i
			left join have(where=(id="usrecm")) j
				on put(i.date,yymm.)=put(j.date,yymm.)
		order by i.n,date;
quit;

ods html close;
ods results=off;
ods listing gpath="!userprofile\desktop\";
ods graphics/reset;

proc sgplot;
	by notsorted id;
	series x=date y=value;
	block x=date block=usrecm/nooutline filltype=alternate fillattrs=(transparency=1) altfillattrs=(color=black transparency=0.8) nolabel;
	xaxis valuesformat=year4. values=("1jan1901"d to "31dec2100"d by year10) valueshint;
	yaxis valuesformat=best8. type=log;
run;

I saw the BLOCK statement for the first time because I have been shading using SGANNO following How to show recessions on your SGplot line graph as aforementioned. It seems this is simpler. But may I ask two more questions?

SGPlot1.png

1. The BLOCK FILLATTRS ALTFILLATTRS results depend on the first value of the dummy variable for BLOCK. For example, the shading outcome is reversed here because the dummy variable value at the starting point of the series is 1 here. How can I correct this?

SGPlot.png

2. I often use multiple shading colors and their orders are not always consistent (for example, white-red-green-red-white-red-green, etc.). Can I use this BLOCK solution for this case too?

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 18 replies
  • 2732 views
  • 15 likes
  • 6 in conversation