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

Hi,

I am creating a stack bar plot using PROC TEMPLATE and SGRENDER.

However, I noticed that the legend values are in the alphabetical order, while I would like them to be in a the 'natural" order.

I.e., White, Black, Other not White, Other, Black OR Black, Other, White.

Basically, is there a way to control the values of the legend?

I tried using numeric values associated with my race group, but then I don't want to display 1,2,3 in the legend.

When I format the 1,2,3 to represent White, Black, Other...the legend values are once again alphabetized.

Thank you!

data clusterbarstack;

    length cluster $9 stack $5;

    input year cluster $ stack $ pct num_stack;

    label pct="Patients (%)";

datalines;

2010 A White 90 1

2010 A Black 8 2

2010 A Other 2 3

2010 B White 85 1

2010 B Black 15 2

2010 B Other 0 3

2010 C White 50 1

2010 C Black 45 2

2010 C Other 5 3

2011 A White 92 1

2011 A Black 7 2

2011 A Other 1 3

2011 B White 85 1

2011 B Black 12 2

2011 B Other 3 3

2011 C White 51 1

2011 C Black 40 2

2011 C Other 9 3

;

run;

proc template;

  define statgraph delete;

  DYNAMIC _WIDTH _HEIGHT

            _XAXIS _YAXIS _CLUSTER _STACK

            _YSTART _YEND _YINC _XSTART _XEND _XINC _YFMT _XFMT _YLO _YHI _XLO _XHI;

    begingraph / designwidth=_WIDTH designheight=_HEIGHT;

      layout gridded;

        layout datalattice columnvar=_XAXIS / headerlabeldisplay=value columnheaders=bottom border=false

                                              columngutter=14

                                              rowaxisopts=(offsetmin=0 offsetmax=0 display=(ticks tickvalues label) displaysecondary=none)

                                               row2axisopts=(offsetmin=0 offsetmax=0 display=none)

                                               columnaxisopts=(display=(line ticks tickvalues));

               layout prototype / cycleattrs=true walldisplay=none;

                barchart x=_CLUSTER y=_YAXIS / name="leg" group=_STACK GROUPORDER = deSCENDING ;

            endlayout;

        endlayout;

        discretelegend "leg" /location=outside /*VALIGN = BOTTOM;**/ across=1 halign=right valign=top opaque=true border=false sortorder=ASCENDINGFORMATTED

;

       endlayout;

     endgraph;

  end;

run;

proc sgrender data=clusterbarstack template=delete;

    DYNAMIC _WIDTH="2400px" _HEIGHT="1200px"

            _XAXIS="year" _YAXIS="pct" _CLUSTER="cluster"

/*            _STACK="stack";*/

            _STACK="num_stack";

run;

proc format;

    value race 1 = "White" 2 = "Black" 3 = "Other";

run;

*apply format;

proc sgrender data=clusterbarstack template=delete;

    DYNAMIC _WIDTH="2400px" _HEIGHT="1200px"

            _XAXIS="year" _YAXIS="pct" _CLUSTER="cluster"

/*            _STACK="stack";*/

            _STACK="num_stack";

            format num_stack race.;

run;

1 ACCEPTED SOLUTION

Accepted Solutions
Adie_efc
Calcite | Level 5

I did this using attrmap as I had a character variable and wanted a specific order. code snippet below.


  discreteattrmap name="colorbysign" / ignorecase=true;

value "PD " /
    fillattrs=GraphData1(color=red )
       markerattrs=GraphData1(color=red )
       lineattrs=GraphData1(color=red );;

    value "SD " /
    fillattrs=GraphData1(color=blue )
       markerattrs=GraphData1(color=blue )
       lineattrs=GraphData1(color=blue );  ; 

    value "PR " /
    fillattrs=GraphData1(color=orange )
       markerattrs=GraphData1(color=orange )
       lineattrs=GraphData1(color=orange ); ;

    value "CR " /
    fillattrs=GraphData1(color=green )
       markerattrs=GraphData1(color=green  )
       lineattrs=GraphData1(color=green );;

    value "NE " /
    fillattrs=GraphData1(color=grey )
       markerattrs=GraphData1(color=grey )
       lineattrs=GraphData1(color=grey ); ;  

  enddiscreteattrmap;

    legenditem type=line name="PD" / LABEL='PD' lineattrs=GraphData1(color=red THICKNESS=10)
                   labelattrs=(size=9 family="Arial") ;
    legenditem type=line name="SD" / LABEL='SD' lineattrs=GraphData1(color=blue THICKNESS=10)
          labelattrs=(size=9 family="Arial");;
    legenditem type=line name="PR" / LABEL='PR' lineattrs=GraphData1(color=orange THICKNESS=10)
             labelattrs=(size=9 family="Arial")     ;
    legenditem type=line name="CR" / LABEL='CR' lineattrs=GraphData1(color=green THICKNESS=10)
          labelattrs=(size=9 family="Arial");;
    legenditem type=line name="NE" / LABEL='NE' lineattrs=GraphData1(color=grey THICKNESS=10)
          labelattrs=(size=9 family="Arial");;

