# How to get the output width of text?

Posted 1 year ago
1932 Views
|
9 Replies
|
6 Total Likes
|
 I cannot find any function which delivers the output width of formatted text. I need that either in absolute printer points or scaled to the enclosing context or as the number of characters in standard output font size (13 in my environment).As an example I want to use Multicolumn for a list of base-b tuples: Block[{ruler = StringRepeat["1234567890", 7], k, tuples, base, cols}, base = 16; k = 3; tuples = RandomChoice[Tuples[Range[0, base - 1], k], 20]; tuples = BaseForm[#, base] & /@ tuples; cols = 5; Print[ruler, "\ncols = ", cols, "\n", Multicolumn[tuples, cols]]; ]; In this example, I use a fixed number of column cols = 5 which gives a total horizontal width of about 69 standard characters. But of course, this number cols should be dependent on the total horizontal width available and the base-dependent width of each tuple, which in turn is depended on Style-formating. As a bypass, I calculate cols in some rude way by the following code for twidth and cols. It is done twice, without and with formatting: Block[{ruler = StringRepeat["1234567890", 7], k, tuples, base, cols, hwidth = 70, ds = 1, twidth, fs}, (* Build tuples *) base = 16; k = 3; tuples = RandomChoice[Tuples[Range[0, base - 1], k], 20]; tuples = BaseForm[#, base] & /@ tuples; (* Calculate the width of one tupel *) twidth = 2 + k - 1 + k*(1 + Switch[Sign[base - 10], 0, 0, +1, 2.00, -1, 1.0]); (* Calculate the number of columns and print *) cols = Max[Floor[(hwidth + ds)/(twidth + ds)], 1]; Print[ruler, "\n{twidth, cols} = ", {twidth, cols}, "\n", Multicolumn[tuples, cols]]; (* The same for a larger font size fs *) fs = 18; tuples = Style[#, Blue, fs] & /@ tuples; twidth = fs/13*(2 + k - 1 + k*(1 + Switch[Sign[base - 10], 0, 0, +1, 2.00, -1, 1.0])); cols = Max[Floor[(hwidth + ds)/(twidth + ds)], 1]; Print[ruler, "\n{twidth, cols} = ", {twidth, cols}, "\n", Multicolumn[tuples, cols]]; ]; The calculation of twidth above is the crucial point. If I had a WL-function like WidthChr[expr], I could just write: twidth = WidthChr[First[tuples]]; or any other formatted or non-formatted expression instead of tuples. Of course, this could be given as a read-only property as well.
9 Replies
Sort By:
Posted 1 year ago
 Werner,How about something like ImageDimensions[Rasterize[First[tuples]]] This gives the x and y dimensions of the rendered text.Regards,Neil
Posted 1 year ago
 I just noticed that "BoundingBox" is an option to Rasterize: Rasterize[First[tuples],"BoundingBox"] You can call this and convert the units, you may or may not need some additional options to rasterize to set the resolution, etc. but that should be straightforward.
Posted 1 year ago
 Putting it together: charwidth = First[Rasterize["A", "BoundingBox"]] Widthch[str_] := First[Rasterize[str, "BoundingBox"]]/charwidth // N should work for you.
Posted 1 year ago
 Thank you very much, Neil. Your Rasterice, BoundingBox proposal sounds very promising. I will try that.I did not come to the idea of rasterizing the object. It's everything but straightforward. I will post a request at Wolfram for a direct object width possibility.
Posted 1 year ago
 The problem with a "direct width" approach is "what do you mean?" the width in characters does not make sense because there are subscripts involved. If all text were the same size then you can compute the string length. As soon as you get into Mathematica expressions, there is no more connection to strings. In fact, to understand how Mathematica represents your tuples, click on one and hit CMD-Shift-E. you will see the actual internal representation of the expression -- it is not a string by any means. It formats into boxes and then separately renders the boxes for the screen. For example:If your tuple is Then the internal representation is actually: Cell[BoxData[ TagBox[ RowBox[{"{", RowBox[{ InterpretationBox[ SubscriptBox["\<\"f\"\>", "\<\"16\"\>"], 15, Editable->False], ",", InterpretationBox[ SubscriptBox["\<\"3\"\>", "\<\"16\"\>"], 3, Editable->False], ",", InterpretationBox[ SubscriptBox["\<\"0\"\>", "\<\"16\"\>"], 0, Editable->False]}], "}"}], BaseForm[#, 16]& ]], "Output", CellChangeTimes->{3.788545301833375*^9}, CellLabel->"Out[143]//BaseForm="] In summary, I think your only viable approach is to see how the text rasterizes and use that as a length indicator. It will be very accurate and is easy. Besides, isn't that what you actually care about?I still recommend you talk to Wolfram. Maybe they have a different idea.Regards,Neil
Posted 1 year ago
 I've been using the same Rasterized method for several years now, and it works great as long as your units are printers points, as in Graphics. Unfortunately, there is not a direct conversion to ItemSize units for Grid, so I've generally had to use some trial and error conversion each time I'm faced with that.If you get a nice implementation, please consider submitting it to the Wolfram Function Repository.Bob
Posted 1 year ago
 Robert,I am not sure I understand the issue with Grid. Why would the Rasterize technique fail for that? Or are you saying that one you have the size of an item it is hard to use that in ImageSize options?Regards,Neil