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

My apologies if this is already answered...I had a heck of a time trying to figure out what to search on!

 

I'm replicating a bar chart design for a client, with lengths and widths set. The client will be passing the contents of the text strings (headers, legend entries, etc.)

 

What I would like is a way to assess how long a given text string formatted with a particular font and size will be rendered. Answers to either of these questions would work for me:

 

Is the length of "Some text string" rendered in size 10 Arial less than one and three quarters inches?

 

How long will "Some text string" be on the screen when it is rendered in size 10 Arial?

 

Thanks for your help,

   Tom

 

1 ACCEPTED SOLUTION

Accepted Solutions
Jay54
Meteorite | Level 14

The GTL TEXTPLOT statement has a preproduction feature that will do exactly what you want.  See the OUTFILE and OUTID options which will output the size of the rendered text box for each string to the outfile by id.  This was alluded to in this blog article:  

 

https://blogs.sas.com/content/graphicallyspeaking/2014/08/29/new-graphics-features-in-sas-9-4m2-part...

 

GTL doc:  https://documentation.sas.com/?docsetId=grstatgraph&docsetTarget=n1nkiqzk2cqi1cn15phrkiop1j6t.htm&do...

 

That said, it is not clear exactly what you want to do.  There may be other ways for you to get what you want using the builtin features of the TEXTPLOT or AXISTABLE.

 

 

 

View solution in original post

4 REPLIES 4
JosvanderVelden
SAS Super FREQ
I don't know if it can be done with sas.
You could try to do it using python (pillow in python 3). Some sample code:
from PIL import ImageFont
font = ImageFont.truetype('times.ttf', 12)
size = font.getsize('Hello world')
print(size)
Jay54
Meteorite | Level 14

The GTL TEXTPLOT statement has a preproduction feature that will do exactly what you want.  See the OUTFILE and OUTID options which will output the size of the rendered text box for each string to the outfile by id.  This was alluded to in this blog article:  

 

https://blogs.sas.com/content/graphicallyspeaking/2014/08/29/new-graphics-features-in-sas-9-4m2-part...

 

GTL doc:  https://documentation.sas.com/?docsetId=grstatgraph&docsetTarget=n1nkiqzk2cqi1cn15phrkiop1j6t.htm&do...

 

That said, it is not clear exactly what you want to do.  There may be other ways for you to get what you want using the builtin features of the TEXTPLOT or AXISTABLE.

 

 

 

TomKari
Onyx | Level 15
Let me start by saying that this is the first time I've really had to dive deep into the SAS graphics capabilities, and I'm absolutely amazed by how much I've been able to accomplish in such a short time! Hats off to all of the developers!
 
In terms of what I'm trying to do, my client has the bar chart shown below, and wishes to reproduce it exactly (two versions shown, good and bad):
 
Pic.png
The values for the label and for the legend labels are client supplied, we may be doing several hundred of these charts immediately, and we'll want the capability to produce them moving forward. The top one is perfect, but in the second one the label and one of the legend labels is too long, and overflows. I don't want to adjust the chart dimensions either vertically or horizontally to accommodate this issue. A simplified version of the code that I use to create the chart is here.
data Have;
	input Var1 Var2;
	cards;
1 1
1 2
1 3
1 4
2 1
2 2
2 3
2 4
3 1
3 2
3 3
3 4
run;

