Formatted Output

Ever since Version 3 of the Wolfram Language, there has been rich support for arbitrary mathematical typesetting and layout. Underlying all that power was a so-called box language, which allowed notebooks themselves to be Wolfram Language expressions. This approach turned out to be very powerful, and has formed the basis of many unique features in the Wolfram Language. However, despite the power of the box language, in practice it was awkward enough for users to access directly that few did.

Starting in Version 6, there is a higher-level interface to this box language which takes much of the pain out of using boxes directly, while still exposing all the same typesetting and layout power. Functions in this new layer are often referred to as box generators, but there is no need for you to be aware of the box language to use them effectively. In this tutorial, we will take a look at box generators that are relevant for displaying a wide variety of expressions, and we will show some ways in which they can be used to generate beautifully formatted output that goes beyond simple mathematical typesetting.

Styling Output

The Wolfram System front end supports all the usual style mechanisms available in word processors, for example including menus for changing font characteristics. However, it used to be very difficult to access those styling mechanisms automatically in generated output. Output continued to be almost universally plain 12 point Courier (or Times for those people using (RefLink[TraditionalForm, paclet:ref/TraditionalForm])). To address this, the function (RefLink[Style, paclet:ref/Style]) was created. Whenever you evaluate a (RefLink[Style, paclet:ref/Style]) expression, its output will be displayed with the given style attributes active.

You can wrap (RefLink[Style, paclet:ref/Style]) around any sort of expression. Here is an example that displays prime and composite numbers using different font weights and colors via (RefLink[Style, paclet:ref/Style]).

Table[If[PrimeQ[i], Style[i, Bold], Style[i, Gray]],{i,1,100}]

There are hundreds of formatting options that you could apply with (RefLink[Style, paclet:ref/Style])—see the documentation for (RefLink[Style, paclet:ref/Style]) for a more complete listing—but there are a handful that are by far the most common, listed here.

({{Menu, (RefLink[Style, paclet:ref/Style])[] option, (RefLink[Style, paclet:ref/Style])[] directive}, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Size, paclet:ref/menuitem/Size]) ▶ 14, FontSize->14, 14}, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Text Color, paclet:ref/menuitem/TextColor]) ▶ Gray, FontColor->Gray, Gray}, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Face, paclet:ref/menuitem/Face]) ▶ Bold, FontWeight->Bold, Bold}, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Face, paclet:ref/menuitem/Face]) ▶ Italic, FontSlant->Italic, Italic}, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Background Color, paclet:ref/menuitem/BackgroundColor]) ▶ Yellow, Background->Yellow,  }, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Font, paclet:ref/menuitem/Font]), FontFamily->"Times",  }, {(MenuGrayLink[Format, paclet:guide/FormatMenu]) ▶ (MenuGrayLink[Style, paclet:ref/menuitem/Style]) ▶ Subsection, "Subsection",  }})

Note that (RefLink[Style, paclet:ref/Style]) can be arbitrarily nested, with the innermost one taking precedence if there is a conflict. Here we wrap (RefLink[Style, paclet:ref/Style]) around the entire list to apply a new font to all elements of the list.

Style[%, FontFamily->"Helvetica"]

Another common thing to want is to have a portion of the output styled like text. It can look quite strange to have text appear in a font which is intended for use by code. For that purpose, we have a function (RefLink[Text, paclet:ref/Text]) which ensures that its argument will always be rendered in a text font. (Those of you familiar with Wolfram Language graphics will recognize the (RefLink[Text, paclet:ref/Text]) function as a graphics primitive, but that use does not conflict with this use outside of graphics.)

Text[%%]

(RefLink[Style, paclet:ref/Style]) can be used to set up a region on the screen where any option is active, not just options related to fonts. Later in this tutorial, we will see how (RefLink[Style, paclet:ref/Style]) can even affect the display characteristics of other formatting constructs, like (RefLink[Grid, paclet:ref/Grid]) or (RefLink[Tooltip, paclet:ref/Tooltip]).

Grid Layout

