Formatted Output
Ever since version 3 of Mathematica, 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 Mathematica expressions. This approach turned out to be very powerful, and has formed the basis of many unique features in Mathematica. 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
Mathematica 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 pt. Courier (or Times for those people using
TraditionalForm). To address this, the function
Style was created. Whenever you evaluate a
Style expression, its output will be displayed with the given style attributes active.
You can wrap
Style around any sort of expression. Here is an example that displays prime and composite numbers using different font weights and colors via
Style.
| Out[1]= |  |
There are hundreds of formatting options that you could apply with
Style—see the documentation for
Style for a more complete listing—but there are a handful that are by far the most common, listed here.
Note that
Style can be arbitrarily nested, with the innermost one taking precedence if there is a conflict. Here we wrap
Style around the entire listing to apply new font to all elements of the list.
| Out[2]= |  |
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
Text which ensures that its argument will always be rendered in a text font. (Those of you familiar with
Mathematica graphics will recognize the
Text function as a graphics primitive, but that use does not conflict with this use outside of graphics.)
| Out[3]= |  |
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
Style can even affect the display characteristics of other formatting constructs, like
Grid or
Tooltip.
Grid layout
Using two dimensional layout structures can be just as useful as applying style directives to those structures. In
Mathematica, the primary function for such layout is
Grid.
Grid has very flexible layout features, including the ability to arbitrarily adjust things like alignment, frame elements, and spanning elements. (Other tutorials go into
Grid's features in greater detail, but we will cover the highlights here.)
Look again at the
Style example which displays prime and composite numbers differently.
To put this into a
Grid, we first use
Partition to turn this 100 element list into a 10×10 array. Although you can give
Grid a ragged array (a list whose elements are lists of different lengths), in this case we give
Grid a regular array, and the resulting display is a nicely formatted layout.
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
Grid's options.
A complete description of all of
Grid's 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
Grid documentation for complete details.
There are a few convenience constructs related to
Grid. One is
Column, which takes a flat list of elements and arranges them vertically. This would be slightly awkward to do with
Grid. Here is a simple example, viewing the options of column in, well, a 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 Grid applied to a 1×n array.
| Out[5]= |  |
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
ItemSize option of
Grid. If you want to allow the elements of a grid to be as wide as they would naturally be, set
ItemSize to
Full.
| Out[7]= |  |
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:
Row.
Given a list of elements,
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)
SequenceForm function.
As you can see,
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.
If you resize the notebook window, you will see that
Grid with
ItemSize->Automatic continues to behave differently than
Row, and each are useful in different circumstances.
Using output as input
This is a good time to point out that
Style,
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
Style or
Grid and reuse that as input, the literal
Style or
Grid expressions would appear in the input expression. Those of you familiar with the old uses of
StyleBox and even functions like
MatrixForm will find this a change.
Consider taking the output of this
Grid command, which has lots of embedded styles, and using it in some input expression.
| Out[17]= |  |
| Out[18]= |  |
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
Grid and
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 you want to get rid of these wrappers and get at your data, that is easy enough to do.
| Out[19]= |  |
Special Grid entries
To allow more flexible two-dimensional layout,
Grid accepts a few special symbols like
SpanFromLeft as entries. The entry
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
SpanFromAbove and
SpanFromBoth. See
"Grids, Rows, and Columns" for detailed information.
This approach can be used to create complicated spanning setups. Typing something like the following in as an input would take a long time. Luckily you can also create them interactively by using and
Split Spanning in the submenu. If you want to see what would be involved in typing this in, evaluate the cell which will show how it should be typed in input.
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
Item, and then specify options to
Item which override the corresponding option in
Grid.
You could override this option with
Style too, but the purpose of
Item is to override it in such a way that knows about the two dimensional layout of
Grid. Notice in the output above 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
Item.
The same thing goes for all of
Item's options, not just
Background. Consider the
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
Grid with the
Frame->True setting. (We will learn a much easier way to add a frame around an arbitrary expression in the next section.)
But notice that adjacent framed elements do not share their boundaries. Compare that with using
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
Item.
Frames and labels
Adding a frame or a label to an expression can be done with
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,
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.
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
Grid example from the last section. (
Spacer is just a function that is designed to leave empty space.)
| Out[19]= |  |
Panel is yet another framing construct, which uses the underlying operating system's panel frame. This is different from
Frame, as different operating systems might use a drop shadow, rounded corners, or fancier graphic design elements for a panel frame.
| Out[20]= |  |
Note that
Panel has its own concept of font family and size as well, so the
Grid's contents change font family and size, and the
Text changes font size. (
Text has its own opinion about font family though, and so it remains in
Mathematica's text font.) We will talk about this in some detail below in the section on the
BaseStyle option.
Finally, we should point out that
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
Panel for more detail.
| Out[37]= |  |
| Out[38]= |  |
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 it.
Tooltip for example does not change the display of its first argument, and it is only when you move the mouse pointer over that display is the second argument shown, as a tooltip.
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
Mouseover's
ImageSize option to leave space for the larger of the two displays, regardless of which is being displayed.
Also similar to
Tooltip are
StatusArea and
PopupWindow.
StatusArea displays the extra information in the notebook's status area, typically in the lower-left corner, while
PopupWindow will display extra information in a new window when clicked.
Finally, you can specify an arbitrary location for an annotation by using the pair
Annotation and
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
ListPlot or
DensityPlot support
Tooltip. See the documentation for details.
| Out[2]= |  |
Default styles
As we saw above, constructs like
Panel actually work much like
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
Style commands, but it can also be overridden for the
Panel itself, through the
BaseStyle option.
BaseStyle can be set to a style or a list of style directives, just like you would use in
Style. And those directives then become the ambient default within the scope of that
Panel.
As we have already seen,
Panel by default uses the dialog font family and size. But that can be overridden by using this
BaseStyle option.
| Out[7]= |  |
Actually, almost all of these box generators have a
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
Style wrapper trumps the outer
Grid BaseStyle. (This is one of the principle characteristics of
option inheritance, which is beyond the scope of this document to discuss.)
Default options
Say you have an expression with multiple occurrences of the same box generator, like a
Framed or a
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.
DefaultOptions is an option to
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
Style wrapper, but only in any instances of the associated box generator.
So if you had an expression that contained a bunch of
Framed items, and you wanted them all to draw with the same background and frame style.
Actually, that input is too short to see the advantage of this syntax. Say you had this same list, but specified manually.
Now inserting
Background and
FrameStyle options into every
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
DefaultOptions, you can effectively set up an environment in which all
Framed wrappers will use your settings for
Background and
FrameStyle, thusly.
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.
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,
Superscript[a, b] will not be interpreted as
Power[a, b], even though their display is identical. So you can use these as structural elements in your formatted output without having to worry about their meaning affecting your display.
| Out[67]= |  |
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 you 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:
RawBoxes.
As with all loopholes,
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.