Data visualization with SAS programming

Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Reply
Occasional Contributor Jud
Occasional Contributor
Posts: 5

Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Hello All,

 

9.4 TS1M4

 

I am trying to control the colors and fill patterns in a waterfall plot (vbar) using a combination of proc template (borrowed from SAS Help Docs) and the data attribute maps so that all groups are consistent over all plots.  However, when I produce the plots, the colors seem to line up, but the fill patterns don't.  Here is an excerpt from my code:

proc template;                                                                
   define style Styles.MyJournal2;                                              
      parent = styles.journal2; 
      style GraphColors from GraphColors /
         'gdata'=cxffffff
         'gdata1'=cxffffff
         'gdata2'=cxc0c0c0
         'gdata3'=cxe0e0e0
         'gdata4'=cxa0a0a0
         'gdata5'=cx909090
         'gdata6'=cxffffff
         'gdata7'=cxc0c0c0
         'gdata8'=cxe0e0e0
         'gdata9'=cxa0a0a0;
      style GraphHistogram from GraphComponent /                              
         displayopts = "outline";                                             
      style GraphEllipse from GraphComponent /                                
         displayopts = "outline";                                             
      style GraphBand from GraphComponent /                                   
         displayopts = "outline";                                             
      style GraphBox from GraphComponent /                                    
         displayopts = "caps median mean outliers"                            
         connect = "mean"                                                     
         capstyle = "serif";                                                  
      style GraphBar from GraphComponent /                                    
         displayopts = "outline fillpattern";                                 
      style GraphData1 from GraphData1 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "L1";                                                  
      style GraphData2 from GraphData2 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "R1";                                                  
      style GraphData3 from GraphData3 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "X1";                                                  
      style GraphData4 from GraphData4 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "L2";                                                  
      style GraphData5 from GraphData5 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "R2";                                                  
      style GraphData6 from GraphData6 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "X2";                                                  
      style GraphData7 from GraphData7 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "L3";                                                  
      style GraphData8 from GraphData8 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "R3";                                                  
      style GraphData9 from GraphData9 /                                      
         contrastcolor=&_contrast.                                                  
         fillpattern = "X3";                                                  
  end;                                                                       

  define style Styles.MyJournal3;                                              
      parent = styles.MyJournal2;
      style GraphBar from GraphComponent /                                    
         displayopts = "fill outline fillpattern";                                 
      style GraphColors from GraphColors /
         'gdata'=cxffffff
         'gdata1'=cx308020
         'gdata2'=cx308020
         'gdata3'=cx308020
         'gdata4'=cx2050ff
         'gdata5'=cx2050ff
         'gdata6'=cx2050ff
         'gdata7'=cx402080
         'gdata8'=cx402080
         'gdata9'=cx402080;
  end;
run;

data brightattrmap;
	length id $50 show $20 value $100 linecolor $50 fillcolor $50 fillstyle $50 markercolor $50;
	infile datalines dsd dlm="|";
	input ID $ show $ value $ linecolor $ fillcolor $ fillstyle $ markercolor $;
datalines;
cohort|ATTRMAP|Part B (Subcutaneous) 300 mg|||GraphData1|
cohort|ATTRMAP|Part B (IV, 2 hr infusion) 300 mg|||GraphData2|
cohort|ATTRMAP|Part B (IV Bolus) 300 mg|||GraphData3|
cohort|ATTRMAP|Part B (Subcutaneous) 600 mg|||GraphData4|
cohort|ATTRMAP|Part B (IV, 2 hr infusion) 600 mg|||GraphData5|
cohort|ATTRMAP|Part B (IV Bolus) 600 mg|||GraphData6|
cohort|ATTRMAP|Part B (Subcutaneous) 900 mg|||GraphData7|
cohort|ATTRMAP|Part B (IV, 2 hr infusion) 900 mg|||GraphData8|
cohort|ATTRMAP|Part B (IV Bolus) 900 mg|||GraphData9|
;
run;

proc sgplot data=&ds. dattrmap=brightattrmap;
	vbar patid / group=cohort response=cfbpct categoryorder=respdesc groupdisplay=cluster attrid=cohort name="vbar";
	refline -50 / axis=y lineattrs=(color=red thickness=3);
	xaxis labelattrs=(family=arial size=11 weight=bold) valueattrs=(family=arial size=11 weight=bold);
	yaxis values=(20 to -100 by -20) labelattrs=(family=arial size=11 weight=bold) valueattrs=(family=arial size=11 weight=bold);
	keylegend "vbar"/ noborder title="Cohort" titleattrs=(family=arial size=11 weight=bold) valueattrs=(family=arial size=11 weight=bold);
