Hello,
I have a data set I want to create a pdf out of. The issue is that I want my data laid out in a certain way and I can't seem to do it with proc report so I wanted to change my data set so it conforms to what I want.
MyData
Year Question AnsCode AnsText QType
2010 "Is this the test 1?" 1 "Yes" "Intro"
2010 "Is this the test 1?" 2 "No" "Intro"
2010 "Is this the test 1?" 3 "N/A" "Intro"
2010 "Is this the test 2?" 1 "Yes" "Sec1"
2010 "Is this the test 2?" 2 "No" "Sec1"
2010 "Is this the test 2?" 3 "N/A" "Sec1"
2014 "Is this the test 3?" 1 "Yes" "Intro"
2014 "Is this the test 3?" 2 "No" "Intro"
2014 "Is this the test 3?" 3 "N/A" "Intro"
This is how I want to display it
2010
Intro
Is this the test 1?
CODES:
1 Yes
2 No
3 N/A
Sec1
Is this the test 2?
CODES:
1 Yes
2 No
3 N/A
2014
Intro
Is this the test 3?
CODES:
1 Yes
2 No
3 N/A
Can I create a dataset like this and then use it in my proc report or is there a way to do it with proc report?
Thank you
A standard data step with PUT statements is what I'd probably recommend.
May be this can generate your desired output.
data have;
input Year Question $ 6-27 AnsCode AnsText $ 30-35 QType $;
datalines;
2010 "Is this the test 1?" 1 "Yes" "Intro"
2010 "Is this the test 1?" 2 "No" "Intro"
2010 "Is this the test 1?" 3 "N/A" "Intro"
2010 "Is this the test 2?" 1 "Yes" "Sec1"
2010 "Is this the test 2?" 2 "No" "Sec1"
2010 "Is this the test 2?" 3 "N/A" "Sec1"
2014 "Is this the test 3?" 1 "Yes" "Intro"
2014 "Is this the test 3?" 2 "No" "Intro"
2014 "Is this the test 3?" 3 "N/A" "Intro"
;
run;
proc tabulate data=have;
class year qtype question anscode;
table year=' '*qtype=' '*question=' '*anscode=' ',n=' ';
run;
Thank you stat@sas,
This also is another good way to look at my issue. I will look at both versions and try and create the desired pdf.
Thank you
Hi,
You can also use escape codes to achieve the same effect:
data have;
attrib Year Question AnsCode AnsText QType format=$200.;
infile datalines delimiter=",";
input year $ question $ anscode $ anstext $ qtype $;
datalines;
2010,"Is this the test 1?",1,"Yes","Intro"
2010,"Is this the test 1?",2,"No","Intro"
2010,"Is this the test 1?",3,"N/A","Intro"
2010,"Is this the test 2?",1,"Yes","Sec1"
2010,"Is this the test 2?",2,"No","Sec1"
2010,"Is this the test 2?",3,"N/A","Sec1"
2014,"Is this the test 3?",1,"Yes","Intro"
2014,"Is this the test 3?",2,"No","Intro"
2014,"Is this the test 3?",3,"N/A","Intro"
;
quit;
data inter (keep=outline);
set have;
attrib outline format=$2000.;
by year;
if first.year then outline=strip(year)||"^n "||strip(qtype)||"^n "||strip(question)||"^nCODES:^n "||strip(anscode)||" "||strip(anstext);
else outline=" "||strip(anscode)||" "||strip(anstext);
run;
ods escapechar="^";
ods pdf file="s:\temp\rob\test.pdf";
proc report data=inter nowindows style(column)=[just=l borderrightcolor=white borderleftcolor=white
bordertopcolor=white borderbottomcolor=white];
define outline / style(column)=[width=8cm asis=on];
run;
ods pdf close;
data have; input Year Question $ 6-27 AnsCode AnsText $ 30-35 QType $; question=dequote(question);anstext=dequote(anstext);qtype=dequote(qtype); datalines; 2010 "Is this the test 1?" 1 "Yes" "Intro" 2010 "Is this the test 1?" 2 "No" "Intro" 2010 "Is this the test 1?" 3 "N/A" "Intro" 2010 "Is this the test 2?" 1 "Yes" "Sec1" 2010 "Is this the test 2?" 2 "No" "Sec1" 2010 "Is this the test 2?" 3 "N/A" "Sec1" 2014 "Is this the test 3?" 1 "Yes" "Intro" 2014 "Is this the test 3?" 2 "No" "Intro" 2014 "Is this the test 3?" 3 "N/A" "Intro" ; run; data report; set have; by Year QType Question; length y t q x z$ 40; if first.Question then do; y=year;output; y=' '; t=qtype;output;t=' '; q=question;output; q='CODES:';output; q=' '; end; x=anscode;z=anstext;output; keep y t q x z; run; ods listing close; ods pdf file='x.pdf'; proc report data=report nowd noheader; run; ods pdf close; ods listing;
Xia Keshan
Thank you Ksharp,
This leads me into a better direction in getting this pdf file created and displayed like the old way.
Thank you so much
Hi Ksharp,
How can I add links to question and qtype to have them point to different locations within the PDF file I'm creating?
Thank you
You would need to use ods anchor, please see thread:
Hi RW9,
I know I have to use an anchor but going off of KSharps example I could I implement the anchor on the question and the qtype?
How come carriage returns in my data don't work within ODS?
Thank you again for your help
Its not straightforward, you would either create a macro or do a call execute, to generate each output, so print row one with anchor xx, then print next one with anchor yy, not breaking between each one. Check out the post: 09-May-2014 04:49 from:
https://communities.sas.com/message/210632#210632
By carriage returns do you mean the embedded ^n. If so then you need the line ods escapechar="^"; If you mean another character then maybe switch to the n, some things that work in RTF for instance don't work in PDF.
I've been learning and experimenting with PDF output lately too and thought it might be a good exercise to do this with LINE statements. I don't know about linking within the document I will be interested to see how/if that is done.
I was a bit disappointed that I had to resort to PROTECTSPECIALCHAR to get the last indentation level for CODES:. I hope comes along and schools us all.
KSharp & data_null_;
thank you both so much for you replies.
It's been so frustrating trying to replicate this other pdf file using SAS. I thought it would be more straight forward then it is. Of course it's escapechar i've used it before but i'm so flustered.
Thanks again and I will reply with any new or helpful information.
Are you going to populate any additional columns with counts or other statistics related to the AnsCode or AnsText?
If so proc tabulate might work with something like:
Proc tabulate data=q; /* to use someone elses data set*/
class Year Question AnsCode AnsText QType; /* assuming none of these variables have missing values*/
table year=""*Qtype=""*Question=""*AnsCode="Codes"*AnsText;
run;
I suspect that if you have actual response data you could skip whatever this step is doing and create summary tables directrly from the data with counts, means or whatever summaries you need from the data. It looks to me that you may be building an empty table that you will then enter data into manually. It might not hurt to describe the next couple of things you are doing with your data.
Hi:
Sorry, I'm late to the party. I was out of town and without my computer.
The OP already has a lot of possible solutions. Data _NULL_, I don't know why you needed PROTECTSPECIALCHARS, especially since ON is the default. But I do have a faint memory of how PDF is not always happy about changing margins inside a single cell, which is what you're creating with your single LINE statement. As you can see, in your example, the string CODES is inside the same line cell as the question. And you already gave that cell a left margin. But I don't think I would have tried to use ODS ESCAPECHAR to try to change the margin, for the reason stated above. I don't believe that you can successfully use a style override in the middle of a single line (even with NEWLINE, it's still 1 line), when the style of the "container" cell has already been specified. That would be a question for the PDF experts in Tech Support.
However, to me, it's moot. I would have approached it a bit differently. I either would have made a single Since the report is so straightforward, I would have just used another variable to hold the "code string" -- which in my program I call the CODESTR variable whose value is set to CODES: and then I can just do a COMPUTE before CODESTR.
You made fixed lengths for all your questions and text, but I prefer to use $varying. in my LINE statements. I think it makes it easier and then since I can use the LENGTH function to find out the exact length of the string I'm about to write, I don't have to worry about one question being or string being really short and another really long.
Then, I used a STYLE(REPORT) override to get rid of interior table lines and the frame box of the table -- this looks more like an outline form or documentation to me.
As an alternative, I would probably have just transposed the data and made some fake ordering variables so that there were only 2 basic character columns on the REPORT -- COL1 and COL2, as shown in the "alt" report. With this approach, the order is imposed either by the order of the data or thru a program and PROC REPORT margins are set based on one of the ordering variables. In the second report, I varied the question text a bit, so that I could test a long question wrapping and used the order variables also to control the order of the codes, since they might not always be in a standard order.
cynthia
data q;
infile datalines;
input Year Question &$quote64. AnsCode (AnsText QType)(&$quote8.);
codestr = 'CODES:';
return;
datalines4;
2010 "Is this the test 1?" 1 "Yes" "Intro"
2010 "Is this the test 1?" 2 "No" "Intro"
2010 "Is this the test 1?" 3 "N/A" "Intro"
2010 "Is this the test 2?" 1 "Yes" "Sec1"
2010 "Is this the test 2?" 2 "No" "Sec1"
2010 "Is this the test 2?" 3 "N/A" "Sec1"
2014 "Is this the test 3?" 1 "Yes" "Intro"
2014 "Is this the test 3?" 2 "No" "Intro"
2014 "Is this the test 3?" 3 "N/A" "Intro"
;;;;
run;
ods listing;
title; footnote;
proc print data=q;
var year qtype question codestr anscode anstext;
run;
ods listing close;
ods pdf file='c:\temp\other_report.pdf' style=printer;
proc report data=q nowd
style(lines)=[TEXTALIGN=left]
style(header)={background=white}
style(report)={rules=none frame=void cellspacing=0 cellpadding=2px};
column year qtype question codestr anscode anstext;
define year / order order=internal noprint;
define qtype / order order=internal noprint;
define question / order order=internal noprint;
define codestr / order noprint;
define anscode / order order=internal ' ' format=1. style(column)={just=r};
define anstext / display ' ' style(column)={just=r};
compute before year ;
line year 4.;
endcomp;
compute before qtype / style=[marginleft=.125in];
tlg = length(qtype);
line qtype $varying. tlg;
endcomp;
compute before question / style={marginleft=.25in};
qlg = length(question);
line question $varying. qlg;
endcomp;
compute before codestr / style={marginleft=.375in};
clg = length(codestr);
line codestr $varying. clg ;
endcomp;
run;
ods pdf close;
title; footnote;
data alt_q;
length col1 $80 col2 $50;
infile datalines dlm=',' dsd;
input yrord ord year col1 $ col2 $;
codestr = 'CODES:';
return;
datalines4;
1,10,2010,"2010"," "
1,11,2010,"Intro"," "
1,12,2010,"Is this test 1?"," "
1,13,2010,"CODES:"," "
1,14,2010,"1","Yes"
1,15,2010,"2","No"
1,16,2010,"3","N/A"
2,11,2010,"Sec1"," "
2,12,2010,"Is this longer for 2?"," "
2,13,2010,"CODES:"," "
2,14,2010,"0","Yes"
2,15,2010,"1","No"
2,16,2010,"2","N/A"
2,17,2010,"9","Other"
3,10,2014,"2014"," "
3,11,2014,"Intro"," "
3,12,2014,"Is this the very very very very very long long long question for test 3?"," "
3,13,2014,"CODES:"," "
3,14,2014,"A","Alpha"
3,15,2014,"B","Beta"
3,16,2014,"C","Gamma"
3,17,2014,"D","Delta"
;;;;
run;
ods listing close;
title; footnote;
ods pdf file='c:\temp\alt_report.pdf' style=printer;
proc report data=alt_q nowd noheader
style(header)={background=white}
style(report)={rules=none frame=void cellspacing=0 cellpadding=2px};
column year yrord ord col1 col2;
define year / order noprint;
define yrord / order noprint;
define ord / order noprint;
define col1 / display
style(column)={width=2in};
define col2 / display
style(column)={width=1in};
compute col1;
if ord = 10 then do;
call define(_col_,'style','style={just=l}');
end;
if ord = 11 then do;
call define(_col_,'style','style={marginleft=0.15in }');
end;
else if ord = 12 then do;
call define(_col_,'style','style={marginleft=0.3in }');
end;
else if ord = 13 then do;
call define(_col_,'style','style={marginleft=0.45in }');
end;
else if ord gt 13 then do;
call define(_col_,'style','style={just=r}');
end;
endcomp;
run;
ods pdf close;
title; footnote;
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 the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.
Find more tutorials on the SAS Users YouTube channel.