discreteattrvar attrvar=signvar var=_var attrmap="colorbysign"; 

      discretelegend "PD" "SD" "PR" "CR" "NE" / title=_label titleattrs=(size=9 family="Arial") BORDER=false;

View solution in original post

14 REPLIES 14
ballardw
Super User

Some example data would help. Also which version of SAS as the capabilities in SG graphics have changed in each recent release? If you're running a SAS 9.2 and get solutions requiring SAS 9.4 it will likely not help.

AncaTilea
Pyrite | Level 9

There is example data, right after I wrote thank you..

I am using SAS 9.3

Anca

Jay54
Meteorite | Level 14

Normally, legend items are in the order reported by each plot.  However, as you have set SORTORDER on the DiscreteLegend, the entries will be in the order you have set.

AncaTilea
Pyrite | Level 9

Understood,

however, with or without the SORTORDER option, the legend values can only be ORDERED based on the alphabetic values - descending or ascending.

Can one modified the values of the legend to be in some very specific order - once again, not alphabetically.

Anca

ballardw
Super User

A dirty version would be to create a numeric variable with values in the order you want AND a custom format for the text. Most of these procedures will use the order of the value but display the formatted value unless you specify to sort by the formatted value.

AncaTilea
Pyrite | Level 9

I am doing that,

but unless I apply a format like this:

proc format;

    value race 1 = "1.White" 2 = "2.Black" 3 = "3.Other";

run;

where I sneak a digit for my preferred format.

So, bottom line is that the values cannot be ordered specifically.

Anca.

DanH_sas
SAS Super FREQ

If you set GROUPORDER=DATA on the BARCHART and remove the sort order on the legend, you should get the legend in natural order.

Jay54
Meteorite | Level 14

Plots will normally report group values in the order they are encountered in the data.  So, if you put them in the order you want, that should be the order in the legend.  There is no way to request a custom order in the legend.  Only alphabetical sorts are supported by sortorder.  Using attr maps or index, you can put groups in your order, and still get the colors you want.

AncaTilea
Pyrite | Level 9

Sanjay,

I was afraid I may have to use the attr maps - which I used once for a very specific example.

Do you think you could provide some example code?

Thank you.

Anca.

Jay54
Meteorite | Level 14

Anca, sometimes, i put dummy observations with the group values in the order i want at the front of the data with missing values for other columns.  This ensures the groups I want are in the data in the order I want.  The missing values ensures the obs are not drawn.  This is also a good way to get all group values into the legend even when some of them may not be in the data today.

Adie_efc
Calcite | Level 5

I did this using attrmap as I had a character variable and wanted a specific order. code snippet below.


  discreteattrmap name="colorbysign" / ignorecase=true;

value "PD " /
    fillattrs=GraphData1(color=red )
       markerattrs=GraphData1(color=red )
       lineattrs=GraphData1(color=red );;

    value "SD " /
    fillattrs=GraphData1(color=blue )
       markerattrs=GraphData1(color=blue )
       lineattrs=GraphData1(color=blue );  ; 

    value "PR " /
    fillattrs=GraphData1(color=orange )
       markerattrs=GraphData1(color=orange )
       lineattrs=GraphData1(color=orange ); ;

    value "CR " /
    fillattrs=GraphData1(color=green )
       markerattrs=GraphData1(color=green  )
       lineattrs=GraphData1(color=green );;

    value "NE " /
    fillattrs=GraphData1(color=grey )
       markerattrs=GraphData1(color=grey )
       lineattrs=GraphData1(color=grey ); ;  

  enddiscreteattrmap;

    legenditem type=line name="PD" / LABEL='PD' lineattrs=GraphData1(color=red THICKNESS=10)
                   labelattrs=(size=9 family="Arial") ;
    legenditem type=line name="SD" / LABEL='SD' lineattrs=GraphData1(color=blue THICKNESS=10)
          labelattrs=(size=9 family="Arial");;
    legenditem type=line name="PR" / LABEL='PR' lineattrs=GraphData1(color=orange THICKNESS=10)
             labelattrs=(size=9 family="Arial")     ;
    legenditem type=line name="CR" / LABEL='CR' lineattrs=GraphData1(color=green THICKNESS=10)
          labelattrs=(size=9 family="Arial");;
    legenditem type=line name="NE" / LABEL='NE' lineattrs=GraphData1(color=grey THICKNESS=10)
          labelattrs=(size=9 family="Arial");;

discreteattrvar attrvar=signvar var=_var attrmap="colorbysign"; 

      discretelegend "PD" "SD" "PR" "CR" "NE" / title=_label titleattrs=(size=9 family="Arial") BORDER=false;

AncaTilea
Pyrite | Level 9

PERFECTION!

THANK YOU!

Jay54
Meteorite | Level 14

Note:  With SAS 9.4M1 onwards, GTL and SGRENDER also support Data Set Attribute Maps, just like SG.  Now, you can define common attribute maps outside your template, and use them with any template without having to change the template itself by using the DATTRMAP option on the SGRENDER proc statement and the new DATTRVAR statement.  See example in blog article:  Group order in GTL - Graphically Speaking

AncaTilea
Pyrite | Level 9

Thanks Sanjay!

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
  • 14 replies
  • 4053 views
  • 3 likes
  • 5 in conversation