MakeBoxes

The code below will ensure any difference of two terms is displayed as a  difference when you use any form that outputs 2D expressions (StandardForm,  MatrixForm, TableForm, etc.).   TraditionalForm displays (b-a) even if you don't make a special definition, it also has many other  conventions that come with it.


The kernel automatically calls MakeBoxes when it needs to format an
expression using 2D notation.  The rules for MakeBoxes specify that how
expressions with a certain form are should be displayed one way, and other
forms should be displayed different ways.  Typically a definition  says a
certain box structure should be built using parts of the given expression.  
The various parts that are used in the box structure are often smaller
expressions that also need to be made into 2D expressions, so MakeBoxes must
be called on these smaller expressions.  This continues recursively until
MakeBoxes formats atoms directly into box structures.



When the kernel calls MakeBoxes it passes the form used in the second
argument. The form can be StandardForm, TraditionalForm, MatrixForm, or any
other form that formats the output as 2D expressions.  A rule for MakeBoxes
can have a specific form for the second argument as in MakeBoxes[pattn,
StandardForm] in which case the definition is only used for StandardForm.  
You can even define your own for using MakeBoxes[pattn, MyForm], and the
provided formatting rules will be used when you evaluate expr//MyForm.  In
the definition below the second argument of MakeBoxes is the pattern (form_).
In this case the formatting rule is used for any form that uses 2D
expressions to format the output.



MakeBoxes has the HoldAllComplete attribute.  As a result you can't use
MakeBoxes[Evaluate[expr], form] to force the evaluation of (expr).  If (expr)
must complete evaluation that can be accomplished using

( MakeBoxes@@{expr,form} ).

MakeBoxes[(n_Real | n_Integer | n_Rational) a_. + b_/;  Head[b] =!= Plus&&n<0, form_] :=   RowBox[{MakeBoxes[b, form], "-", MakeBoxes @@ {-n  a, form}}] ;


The above rules for MakeBoxes will produce a more readable display of
expressions such as the following:

Clear[a, y] ;  Log[y - 2/3]/Sqrt[y - 4 a] - Exp[y - 2.4]

Log[y - 2/3]/(y - 4 a)^(1/2) - ^(y - 2.4)

The rules for MakeBoxes are stored as FormatValues.

FormatValues[MakeBoxes]

{HoldPattern[MakeBoxes[(n_Real | n_Integer | n_Rational) a_. + b_/;Head[b] =!= Plus&&n<0, form_]] RowBox[{MakeBoxes[b, form], -, MakeBoxes @@ {-n a, form}}]}


It may be tempting to write a slightly simpler implementation, but this
simpler implementation has flaws.


The simpler implementation is:

    MakeBoxes[(n_Real|n_Integer|n_Rational)a_.+b_/;

    Head[b]=!=Plus&&n<0,form_]:=

    RowBox[{MakeBoxes[b,form],MakeBoxes@@{n*a,form}}];



In private email Neil Soiffer of Wolfram Research noted that the version
above has a few problems.

(1) The '-' sign is grouped with the subsequent term as a unary "minus",
instead of binary "difference".

This will effect spacing after the minus (not symmetric with respect to '-'
as is easily seen with 'a-b').

(2) Grouping doesn't work well.  If one evaluates (a-b) and triple clicks on
the '-' in the output, automatic grouping doesn't work right.

(3)  Perhaps the worst problem is that because '-' is interpreted as a unary
minus, there is implied multiplication between the 'a' and the '-b' and so it
will evaluate incorrectly.  Evaluate (a-b) and select the output cell, go to

cell | cell properties | cell evaluatable to make the output cell
evaluatable, and then evaluate the cell.  The result looks like '-a b'.

Another example


David park noted that the minus sign gets pulled into the sum in the next
input.

(-1/2) (a + 2.3 * b + c)

1/2 (-a - 2.3 b - c)


By looking at the box structure of the output cell above you can see what we
need to use in a MakeBoxes definition.  The input in the next cell does the
job.  The first definition ensures the negative sign is factored out, and the
second definition puts the negative sign in the numerator.

MakeBoxes[a_ * b : Plus[_ ? Negative * _, (_ ? Negative * _) ..], form : (StandardForm | Tradi ... onalForm)] := FractionBox[MakeBoxes @@ {Numerator[p], form}, MakeBoxes @@ {Denominator[p], form}]

Now the negative sign is always factored out.

{-(1/2) (a + 2.3 * b + c), 1/2 (-a - 2.3 * b - c)}

{-1/2 (a + 2.3 b + c), -1/2 (a + 2.3 b + c)}


Created by Mathematica  (May 16, 2004)

Back to Ted’s Tricks index page