The SAS Output Delivery System and reporting techniques

Modifying CSS style in ODS PDF

Reply
Frequent Contributor
Posts: 79

Modifying CSS style in ODS PDF

Hi - I am trying to update only a few elements using CSS, however as soon as I provide my CSS style, elements for which I did not specify a style also change.

 

For example in the attached picture (left=document with no cssstyle statement; right=document with cssstyle element as per code):

  • The list also has an outline
  • The grid in the first plot is much darker
  • The colours change in the second plot (although I didn't choose the colours in the first plot and don't particularly like them anyway - however once I specify colours I will not want them to change when a .css file is specified)

The following is my sample code:

ods pdf file="c:\temp\cssChecking.pdf" startpage=never
cssstyle="c:\temp\mycssstyle.css";
title "Report Header";

title 'A List';
proc odstext;
   list;
      item "Item 1" ;
	  item "Item 2" ;
	  item "Item 3" ;
      end;
   end;
run;

title 'A Plot - no colour';
proc sgplot data=sashelp.cars;
	histogram weight;
	xaxis grid display=(noline) label='Weight';
	yaxis grid display=(noline);
run;

ods exclude all;
proc report data=sashelp.cars out=temp;
column origin  msrp pctMsrp invoice pctInvoice;
define origin / 'Origin' group;
define msrp / 'MSRP' analysis sum format=comma13.;
define pctMsrp / '%MSRP' computed format=percent8.2;
define invoice / 'Invoice' analysis sum format=comma13.;
define pctInvoice / '%Invoice' computed format=percent8.2;
compute before;
	totMSRP = msrp.sum;
	totInvoice = invoice.sum;
	endcomp;
compute pctMsrp;
	pctMsrp = msrp.sum / totMSRP;
	endcomp;
compute pctInvoice;
	pctInvoice = invoice.sum / totInvoice;
	endcomp;
run;
ods exclude none;

proc transpose data=temp(where=(_break_ is null)) out=temp;
by origin;
var pctMsrp pctInvoice;
run;
proc sgplot data= temp ( rename=(col1=value _label_=measure));
vbar origin/ response=value group=measure groupdisplay=cluster;
format value percent6.0;
label measure='Measure' value = 'Value';
run;
proc datasets nolist;
delete temp;
run;

ods pdf close;

 

And here is the code from the css file:

@import 'C:\temp\normal.css';

.body, .systemtitle, .header .roweader, .data 
{
	font-family: arial, sans-serif;
}

.systemtitle
{
	color: blue;
}

.listitem, .listitem li::marker
{
	list-style-type: circle;
}
.graph
{
  border: none;
}
.graphcharts
{
  border: none;
}

What is the best way for updating the style of only a few elements using a .css file?

 

All help will be much appreciated.


Thanks,
Marie


EffectofSASCss.png
SAS Super FREQ
Posts: 8,819

Re: Modifying CSS style in ODS PDF

[ Edited ]

Hi:

 
Just a comment. I'm not sure I would ever use Arial with ODS PDF. As this paper explains http://support.sas.com/resources/papers/proceedings10/035-2010.pdf -- Albany AMT is the "Arial" lookalike. In the early days of ODS (back in V8), when you used "plain" Arial with ODS PDF, behind the scenes, it got Helvetica substituted for it in order to be rendered by Adobe.

   

I am not sure your @import inside the CSS file is going to work the way you want. And I am pretty sure that if you tried parent= in PROC TEMPLATE, it would not work either But if you have already made a copy of normal.css, then this should work:

 

filename ncss 'c:\temp\normal.css';
filename excss 'c:\temp\extra.css';

proc template;
  define style mycss_style;
     import ncss; /* import normal.css first */
     import excss; /* then import extra css */
  end;
run;

** change order of import;
proc template;
  define style mycss_diff;
     import excss;
     import ncss;
  end;