Using two-dimensional layout structures can be just as useful as applying style directives to those structures. In the Wolfram Language, the primary function for such layout is (RefLink[Grid, paclet:ref/Grid]). (RefLink[Grid, paclet:ref/Grid]) has very flexible layout features, including the ability to arbitrarily adjust things like alignment, frame elements, and spanning elements. (Other tutorials go into (RefLink[Grid, paclet:ref/Grid]) features in greater detail, but we will cover the highlights here.)

Look again at the (RefLink[Style, paclet:ref/Style]) example which displays prime and composite numbers differently.

ptable=Table[If[PrimeQ[i], Style[i, Bold], Style[i, Gray]],{i,1,100}];

To put this into a (RefLink[Grid, paclet:ref/Grid]), we first use (RefLink[Partition, paclet:ref/Partition]) to turn this 100-element list into a 10×10 array. Although you can give (RefLink[Grid, paclet:ref/Grid]) a ragged array (a list whose elements are lists of different lengths), in this case we give (RefLink[Grid, paclet:ref/Grid]) a regular array, and the resulting display is a nicely formatted layout.

Grid[Partition[ptable,10]]

Notice that the columns are aligned on center, and there are no frame lines. It is an easy matter to change either of these using (RefLink[Grid, paclet:ref/Grid]) options.

Grid[Partition[ptable,10], Alignment -> Right, Frame -> True, Background -> LightBlue]

A complete description of all (RefLink[Grid, paclet:ref/Grid]) options and their syntax is beyond the scope of this document, but it is possible to do some remarkable things with them. See the complete (RefLink[Grid, paclet:ref/Grid]) documentation for complete details.

There are a few convenience constructs related to (RefLink[Grid, paclet:ref/Grid]). One is (RefLink[Column, paclet:ref/Column]), which takes a flat list of elements and arranges them vertically. This would be slightly awkward to do with (RefLink[Grid, paclet:ref/Grid]). Here is a simple example, viewing the options of column in, well, a column.

Column[Options[Column]]

What about laying out a list of things horizontally? In that case, the main question you need to ask is whether you want the resulting display to line wrap like a line of math or text would, or whether you want the elements to remain on a single line. In the latter case, you would use (RefLink[Grid, paclet:ref/Grid]) applied to a 1×n array.

Grid[{Range[15]!}]

But notice in this example that the overall grid shrinks so that it fits in the available window width. As a result, there are elements of the grid which themselves wrap onto multiple lines. This is due to the default (RefLink[ItemSize, paclet:ref/ItemSize]) option of (RefLink[Grid, paclet:ref/Grid]). If you want to allow the elements of a grid to be as wide as they would naturally be, set (RefLink[ItemSize, paclet:ref/ItemSize]) to (RefLink[Full, paclet:ref/Full]).

Grid[{Range[15]!},ItemSize->Full]

Of course, now the whole grid is too wide to fit on one line (unless you make this window very wide), and so there are elements in the grid which you cannot see. That brings us to the other horizontal layout function: (RefLink[Row, paclet:ref/Row]).

Given a list of elements, (RefLink[Row, paclet:ref/Row]) will allow the overall result to word wrap in the natural way, just like a line of text or math would. This type of layout will be familiar to those of you who might have used the old (and now obsolete) (RefLink[SequenceForm, paclet:ref/SequenceForm]) function.

Row[Range[15]!]

As you can see, (RefLink[Row, paclet:ref/Row]) does not leave space between elements by default. But if you give a second argument, that expression is inserted between elements. Here we use a comma, but any expression can be used.

Row[Range[15]!, ","]

If you resize the notebook window, you will see that (RefLink[Grid, paclet:ref/Grid]) with (RefLink[ItemSize, paclet:ref/ItemSize])->(RefLink[Automatic, paclet:ref/Automatic]) continues to behave differently than (RefLink[Row, paclet:ref/Row]), and each is useful in different circumstances.

Using Output as Input

