Dear all,
I have this code and I wish to shade the backgroud of plot indicating the normal and critical areas.
data have;
infile datalines;
input type $10. num_pat num_centers 3.;
datalines;
liver 8 6
stomach 4 6
breast 20 10
ovary 15 8
kidney 18 10
leucemia 16 2
intestine 4 2
CNS 5 1
lung 14 7
uterus 16 8
;
run;
data have;
set have;
r_value=num_pat/num_centers;
if r_value < 2 then grup="critical";else grup="normal";
if grup="normal" then high=.; else if grup="critical" then high=1.99;
label r_value= R-Values;
run;
proc sort data=have;
by descending r_value;
run;
proc sgplot data=have noautolegend ;
styleattrs datacolors=('CX5F9EA0' 'CX00FFFF' ) datacontrastcolors=('CX5F9EA0' 'CX00FFFF' );
label;
vbar type /response= num_centers missing baselineattrs=(thickness=0) legendlabel='Number of treatment centers' name='a';
vbar type /response= num_pat missing baselineattrs=(thickness=0) barwidth=0.5 legendlabel='Number of patients' name='b';
xaxis type=discrete discreteorder=data display=(nolabel) valueattrs=(size=6pt family=arial);
yaxis display=(nolabel) valueattrs=(size=7pt family=arial) grid;
y2axis labelattrs=(size=8pt family=arial color=dimgray) valueattrs=(size=7pt family=arial);
vline type / response=r_value y2axis lineattrs=(color=gold pattern=solid thickness=2) nostatlabel legendlabel='R-values' name='c';
keylegend 'a' 'b' 'c' / location=outside position=bottom across=0 title="" valueattrs=(size=7pt family=arial) outerpad=(top=0.2cm) noborder;
run;
something like this:
how do I do that?
Hello @Anita_n,
You could add the WALLCOLOR= option to your STYLEATTRS statement to define the color of the "normal" area and add one or two VBAR statements to draw the "critical" area (using a constant variable).
data want; set have; critlimit=2; label critlimit='R-Values'; run; proc sgplot data=want noautolegend ; styleattrs datacolors=('CX5F9EA0' 'CX00FFFF') datacontrastcolors=('CX5F9EA0' 'CX00FFFF') wallcolor=lightgrey; label; vbar type /response= critlimit nooutline barwidth=1 fillattrs=(color=lightpink) y2axis discreteoffset=-0.1; vbar type /response= critlimit nooutline barwidth=1 fillattrs=(color=lightpink) y2axis discreteoffset= 0.1; vbar type /response= num_centers fillattrs=(color='CX5F9EA0') missing baselineattrs=(thickness=0) legendlabel='Number of treatment centers' name='a'; vbar type /response= num_pat fillattrs=(color='CX00FFFF') missing baselineattrs=(thickness=0) barwidth=0.5 legendlabel='Number of patients' name='b'; xaxis type=discrete discreteorder=data display=(nolabel) valueattrs=(size=6pt family=arial); yaxis display=(nolabel) valueattrs=(size=7pt family=arial) grid offsetmin=0; y2axis labelattrs=(size=8pt family=arial color=dimgray) valueattrs=(size=7pt family=arial) min=0.66667; vline type / response=r_value y2axis lineattrs=(color=gold pattern=solid thickness=2) nostatlabel legendlabel='R-values' name='c'; keylegend 'a' 'b' 'c' / location=outside position=bottom across=0 title="" valueattrs=(size=7pt family=arial) outerpad=(top=0.2cm) noborder; run;
(I had to add the FILLATTRS= and MIN= options to existing statements because of interactions with the new VBAR statements. The OFFSETMIN=0 option avoids a margin of background color below the bars.)
Define "critical area" for your plot, which is two overlayed VBAR plots and has nothing in common with the "example" picture.
An axis for a continuous variable can be defined with ranges in data and overlay any of a number of things. But your xaxis for VBAR is categorical and so you are going to have some fun defining a range of the xaxis values.
Hello @Anita_n,
You could add the WALLCOLOR= option to your STYLEATTRS statement to define the color of the "normal" area and add one or two VBAR statements to draw the "critical" area (using a constant variable).
data want; set have; critlimit=2; label critlimit='R-Values'; run; proc sgplot data=want noautolegend ; styleattrs datacolors=('CX5F9EA0' 'CX00FFFF') datacontrastcolors=('CX5F9EA0' 'CX00FFFF') wallcolor=lightgrey; label; vbar type /response= critlimit nooutline barwidth=1 fillattrs=(color=lightpink) y2axis discreteoffset=-0.1; vbar type /response= critlimit nooutline barwidth=1 fillattrs=(color=lightpink) y2axis discreteoffset= 0.1; vbar type /response= num_centers fillattrs=(color='CX5F9EA0') missing baselineattrs=(thickness=0) legendlabel='Number of treatment centers' name='a'; vbar type /response= num_pat fillattrs=(color='CX00FFFF') missing baselineattrs=(thickness=0) barwidth=0.5 legendlabel='Number of patients' name='b'; xaxis type=discrete discreteorder=data display=(nolabel) valueattrs=(size=6pt family=arial); yaxis display=(nolabel) valueattrs=(size=7pt family=arial) grid offsetmin=0; y2axis labelattrs=(size=8pt family=arial color=dimgray) valueattrs=(size=7pt family=arial) min=0.66667; vline type / response=r_value y2axis lineattrs=(color=gold pattern=solid thickness=2) nostatlabel legendlabel='R-values' name='c'; keylegend 'a' 'b' 'c' / location=outside position=bottom across=0 title="" valueattrs=(size=7pt family=arial) outerpad=(top=0.2cm) noborder; run;
(I had to add the FILLATTRS= and MIN= options to existing statements because of interactions with the new VBAR statements. The OFFSETMIN=0 option avoids a margin of background color below the bars.)
Thanks to you all for your suggestions
@FreelanceReinh : I adjusted your code this way:
data want;
set have;
if high ^=. then critlimit=35;
run;
proc sgplot data=want noautolegend ;
styleattrs datacolors=('CX5F9EA0' 'CX00FFFF') datacontrastcolors=('CX5F9EA0' 'CX00FFFF') wallcolor=dimgrey;
label;
vbar type /response= critlimit nooutline barwidth=1 fillattrs=(color=lightpink) y2axis discreteoffset=-0.1;
vbar type /response= critlimit nooutline barwidth=1 fillattrs=(color=lightpink) y2axis discreteoffset= 0.1;
vbar type /response= num_centers fillattrs=(color='CX5F9EA0') missing baselineattrs=(thickness=0) legendlabel='Number of treatment centers' name='a';
vbar type /response= num_pat fillattrs=(color='CX00FFFF') missing baselineattrs=(thickness=0) barwidth=0.5 legendlabel='Number of patients' name='b';
xaxis type=discrete discreteorder=data display=(nolabel) valueattrs=(size=6pt family=arial);
yaxis display=(nolabel) valueattrs=(size=7pt family=arial) grid offsetmin=0;
y2axis labelattrs=(size=8pt family=arial color=dimgray) valueattrs=(size=7pt family=arial) min=0.66667;
vline type / response=r_value y2axis lineattrs=(color=gold pattern=solid thickness=2) nostatlabel legendlabel='R-values' name='c';
inset "critical areas" / position=NE textattrs=(color=red family=arial size=7pt weight=bold);
inset "normal areas" / position=NW textattrs=(color=black family=arial size=7pt weight=bold);
keylegend 'a' 'b' 'c' / location=outside position=bottom across=0 title="" valueattrs=(size=7pt family=arial) outerpad=(top=0.2cm) noborder;
run;
I don't know if it make sense to do it this way but it seems to produce what I want
@Anita_n wrote:I don't know if it make sense to do it this way but it seems to produce what I want
Great that it produces what you want. (But did you notice the change of the y2-axis label?)
My interpretation of
if r_value < 2 then grup="critical";else grup="normal";
was that the "critical" area was a horizontal stripe (unlike in the picture you posted) with upper limit r_value=2. If I had realized that it was really meant to be vertical, I would have suggested a BLOCK statement (as DanH_sas did) because I produced those block plots in the past.
@FreelanceReinh yes , you right. that is the right defination for the critical and normal areas but I want the background to start from 0 to the maximum y2axis value (that is why I am asking if there is a better way to do that). I will can also try @DanH_sas suggestion but at the moment your code worked for me, thanks.
In this case, you might want to use a SERIES plot instead of a VLINE, unless you need the data summarized. For the background, you just need BLOCK plot. Here is a simple example:
data air;
set sashelp.air;
if (date <= '01jan1958'd) then period="earlier";
else period="later";
run;
proc sgplot data=air;
block x=date block=period / filltype=alternate;
series x=date y=air;
run;
Sorry, I just realized that your code also has VBARs in it. What I would do is use PROC SUMMARY or PROC MEANS to summarize the data. Then, use VBARPARMs and a SERIES instead so that I can put a BLOCK plot behind it, like in the example in my previous post.
For an example of this kind of block plot, see
https://blogs.sas.com/content/iml/2016/11/21/forecast-regions.html
@DanH_sas the Vbarparm statement in combination with series and block statement is a very efficient way of solving this problem. I like that😊. Thankyou all for the help
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 25. Read more here about why you should contribute and what is in it for you!
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.