BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
MFraga
Quartz | Level 8
/*
Dear all,
I am trying to create a VBARPARM graph in which I can customize several of its elements,
as you can see in the syntax below. This is a graph that needs to be updated every year.
Therefore, the objective is to create a program that allows me to build this graph while
reducing the need for manual code manipulation as much as possible.
 
The customizations I want to apply (and so far, I have not been able to find a solution)
are the following:
 
- Set the bar corresponding to region = "World" to the color orange, and set the bars
  of all other regions to the color green.
 
- Display the revenue values by region inside all bars, with the text oriented vertically.
 
- Display the revenue values in black for all regions, except for region = "World",
  whose revenue value should be displayed in blue.
 
- Display the region name "World" below the corresponding bar in bold. In other words,
  I want to automatically draw the reader's attention to WORLD by showing the label in
  bold. Ideally, this should be done without using SGANNO, because the reference region
  may change its relative value from one year to another and therefore may change its
  position in the graph.
 
 
Would anyone be able to suggest how to address this issues?
Up to now, the progress I have made is reflected in the syntax below.
As shown, there are still some problems that I have not been able
to identify the source of.
*/
 
/*
An example of the graph that I am trying to reproduce is in the word file attached.
*/
 
 
/* ========================================================= */
/* Input data                                                 */
/* ========================================================= */
data have;
    input region_code region $ 3-16 income year;
datalines;
0  North America 50432 2024
1  South America 43713 2024
2  Asia          56297 2024
3  Europe        49000 2024
4  Africa        48383 2024
5  Oceania       38765 2024
99 World         47765 2024
;
run;
 
 
/* ========================================================= */
/* Sort regions according to the order of interest            */
/* (here: descending income)                                  */
/* ========================================================= */
proc sort data=have out=ord;
    by descending income; 
run;
 
 
/* ========================================================= */
/* Create an index variable to preserve the sorted order      */
/* ========================================================= */
data ord;
    set ord;
    index = _N_;   /* Create an index variable reflecting the ranking */
run;
 
 
/* ========================================================= */
/* Format region labels to control line breaks on the graph   */
/* ========================================================= */
proc format;
    value $region_fmt
        'North America' = 'North#America'
        'South America' = 'South#America'
        'Asia'          = 'Asia'
        'Europe'        = 'Europe'
        'Africa'        = 'Africa'
        'Oceania'       = 'Oceania'
        'World'         = 'World';
run;
 
 
/* ========================================================= */
/* Macro to place regions in the desired order on the graph   */
/* based on the previously created index variable             */
/* ========================================================= */
%macro ordre;
%do ordre_index = 1 %to 7;
    if index = &ordre_index. then do;
        region_&ordre_index. = region;
        format region_&ordre_index. $region_fmt.;
    end;
%end;
%mend;
 
 
/* ========================================================= */
/* Build the final graph dataset                               */
/* - Applies the region ordering                               */
/* - Identifies the position of "World" to allow special      */
/*   formatting later (bold/highlight)                         */
/* ========================================================= */
data graph;
    set ord;
 
    %ordre
 
    /* Store the ranking position of World in a macro variable */
    if region_code = 99 then call symputx("num_bold", index);
 
    /* Helper variable for text annotation positioning */
    yposition = 0;
 
    /* Format income values */
    format income NLNUM8.;
run;
 
%put &=num_bold;
 
 
/* ========================================================= */
/* Discrete attribute map definition                           */
/* - Controls bar colors and text attributes by region_code    */
/* - World (code 99) receives special formatting               */
/* ========================================================= */
data my_dattrmap;
    length 
        id          $10 
        value       $10
        fillcolor   $10
        filltransparency $10
        textfamily  $40 
        textsize    $10 
        textcolor   $10 
        textstyle   $10 
        textweight  $10;
 
    /* Default attributes for all regions (codes 1 to 7) */
    do i = 1 to 7;
        id    = "code_text";
        value = strip(put(i, best.));
 
        fillcolor          = "green";
        filltransparency   = 0;
 
        textfamily = "Arial Symbol";
        textsize   = 10;
        textcolor  = "black";
        textstyle  = "Normal";
        textweight = "Normal";
        output;
    end;
 
    /* Special attributes for World (code 99) */
    id    = "code_text";
    value = "99";
 
    fillcolor        = "orange";
    filltransparency = 0;
 
    textfamily = "Arial Symbol";
    textsize   = 10;
    textcolor  = "blue";
    textstyle  = "Normal";
    textweight = "Bold";
    output;
 
    drop i;
