☑ This topic is solved.
Need further help from the community? Please
sign in and ask a new question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Posted 08-12-2025 01:06 PM
(795 views)
/*Dear all,
I would like to know how I can assign different font formats
using different attribute maps for the same graph.
In other words, I want to automate the customization of the graph's
attributes so that next year, when I have new data,
it follows the same logic as the program below and I do not
need to manually configure the values using a 'sganno' option
to replace the values for what I want
to replace the values for what I want
(I am not sure whether sganno can follow the same logic as the code below
with updated input data and without requiring manual corrections.
Please, correct me if I am saying something incorrect).*/
/* Here is my data */
data have;
input code region $ 3-16 growth_rate year;
datalines;
0 North America -5.92 2020
0 North America -2.18 2021
0 North America -7.47 2022
0 North America -2.17 2023
0 North America -9.64 2024
1 South America 0.36 2020
1 South America 2.69 2021
1 South America -8.13 2022
1 South America 1.22 2023
1 South America -1.34 2024
2 Asia -1.53 2020
2 Asia 2.18 2021
2 Asia 5.64 2022
2 Asia 6.80 2023
2 Asia 8.70 2024
3 Europe -9.68 2020
3 Europe 3.91 2021
3 Europe 5.48 2022
3 Europe 3.52 2023
3 Europe 3.69 2024
4 Africa 3.29 2020
4 Africa 7.97 2021
4 Africa 2.48 2022
4 Africa 7.36 2023
4 Africa 1.31 2024
5 Oceania 8.00 2020
5 Oceania -6.05 2021
5 Oceania 6.91 2022
5 Oceania -1.09 2023
5 Oceania -7.46 2024
;
run;
/* Here we can see the font formats that are installed on SAS system */
proc qdevide report=font out=fonts;
printer "svg"; /* I want to export the graph in SVG using ODS */
run;
proc print data=fonts;
run;
/* Now that I know which font formats are available, I customize the graph
using a discrete attribute map for fonts and a range attribute map for bar colors.*/
/* First, I want to determine the order in which the values will be displayed */
proc sort data=have(where=(year=2024)) out=temp;
by descending growth_rate ;
run;
data fmt;
set temp(rename=(region=start));
retain fmtname 'fmt' type 'c';
length label $ 80;
label=repeat(' ',_n_)||strip(start);
keep fmtname type start label;
run;
proc format cntlin=fmt;
run;
/* Here, I determine the colors of the hbars*/
data have2;
set have;
_region=put(region,$fmt32.);
if region = "North America" then do;
if year=2020 then color_region=1;
else if year=2021 then color_region=2;
else if year=2022 then color_region=3;
else if year=2023 then color_region=4;
else if year=2024 then color_region=5;
end;
else do;
if year=2020 then color_region=6;
else if year=2021 then color_region=7;
else if year=2022 then color_region=8;
else if year=2023 then color_region=9;
else if year=2024 then color_region=10;
end;
run;
/* Now, I create a discrete attribute map for the font*/
/*I write EXACTLY as they appear in the output table in SAS
with the information about the available fonts
(I am not sure whether uppercase or lowercase letters need to be respected here.
If someone could tell me, it would be great).*/
data my_attrmap;
length id $7 value $15 textfamily $20 textcolor $10 textstyle $10 textweight $10;
/* North America */
id = "fontmap";
value = "North America";
textfamily = "Times New Roman Uni";
textcolor = "red";
textstyle = "Italic";
textweight = "Bold"; output;
/* Oceania */
id = "fontmap";
value = "Oceania";
textfamily = "Arial Symbol";
textcolor = "blue";
textstyle = "Normal";
textweight = "Normal"; output;
/* South America*/
id = "fontmap";
value = "South America";
textfamily = "Arial Symbol";
textcolor = "blue";
textstyle = "Normal";
textweight = "Normal"; output;
/* Africa */
id = "fontmap";
value = "Africa";
textfamily = "Arial Symbol";
textcolor = "blue";
textstyle = "Normal";
textweight = "Normal"; output;
/* Europe */
id = "fontmap";
value = "Europe";
textfamily = "Arial Symbol";
textcolor = "blue";
textstyle = "Normal";
textweight = "Normal"; output;
/* Asia */
id = "fontmap";
value = "Asia";
textfamily = "Arial Symbol";
textcolor = "blue";
textstyle = "Normal";
textweight = "Normal"; output;
run;
/* Now, I create my range attribute map to customize the bar colors */
data my_rattrmap;
retain in "barcolor" altcolor "black";
input min $ max $ color $;
datalines;
1 1 cxf7ebde
2 2 cxefdbc6
3 3 cxe1ca9e
4 4 cxd6ae6b
5 5 cxb4771f
6 6 cxdeebf7
7 7 cxc6dbef
8 8 cx9ecae1
9 9 cx6baed6
10 10 cx1f77b4
;
run;
/*Next, I try to apply different fonts to format the different levels of the '_region'
variable and the values that appear next to each bar by including the option 'datalabelfitpolicy=none'*/
proc sgplot data=have2 dattrmap=my_attrmap rattrmap=my_rattrmap noautolegend;
title "Growth rate";
hbar _region / response=growth_rate group=year colorresponse=color_region attrid=fontmap rattrid=barcolor
groupdisplay=cluster
clusterwidth=0.9
datalabel DATALABELFITPOLICY=NONE
datalabelattrs=(size=8.5pt)
barwidth=1 nooutline
transparency=0 dataskin=none;
xaxis display=(nolabel) min=-12 max=12;
yaxis display=(nolabel) colorbands=even ;
run;
/*SAS displays the graph in the visualization window,
but it does not apply the formatting to the levels of the '_region'
variable as I defined in 'my_attrmap',
and it also shows the error message 'ERROR: The same group variable must be used for summarized plots'.
Does anyone have any idea why this is happening?
Is there a way to configure the graph values without having to manually replace them using sganno? */
/*In summary, I want the name 'North America' to be the only one to use Times New Roman,
be bold and red, and I also want the corresponding 'growth_rate'
values next to the bars for the different 'year' entries displayed for "North America"
in the graph to also use Times New Roman, bold, and red.*/
Thank you in advance for your help!
1 ACCEPTED SOLUTION
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I should clarify that DARRTMAP dataset is applied to " group=year" , is unable to apply to "_region " ,so you can not change style of "_region ".
Anyway a workaround way is using YAXISTABLE statement to mock YAXIS values:
/* Here is my data */
data have;
input code region $ 3-16 growth_rate year;
datalines;
0 North America -5.92 2020
0 North America -2.18 2021
0 North America -7.47 2022
0 North America -2.17 2023
0 North America -9.64 2024
1 South America 0.36 2020
1 South America 2.69 2021
1 South America -8.13 2022
1 South America 1.22 2023
1 South America -1.34 2024
2 Asia -1.53 2020
2 Asia 2.18 2021
2 Asia 5.64 2022
2 Asia 6.80 2023
2 Asia 8.70 2024
3 Europe -9.68 2020
3 Europe 3.91 2021
3 Europe 5.48 2022
3 Europe 3.52 2023
3 Europe 3.69 2024
4 Africa 3.29 2020
4 Africa 7.97 2021
4 Africa 2.48 2022
4 Africa 7.36 2023
4 Africa 1.31 2024
5 Oceania 8.00 2020
5 Oceania -6.05 2021
5 Oceania 6.91 2022
5 Oceania -1.09 2023
5 Oceania -7.46 2024
;
run;
/* First, I want to determine the order in which the values will be displayed */
proc sort data=have(where=(year=2024)) out=temp;
by descending growth_rate ;
run;
data fmt;
set temp(rename=(region=start));
retain fmtname 'fmt' type 'c';
length label $ 80;
label=repeat(' ',_n_)||strip(start);
keep fmtname type start label;
run;
proc format cntlin=fmt;
run;
/* Here, I determine the colors of the hbars*/
data have2;
set have;
_region=put(region,$fmt32.);
run;
/* Now, I create my range attribute map to customize the bar colors */
data dattrmap;
infile cards truncover;
input id $ value $ fillcolor $ textfamily &$40. textcolor $ textstyle $ textweight $;
datalines;
year1 2020 cxf7ebde
year1 2021 cxefdbc6
year1 2022 cxe1ca9e
year1 2023 cxd6ae6b
year1 2024 cxb4771f
year2 2020 cxdeebf7
year2 2021 cxc6dbef
year2 2022 cx9ecae1
year2 2023 cx6baed6
year2 2024 cx1f77b4
code 0 . Times New Roman Uni red Italic Bold
code 1 . Arial blue Normal Normal
code 2 . Arial blue Normal Normal
code 3 . Arial blue Normal Normal
code 4 . Arial blue Normal Normal
code 5 . Arial blue Normal Normal
;
data have3;
set have2;
if strip(_region)="North America" then do;region1=_region;year1=year;end;
else do;region2=_region;year2=year;end;
run;
proc sort data=have3;
by _region year;
run;
/*Next, I try to apply different fonts to format the different levels of the '_region'
variable and the values that appear next to each bar by including the option 'datalabelfitpolicy=none'*/
proc sgplot data=have3 dattrmap=dattrmap noautolegend;
title "Growth rate";
hbarparm category=region1 response=growth_rate /group=year1 attrid=year1
groupdisplay=cluster
clusterwidth=0.9
datalabel DATALABELFITPOLICY=NONE
datalabelattrs=(size=8.5pt family='Times New Roman Uni' color=red style=Italic weight=bold)
barwidth=1 nooutline
transparency=0 dataskin=none;
hbarparm category=region2 response=growth_rate /group=year2 attrid=year2
groupdisplay=cluster
clusterwidth=0.9
datalabel DATALABELFITPOLICY=NONE
datalabelattrs=(size=8.5pt family='Arial' color=blue style=Normal weight=Normal)
barwidth=1 nooutline
transparency=0 dataskin=none;
xaxis display=(nolabel) min=-12 max=12;
yaxis display=(nolabel novalues) colorbands=even ;
yaxistable _region/nolabel y=_region position=left valueattrs=(size=10pt) textgroup=code textgroupid=code;
run;
2 REPLIES 2
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I should clarify that DARRTMAP dataset is applied to " group=year" , is unable to apply to "_region " ,so you can not change style of "_region ".
Anyway a workaround way is using YAXISTABLE statement to mock YAXIS values:
/* Here is my data */
data have;
input code region $ 3-16 growth_rate year;
datalines;
0 North America -5.92 2020
0 North America -2.18 2021
0 North America -7.47 2022
0 North America -2.17 2023
0 North America -9.64 2024
1 South America 0.36 2020
1 South America 2.69 2021
1 South America -8.13 2022
1 South America 1.22 2023
1 South America -1.34 2024
2 Asia -1.53 2020
2 Asia 2.18 2021
2 Asia 5.64 2022
2 Asia 6.80 2023
2 Asia 8.70 2024
3 Europe -9.68 2020
3 Europe 3.91 2021
3 Europe 5.48 2022
3 Europe 3.52 2023
3 Europe 3.69 2024
4 Africa 3.29 2020
4 Africa 7.97 2021
4 Africa 2.48 2022
4 Africa 7.36 2023
4 Africa 1.31 2024
5 Oceania 8.00 2020
5 Oceania -6.05 2021
5 Oceania 6.91 2022
5 Oceania -1.09 2023
5 Oceania -7.46 2024
;
run;
/* First, I want to determine the order in which the values will be displayed */
proc sort data=have(where=(year=2024)) out=temp;
by descending growth_rate ;
run;
data fmt;
set temp(rename=(region=start));
retain fmtname 'fmt' type 'c';
length label $ 80;
label=repeat(' ',_n_)||strip(start);
keep fmtname type start label;
run;
proc format cntlin=fmt;
run;
/* Here, I determine the colors of the hbars*/
data have2;
set have;
_region=put(region,$fmt32.);
run;
/* Now, I create my range attribute map to customize the bar colors */
data dattrmap;
infile cards truncover;
input id $ value $ fillcolor $ textfamily &$40. textcolor $ textstyle $ textweight $;
datalines;
year1 2020 cxf7ebde
year1 2021 cxefdbc6
year1 2022 cxe1ca9e
year1 2023 cxd6ae6b
year1 2024 cxb4771f
year2 2020 cxdeebf7
year2 2021 cxc6dbef
year2 2022 cx9ecae1
year2 2023 cx6baed6
year2 2024 cx1f77b4
code 0 . Times New Roman Uni red Italic Bold
code 1 . Arial blue Normal Normal
code 2 . Arial blue Normal Normal
code 3 . Arial blue Normal Normal
code 4 . Arial blue Normal Normal
code 5 . Arial blue Normal Normal
;
data have3;
set have2;
if strip(_region)="North America" then do;region1=_region;year1=year;end;
else do;region2=_region;year2=year;end;
run;
proc sort data=have3;
by _region year;
run;
/*Next, I try to apply different fonts to format the different levels of the '_region'
variable and the values that appear next to each bar by including the option 'datalabelfitpolicy=none'*/
proc sgplot data=have3 dattrmap=dattrmap noautolegend;
title "Growth rate";
hbarparm category=region1 response=growth_rate /group=year1 attrid=year1
groupdisplay=cluster
clusterwidth=0.9
datalabel DATALABELFITPOLICY=NONE
datalabelattrs=(size=8.5pt family='Times New Roman Uni' color=red style=Italic weight=bold)
barwidth=1 nooutline
transparency=0 dataskin=none;
hbarparm category=region2 response=growth_rate /group=year2 attrid=year2
groupdisplay=cluster
clusterwidth=0.9
datalabel DATALABELFITPOLICY=NONE
datalabelattrs=(size=8.5pt family='Arial' color=blue style=Normal weight=Normal)
barwidth=1 nooutline
transparency=0 dataskin=none;
xaxis display=(nolabel) min=-12 max=12;
yaxis display=(nolabel novalues) colorbands=even ;
yaxistable _region/nolabel y=_region position=left valueattrs=(size=10pt) textgroup=code textgroupid=code;
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thanks a lot @Ksharp . Great solution!