run;

Here is the legend from 2 of the plots with different groupings.  Notice that the 300 mg groups are green, 600 mg blue, 900 mg purple as defined in the dattrmap, but the patterns seem to be random.  You can see in the template that there are no "SOLID" or empty patterns but a few showed up with no pattern?

 

image.pngimage.png

 

Anyway, I am looking for help getting this worked out or if you have an alternate way of doing this, I am open to suggestions!

 

Thanks everyone!

 

 

Occasional Contributor Jud
Occasional Contributor
Posts: 5

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Hello All,

 

A little more information to help diagnose...

 

If I remove "ATTRMAP" from the attribute table and allow the default of "DATA", I get the following results.  The groups that have no data are removed and so are the solid legend labels.  Also, the order now changes to the order in which the results of the vbar are displayed on the plot.  The colors are associated with the appropriate group, but the fill patterns show up in order of definition graphdata1, graphdata2, ... L, R, X, L, R, X and not with what was defined in the attribute map table.

 

image.png

SAS Super FREQ
Posts: 496

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

https://blogs.sas.com/content/graphicallyspeaking/2017/04/04/consistent-ordering-graph-components/

This blog provides an example of specifying style elements in an attribute map.

 

I don't think it recognizes your style elements when you specify them as colors.

Occasional Contributor Jud
Occasional Contributor
Posts: 5

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Posted in reply to WarrenKuhfeld

Thank you very much for the prompt reply, but I'm still having issues with the patterns staying aligned with the attribute map.  The colors and order work as expected.

 

Can you elaborate on "I don't think it recognizes your style elements when you specify them as colors."?  Did you mean the columns in my attribute table?  I changed them to match yours, but same results.

data brightattrmap;
	length ID $50 show $20 value $100 linestyle $50 markerstyle $50 fillstyle $50 textstyleelement $50;
	infile datalines dsd dlm="|";
	input ID $ show $ value $ linestyle $ markerstyle $ fillstyle $ textstyleelement $;
datalines;
cohort|attrmap|Part B (Subcutaneous) 300 mg|GraphData1|GraphData1|GraphData1|GraphData1
cohort|attrmap|Part B (IV, 2 hr infusion) 300 mg|GraphData2|GraphData2|GraphData2|GraphData2
cohort|attrmap|Part B (IV Bolus) 300 mg|GraphData3|GraphData3|GraphData3|GraphData3
cohort|attrmap|Part B (Subcutaneous) 600 mg|GraphData4|GraphData4|GraphData4|GraphData4
cohort|attrmap|Part B (IV, 2 hr infusion) 600 mg|GraphData5|GraphData5|GraphData5|GraphData5
cohort|attrmap|Part B (IV Bolus) 600 mg|GraphData6|GraphData6|GraphData6|GraphData6
cohort|attrmap|Part B (Subcutaneous) 900 mg|GraphData7|GraphData7|GraphData7|GraphData7
cohort|attrmap|Part B (IV, 2 hr infusion) 900 mg|GraphData8|GraphData8|GraphData8|GraphData8
cohort|attrmap|Part B (IV Bolus) 900 mg|GraphData9|GraphData9|GraphData9|GraphData9
;
run;

Thanks again!

 

 

 

SAS Super FREQ
Posts: 496

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

In many cases, I can't fully answer a question unless you provide full code along with sample data that I can run.  Still I might comment if I think I can say something helpful.  I was not trying to suggest that you change your code to be more like my example.  Or if you did change it, I hoped to convey that you don't have to type "GraphData" over and over and over .....  I was trying to say that I believe that you need to specify colors in the color options, and you were not doing that.  If you want to specify style elements, use the appropriate variable names.  In many cases, ODS Graphics silently ignores things that it does not understand (like color names that begin with "GraphData") without complaining about them.  This is by design and is often quite helpful. Maybe that is related to your problem, but maybe not. All that said, I don't know what your issue is.  I just noticed that you were not specifying colors in your color variable. I also noticed that you were making your life harder by typing and retyping instead of using assignment statements.

Super User
Posts: 13,066

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Example data, indicate where you set the use of the style (there is no indication in your code) so we can attempt to replicate the issue.

 

Any log messages from your run might be useful as well.

 

 

Occasional Contributor Jud
Occasional Contributor
Posts: 5

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Hello All,

 

First of all, thank you for taking the time to help me diagnose.  I have created a little self contained program that demonstrates my issue.

 

%let _col1=#bb0000;
%let _col2=#0000bb;
%let _col3=#00bb00;
%let _contrast=#ffffff;

