7
$\begingroup$

I would like to define a version of MatrixForm that prints entries equal to zero in gray. The definition

matrixform[X_] := MatrixForm[X /. entry_ /; entry == 0 -> Style[0, LightGray]]

produces an output that looks how I'd want, but it actually changes the entries, rather than just the way they are displayed, so one cannot just use the output of my matrixform via % in algebraic manipulations.

Ideally I'm looking for an answer that works for sparse arrays too, without the conversion to a normal array: at least, I'd like to be able to work with the output without having to convert it back to a sparse array.

Note that I don't want just all zeroes in my notebook to be formatted in gray (so I don't think I can use Format), and I don't want matrices to be formatted as above automatically either.


Edit. Here is an example of what I'm hoping to achieve:

A = SparseArray[{1,1}->x,{2,2}]
(* Out: SparseArray[..., Specified elements: 1, Dimensions: {2,2}] as usual *) 

% // matrixform
(* Out: MatrixForm of A with 0s shown in gray *)

2 %
(* Out: SparseArray[..., Specified elements: 1, Dimensions: {2,2}] as usual *)

% // matrixform
(* Out: MatrixForm of 2*A with 0s shown in gray *)
$\endgroup$
1
  • $\begingroup$ PS. I don't really understand if there's a difference between the tags output-formatting and formatting, so I've used both; feel free to edit them. $\endgroup$ Commented Feb 5, 2018 at 13:57

2 Answers 2

8
$\begingroup$

To get the % behavior you want, you need to create a wrapper, that is, a function that does not evaluate, but creates a nice format when it is rendered. The usual way to do this is to use MakeBoxes. Here is a version that should target only matrix entries, and also avoid evaluation leaks:

matrixForm /: MakeBoxes[matrixForm[x_List], StandardForm] := Replace[
    Replace[Hold[x], 0->Style[0, Red], {3}],
    Hold[z_] :> MakeBoxes[MatrixForm[z]]
]

Note that I used Red instead of LightGray to improve visualization for this answer. Now that matrixForm is a wrapper, you can add it to $OutputForms as suggested in (51898).

Unprotect[$OutputForms];
AppendTo[$OutputForms, matrixForm];
Protect[$OutputForms];

Example:

matrixForm[{{f[0], 0}, {1, 0}}]

enter image description here

And using %:

%

{{f[0], 0}, {1, 0}}

For SparseArray objects, you could add the following format, but note that it relies on being able to reconstruct a SparseArray from its FullForm, updated to work in M13 as well (note that being able to reconstruct a sparse array in this way may change in the future):

matrixForm /: MakeBoxes[matrixForm @ s_SparseArray, StandardForm] := With[
    {
    new = SparseArray[
        Automatic, 
        Dimensions[s], 
        Style[s["Background"], Red],
        {1, {s["RowPointers"], s["ColumnIndices"]}, s["NonzeroValues"]}]
    },
    MakeBoxes[
        MatrixForm @ new,
        StandardForm
    ]
]

Example:

matrixForm[IdentityMatrix[3, SparseArray]]

enter image description here

Check %:

%

SparseArray[Automatic, {3, 3}, 0, { 1, {{0, 1, 2, 3}, {{1}, {2}, {3}}}, {1, 1, 1}}]

$\endgroup$
6
  • $\begingroup$ Very nice! Do also know how to make it work for displaying sparse arrays as well, without turning the % into normal form? $\endgroup$ Commented Feb 5, 2018 at 16:09
  • $\begingroup$ @JulesLamers See update $\endgroup$
    – Carl Woll
    Commented Feb 5, 2018 at 16:17
  • $\begingroup$ Fantastic, that does exactly what I want. Thanks! $\endgroup$ Commented Feb 5, 2018 at 16:24
  • $\begingroup$ In Mma v13 the part of your answer for sparse arrays no longer works. Do you know how this can be fixed? $\endgroup$ Commented Jul 24, 2023 at 2:55
  • 1
    $\begingroup$ @JulesLamers See update. $\endgroup$
    – Carl Woll
    Commented Jul 24, 2023 at 14:38
6
$\begingroup$
SeedRandom[0]

(m = RandomInteger[{0, 2}, {4, 4}]) // MatrixForm

enter image description here

Note that by using parentheses, the definition of m does not include the wrapper MatrixForm

matrixForm[x_List] := ((x /. 0 :> Style[0, LightGray]) // MatrixForm)

m // matrixForm

enter image description here

The wrappers, MatrixForm or matrixForm are only for display. If you want to use the matrix, use m. Any subsequent operation is done on m and the display is formatted using the wrapper.

(m2 = Transpose@m) // matrixForm

enter image description here

m == (m2 // Transpose)

(* True *)
$\endgroup$
8
  • $\begingroup$ I think that does more or less what my matrixform does. The problem is that such definitions alter the matrix you're displaying: the line after m // matrixform, writing e.g. 2 % gives {{4,4,2,2*Style[0,LightGray]},...} $\endgroup$ Commented Feb 5, 2018 at 14:07
  • $\begingroup$ Ad edit: Output formatted with MatrixForm can be used for algebraic manipulations. For example, starting from some sparse array a, even though the output of a // MatrixForm is nicely formatted, one can actually use that output in something like 2 % to get a sparse array whose entries are twice those of a. I am looking for something similar here, perferably without having to use parentheses as in(...) // matrixform, if possible $\endgroup$ Commented Feb 5, 2018 at 14:46
  • $\begingroup$ @JulesLamers - Then just use 2 % // matrixform $\endgroup$
    – Bob Hanlon
    Commented Feb 5, 2018 at 15:00
  • 3
    $\begingroup$ @JulesLamers To get the % behavior you want, see (51898). $\endgroup$
    – Carl Woll
    Commented Feb 5, 2018 at 15:19
  • $\begingroup$ @CarlWoll Thanks! That looks very relevant. (And complicated...) I'll take a better look at it later $\endgroup$ Commented Feb 5, 2018 at 15:25

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.