3
$\begingroup$

I am looking for something which acts like Print, preferably with the same syntax, which lets me arrange things in columns of proper width (i.e. if an item in a column is wider than the elements below it, the whole column is made as wide as necessary to represent it).

In order to assign something to the next column, I want to use \t. In order to assign the stuff following to a new row, I want to use \n. I want an option WordWrap to let it word wrap things in a column if the column would become too wide to let the whole output be represented. Another useful option would be Hyphenate. One also needs some options to define the minimum/maximum column width for the particular columns and the maximum width of the whole output.

Since there are already so many practical things im Mma, most probably something of what I have outlined is already present. On the other hand, in there was a similar but less general question, suggesting to use

Print @ Grid[ImportString["a\t55\n33\t44", "Table"], Alignment -> Left]

ImportString however separates columns not only at \t, but also at a space.

Print @ Grid[ImportString["a 55\n33 44", "Table"], Alignment -> Left]

yields the same results as the example above.

Print @ Grid[ImportString["a lengthy string with spaces 55\n33 44", "Table"], Alignment -> Left]

therefore arranges the word lengthy into the same column as 44. Further ImportString strictly requires a string as its first parameter. I would like to use what Print offers.

If there would be some function called PrettyPrint, I would like it to invoke it like Print, e.g.

PrettyPrint["This goes to the first column\tand this to the second one\n"
, "x=", x, "\tx^2=\t", x^2, "\tSquares are easyly computed by hand.\n"
, "x=", x, "\tSqrt[x]=\t",Sqrt[x], "\tSquare roots are more difficult.\n"
, "x=", 2, "\tSqrt[x]=\t",Sqrt[2], "\teasy as a symbol\n"
, "x=", 2., "\tSqrt[x]=\t",Sqrt[2.], "\tendless numerical work."
, WordWrap->True
, Hyphenate->English
, MinColumnWidth->{"1 cm","1 cm","3 cm",Automatic}
, MaxColumnWidth->{"3 cm","3 cm","5 cm",Automatic}
, MaxWidth->"17 cm"
];
$\endgroup$

2 Answers 2

6
$\begingroup$

I am looking for something which acts like Print, preferably with the same syntax...

... ImportString strictly requires a string as its first parameter. I would like to use what Print offers.

You know that Print doesn't have options, because it must print arguments of any type, including options. Hence if you want to handle options, you need either other syntax, or specify options separately.


Here is a quick try on what you seemingly wish to achieve (without options handling):