proc template;
   define style styles.mypatterns;
   parent=styles.journal2;

      style GraphBar from GraphComponent /                                 
         displayopts = "fill outline fillpattern";  

      style GraphData1 from GraphComponent  /                                      
            fillpattern = "L2"
            color=&_col1                                                 
            contrastcolor=&_contrast.;                                                  
      style GraphData2 from GraphComponent  /                                      
            fillpattern = "R2"
            color=&_col1                                                 
            contrastcolor=&_contrast.;                                                  
      style GraphData3 from GraphComponent  /                                      
            fillpattern = "X2"
            color=&_col1                                                 
            contrastcolor=&_contrast.;                                                  
      style GraphData4 from GraphComponent /                                      
            fillpattern = "L5"
            color=&_col2                                                 
            contrastcolor=&_contrast.;                                                  
      style GraphData5 from GraphComponent /                                      
            fillpattern = "X5"
            color=&_col3                                                 
            contrastcolor=&_contrast.;                                                  
      end;
run;

data attr;        			
   retain ID 'a' Show 'AttrMap' ;
   input value;     			
   LineStyle        = cats('GraphData', value); 		
   MarkerStyle      = linestyle;           	 	
   FillStyle        = linestyle;
   TextStyleElement = linestyle;
   datalines;
1
2
3
4
5
run;

data x;        			
   input grp pat val;     			
   datalines;
1 1 4
1 2 6
1 3 7
2 4 5
2 5 8
3 6 6
3 7 9
3 8 10
4 9 12
4 10 13
5 11 1
5 12 3
run;

data y;        			
   input grp pat val;     			
   datalines;
1 1 4
1 2 6
1 3 7
2 4 5
2 5 8
3 6 6
3 7 9
3 8 10
5 11 1
5 12 3
run;

options orientation=landscape;
ods listing close;
ods noresults;
ods graphics on / height=6in width=9in noborder;
ods rtf file="wf_x.rtf" style=mypatterns nogtitle nogfootnote;

title "graph with all groups represented in data";

proc sgplot data=x dattrmap=attr nocycleattrs;
	vbar pat / group=grp response=val attrid=a name="vbar";
run;

title "graph with group 4 missing";

proc sgplot data=y dattrmap=attr nocycleattrs;
	vbar pat / group=grp response=val attrid=a name="vbar";
run;

ods rtf close;
ods listing;

 

You will see that the first bar graph uses the colors and patterns as defined in the template.  However, if one of the groups is removed (group 4 in the example), the color green from the graphdata5 style remains on group 5, but the pattern from the graphdata4 style gets applied to group 5 and group 4 gets no pattern in the legend.  It appears that the attribute map can map the color, but not the fillpattern.  Output in rtf attached.

 

Thanks again!

 

 

 

 

Super User
Posts: 13,066

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

I think I would suggest contacting tech support on this. I suspect that since the DATTRMAP data set does not support FILLPATTERN and since FILLPATTERN is apparently only usable with the Journal Styles and derivatives that the pattern part is not interpreted correctly.

 

The missing legend/color issue would be associated with not having a SHOW parameter in attribute set. SHOW defaults to "data" which only displays elements in the legend with data. Add SHOW='ATTRMAP" to the attribute set to force all the defined attributes to appear. But this still has an issue with the pattern element not used correctly though it will show the color block for value 4, hence my suggestion to contact tech support.

I notice that the documentation for the GRAPHBAR style element and DISPLAYOPTS does not show "fillpattern" as one of the possible values.

 

For what it's worth, your example did not require an entire different data set. You could do the "without 4" graph using Data=x (where=(grp ne 4)) as a data step option or add a where statement to the body of the procedure: where grp ne 4;

 

 

Occasional Contributor Jud
Occasional Contributor
Posts: 5

Re: Controlling Grouped Fill Patterns, Colors and Legend Order in waterfall plot.

Thank you very much for the help!  

 

1. Show is defaulted to "attrmap" in the retain statement.  if i default it to "data" or blank, the 4 dissappears from the legend but the group 5 still has the graphdata4 fillpattern.

data attr;        			
   retain ID 'a' Show 'AttrMap' ;
   input value;     			
   LineStyle        = cats('GraphData', value); 		
   MarkerStyle      = linestyle;           	 	
   FillStyle        = linestyle;
   TextStyleElement = linestyle;
   datalines;
1
2
3
4
5
run;

2. Good point on the second (y) data step!

 

Thanks again!

Ask a Question
Discussion stats
  • 8 replies
  • 220 views
  • 3 likes
  • 3 in conversation