run;

 

  When inheritance is resolved in the 2 CSS files, the CSS file listed last should override the CSS file listed first. For example, if you have .Header color: red in the extra.css file but it is not red in the normal.css file, then the color listed last for .Header should be the one that "wins". 

   

For more information, I recommend this paper https://support.sas.com/resources/papers/proceedings13/365-2013.pdf  . And for more in-depth help, I recommend working with Tech Support because I do not know whether all of the CSS techniquest used in the paper will work with ODS PDF in the same way they work with ODS HTML.

  

cynthia

 

 

 

Frequent Contributor
Posts: 79

Re: Modifying CSS style in ODS PDF

Hi Cynthia - Thanks your feedback and references, however, unfortunately your method seems to have the same effect.  

 

I took normal.css from C:\Program Files\SASHome\SASEnterpriseGuide\7.1\Styles.  However, it appears that this stylesheet is not used (despite having it listed in Tools > Options > Results > PDF > Style.  Because when I specify ncss (without ecss), I get the lines around the text lists and strong borders around the charts etc.

 

If I change the underlying style to Sapphire (using your method or the original), I no longer have the borders around the text lists, but still have strong gridlines, etc in the charts.  

 

I have tried taking away all borders and gridlines in a copy of normal.css and they still persist in the PDF output.  What I need to find is the stylesheet used to generate the PDF option when no style / stylesheet is specified .... or otherwise learn which part in the CSS file I need to change (or what I need to add) to remove the resulting strong chart gridlines, chart borders, etc...

SAS Super FREQ
Posts: 8,819

Re: Modifying CSS style in ODS PDF

Hi:
I think the CSS method may be geared to how HTML builds grid lines -- so if you are working on borders and grid lines, that would probably need consultation with Tech Support.

The import method did work for me when I played with PEARL and with a separate, smaller CSS file. I'll post the screen shots and code when I'm on my other computer.

cynthia
Frequent Contributor
Posts: 79

Re: Modifying CSS style in ODS PDF

That will be great - thanks!

##- Please type your reply above this line. Simple formatting, no
attachments. -##
SAS Super FREQ
Posts: 8,819

Re: Modifying CSS style in ODS PDF

Hi:

  So here's what I did. I started with a copy of PEARL.CSS, which is a copy of the PEARL style definition. Then I changed the .systemfooter class selector in the CSS file to be a purple, because I always wanted to  be able to see the PEARL was used. So in the PEARL.CSS file, this is all I changed:

.systemfooter
{
  background-color: #FFFFFF;
  color: purple;
  font-family: 'Albany AMT', Albany;
  font-size: 11pt;
  font-style: normal;
  font-weight: bold;
}

(All of PEARL.CSS is too lengthy to post here. The whole file was c:\temp\PEARL.CSS)

 

 

Then I made a second CSS file that had some fairly noticeable color and font changes. I used Courier New to be really certain when that CSS file was used:

 

.body, .systemtitle, .header, .roweader, .data {
  font-family: Courier New;
}
.header {
  color: red;
}
.systemtitle {
  color: green;
}
.listitem, .listitem li::marker {
  list-style-type: square;
  color: green;
}
.graph {
  border: none;
}
.graphcharts {
  border: none;
}

and that file was stored in: c:\temp\extrastyle.css

 

 

Then I had 2 FILENAME statements and made 2 different templates, just switching the order of the 2 CSS files:

 


filename pcss 'c:\temp\pearl.css';
filename css 'c:\temp\extrastyle.css';
  
proc template;
  define style mycss_style;
    import pcss;   /* import pearl.css first */
    import css;   /* then import extrastyle.css */
  end;
run;
  
** change order of import;
proc template;
  define style mycss_diff;
    import css;
    import pcss;
  end;
run;

ods _all_ close;
ods html file="c:\temp\cssChecking1.html"   style=mycss_style;
ods rtf file="c:\temp\cssChecking2.rtf" style=mycss_style;
ods pdf file="c:\temp\cssChecking3.pdf" startpage=never style=mycss_style;

title "Proc PRINT title -- this should be green";
footnote "This should be purple";

proc print data=sashelp.class(obs=5);
title2 'font defined courier new in import css';
run;
ods _all_ close;

 

  I started with the PEARL style because it was originally written for compatibility with the PDF destination, whereas the NORMAL style was not originally written for PDF. NORMAL was originally written for EG and Web Report Studio -- neither of which were PDF-based destinations.

 

  I also only tested with PROC PRINT because my goal was to show that the order of resolution for the class selectors with the same name, either worked or didn't work. The results from using mycss_style are shown here in Acrobat Reader:

 

mycss_style.png

 

 

As you can see, since Pearl was imported first and the extrastyle.css was imported second, the colors from extrastyle.css were used for the header and title and Courier was used for the data cell and header fonts, but the color from Pearl.css was used for the footnote. So this shows that both CSS files were imported and the class selectors were resolved with the second set of selectors "overriding" the first set of selectors.

 

Then I tested the "different" style template, the one that imported the sheets in a different order. The code to test the different style template was:

 


ods _all_ close;
ods html file="c:\temp\cssChecking4.html"   style=mycss_diff;
ods rtf file="c:\temp\cssChecking5.rtf" style=mycss_diff;
ods pdf file="c:\temp\cssChecking6.pdf" startpage=never style=mycss_diff;

title "Proc PRINT title pearl.css imported second -- will this be green or not";
footnote "This should be purple";

proc print data=sashelp.class(obs=5);
title2 'font was courier new in import css file what will it be?';
run;
ods _all_ close;

and these results were:

 

mycss_diff.png

 

Since Pearl.css was imported second, all the Pearl settings overrode what was in the first extrastyle.css sheet. So the resolution works as expected, when there are same named class selectors.

 

When I swap out the Pearl.CSS for NORMAL.CSS, I see the same results with this new code:


filename ncss 'C:\Program Files\SASHome\SASEnterpriseGuide\7.1\Styles\normal.css';
filename css 'c:\temp\extrastyle.css';
  
proc template;
  define style mynorm_style;
    import ncss;   /* import pearl.css first */
    import css;   /* then import extrastyle.css */
  end;
run;
  

ods _all_ close;
ods html file="c:\temp\cssChecking1n.html"   style=mynorm_style;
ods rtf file="c:\temp\cssChecking2n.rtf" style=mynorm_style;
ods pdf file="c:\temp\cssChecking3n.pdf" startpage=never style=mynorm_style;

title "Proc PRINT title -- this should be green";
footnote "This will be default for Normal style";

proc print data=sashelp.class(obs=5);
title2 'font defined courier new in import css';
run;
ods _all_ close;

Then I observe the same behavior as with the Pearl test. If Normal.CSS comes in first in the IMPORT, then the EXTRASTYLE.CSS changes the same named class selectors:

 

use_normal_style_with_import.png

 

so this shows me that the new CSS file is being used.

 

You had some specific points that you noted:

  • The list also has an outline
  • The grid in the first plot is much darker
  • The colours change in the second plot (although I didn't choose the colours in the first plot and don't particularly like them anyway - however once I specify colours I will not want them to change when a .css file is specified)

 

1) Yes, when I run your example code, I do see that the list has an outline. I am guessing that has something to do with the fact that all tables with ODS do have a table outside "frame" or border. Usually in PROC REPORT, PROC PRINT or PROC TABULATE, you have to specify FRAME=VOID to get rid of the frame for a TABLE. What I do observe is that if I take the whole issue of CSS out of the  CSS picture and I just I use PROC ODSTEXT with style Pearl vs style Normal, is that the table output from Pearl does NOT have a border/outline, but that the table output from Normal has a border -- so you might have to work with Tech Support to find out what has to change in the Normal style to make no outline.

 

