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

When defining header text using the COLUMN statement in PROC REPORT, I want to separately control the justification of each header. E.g. the first column's header should be left-justified, and the next column right-justified. I want this to work for HTML output.

 

Here's another post on this forum which shows how to do this for RTF output. You can do inline formatting with an escape character, e.g., "^S={just=r}My header". However, this does not work for the default HTML destination.

 

Here's some example code to work with:

 

proc report data=sashelp.classfit(obs=5) nowd;
	columns ('Name' name) ('True/Weight' weight)
		('Predicted/Weight' predict) ('Predicted/95% CI' lower upper);
	define name / '';
	define weight / '';
	define predict / '';
	define lower / '';
	define upper / '';
run;

It produces this table in the default HTML output:

 

Classfit Table with Headers.png

 

How would I, say, make "Name" left-aligned, "True Weight" and "Predicted Weight" right-aligned, and "Predicted 95%CI" center-aligned? To be clear, I'm not referring to the values in the table body, just to the headers at the top (in blue).

1 ACCEPTED SOLUTION

Accepted Solutions
Cynthia_sas
SAS Super FREQ

Hi:

  There are 2 ways to do this: 1) use PROC REPORT, but you'll also need to make some "helper" variables so you can apply differing justification to each header or 2) switch to the Report Writing Interface. Both methods are illustrated in this program.

** make "helper" variables for method #1;
data classfit;
  length nhd twhd pwhd pci $20;
  set sashelp.classfit;
  nhd =  'Name';
  twhd = 'True/Weight';
  pwhd = 'Predicted/Weight';
  pci =  'Predicted/95% CI';
  dummyvar = 1;
run;

ods html path='c:\temp' file='two_methods.html';

proc report data=classfit(obs=5) nowd split='/'
   style(column)={width=1.0in};
   title '1) Use helper variables for headers';
	columns dummyvar nhd,name  
             twhd,weight 
		     pwhd,predict  
             pci,(lower upper );
	define dummyvar /order noprint;
	define nhd / ' ' across style(header)={just=l vjust=b};
	define name / ' ';
	define twhd / ' ' across style(header)={just=r};
	define weight / ' ';
	define pwhd / ' ' across style(header)={just=r};
	define predict / ' ';
	define pci / ' '  across style(header)={just=c};
	define lower / ' ';
	define upper / ' ';
run;


title '2) Or, use RWI to write report and do column spanning';
data _null_; 
  set SASHELP.CLASSFIT (obs=5) end=last; 
  if _N_ = 1 then do; 
      dcl odsout obj(); 
      obj.table_start(); 
      obj.head_start(); 
	  ** Header row 1;
      obj.row_start(type: "Header"); 
      obj.format_cell(text: "Name", style_attr:"just=l vjust=b width=1in"); 
      obj.format_cell(text: "True/Weight", split:'/',style_attr:"just=r width=1in"); 
      obj.format_cell(text: "Predicted/Weight", split:'/', style_attr:"just=r width=1in"); 
      obj.format_cell(text: "Predicted/95% CI",split:'/', column_span:2, style_attr:"just=c"); 
      obj.row_end(); 
      obj.head_end(); 
    end;
  ** row for every obs;
      obj.row_start(); 
      obj.format_cell(data: name , style_attr: "just=l" ); 
      obj.format_cell(data: weight, style_attr: "just=r"); 
      obj.format_cell(data: predict, style_attr: "just=r"); 
      obj.format_cell(data: lower, style_attr: "just=r width=1in"); 
      obj.format_cell(data: upper, style_attr: "just=r width=1in"); 
      obj.row_end(); 
   
  if last then do; 
      obj.table_end(); 
    end; 
run; 
ods html close;

For the kind of control you want over the headers, using the "helper" variables as across items gives you that control just using STYLE overrides in the DEFINE statement. With ACROSS items, you need an ORDER or GROUP item as the left most column, which is what the DUMMYVAR helper variable is doing. The variable is given a value of 1 on each row, so it really just makes the other headers work. And it is a NOPRINT item, so you don't have to see it, you just need it to be there. I made the columns a bit wider than needed so you could see that the justifications were used.

 

Here's the output;

two_method.png

Hope this helps,

cynthia

 

View solution in original post

2 REPLIES 2
Cynthia_sas
SAS Super FREQ

Hi:

  There are 2 ways to do this: 1) use PROC REPORT, but you'll also need to make some "helper" variables so you can apply differing justification to each header or 2) switch to the Report Writing Interface. Both methods are illustrated in this program.

** make "helper" variables for method #1;
data classfit;
  length nhd twhd pwhd pci $20;
  set sashelp.classfit;
  nhd =  'Name';
  twhd = 'True/Weight';
  pwhd = 'Predicted/Weight';
  pci =  'Predicted/95% CI';
  dummyvar = 1;
run;

ods html path='c:\temp' file='two_methods.html';

proc report data=classfit(obs=5) nowd split='/'
   style(column)={width=1.0in};
   title '1) Use helper variables for headers';
	columns dummyvar nhd,name  
             twhd,weight 
		     pwhd,predict  
             pci,(lower upper );
	define dummyvar /order noprint;
	define nhd / ' ' across style(header)={just=l vjust=b};
	define name / ' ';
	define twhd / ' ' across style(header)={just=r};
	define weight / ' ';
	define pwhd / ' ' across style(header)={just=r};
	define predict / ' ';
	define pci / ' '  across style(header)={just=c};
	define lower / ' ';
	define upper / ' ';
run;


title '2) Or, use RWI to write report and do column spanning';
data _null_; 
  set SASHELP.CLASSFIT (obs=5) end=last; 
  if _N_ = 1 then do; 
      dcl odsout obj(); 
      obj.table_start(); 
      obj.head_start(); 
	  ** Header row 1;
      obj.row_start(type: "Header"); 
      obj.format_cell(text: "Name", style_attr:"just=l vjust=b width=1in"); 
      obj.format_cell(text: "True/Weight", split:'/',style_attr:"just=r width=1in"); 
      obj.format_cell(text: "Predicted/Weight", split:'/', style_attr:"just=r width=1in"); 
      obj.format_cell(text: "Predicted/95% CI",split:'/', column_span:2, style_attr:"just=c"); 
      obj.row_end(); 
      obj.head_end(); 
    end;
  ** row for every obs;
      obj.row_start(); 
      obj.format_cell(data: name , style_attr: "just=l" ); 
      obj.format_cell(data: weight, style_attr: "just=r"); 
      obj.format_cell(data: predict, style_attr: "just=r"); 
      obj.format_cell(data: lower, style_attr: "just=r width=1in"); 
      obj.format_cell(data: upper, style_attr: "just=r width=1in"); 
      obj.row_end(); 
   
  if last then do; 
      obj.table_end(); 
    end; 
run; 
ods html close;

For the kind of control you want over the headers, using the "helper" variables as across items gives you that control just using STYLE overrides in the DEFINE statement. With ACROSS items, you need an ORDER or GROUP item as the left most column, which is what the DUMMYVAR helper variable is doing. The variable is given a value of 1 on each row, so it really just makes the other headers work. And it is a NOPRINT item, so you don't have to see it, you just need it to be there. I made the columns a bit wider than needed so you could see that the justifications were used.

 

Here's the output;

two_method.png

Hope this helps,

cynthia

 

dagremu
Obsidian | Level 7
Thank you, Cynthia! I really appreciate your help. And I had never heard of the Report Writing Interface -- looks powerful.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 2 replies
  • 5173 views
  • 2 likes
  • 2 in conversation