Paired bar charts in SAS - sas

I need help creating a single bar chart, that pairs bars together (by two levels of Group), for four time periods. Here's what my table of data look like, sorted by 'Group':
I've figured out how to plot the means for both groups, but only for one time period at a time:
proc sgplot data=Testdata;
vbar Group /
response=Baseline
stat=mean
GROUPDISPLAY = CLUSTER;
run;
Which gets me this:
However, I'd like to "smoosh" these two bars together, so that they're touching, and then add the means, for each level of group, for the other three time periods, all in one plot. I've tried just adding the other time periods to the 'response=' line (both with, and without commas) but that doesn't work.
Please help!
(And I know this is kind of greedy, but it would be great if anyone could tell me how to change the bar color based on Group level)
TIA for any help.

You will want to transpose the data so you have columns id, group, period, result.
The VBAR satement would change from
VBAR GROUP to
VBAR PERIOD
and you can use the VBAR features
group = GROUP
datalabel = result
statlabel
Example:
data have;
call streaminit(123);
do group = 'A' , 'B';
do _n_ = 1 to ifn(group='A',6,11);
id + 1;
baseline = ifn(group='A', 2125, 4400) + rand('integer', 400) - 200;
period1 = ifn(group='A', 2425, 4100) + rand('integer', 600) - 300;
period2 = ifn(group='A', 1800, 3600) + rand('integer', 500) - 250;
period3 = ifn(group='A', 1600, 2800) + rand('integer', 500) - 250;
output;
end;
end;
label
baseline = 'Basline'
period1 = '14 Day Average'
period2 = '30 Day Average'
period3 = '60 Day Average'
;
run;
proc transpose data=have
out=plotdata (
rename=(
_name_ = period
_label_ = period_label
col1 = result
))
;
by id group notsorted;
var baseline period1-period3;
label period = ' ';
label period_label = ' ';
run;
ods html file='plot.html' style=plateau;
proc sgplot data=plotdata;
vbar period_label /
response = result
stat = mean
groupdisplay = cluster
group = group
datalabel = result statlabel
;
xaxis display=(nolabel);
run;
ods html close;
Image

Related

SAS - SGPLOT - adding XAXIS group label

I am looking for an option to add a group label (grouping value of Xaxis). I tried X2AXIS and REFLINE option but none is working exactly. (see attached image for reference - I would like to add G1, G2 and G3 with brackets)
As a starting point, consider
data have;
call streaminit(2021);
do x = 1 to 6;
do _n_ = 1 to 2+ rand('integer', 5);
y = 5 + rand('integer', 10);
group = cats ('G', int((x+1)/2));
output;
end;
end;
run;
ods html file='plot.html';
proc sgplot data=have;
vbox y / group=group category=x;
run;
ods html close;
which produces

Overlaying time series for individuals and mean values in a single graph using SAS SGPLOT