ods pdf file='c:\temp\test_text_pearl.pdf' style=pearl;
title "Report Header no border on output";
title2 'A List';
proc odstext;
   list;
      item "Item 1" ;
	  item "Item 2" ;
	  item "Item 3" ;
      end;
   end;
run;
ods _all_ close;

ods pdf file='c:\temp\test_text_normal.pdf' style=normal;
title "Report Header does have border on output";
title2 'A List';
proc odstext;
   list;
      item "Item 1" ;
	  item "Item 2" ;
	  item "Item 3" ;
      end;
   end;
run;
ods _all_ close;

2) When you say that the grid in the first plot is darker than the second plot, that's not what I observe. There is a grid in the first plot, but no grid in the second plot. If I print or zoom to 100% the lines look the same to me.

 

3) You say that you don't understand why the colors change in the second plot. They changed because your Histogram was not a grouped plot. So there is one color used in the style for "ungrouped" data and a different set of colors used for "grouped" data:

grouped_vs_ungrouped_output.png

 

If you run code like this, without GROUP=, but instead using BY,  then you will get the same colors.

ods pdf file='c:\temp\showby.pdf' style=mynorm_style;
title2 'A Plot - no colour';
proc sgplot data=sashelp.cars;
	histogram weight;
	xaxis grid display=(noline) label='Weight';
	yaxis grid display=(noline);
