HBar with Data Labels


A common request on the communities page is to place data labels on horizontal bar charts.  Often users want to display stacked horizontal bar charts, with the values displayed for each segment and the overall value of the bar itself as shown in the example below.

In this example, the graph displays the summarized values for actual sales by country and product as a stacked horizontal bar chart.  There are multiple observations in the data set or each combination of country and product, so the values for each bar segment is also aggregated.

Prior to SAS 9.40M3, one would do this by summarizing the actual sales using the MEANS procedure with country and product as class variables.  Then, one can use a stacked VBARPARM to display the bars by country and product with the overall bar value at the top.  Then, we can use a SCATTER plot with MARKERCHAR to overlay the segment values in the middle of each segment.  This is needed because you cannot layer a SCATTER plot on a HBAR, and you need to know the position where the text has to be layered.

With SAS 9.4M3, the HBAR statement supports the SEGLABEL option that automatically displays the summarized value for each segment.  So, for the graph shown above, there is no need to first use the PROC MEANS step.  The HBAR statemene does all the work for us.  The program for the graph is shown below.

title 'Product Sales by Country';
proc sgplot data=sashelp.prdsale noborder;
    format actual dollar8.0;
    hbar country / response=actual group=product displaybaseline=auto barwidth=0.6
            seglabel datalabel dataskin=pressed;
    yaxis display=(noline noticks nolabel);
    xaxis display=(noline noticks nolabel) grid;
    keylegend / location=outside position=top fillheight=10 fillaspect=2 ;

Note the following options used in the program above:

  • SEGLABEL option is used to display the values for each segment.
  • DATALABEL option is used to display the value for the full bar.
  • DISPLAYBASELINT=AUTO option is used to only display the baseline if necessary.
  • FILLHEIGHT and FILLASPECT options are used in the KEYLEGEND to shape the color swatches.

Stacking order for the group values can be reversed by setting GROUPORDER=ReverseData as shown in the graph below.  We have also set a fill transparency so the segment labels show up better.  Note, the order of the fill color swatches in the legend is also changed.

Finally, let us also discuss a new value for the option DATALABELFITPOLICY=InsidePreferrd released with SAS 9.4M5.  For a non-grouped horizontal bar chart, users expressed a desire to be able to place the data labels inside or outside a horizontal bar.  This is especially useful when the data label is not necessarily the value of the bar, but some other text string from another column in the data.  When data labels are long, this can save space, and for shorter bars, the labels can be placed outside as shown in the graph below.

For this graph, I generated some random response values and random text strings as shown in the program in the link below.  CATEGORYORDER=respdesc is used to get a graph with descending response values.  Here is the SGPLOT program.

title 'Actual Values by Name with Data Labels';
proc sgplot data=bars noborder noautolegend;
    hbar name / response=actual nostatlabel dataskin=pressed displaybaseline=auto
           datalabel=name datalabelattrs=(weight=bold) datalabelfitpolicy=insidepreferred
    yaxis display=none;
    xaxis offsetmin=0 display=(nolabel noline noticks) grid;

SGPLOT program:  SG_Survival_Plot


About Author

Sanjay Matange

Director, R&D

Sanjay Matange is R&D Director in the Data Visualization Division responsible for the development and support of the ODS Graphics system, including the Graph Template Language (GTL), Statistical Graphics (SG) procedures, ODS Graphics Designer and related software. Sanjay has co-authored a book on SG Procedures with SAS/PRESS.


  1. Rick Wicklin

    I like the new DATALABELFITPOLICY=InsidePreferrd option! In your example, you used the GROUPORDER=ReverseData option to reverse the order of the bars. Another option is to use the new SORTORDER=ReverseAuto option on the KEYLEGEND statement (requires SAS 9.4M5).

    If you have many categories (30 or more), a bar chart can get cluttered. If the categories are ordered (for example, years), you can switch to a stacked BAND plot.

    • Sanjay Matange
      Sanjay Matange on

      Thanks, Rick. While you can use the SORTORDER option in the KEYLEGEND, it is not needed for the horizontal legend as reversing the group correctly reverses the items in the legend so they stay in sync. For vertical stacked plot, one needs the SORTORDER option to make the stack in the legend be in the same order as the stacked groups, if you use a vertical legend.

  2. Sanjay:

    In this example, if I also calculated the percentage of total sales and put them in a column called "PctOfTotal", can I display the summarized % outside the bar ? For example, assume that Canada has 35% of sales, Germany has 34%, and USA has 31%. I put "datalabel=PctOfTotal" in my code but found SAS just ignored it without any error message or warnings, and still printed the total sales for each country in the end of bar.

    Is it possible to print summarized percentage numbers instead of sales for each country?



    • Sanjay Matange
      Sanjay Matange on

      Yes. You can use DATALABEL option to display the summarized value for the bar response at the top of the bar. Additionally, you can use an AXISTABLE to display other values at the top of the graph from another column(s). OR, you could use the SEGLABEL to display the computed value per bar and group (OK if you don't have groups) inside the bar and then use DATALABEL=column to display values from another column at the top of the bar.

Leave A Reply

Back to Top