run;
 
 
/* ========================================================= */
/* Macro to generate one VBARPARM statement per ordered region */
/* - GROUP=region_code activates the discrete attribute map    */
/* ========================================================= */
%macro vbarparm_region;
%do num = 1 %to 7;
    vbarparm
        category = region_&num.
        response = income
/
        group    = region_code
        attrid   = code_text
        barwidth = 0.8
        baselineattrs = (thickness = 0pt)
        dataskin = none
        nooutline;
%end;
%mend;
 
 
/* ========================================================= */
/* SG annotation: draw a dollar symbol next to the axis        */
/* ========================================================= */
data sganno_graph;
    length function $12 label $1;
    retain drawspace "graphpercent";
 
    function = "text"; 
    label    = "$"; 
    rotate   = 0;        /* Keep text horizontal */
    x1       = 3;        /* Horizontal position in percent of graph */
    y1       = 90;       /* Vertical position in percent of graph */
 
    textfamily = "Arial Symbol";
    textstyle  = "Normal";
    textweight = "Normal";  
    textcolor  = "black";
    textsize   = 10;
    output;
run;
 

/* ========================================================= */
/* Enable full attribute control                               */
/* ========================================================= */
ods graphics / attrpriority=none;
 
 
/* Clear existing titles and footnotes */
title;
footnote;
 
 
/* ========================================================= */
/* Create the bar chart                                       */
/* ========================================================= */
proc sgplot data=graph
    dattrmap = my_dattrmap
    sganno   = sganno_graph
    noautolegend
    noborder;
 
    %vbarparm_region
 
    /* X-axis configuration */
    xaxis
display=(nolabel)
        tickstyle = inbetween
        fitpolicy = split
        splitchar = '#';
 
    /* Y-axis configuration */
    yaxis
        values = (30000 to 60000 by 2000)
        display = (nolabel noline)
        valueattrs = (family = 'Arial Symbol')
        valueshint
        valuesformat = $region_axis_fmt.;
 
    /* Display income values as vertical text above bars */
    text x=region y=yposition text=income / 
        attrid    = code_text
        position  = top
        backlight = 0
        rotate    = 90;
run;
 
 
 
1 ACCEPTED SOLUTION

Accepted Solutions
MarciaS
SAS Employee

Hi @MFraga 

You can use the code below as a starter for your graph. It uses an attribute map to change the color for the bars and the text within the bars. An XAXISTABLE statement is used with an attribute map to change the font weight for the World region. 

I hope this helps. 

Regards,
Marcia

/* ========================================================= */
/* Input data                                                 */
/* ========================================================= */
data have;
    input region_code region $ 3-16 income year;
	/* create duplicate region variable for axistable attribute map */
	regionlbl=region;
	/* define the location for the bar label */
	label_loc=0;
datalines;
0  North America 50432 2024
1  South America 43713 2024
2  Asia          56297 2024
3  Europe        49000 2024
4  Africa        48383 2024
5  Oceania       38765 2024
99 World         47765 2024
;
run;
 
 
/* ========================================================= */
/* Sort regions according to the order of interest            */
/* (here: descending income)                                  */
/* ========================================================= */
proc sort data=have out=ord;
    by descending income; 
run;
proc format;
    value $region_fmt
        'North America' = 'North#America'
        'South America' = 'South#America'
        'Asia'          = 'Asia'
        'Europe'        = 'Europe'
        'Africa'        = 'Africa'
        'Oceania'       = 'Oceania'
        'World'         = 'World';
run;
/* attribute map for bar chart and text plot */
data attrmap;
  set ord;
  length textcolor $9 fillcolor textweight $6;
  id='code_text';
  value=region;

  if region_code=99 then do;
    fillcolor='orange';
	textcolor='blue';
  end;
  else do;
    fillcolor='green';
	textcolor='black';
  end;
  textfamily = "Arial Symbol";
  textsize   = 10;
  textstyle  = "Normal";
  textweight = "Bold";
run;
/* attribute map for axis table */
data attrmap2;
  id="region";
  length textcolor $9 textweight $6;
  set ord;
  value=region;
  textcolor='black';
  if region_code=99 then textweight="bold";
  else textweight='normal';
run;
data allattr;
  set attrmap attrmap2;