This is a good time to point out that (RefLink[Style, paclet:ref/Style]), (RefLink[Grid, paclet:ref/Grid]), and all other box generators are persistent in output. If you were to take a piece of output that had some formatting created by (RefLink[Style, paclet:ref/Style]) or (RefLink[Grid, paclet:ref/Grid]) and reuse that as input, the literal (RefLink[Style, paclet:ref/Style]) or (RefLink[Grid, paclet:ref/Grid]) expressions would appear in the input expression. Those of you familiar with the old uses of (RefLink[StyleBox, paclet:ref/StyleBox]) and even functions like (RefLink[MatrixForm, paclet:ref/MatrixForm]) will find this a change.

Consider taking the output of this (RefLink[Grid, paclet:ref/Grid]) command, which has lots of embedded styles, and using it in some input expression.

Grid[Partition[Take[ptable,16],4], Alignment -> Right, Frame -> True, Background -> LightBlue]

(((({{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}})+5))^3)//Expand

Notice that the grid is still a grid, it is still blue, and the elements are still bold or gray as before. Also notice that having literal (RefLink[Grid, paclet:ref/Grid]) and (RefLink[Style, paclet:ref/Style]) in the expression interferes with what would have otherwise been adding a scalar to a matrix, and raising the result to a power. This distinction is very important, since you almost always want these composite structures to resist being interpreted automatically in some way. However, if you ever do want to get rid of these wrappers and get at your data, that is easy enough to do.

% //. {Grid[a_,___]:>a,Style[a_,___]:>a}

Special Grid Entries

To allow more flexible two-dimensional layout, (RefLink[Grid, paclet:ref/Grid]) accepts a few special symbols like (RefLink[SpanFromLeft, paclet:ref/SpanFromLeft]) as entries. The entry (RefLink[SpanFromLeft, paclet:ref/SpanFromLeft]) indicates that the grid entry immediately to the left should take up its own space and also the space of the spanning character. There are also (RefLink[SpanFromAbove, paclet:ref/SpanFromAbove]) and (RefLink[SpanFromBoth, paclet:ref/SpanFromBoth]). See "Grids, Rows, and Columns" for detailed information.

Grid[{
{1,2,3,4,5},
{6,7,SpanFromLeft,SpanFromLeft,10},
{11,SpanFromAbove,SpanFromBoth,SpanFromBoth,15},
{16,17,18,19,20}}, Frame->All]

This approach can be used to create complicated spanning setups. Typing something like the following as an input would take a long time. Luckily you can create this table interactively by using (MenuGrayLink[Make Spanning, paclet:ref/menuitem/MakeSpanning]) and (MenuGrayLink[Split Spanning, paclet:ref/menuitem/SplitSpanning]) in the (MenuGrayLink[Insert, paclet:guide/InsertMenu]) ▶ (MenuGrayLink[Table/Matrix, paclet:ref/menuitem/TableMatrix]) submenu. If you want to see what would be involved in typing this, evaluate the cell, which will show how it should be typed as input.