run;

proc sort data=trtemp;
by _label_;
run;

proc sgplot data= trtemp ( rename=(col1=value _label_=measure));
by measure;
vbar origin/ response=value /* group=measure groupdisplay=cluster*/;
format value percent6.0;
label measure='Measure' value = 'Value';
run;

ods pdf close;

no_group_same_color.png

 

So I think that your original @import method many not work as you envisioned, but the PROC TEMPLATE with the IMPORT statement should do some of what you want, if you can get the CLASS selectors right. I think my test verifies that the PROC TEMPLATE approach with the IMPORT statement will have the selectors resolve in the expected order.

 

The issue with the line around the PROC ODSTEXT output is probably something you need to investigate with Tech Support. If you want to change the colors used for the ungrouped or grouped data, then you either have to change the style template colors or you have to use syntax in sgplot, such as an attribute map to change the colors.

 

Sorry for the long post. Hope this helps,

 

cynthia

Frequent Contributor
Posts: 79

Re: Modifying CSS style in ODS PDF

[ Edited ]

Hi Cythia, 

 

Thanks so much for following this through.  I have replicated your examples and make the following notes:

 

  •  What I meant by the colours changing was that the colours of the chart is different when no style option is used compared to when same style (i.e., as specified in EG Tools > Options > Results > PDF Style) is applied using the style option in the ods pdf statement.  I would expect that by specifying the the same style sheet as EG uses in the style option that I would get exactly the same results than when the style option is not used.

EffectofSASCss (2).png

  • By modifying the pearl file (base css) as you suggested (with the purple footnote), it is clear that my original method (@import method) works the same as the method you propose.  
  • I know what needs to be changed within extrastyle.css file to adjust the chart colours, but will follow up with technical support the CSS elements that need to be adjusted to change the appearance of the gridlines (using pearl or sapphire instead of normal removes the borders around lists issue - although I have no idea what changed there)

Thanks again for your help.

SAS Super FREQ
Posts: 8,819

Re: Modifying CSS style in ODS PDF

Hi, the blue and red colors are the default colors for graph object groups when no style is specified. They come from the "LISTING" style which produces plain tabulate output to the SAS Output Window, but graphics need colors so the blue and red are the default grouped colors when you don't specify a style.

Somehow in the "red and blue" output, ODS thought that the LISTING style needed to be used. There are a few other styles that use red and blue, too so it's possible that one of them was defined in your Tools--> Options --> Results choices in EG.

cynthia
Ask a Question
Discussion stats
  • 7 replies
  • 679 views
  • 0 likes
  • 2 in conversation