I am trying to generate the ODS pdf file after running the proc report syntex.
ods pdf file = "D:\New folder (2)\Assignment\Case_Study_1\Summary.pdf";
proc report data = Cs1.olympics headline;
column Probability Stage (n) Total_Media_Value Tot_Forecast;
where Probability > 0;
define Probability/group Descending 'Probability';
define Stage/group noprint;
define n / format = comma6. 'Nbr_of_Optys';
define Total_Media_Value/analysis format = dollar25. 'Tot_Budget';
define Tot_Forecast/computed format = dollar25.;
compute Tot_Forecast;
if upcase (_BREAK_) = ' ' then do;
Tot_Forecast = (Total_Media_Value.sum*Probability)/100;
Tot_Forecast_Summer=sum(Tot_Forecast_Summer,Tot_Forecast);
end;
else do;
Tot_Forecast=Tot_Forecast_Summer;
end;
endcomp;
rbreak after / summarize ol ul;
run;
ods pdf close;
I am not able to generate the pdf. Can you please help me out.
Thanks is advance.
Related
I have two datasets, one extract the extreme values from proc univariate. I would like to create a new variable and label them as 1 if the n in the original dataset equals the extracted line number in the univariate dataset. But I don't know how to program it not manually enter the line number.
There're a few ways to do this, but one easy way is to just add the rownum to the original dataset and merge on it.
Here's an example.
ods output extremeobs=extreme_test;
proc univariate data=sashelp.heart;
run;
ods output close;
data extreme_diastolic extreme_systolic; *just creating the extreme datasets;
set extreme_test;
if varname='Diastolic' then output extreme_diastolic;
else if varname='Systolic' then output extreme_systolic;
run;
data for_merge; *adding rownum on to the original dataset;
set sashelp.heart;
rownum = _n_;
run;
*now, sort the extreme datasets by the `highobs` and `lowobs` values respectively and save those as `rownum`, so they can be merged;
proc sort data=extreme_diastolic out=high_diastolic(keep=highobs rename=highobs=rownum);
by highobs;
run;
proc sort data=extreme_systolic out=high_systolic(keep=highobs rename=highobs=rownum);
by highobs;
run;
proc sort data=extreme_diastolic out=low_diastolic(keep=lowobs rename=lowobs=rownum);
by lowobs;
run;
proc sort data=extreme_systolic out=low_systolic(keep=lowobs rename=lowobs=rownum);
by lowobs;
run;
*now, merge those on using `in=` to identify which are matches.;
data heart_extremes;
merge for_merge high_diastolic(in=_highd) high_systolic(in=_highs) low_diastolic(in=_lowd) low_systolic(in=_lows);
by rownum;
if _highd then high_diastolic = 1;
if _highs then high_systolic = 1;
if _lowd then low_diastolic = 1;
if _lows then low_systolic = 1;
run;
I'm using tagsets.excelxp in SAS to output dozens of two-way tables to an .xml file. Is there syntax that will suppress rows (frequencies and percents) if the frequency in that row is less than 10? I need to apply that in order to de-identify the results, and it would be ideal if I could automate the process rather than use conditional formatting in each of the outputted tables. Below is the syntax I'm using to create the tables.
ETA: I need those suppressed values to be included in the computation of column frequencies and percents, but I need them to be invisible in the final table (examples of options I have considered: gray out the entire row, turn the font white so it doesn't show for those cells, replace those values with an asterisk).
Any suggestions would be greatly appreciated!!!
Thanks!
dr j
%include 'C:\Users\Me\Documents\excltags.tpl';
ods tagsets.excelxp file = "C:\Users\Me\Documents\Participation_rdg_LSS_3-8.xml"
style = MonoChromePrinter
options(
convert_percentages = 'yes'
embedded_titles = 'yes'
);
title1 'Participation';
title2 'LSS-Level';
title3 'Grades 3-8';
title4 'Reading';
ods noproctitle;
proc sort data = part_rdg_3to8;
by flag_accomm flag_participation lss_nm;
run;
proc freq data = part_rdg_3to8;
by flag_accomm flag_participation;
tables lss_nm*grade_p / crosslist nopercent;
run;
ods tagsets.excelxp close;
D.Jay: Proc FREQ does not contain any options for conditionally masking cells of it's output. You can leverage the output data capture capability of the ODS system with a follow-up Proc REPORT to produce the desired masked output.
I am guessing on the roles of the lss and grade_p as to be a skill level and a student grade level respectively.
Generate some sample data
data have;
do student_id = 1 to 10000;
flag1 = ranuni(123) < 0.4;
flag2 = ranuni(123) < 0.6;
lss = byte(65+int(26*ranuni(123)));
grade = int(6*ranuni(123));
* at every third lss force data to have a low percent of grades < 3;
if mod(rank(lss),3)=0 then
do until (grade > 2 or _n_ < 0.15);
grade = int(6*ranuni(123));
_n_ = ranuni(123);
end;
else if mod(rank(lss),7)=0 then
do until (grade < 3 or _n_ < 0.15);
grade = int(6*ranuni(123));
_n_ = ranuni(123);
end;
output;
end;
run;
proc sort data=have;
by flag1 flag2;
*where lss in ('A' 'B') and flag1 and flag2; * remove comment to limit amount of output during 'learning the code' phase;
run;
Perform the Proc FREQ
Only capture the data corresponding to the output that would have been generated
ods _all_ close;
* ods trace on;
/* trace will log the Output names
* that a procedure creates, and thus can be captured
*/
ods output CrossList=crosslist;
proc freq data=have;
by flag1 flag2;
tables lss * grade / crosslist nopercent;
run;
ods output close;
ods trace off;
Now generate output to your target ODS destination (be it ExcelXP, html, pdf, etc)
Reference output of which needs to be produced an equivalent having masked values.
* regular output of FREQ, to be compare to masked output
* of some information via REPORT;
proc freq data=have;
by flag1 flag2;
tables lss * grade / crosslist nopercent;
run;
Proc REPORT has great features for producing conditional output. The compute block is used to select either a value or a masked value indicator for output.
options missing = ' ';
proc format;
value $lss_report ' '= 'A0'x'Total';
value grade_report . = 'Total';
value blankfrq .b = '*masked*' ._=' ' other=[best8.];
value blankpct .b = '*masked*' ._=' ' other=[6.2];
proc report data=CrossList;
by flag1 flag2;
columns
('Table of lss by grade'
lss grade
Frequency RowPercent ColPercent
FreqMask RowPMask ColPMask
)
;
define lss / order order=formatted format=$lss_report. missing;
define grade / display format=grade_report.;
define Frequency / display noprint;
define RowPercent / display noprint;
define ColPercent / display noprint;
define FreqMask / computed format=blankfrq. 'Frequency' ;
define RowPMask / computed format=blankpct. 'Row/Percent';
define ColPMask / computed format=blankpct. 'Column/Percent';
compute FreqMask;
if 0 <= RowPercent < 10
then FreqMask = .b;
else FreqMask = Frequency;
endcomp;
compute RowPMask;
if 0 <= RowPercent < 10
then RowPMask = .b;
else RowPMask = RowPercent;
endcomp;
compute ColPMask;
if 0 <= RowPercent < 10
then ColPMask = .b;
else ColPMask = ColPercent;
endcomp;
run;
ods html close;
If you have to produce lots of cross listings for different data sets, the code is easily macro-ized.
When I've done this in the past, I've first generated the frequency to a dataset, then filtered out the N, then re-printed the dataset (using tabulate usually).
If you can't recreate the frequency table perfectly from the freq output, you can do a simple frequency, check which IDs or variables or what have you to exclude, and then filter them out from the input dataset and rerun the whole frequency.
I don't believe that you can with PROC FREQ, but you can easily replicate your code with PROC TABULATE and you can use a custom format there to mask the numbers. This example sets it to M for missing and N for less than 5 and with one decimal place for the rest of the values. You could also replace the M/N with a space (single space) to have no values shown instead.
*Create a format to mask values less than 5;
proc format;
value mask_fmt
. = 'M' /*missing*/
low - < 5='N' /*less than 5 */
other = [8.1]; /*remaining values with one decimal place*/
run;
*sort data for demo;
proc sort data=sashelp.cars out=cars;
by origin;
run;
ods tagsets.excelxp file='/folders/myfolders/demo.xml';
*values partially masked;
proc tabulate data=cars;
where origin='Asia';
by origin;
class make cylinders;
table make, cylinders*n*f=mask_fmt. ;
run;
ods tagsets.excelxp close;
This was tested on SAS UE.
EDIT: Forgot the percentage piece, so this likely will not work for that, primarily because I don't think you'll get the percentages the same as in PROC FREQ (appearance) so it depends on how important that is to you. The other possibility to accomplish this would be to modify the PROC FREQ template to use the custom format as above. Unfortunately I do not have time to mock this up for you but maybe someone else can. I'll leave this here to help get you started and delete it later on.
How can I make the outcome of this code to print into html using proc print? This is because I have to integrate the code inside an existing code that uses only proc print. Thanks in advance.
filename cmd pipe "dir G:\ | findstr /c:""bytes free""";
data _null_;
infile cmd;
input;
free_space_gb = input(scan(_infile_,3,' '), comma20.) * 2**-30;
put "There is currently " free_space_gb 8.2 "GB of free space on the G
drive";
call symput('free_space_gb',free_space_gb); /*Create macro variable*/
run;
%macro print_alert_html;
%if &free_space_gb < 1 %then %do;
ods listing close;
ods html file = "%sysfunc(pathname(work))\report.html";
ods html text = "Alert: only &free_space_gb GB of space left on the G
drive!";
ods html close;
ods listing;
%end;
%mend;
If you need to use Proc PRINT then the Gb information needs to be kept in a data set. You might want to use Proc REPORT when outputting a status message because it has a NOHEADER option.
The REPORT where clause will cause output only when the Gb is < 1.
filename cmd pipe "dir G:\ | findstr /c:""bytes free""";
data message;
infile cmd;
input;
free_space_gb = input(scan(_infile_,3,' '), comma20.) * 2**-30;
message = "There is currently " || strip(put(free_space_gb, 8.2)) || "GB of free space on the G drive";
run;
%macro print_alert_html;
ods listing close;
ods html file = "%sysfunc(pathname(work))\report.html";
title;
footnote;
options nocenter nodate nonumber;
proc report data=message noheader;
column message;
where free_space_gb < 1.00;
run;
ods html close;
ods listing;
%mend;
%print_alert_html;
I would like to to have my footnote just under the bottom of my table and perfectly left aligned with the left hand side data of the table. Can someone help me to achieve that ?
Currently
___________bottom line of table___________
Note: Is my footnote just under the line and aligned ?
But would like this :
______________bottom line of table here________
Note: Is my footnote just under the line and aligned ?
Here is the code :
data test;
input alpha $1-16 beta $18-41;
cards;
abc+def+ghi+jkl (zmc*[100]/1000-200)+23)
cab+ddd+ggg+jjj (zab*[100]/1000-200)+21)
;
run;
%let path=C:\;
ODS LISTING CLOSE;
ODS RTF PATH="&path." FILE='test.rtf '
BODYTITLE;
ODS TRACE ON;
ODS ESCAPECHAR='^';
ODS PATH SHOW;
proc report data=TEST nowd
style(report)=[background=white fontstyle=roman fontsize=2.5 fontweight=medium width=85% fontfamily='courier new']
style(header)=[background=white foreground=blue fontstyle=roman fontsize=2.5 fontweight=medium just=left fontfamily='courier new']
style(column)=[background=white fontstyle=roman fontsize=2.5 fontweight=medium fontfamily='courier new' ]
;
title "^S={ fontstyle=roman fontsize=2.5 fontweight=medium fontfamily='courier new'} testsing my footnote";
footnote"^S={fontstyle=roman just=l fontfamily='courier new'fontsize=2.5 fontweight=medium } Note: Is my footnote just under the line and aligned ?";
column alpha beta;
define alpha/order ;
define beta/order;
compute before;
line #1 '';
endcomp;
run;
ODS RTF CLOSE;
ODS LISTING;
Not a great solution, but replace just=l with j=l outside of the escapes, then add some spaces to align it to the table.
footnote j=l "^S={fontstyle=roman just=l fontfamily='courier new'fontsize=2.5 fontweight=medium } Note: Is my footnote just under the line and aligned ?";
Otherwise to get it perfectly aligned underneath the table and by default and left aligned use a spanned row as part of your proc report, see the example below.
options nodate nonumber;
title 'Notes After Every Table';
ods rtf file='c:\temp\tablenote.rtf' startpage=no;
ods escapechar='^';
proc report data=sashelp.class nowd;
column sex height,(Min Mean Max N);
define sex / group 'Sex ^{super 1}';
define height /analysis 'Height';
compute after / style={just=l};
line '^{super 1} Age span for students 11-16 years';
endcomp;
run;
proc report data=sashelp.class nowd;
column sex weight,(Min Mean Max N);
define sex / group 'Sex ^{super 2}';
define weight /analysis 'Weight';
compute after / style={just=l};
line '^{super 2} Note there are more boys than girls';
endcomp;
run;
ods _all_ close;
Courtesy of Cynthia Zender#SAS: https://communities.sas.com/message/231503#231503
If you want everything justified left, you could just use options nocenter;.
If you just want the report left justified, you could just use the nocenter option in the proc report statement.
Ok I see...When I use this template procedure It doesn't work :
proc template;
define style styles.testme;
parent=styles.rtf;
replace color_list/
'bgH'=white;
replace body from document / bottommargin = .2in
topmargin = .2in
rightmargin = .2in
leftmargin = .2in;
replace table from output / outputwidth = 50%
frame = hsides
rules = groups
cellpadding = 1.0pt
cellspacing = 0.1pt
borderwidth = 1.0pt;
end;
run;
I'm a beginner in SAS and I have the following problem.
I need to calculate counts and percents of several variables (A B C) from one dataset and save the results to another dataset.
my code is:
proc freq data=mydata;
tables A B C / out=data_out ; run;
the result of the procedure for each variable appears in the SAS output window, but data_out contains the results only for the last variable. How to save them all in data_out?
Any help is appreciated.
ODS OUTPUT is your answer. You can't output directly using the OUT=, but you can output them like so:
ods output OneWayFreqs=freqs;
proc freq data=sashelp.class;
tables age height weight;
run;
ods output close;
OneWayFreqs is the one-way tables, (n>1)-way tables are CrossTabFreqs:
ods output CrossTabFreqs=freqs;
ods trace on;
proc freq data=sashelp.class;
tables age*height*weight;
run;
ods output close;
You can find out the correct name by running ods trace on; and then running your initial proc whatever (to the screen); it will tell you the names of the output in the log. (ods trace off; when you get tired of seeing it.)
Lots of good basic sas stuff to learn here
1) Run three proc freq statements (one for each variable a b c) with a different output dataset name so the datasets are not over written.
2) use a rename option on the out = statement to change the count and percent variables for when you combine the datasets
3) sort by category and merge all datasets together
(I'm assuming there are values that appear in in multiple variables, if not you could just stack the data sets)
data mydata;
input a $ b $ c$;
datalines;
r r g
g r b
b b r
r r r
g g b
b r r
;
run;
proc freq noprint data = mydata;
tables a / out = data_a
(rename = (a = category count = count_a percent = percent_a));
run;
proc freq noprint data = mydata;
tables b / out = data_b
(rename = (b = category count = count_b percent = percent_b));
run;
proc freq noprint data = mydata;
tables c / out = data_c
(rename = (c = category count = count_c percent = percent_c));
run;
proc sort data = data_a; by category; run;
proc sort data = data_b; by category; run;
proc sort data = data_c; by category; run;
data data_out;
merge data_a data_b data_c;
by category;
run;
As ever, there are lots of different ways of doing this sort of thing in SAS. Here are a couple of other options:
1. Use proc summary rather than proc freq:
proc summary data = sashelp.class;
class age height weight;
ways 1;
output out = freqs;
run;
2. Use multiple table statements in a single proc freq
This is more efficient than running 3 separate proc freq statements, as SAS only has to read the input dataset once rather than 3 times:
proc freq data = sashelp.class noprint;
table age /out = freq_age;
table height /out = freq_height;
table weight /out = freq_weight;
run;
data freqs;
informat age height weight count percent;
set freq_age freq_height freq_weight;
run;
This is a question I've dealt with many times and I WISH SAS had a better way of doing this.
My solution has been a macro that is generalized, provide your input data, your list of variables and the name of your output dataset. I take into consideration the format/type/label of the variable which you would have to do
Hope it helps:
https://gist.github.com/statgeek/c099e294e2a8c8b5580a
/*
Description: Creates a One-Way Freq table of variables including percent/count
Parameters:
dsetin - inputdataset
varlist - list of variables to be analyzed separated by spaces
dsetout - name of dataset to be created
Author: F.Khurshed
Date: November 2011
*/
%macro one_way_summary(dsetin, varlist, dsetout);
proc datasets nodetails nolist;
delete &dsetout;
quit;
*loop through variable list;
%let i=1;
%do %while (%scan(&varlist, &i, " ") ^=%str());
%let var=%scan(&varlist, &i, " ");
%put &i &var;
*Cross tab;
proc freq data=&dsetin noprint;
table &var/ out=temp1;
run;
*Get variable label as name;
data _null_;
set &dsetin (obs=1);
call symput('var_name', vlabel(&var.));
run;
%put &var_name;
*Add in Variable name and store the levels as a text field;
data temp2;
keep variable value count percent;
Variable = "&var_name";
set temp1;
value=input(&var, $50.);
percent=percent/100; * I like to store these as decimals instead of numbers;
format percent percent8.1;
drop &var.;
run;
%put &var_name;
*Append datasets;
proc append data=temp2 base=&dsetout force;
run;
/*drop temp tables so theres no accidents*/
proc datasets nodetails nolist;
delete temp1 temp2;
quit;
*Increment counter;
%let i=%eval(&i+1);
%end;
%mend;
%one_way_summary(sashelp.class, sex age, summary1);
proc report data=summary1 nowd;
column variable value count percent;
define variable/ order 'Variable';
define value / format=$8. 'Value';
define count/'N';
define percent/'Percentage %';
run;
EDIT (2022):
Better way of doing this is to use the ODS Tables:
/*This code is an example of how to generate a table with
Variable Name, Variable Value, Frequency, Percent, Cumulative Freq and Cum Pct
No macro's are required
Use Proc Freq to generate the list, list variables in a table statement if only specific variables are desired
Use ODS Table to capture the output and then format the output into a printable table.
*/
*Run frequency for tables;
ods table onewayfreqs=temp;
proc freq data=sashelp.class;
table sex age;
run;
*Format output;
data want;
length variable $32. variable_value $50.;
set temp;
Variable=scan(table, 2);
Variable_Value=strip(trim(vvaluex(variable)));
keep variable variable_value frequency percent cum:;
label variable='Variable'
variable_value='Variable Value';
run;
*Display;
proc print data=want(obs=20) label;
run;
The option STACKODS(OUTPUT) added to PROC MEANS in 9.3 makes this a much simpler task.
proc means data=have n nmiss stackods;
ods output summary=want;
run;
| Variable | N | NMiss |
| ------ | ----- | ----- |
| a | 4 | 3 |
| b | 7 | 0 |
| c | 6 | 1 |