I am comparing the evolution of plasma concentrations over time for different treatments of patients.
We applied each treatment to different subjects and for each treatment we want a graph with the evolution for each subject in black, as well as for the the mean in red.
It should look like this
but it does look like this
My data has variable
trtan and trta for treatment number and name
subjid for the patient receiving that treatment
ATPT for timepoint
AVAL for Individual Concentrations
MEAN for average Concentrations
I am using SGPLOT to produce this line plot. y axis has concentrations while x axis has time points, I am sorting data by treatment, subject and timepoint before passing to Proc SGPLOT.
Lines for indivizual subjects are fine, Issue is with mean line plot, Since dataset is sorted by subject i am getting multiple mean plots by subject as well.
My requirement is to have multiple indivizual plots and an overlaying mean plot. Can anyone advise how can i solve this.
I am using below code. How can I repair it?
proc sort data = pc2;
by trtan trta subjid atptn atpt;
run;
proc sgplot data = pc2 dattrmap = anno pad = (bottom = 20%) NOAUTOLEGEND ;
by trtan trta;
series x = atptn y = aval/ group = trta
lineattrs = (color = black thickness = 1 pattern = solid );
series x = atptn y = mean/ group = trta attrid = trtcolor
lineattrs = (thickness = 2 pattern = solid );
xaxis label= "Actual Time (h)"
labelattrs = (size = 10)
values = (0 12 24 36 48 72 96 120 168)
valueattrs = (size = 10)
grid;
yaxis label= "Plasma Concentration (ng/mL)"
labelattrs = (size = 10)
valueattrs = (size = 10)
grid;
run;
This is not a problem with the mean only.
Leave out the mean, ass min=-20 to your yaxis specification, and you will see the same problem.
Alternatively run this code
data pc2;
do subj = 1 to 3;
do time = 1 to 25;
value = 2*sin(time/3) + rand('Normal');
output;
end;
end;
run;
proc sgplot data=pc2;
series x=time y=value;
run;
and you will get
The solution is to have one plot for each subject, so first sort the data by time and transpose it to have one variable subj_1 etc. for each subject.
proc sort data=pc2 out=SORTED;
by time subj;
run;
proc transpose data=TEST out=TRANS prefix=subj_;
by time;
id subj;
run;
I leave it as an exercise for you to add the mean to this dataset.
Then run sgplot with a series statement per subject. To build these statements, we interrogate the meta data in dataset WORK.TRANS
proc sql;
select distinct 'series x=time y='|| name ||'/lineattrs = (color=black)'
into :series_statements separated by ';'
from sasHelp.vColumn
where libname eq 'WORK' and memName eq 'TRANS'
and (name like 'subj%' or name = mean;
quit;
proc sgplot data=TRANS;
&series_statements;
run;
The result, without the mean, looks like this for my example:
Of course, you will have to do some graphical fine tuning.
We can achive it simply by taking the mean by ATPT and then instead of merging the mean record to the PK data by ATPT, you need to append the records and then you can run your code and it will give you the result you are expecting, please let me know if it does not work, it seems to have worked for me.

how to vertically sum a range of dynamic variables in sas?

I have a dataset in SAS in which the months would be dynamically updated each month. I need to calculate the sum vertically each month and paste the sum below, as shown in the image.
Proc means/ proc summary and proc print are not doing the trick for me.
I was given the following code before:
`%let month = month name;
%put &month.;
data new_totals;
set Final_&month. end=end;
&month._sum + &month._final;
/*feb_sum + &month._final;*/
output;
if end then do;
measure = 'Total';
&month._final = &month._sum;
/*Feb_final = feb_sum;*/
output;
end;
drop &month._sum;
run; `
The problem is this has all the months hardcoded, which i don't want. I am not too familiar with loops or arrays, so need a solution for this, please.
enter image description here
It may be better to use a reporting procedure such as PRINT or REPORT to produce the desired output.
data have;
length group $20;
do group = 'A', 'B', 'C';
array month_totals jan2020 jan2019 feb2020 feb2019 mar2019 apr2019 may2019 jun2019 jul2019 aug2019 sep2019 oct2019 oct2019 nov2019 dec2019;
do over month_totals;
month_totals = 10 + floor(rand('uniform', 60));
end;
output;
end;
run;
ods excel file='data_with_total_row.xlsx';
proc print noobs data=have;
var group ;
sum jan2020--dec2019;
run;
proc report data=have;
columns group jan2020--dec2019;
define group / width=20;
rbreak after / summarize;
compute after;
group = 'Total';
endcomp;
run;
ods excel close;
Data structure
The data sets you are working with are 'difficult' because the date aspect of the data is actually in the metadata, i.e. the column name. An even better approach, in SAS, is too have a categorical data with columns
group (categorical role)
month (categorical role)
total (continuous role)
Such data can be easily filtered with a where clause, and reporting procedures such as REPORT and TABULATE can use the month variable in a class statement.
Example:
data have;
length group $20;
do group = 'A', 'B', 'C';
do _n_ = 0 by 1 until (month >= '01feb2020'd);
month = intnx('month', '01jan2018'd, _n_);
total = 10 + floor(rand('uniform', 60));
output;
end;
end;
format month monyy5.;
run;
proc tabulate data=have;
class group month;
var total;
table
group all='Total'
,
month='' * total='' * sum=''*f=comma9.
;
where intck('month', month, '01feb2020'd) between 0 and 13;
run;
proc report data=have;
column group (month,total);
define group / group;
define month / '' across order=data ;
define total / '' ;
where intck('month', month, '01feb2020'd) between 0 and 13;
run;
Here is a basic way. Borrowed sample data from Richard.
data have;
length group $20;
do group = 'A', 'B';
array months jan2020 jan2019 feb2020 feb2019 mar2019 apr2019 may2019 jun2019 jul2019 aug2019 sep2019 oct2019 oct2019 nov2019 dec2019;
do over months;
months = 10 + floor(rand('uniform', 60, 1));
end;
output;
end;
run;
proc summary data=have;
var _numeric_;
output out=temp(drop=_:) sum=;
run;
data want;
set have temp (in=t);
if t then group='Total';
run;

Proc Format for traffic lighting not working

I am attempting to create traffic lighting in a report using proc format. But even though the values can be greater than 1 or below 1 the colors are always the lowest color. In this case, they are all red. Why is SAS not seeing the values?
proc format;
value forecast
low - < 0.70 = 'red'
0.70 - <0.90 = 'yellow'
0.90 - high = 'green';
run;
%macro perform_target (cc, year, career_id, cc_name) ;
data Performance_&career_id._&cc._&year. ;
set post_target_comparisons1;
where institution = "&cc." and year = "&year." and career_id = "&career_id.";
run;
ods excel file = "Y:\General - CTE\2019 CTE Accountability\2020\Need Assessment Performance
Tables\Performance_&career_id._&cc._&year..xlsx" style = sasdocprinter;
ods excel options(autofilter="2-39" sheet_name = "Performance &year." embedded_titles = 'yes');
run;
title j= C "Actual to Target Comparisons";
title2 j = C "Academic Year - &year.";
run;
proc report data = Performance_&career_id._&cc._&year.;
column community_college cluster_label measure_label year total_students total_male percent_male
target forecast_male forecast_female forecast_AI forecast_AS forecast_AA forecast_HI forecast_PI
forecast_W forecast_MU forecast_disabled forecast_farms forecast_single forecast_displaced
forecast_ell forecast_nontrad;
define forecast_male/display 'Percent to Forecast Male' style(column) = [cellwidth=1in
tagattr="format:####.##\%" fontweight = bold foreground = forecast.];
run;
ods excel close;
%mend perform_target;
%perform_target (010042, 2016, 01);
This works so I expect your data is the issue.
proc format;
value forecast
low - < 0.70 = 'red'
0.70 - <0.90 = 'yellow'
0.90 - high = 'green';
run;
data have;
do x = 0 to 1 by .05;
output;
end;
run;
ods excel file='test.xlsx';
proc report data=have list;
columns x;
define x / display /*format=percent12.2*/ style(column)=[cellwidth=1in tagattr="format:####.##\%" fontweight = bold foreground = forecast.];
run;
ods excel close;

Bar chart with 2 variable on x axis and 1 in Y axis

I want to create a bar chart on yearly death count (based on gender). I want to plot gender and year on x axis and count on Y axis. Can you kindly help how to modify the below code?
TITLE 'DEATH GRAPH BY GENDER';
PROC SGPLOT DATA = DREPORT;
VBAR deathcount / GROUP = gender GROUPDISPLAY = CLUSTER;
RUN;
I am not able to put deathyear in the Y axis. Kindly frame the code.
The VBAR variable is the mid-point values to show on the horizontal axis.
Are you sure that is what you want ?
Do you really want to know how many times a give death count occurred over all the years ?
You probably want deathcount as the response
Consider this example:
data have_raw;
do id = 1 to 1000;
gender = substr('MF',1 + 2 * ranuni(123),1);
year = 2019 - floor (30 * ranuni(123));
output;
end;
run;
proc sql;
create table have as
select year, gender, count(*) as deathcount
from have_raw
group by year, gender
;
proc sgplot data=have;
vbar gender
/ response=deathcount
group=year
groupdisplay=cluster
;
run;