PrettyPrint[args__] := 
 Print@Module[{tab, newline}, 
   Grid[Map[TextCell[Row[#]] &, 
      Split[#, # =!= tab &] & /@ 
       Split[Flatten[
         Replace[{args}, {s_String :> StringSplit[s, {"\t" -> tab, "\n" -> newline}]}, 1],
          1], # =!= newline &], {2}] /. {tab | newline -> Nothing}, Alignment -> Left]]

With your example:

PrettyPrint["This goes to the first column\tand this to the second one\n", "x=", x, "\t\
x^2=\t", x^2, "\tSquares are easyly computed by hand.\n", "x=", x, "\tSqrt[x]=\t", 
 Sqrt[x], "\tSquare roots are more difficult.\n", "x=", 2, "\tSqrt[x]=\t", 
 Sqrt[2], "\teasy as a symbol\n", "x=", 2., "\tSqrt[x]=\t", 
 Sqrt[2.], "\tendless numerical work."]

output

If you reduce the width of the Notebook window, columns widths are automatically adapted and proper word-wrapping is applied to long rows of text:

output

With an example TSV file imported as "Text":

tsv = Import["ExampleData/classification.tsv", "Text"];
PrettyPrint[tsv]

output


One possible approach to handle options is to specify them separately via Options[PrettyPrint]:

Options[PrettyPrint] = {ColumnWidths -> Automatic};
PrettyPrint[args__] := 
 Print@Module[{tab, newline}, 
   Grid[Map[TextCell[Row[#], 
        PageWidth -> OptionValue[Options[PrettyPrint], ColumnWidths]] &, 
      Split[#, # =!= tab &] & /@ 
       Split[Flatten[
         Replace[{args}, {s_String :> StringSplit[s, {"\t" -> tab, "\n" -> newline}]}, 1],
          1], # =!= newline &], {2}] /. {tab | newline -> Nothing}, Alignment -> Left]]

Now with your example:

Options[PrettyPrint] = {ColumnWidths -> 150};
PrettyPrint["This goes to the first column\tand this to the second one\n", "x=", x, "\t\
x^2=\t", x^2, "\tSquares are easyly computed by hand.\n", "x=", x, "\tSqrt[x]=\t", 
 Sqrt[x], "\tSquare roots are more difficult.\n", "x=", 2, "\tSqrt[x]=\t", 
 Sqrt[2], "\teasy as a symbol\n", "x=", 2., "\tSqrt[x]=\t", 
 Sqrt[2.], "\tendless numerical work."]

output

With this implementation the option ColumnWidths in fact determines the maximum column width, because when we reduce the window width, columns will become even narrower. Hence the minimal column width is actually determined by the minimal width of the whole Grid.

$\endgroup$
3
  • $\begingroup$ Alexey, thank you very much for your beautiful and extensive Answer. You transplant the rhs of option ColumnsWidth to the rhs of option PageWidth to TextCell. How would one apply the first of such widths to the first TextCell in a row, the second one to the second and so on if several column widths are given? (possibly repeating the last one if an insufficient number of them is given) $\endgroup$ May 14, 2022 at 15:20
  • $\begingroup$ Alexey, PageWidth->something determines the maximum width of a column. How can I define a minimum column width? Of course, the window would have to be wide enough to allow the sum of all minimum column widths. $\endgroup$ Jun 9, 2022 at 13:37
  • $\begingroup$ I just have found undocumented syntax form of ImageSize for Pane, which can be useful for implementing the MinColumnWidth and MaxColumnWidth functionality. It is ImageSize -> {{minWidth, maxWidth}, Automatic}. $\endgroup$ Aug 24, 2022 at 20:24
0
$\begingroup$

Looking at the solution from Alexey Popkov I have seen that the RawInputForm (Shift-Ctl-r) of the generated output is

Grid[{{TextCell[Row[{"This goes to the first column"}], PageWidth -> 150], 
    TextCell[Row[{"and this to the second one"}], PageWidth -> 150], Null, 
    Null}, {TextCell[Row[{"x=", x}], PageWidth -> 150], 
    TextCell[Row[{"x^2="}], PageWidth -> 150], TextCell[Row[{x^2}], 
     PageWidth -> 150], TextCell[Row[{"Squares are easily computed by hand."}], PageWidth -> 150]}, 
   {TextCell[Row[{"x=", x}], PageWidth -> 150], TextCell[Row[{"Sqrt[x]="}], 
     PageWidth -> 150], TextCell[Row[{Sqrt[x]}], PageWidth -> 150], 
    TextCell[Row[{"Square roots are more difficult."}], PageWidth -> 150]}, 
   {TextCell[Row[{"x=", 2}], PageWidth -> 150], TextCell[Row[{"Sqrt[x]="}], 
     PageWidth -> 150], TextCell[Row[{Sqrt[2]}], PageWidth -> 150], 
    TextCell[Row[{"easy as a symbol"}], PageWidth -> 150]}, 
   {TextCell[Row[{"x=", 2.}], PageWidth -> 150], TextCell[Row[{"Sqrt[x]="}], 
     PageWidth -> 150], TextCell[Row[{1.4142135623730951}], 
     PageWidth -> 150], TextCell[Row[{"endless numerical work."}], 
     PageWidth -> 150]}}, Alignment -> Left, 
  ItemSize -> {Automatic, Automatic}]

Looking closer at it shows me that each TextCell is equipped with an option PageWidth -> 150. If I remove those options beginning at the second row, the appearance of the output remains looks as before after applying TraditionalForm to the cell (mark the cell bracket, then press Shift-Ctl-t).

Then I have modified the widths of the columns like this:

Grid[{{TextCell[Row[{"This goes to the first column"}], PageWidth -> 80], 
    TextCell[Row[{"and this to the second one"}], PageWidth -> 150], Null, 
    Null}, {TextCell[Row[{"x=", x}]], TextCell[Row[{"x^2="}]], 
    TextCell[Row[{x^2}]], TextCell[
     Row[{"Squares are easyly computed by hand."}]]}, 
   {TextCell[Row[{"x=", x}]], TextCell[Row[{"Sqrt[x]="}]], 
    TextCell[Row[{Sqrt[x]}]], TextCell[
     Row[{"Square roots are more difficult."}]]}, 
   {TextCell[Row[{"x=", 2}]], TextCell[Row[{"Sqrt[x]="}]], 
    TextCell[Row[{Sqrt[2]}]], TextCell[Row[{"easy as a symbol"}]]}, 
   {TextCell[Row[{"x=", 2.}]], TextCell[Row[{"Sqrt[x]="}]], 
    TextCell[Row[{1.4142135623730951}]], 
    TextCell[Row[{"endless numerical work."}]]}}, Alignment -> Left, 
  ItemSize -> {Automatic, Automatic}]

and after Shift-Ctl-t the column width of the first column becomes smaller (maintaining the nice property mentioned by Alexey when I reduce the window width).

This might give a hint how to prepare for different column widths. - My example was less than optimal since the first line has less columns than the following ones, resulting in the two entries Null in the first line of the two-dimensional list to be shown.

One might further vary Alexey's output prepending it with a row only defining the columns widths and no text like this:

Grid[{{TextCell[Row[{""}], PageWidth -> 80], TextCell[Row[{""}], 
     PageWidth -> 80], TextCell[Row[{""}], PageWidth -> 150], 
    TextCell[Row[{""}], PageWidth -> 150]}, 
   {TextCell[Row[{"This goes to the first column"}]], 
    TextCell[Row[{"and this to the second one"}]], Null, Null}, 
   {TextCell[Row[{"x=", x}]], TextCell[Row[{"x^2="}]], TextCell[Row[{x^2}]], 
    TextCell[Row[{"Squares are easily computed by hand."}]]}, 
   {TextCell[Row[{"x=", x}]], TextCell[Row[{"Sqrt[x]="}]], 
    TextCell[Row[{Sqrt[x]}]], TextCell[
     Row[{"Square roots are more difficult."}]]}, 
   {TextCell[Row[{"x=", 2}]], TextCell[Row[{"Sqrt[x]="}]], 
    TextCell[Row[{Sqrt[2]}]], TextCell[Row[{"easy as a symbol"}]]}, 
   {TextCell[Row[{"x=", 2.}]], TextCell[Row[{"Sqrt[x]="}]], 
    TextCell[Row[{1.4142135623730951}]], 
    TextCell[Row[{"endless numerical work."}]]}}, Alignment -> Left, 
  ItemSize -> {Automatic, Automatic}]

This observation gives rise to a not yet solved idea to provide two functions:

PrintTableHeadline[headline_String, MaximumColumnWidths->list] where headline is a string consisting of the column headlines, separated by \t and list is a list of numbers representing the column widths (preferably in some practical unit like cm or mm).

Then PrettyPrint should adopt the column widths from the last call to PrintTableHeadline, accept all kinds of parameters like Print and separate the generated output to the columns like before.

It remains the problem to append subsequent output as a new row to an existing Grid.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.