data AnnoText1;
	%sganno;

	/* Print the heading */
	%sgtext(label="Label for the chart", anchor="center", x1space="graphpercent", y1space="graphpercent", justify="center", textfont="Arial", textweight="bold", textsize=13, x1=50, y1=93, textcolor="black", width=100);
	%sgtext(label="", reset="all");

	/* Print the column headings above the three bars */
	%sgtext(label="V1 Val 1", anchor="center", x1space="datavalue", y1space="graphpercent", justify="center", textfont="Arial", textweight="normal", textsize=10, x1=1, y1=82, textcolor="black", width=33);
	%sgtext(label="V1 Val 2", anchor="center", x1space="datavalue", y1space="graphpercent", justify="center", textfont="Arial", textweight="normal", textsize=10, x1=2, y1=82, textcolor="black", width=33);
	%sgtext(label="V1 Val 3", anchor="center", x1space="datavalue", y1space="graphpercent", justify="center", textfont="Arial", textweight="normal", textsize=10, x1=3, y1=82, textcolor="black", width=33);
	%sgtext(label="", reset="all");

	/* Draw the three gray lines at the top of the bars */
	do _i = 8 to 68 by 30;
		_x2 = _i + 24;

		%sgline(x1=_i, x2=_x2, y1=78, y2=78, drawspace="graphpercent", linecolor="CXD8D8D8");
	end;

	%sgline(x1=0, x2=0, y1=0, y2=0, reset="all");

	/* Draw the circles on the legend */
	%sgoval(x1=18, y1=26, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CXDD5D4E");
	%sgoval(x1=18, y1=26, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(x1=18, y1=20, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CXF7D659");
	%sgoval(x1=18, y1=20, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(x1=18, y1=14, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CX53B0D1");
	%sgoval(x1=18, y1=14, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(x1=18, y1=8, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CX82BA59");
	%sgoval(x1=18, y1=8, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(reset="all");

	/* Print the text on the legend */
	%sgtext(label="Var 2 Value 1", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=26, textcolor="black", width=79);
	%sgtext(label="Var 2 Value 2", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=20, textcolor="black", width=79);
	%sgtext(label="Var 2 Value 3", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=14, textcolor="black", width=79);
	%sgtext(label="Var 2 Value 4", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=8, textcolor="black", width=79);
	%sgtext(label="", reset="all");
run;

data AnnoText2;
	%sganno;

	/* Print the heading */
	%sgtext(label="Label for the chart, but really long so that it fills up more than the space available for it on the chart and causes us a problem", anchor="center", x1space="graphpercent", y1space="graphpercent", justify="center", textfont="Arial", textweight="bold", textsize=13, x1=50, y1=93, textcolor="black", width=100);
	%sgtext(label="", reset="all");

	/* Print the column headings above the three bars */
	%sgtext(label="V1 Val 1", anchor="center", x1space="datavalue", y1space="graphpercent", justify="center", textfont="Arial", textweight="normal", textsize=10, x1=1, y1=82, textcolor="black", width=33);
	%sgtext(label="V1 Val 2", anchor="center", x1space="datavalue", y1space="graphpercent", justify="center", textfont="Arial", textweight="normal", textsize=10, x1=2, y1=82, textcolor="black", width=33);
	%sgtext(label="V1 Val 3", anchor="center", x1space="datavalue", y1space="graphpercent", justify="center", textfont="Arial", textweight="normal", textsize=10, x1=3, y1=82, textcolor="black", width=33);
	%sgtext(label="", reset="all");

	/* Draw the three gray lines at the top of the bars */
	do _i = 8 to 68 by 30;
		_x2 = _i + 24;

		%sgline(x1=_i, x2=_x2, y1=78, y2=78, drawspace="graphpercent", linecolor="CXD8D8D8");
	end;

	%sgline(x1=0, x2=0, y1=0, y2=0, reset="all");

	/* Draw the circles on the legend */
	%sgoval(x1=18, y1=26, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CXDD5D4E");
	%sgoval(x1=18, y1=26, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(x1=18, y1=20, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CXF7D659");
	%sgoval(x1=18, y1=20, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(x1=18, y1=14, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CX53B0D1");
	%sgoval(x1=18, y1=14, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(x1=18, y1=8, height=4, width=4.8484848485, drawspace="graphpercent", display="fill", fillcolor="CX82BA59");
	%sgoval(x1=18, y1=8, height=2.8, width=3.3939393939, drawspace="graphpercent", display="fill", fillcolor="white");
	%sgoval(reset="all");

	/* Print the text on the legend */
	%sgtext(label="Var 2 Value 1", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=26, textcolor="black", width=79);
	%sgtext(label="Var 2 Value 2, really long so that it folds over on top of the Value 3 label and doesn't look good on the chart", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=20, textcolor="black", width=79);
	%sgtext(label="Var 2 Value 3", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=14, textcolor="black", width=79);
	%sgtext(label="Var 2 Value 4", anchor="left", x1space="graphpercent", y1space="graphpercent", justify="left", textfont="Albany AMT", textweight="bold", textsize=11, x1=21, y1=8, textcolor="black", width=79);
	%sgtext(label="", reset="all");
run;

options nodate nonumber;
ods graphics / reset=all;
ods graphics / height=4in width=3.3in outputfmt=png border=off;
ods html path='C:\SAS Tech Support Query';

proc sgplot data=Have noautolegend noborder pad=(top=23pct bottom=33pct) sganno=AnnoText1;
	styleattrs datacolors=(CXDD5D4E CXF7D659 CX53B0D1 CX82BA59);
	vbar Var1 / group=Var2 groupdisplay=stack displaybaseline=off nooutline barwidth=.8;
	xaxis display=none;
	yaxis display=none;
run;

proc sgplot data=Have noautolegend noborder pad=(top=23pct bottom=33pct) sganno=AnnoText2;
	styleattrs datacolors=(CXDD5D4E CXF7D659 CX53B0D1 CX82BA59);
	vbar Var1 / group=Var2 groupdisplay=stack displaybaseline=off nooutline barwidth=.8;
	xaxis display=none;
	yaxis display=none;
run;

ods _all_ close;
My desire was to evaluate these text strings, and determine if any of them would cause a problem prior to producing the chart. Corrective action could then be taken in advance. The options that you mention are absolutely perfect, in that they let me evaluate the length of the text strings taking into account the final formatting. I spent a delightful afternoon noodling around with them, and now my head hurts!
 
One small glitch; if the text field has a comma in it, the csv data isn't being rendered correctly; the text value isn't in quotes.
 
Thanks again for the quick response to this question!
   Tom
Jay54
Meteorite | Level 14

You are using annotation to do a lot of work that the plot statements can do for you.  If you can compute the sum of the stacked segments (proc means), then, you can use other plot statements to position labels, etc.  Here "Res" is the response for each segment, and 'ResTotal" is the height of each stacked bar.  Labels are also added in the data.  I took the easy way out of just setting these values.  For real world cases, I would compute these using proc means and merge the data back in.  You can use TEXT statement to place the labels.  No annotation is needed.  There is no limit to the number of plot layers you can use.  VBarParm is used when overlaying other statements. 

 

Using unfilled shapes for legend items can be an issue as the colors get diluted by all the white pixels.  Using filled items for filled bars is better.  Also more effective if you use any data skins.  You can adjust the shape of the legend items using the options in the KEYLEGEND statement.  Legend could be placed on the right side.  Or, for very long group values, you could trim the group values.

 

Personally, I try to avoid using annotation for display of visual elements inside the data area, since annotation does not automatically work with axes or legends.  Annotation is not scaleable.  Annotation makes more sense for other decoration.  Just my opinion...

 

data Have;
length label $10;
input Var1 Var2 label $5-15;
res=1; restotal=4;
cards;
1 1 V1 Var 1
1 2
1 3
1 4
2 1 V1 Var 2
2 2
2 3
2 4
3 1 V1 Var 3
3 2
3 3
3 4
run;
proc print;run;

 

proc sgplot data=Have noborder;
vbarparm category=Var1 response=res / group=Var2 groupdisplay=stack
                displaybaseline=off nooutline name='bar' dataskin=pressed;
textplot x=var1 y=restotal text=label / position=top textattrs=(size=12);
xaxis display=none;
yaxis display=none;
keylegend 'bar' / fillheight=12 fillaspect=golden;
run;

 

Bar.png

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 4 replies
  • 1731 views
  • 1 like
  • 3 in conversation