({{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {11, 12, 13, , 15, 16, , , , }, {21, 22, , , 25, , , , , }, {31, 32, 33, 34, 35, , , , , }, {41, , , , , , , , , }, {51, 52, 53, 54, 55, , , , , }, {61, 62, 63, , , , , , , }, {71, 72, , , , 76, 77, , , }, {81, 82, , , , 86, , , , }, {91, 92, , , , 96, , , , }})//InputForm

We have already seen how to apply things like alignment and background to a grid as a whole, or to individual columns or rows. What we have not seen though is how to override that for an individual element. Say you want your whole grid to have the same background, except for a few special elements. A convenient way to do that is to wrap each such element in (RefLink[Item, paclet:ref/Item]), and then specify options to (RefLink[Item, paclet:ref/Item]) which override the corresponding option in (RefLink[Grid, paclet:ref/Grid]).

Grid[Partition[Table[If[PrimeQ[i],Item[i, Background -> LightYellow],i],{i,1,100}],10], Background->LightBlue]

You could override this option with (RefLink[Style, paclet:ref/Style]) too, but the purpose of (RefLink[Item, paclet:ref/Item]) is to override it in a way that knows about the two-dimensional layout of (RefLink[Grid, paclet:ref/Grid]). Notice in the preceding output that whenever two of the yellow cells are next to each other, there is no blue space between them. That would be impossible to do with constructs other than (RefLink[Item, paclet:ref/Item]).

The same thing goes for all (RefLink[Item, paclet:ref/Item]) options, not just (RefLink[Background, paclet:ref/Background]). Consider the (RefLink[Frame, paclet:ref/Frame]) option. If you want no frame elements except around certain specified elements, you might think that you have to wrap them in their own (RefLink[Grid, paclet:ref/Grid]) with the (RefLink[Frame, paclet:ref/Frame])->(RefLink[True, paclet:ref/True]) setting. (We will learn a much easier way to add a frame around an arbitrary expression in the next section.)

Grid[Partition[Table[If[PrimeQ[i],Grid[{{i}},Frame->True],i],{i,1,100}],10]]

But notice that adjacent framed elements do not share their boundaries. Compare that with using (RefLink[Item, paclet:ref/Item]), below, which has enough information to not draw more frame elements than are necessary. Notice now the frames of 2 and 11 meet at a single point, and how the frames of 2 and 3 share a single-pixel line, which in turn is perfectly aligned with the left frame of 13 and 23. That is the power of (RefLink[Item, paclet:ref/Item]).

Grid[Partition[Table[If[PrimeQ[i],Item[i, Frame -> True],i],{i,1,100}],10]]

Frames and Labels

Adding a frame or a label to an expression can be done with (RefLink[Grid, paclet:ref/Grid]), but conceptually these are much simpler operations than general two-dimensional layout, and so there are correspondingly simpler ways to get them. For instance, (RefLink[Framed, paclet:ref/Framed]) is a simple function for drawing a frame around an arbitrary expression. This can be useful to draw attention to parts of an expression, for instance.

Table[If[PrimeQ[i],Framed[i, Background -> LightYellow],i],{i,1,100}]

(RefLink[Labeled, paclet:ref/Labeled]) is another such function, which allows labels to be placed at arbitrary locations around a given expression. Here we add a legend to the (RefLink[Grid, paclet:ref/Grid]) example from the last section. ((RefLink[Spacer, paclet:ref/Spacer]) is just a function that is designed to leave empty space.)

Labeled[
Grid[Partition[ptable,10], Alignment -> Right, Frame -> True],
Text[Row[{Style["• Prime",Bold], Style["• Composite",Gray]},Spacer[15]]]]

(RefLink[Panel, paclet:ref/Panel]) is yet another framing construct, which uses the underlying operating system's panel frame. This is different from (RefLink[Frame, paclet:ref/Frame]), as different operating systems might use a drop shadow, rounded corners, or fancier graphic design elements for a panel frame.

Panel[%]

Note that (RefLink[Panel, paclet:ref/Panel]) has its own concept of font family and size as well, so the contents of (RefLink[Grid, paclet:ref/Grid]) change font family and size, and the (RefLink[Text, paclet:ref/Text]) changes font size. ((RefLink[Text, paclet:ref/Text]) has its own opinion about font family though, and so it remains in the Wolfram System's text font.) We will talk about this in some detail below in the section on the (RefLink[BaseStyle, paclet:ref/BaseStyle]) option.

Finally, we should point out that (RefLink[Panel, paclet:ref/Panel]) itself has an optional second argument to specify one or more labels, which are automatically positioned outside the panel, and an optional third argument to give details of that position. See the documentation for (RefLink[Panel, paclet:ref/Panel]) for more detail.

Panel[ptable, "Primes and Composites"]

Panel[ptable, {"Primes and Composites"}, {{Bottom,Right}}]

Other Annotations

The annotations mentioned so far have a very definite visual component. There are a number of annotations which are effectively invisible, until the user needs them. (RefLink[Tooltip, paclet:ref/Tooltip]) for example does not change the display of its first argument, and only when you move the mouse pointer over that display is the second argument shown, as a tooltip.

Table[Tooltip[i,Divisors[i]],{i,1,100}]

(RefLink[Mouseover, paclet:ref/Mouseover]) is another such function, but instead of displaying the result in a tooltip, it uses the same area of the screen that had been used for the display before you moved the mouse pointer over it. If the two displays are different sizes, then the effect can be jarring, so it is a good idea to use displays which are closer to the same size, or use the (RefLink[Mouseover, paclet:ref/Mouseover]) (RefLink[ImageSize, paclet:ref/ImageSize]) option to leave space for the larger of the two displays, regardless of which is being displayed.

Table[Mouseover[i,Framed[Divisors[i], Background->LightYellow]],{i,1,100}]

Also similar to (RefLink[Tooltip, paclet:ref/Tooltip]) are (RefLink[StatusArea, paclet:ref/StatusArea]) and (RefLink[PopupWindow, paclet:ref/PopupWindow]). (RefLink[StatusArea, paclet:ref/StatusArea]) displays the extra information in the notebook's status area, typically in the lower-left corner, while (RefLink[PopupWindow, paclet:ref/PopupWindow]) will display extra information in a new window when clicked.

Table[StatusArea[i,Divisors[i]],{i,1,100}]

Table[PopupWindow[i,Divisors[i]],{i,1,100}]

Finally, you can specify an arbitrary location for an annotation by using the pair (RefLink[Annotation, paclet:ref/Annotation]) and (RefLink[MouseAnnotation, paclet:ref/MouseAnnotation]).

Table[Annotation[i,Divisors[i],"Mouse"],{i,1,100}]
Dynamic[MouseAnnotation[]]

When using annotations that are triggered merely by moving the mouse pointer over a region of the screen, it is important to keep the user in mind. Moving the mouse is not something that should trigger a long evaluation or a lot of visual clutter. But used sparingly, annotations can be quite helpful to users.

Finally, note that all these annotations work perfectly well in graphics too. So you can provide tooltips or mouseovers to aid users in understanding a complicated graphic you have created. In fact, even visualization functions like (RefLink[ListPlot, paclet:ref/ListPlot]) or (RefLink[DensityPlot, paclet:ref/DensityPlot]) support (RefLink[Tooltip, paclet:ref/Tooltip]). See the documentation for details.

Graphics[{LightBlue,EdgeForm[Gray],Tooltip[CountryData[#,"SchematicPolygon"],#]&/@CountryData[]}, ImageSize->Full]

Default Styles

As we saw in the section "Frames and Labels", constructs like (RefLink[Panel, paclet:ref/Panel]) actually work much like (RefLink[Style, paclet:ref/Style]), in that they set up an environment in which a set of default styles is applied to their contents. This can be overridden by explicit (RefLink[Style, paclet:ref/Style]) commands, but it can also be overridden for the (RefLink[Panel, paclet:ref/Panel]) itself, through the (RefLink[BaseStyle, paclet:ref/BaseStyle]) option. (RefLink[BaseStyle, paclet:ref/BaseStyle]) can be set to a style or a list of style directives, just like you would use in (RefLink[Style, paclet:ref/Style]). And those directives then become the ambient default within the scope of that (RefLink[Panel, paclet:ref/Panel]).

As we have already seen, (RefLink[Panel, paclet:ref/Panel]) by default uses the dialog font family and size. But that can be overridden by using this (RefLink[BaseStyle, paclet:ref/BaseStyle]) option.

Panel[Range[10]]

Panel[Range[10], BaseStyle -> {"StandardForm"}]

Actually, almost all of these box generators have a (RefLink[BaseStyle, paclet:ref/BaseStyle]) option. For instance, here is a grid in which the default font color is blue. Notice that the elements that were gray stay gray, since the inner (RefLink[Style, paclet:ref/Style]) wrapper trumps the outer (RefLink[Grid, paclet:ref/Grid]) (RefLink[BaseStyle, paclet:ref/BaseStyle]). (This is one of the principal characteristics of option inheritance, which is beyond the scope of this document to discuss.)

Grid[Partition[ptable, 10], BaseStyle -> {FontColor -> Blue}]

Default Options

Say you have an expression with multiple occurrences of the same box generator, like a (RefLink[Framed, paclet:ref/Framed]) or a (RefLink[Panel, paclet:ref/Panel]), and you want to change all of them to have the same set of options. It might be cumbersome to go through and add the same set of options to every occurrence of that function. Thankfully, there is an easier way.

(RefLink[DefaultOptions, paclet:ref/DefaultOptions]) is an option to (RefLink[Style, paclet:ref/Style]) which, when set to a list of elements of the form head->{opt->val,…}. sets up an environment with the given options as the ambient default for the given box-generating head. Those options will be active throughout the (RefLink[Style, paclet:ref/Style]) wrapper, but only in any instances of the associated box generator.

Suppose you had an expression that contained some (RefLink[Framed, paclet:ref/Framed]) items, and you wanted them all to be drawn with the same background and frame style.

Table[If[PrimeQ[i],Framed[i],i],{i,1,100}]

Actually, that input is too short to see the advantage of this syntax. Say you had this same list, but specified manually.

biglist = {1,Framed[2],Framed[3],4,Framed[5],6,Framed[7],8,9,10,Framed[11],12,Framed[13],14,15,16,Framed[17],18,Framed[19],20,21,22,Framed[23],24,25,26,27,28,Framed[29],30,Framed[31],32,33,34,35,36,Framed[37],38,39,40,Framed[41],42,Framed[43],44,45,46,Framed[47],48,49,50,51,52,Framed[53],54,55,56,57,58,Framed[59],60,Framed[61],62,63,64,65,66,Framed[67],68,69,70,Framed[71],72,Framed[73],74,75,76,77,78,Framed[79],80,81,82,Framed[83],84,85,86,87,88,Framed[89],90,91,92,93,94,95,96,Framed[97],98,99,100}

Now inserting (RefLink[Background, paclet:ref/Background]) and (RefLink[FrameStyle, paclet:ref/FrameStyle]) options into every (RefLink[Framed, paclet:ref/Framed]) wrapper is prohibitively time consuming, although you certainly could do it (or you could write a program to do it for you). But using (RefLink[DefaultOptions, paclet:ref/DefaultOptions]), you can effectively set up an environment in which all (RefLink[Framed, paclet:ref/Framed]) wrappers will use your settings for (RefLink[Background, paclet:ref/Background]) and (RefLink[FrameStyle, paclet:ref/FrameStyle]), thus.

Style[biglist, DefaultOptions -> {Framed -> {Background -> LightYellow, FrameStyle->Blue}}]

This approach makes it easy to create structures that follow uniform style guidelines without having to specify those styles in more than one place, which makes for considerably cleaner code, smaller file sizes, and easier maintenance.

Mathematical Typesetting

No discussion of formatted output would be complete without at least a nod toward the formatting constructs that are unique to mathematical syntaxes.

{Subscript[a,b],Superscript[a,b],Underscript[a,b],Overscript[a,b], Subsuperscript[a,b,c], Underoverscript[a,b,c]}

We will not discuss these at length, but we will point out that these constructs do not have any built-in mathematical meaning in the kernel. For example, (RefLink[Superscript, paclet:ref/Superscript])[a,b] will not be interpreted as (RefLink[Power, paclet:ref/Power])[a,b], even though their displays are identical. So you can use these as structural elements in your formatted output without having to worry about their meaning affecting your display.

Table[Row[{i,Row[Superscript @@@ FactorInteger[i],"×"]},"=="],{i,100}]

Using the Box Language

One final note. Those of you who are already familiar with the box language might occasionally find that these box generators get in the way of your constructing low level boxes yourselves, and inserting their display into a piece of output. That can be true for any layered technology where one abstraction layer attempts to hide the layers on which it sits. However, there is a simple loophole through which you can take boxes which you happen to know are valid, and display them directly in output: (RefLink[RawBoxes, paclet:ref/RawBoxes]).

{a,b,RawBoxes[SubscriptBox["c","d"]],e}

As with all loopholes, (RefLink[RawBoxes, paclet:ref/RawBoxes]) gives you added flexibility, but it also allows you to shoot yourself in the foot. Use with care. And if you are not yet familiar with the box language, perhaps you should not use it at all.