run;
ods graphics / attrpriority=none;
proc sgplot data=ord dattrmap=allattr noautolegend noborder;
vbarparm
        category = region
        response = income
        /
        group    = region
        attrid   = code_text
        barwidth = 0.8
        baselineattrs = (thickness = 0pt)
        dataskin = none
        nooutline;
    /* Display income values as vertical text above bars */
    text x=region y=label_loc text=income / group=region
        attrid    = code_text  
        position  = right 
        textattrs=(size=10)
        rotate    = 90;
	xaxistable regionlbl / textgroup=regionlbl textgroupid=region nolabel valueattrs=(size=10);
		    /* X-axis configuration */
    xaxis discreteorder=data
        display=(nolabel novalues)
        tickstyle = inbetween
        fitpolicy = split
        splitchar = '#';
 
    /* Y-axis configuration */
    yaxis
        values = (30000 to 60000 by 2000)
        display = (nolabel noline)
        valueattrs = (family = 'Arial Symbol')
        valueshint
        valuesformat = $region_axis_fmt.
        offsetmin=0;
 
	run;

View solution in original post

2 REPLIES 2
MarciaS
SAS Employee

Hi @MFraga 

You can use the code below as a starter for your graph. It uses an attribute map to change the color for the bars and the text within the bars. An XAXISTABLE statement is used with an attribute map to change the font weight for the World region. 

I hope this helps. 

Regards,
Marcia

/* ========================================================= */
/* Input data                                                 */
/* ========================================================= */
data have;
    input region_code region $ 3-16 income year;
	/* create duplicate region variable for axistable attribute map */
	regionlbl=region;
	/* define the location for the bar label */
	label_loc=0;
datalines;
0  North America 50432 2024
1  South America 43713 2024
2  Asia          56297 2024
3  Europe        49000 2024
4  Africa        48383 2024
5  Oceania       38765 2024
99 World         47765 2024
;
run;
 
 
/* ========================================================= */
/* Sort regions according to the order of interest            */
/* (here: descending income)                                  */
/* ========================================================= */
proc sort data=have out=ord;
    by descending income; 
run;
proc format;
    value $region_fmt
        'North America' = 'North#America'
        'South America' = 'South#America'
        'Asia'          = 'Asia'
        'Europe'        = 'Europe'
        'Africa'        = 'Africa'
        'Oceania'       = 'Oceania'
        'World'         = 'World';
run;
/* attribute map for bar chart and text plot */
data attrmap;
  set ord;
  length textcolor $9 fillcolor textweight $6;
  id='code_text';
  value=region;

  if region_code=99 then do;
    fillcolor='orange';
	textcolor='blue';
  end;
  else do;
    fillcolor='green';
	textcolor='black';
  end;
  textfamily = "Arial Symbol";
  textsize   = 10;
  textstyle  = "Normal";
  textweight = "Bold";
run;
/* attribute map for axis table */
data attrmap2;
  id="region";
  length textcolor $9 textweight $6;
  set ord;
  value=region;
  textcolor='black';
  if region_code=99 then textweight="bold";
  else textweight='normal';
run;
data allattr;
  set attrmap attrmap2;
run;
ods graphics / attrpriority=none;
proc sgplot data=ord dattrmap=allattr noautolegend noborder;
vbarparm
        category = region
        response = income
        /
        group    = region
        attrid   = code_text
        barwidth = 0.8
        baselineattrs = (thickness = 0pt)
        dataskin = none
        nooutline;
    /* Display income values as vertical text above bars */
    text x=region y=label_loc text=income / group=region
        attrid    = code_text  
        position  = right 
        textattrs=(size=10)
        rotate    = 90;
	xaxistable regionlbl / textgroup=regionlbl textgroupid=region nolabel valueattrs=(size=10);
		    /* X-axis configuration */
    xaxis discreteorder=data
        display=(nolabel novalues)
        tickstyle = inbetween
        fitpolicy = split
        splitchar = '#';
 
    /* Y-axis configuration */
    yaxis
        values = (30000 to 60000 by 2000)
        display = (nolabel noline)
        valueattrs = (family = 'Arial Symbol')
        valueshint
        valuesformat = $region_axis_fmt.
        offsetmin=0;
 
	run;
MFraga
Quartz | Level 8

Dear @MarciaS , 

Thank you very much for the suggestion regarding the use of the XAXISTABLE.
 
Best !

Catch up on SAS Innovate 2026

Dive into keynotes, announcements and breakthroughs on demand.

Explore 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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 2 replies
  • 198 views
  • 1 like
  • 2 in conversation