# MatrixPlot with Tooltips

MatrixPlot is very nice to have a first look of data, I would like to have a MatrixPlot with tooltips for each value. I tried adding Tooltip to all the values but it didn't work. My matrix is not very big (~20x25), so each square is visible.

EDIT: This is the version I did using the answer of Heike:

matPlot[matWithTooltips_, opts : OptionsPattern[]] :=
With[{dim = Dimensions[matWithTooltips],
mat = matWithTooltips /. Tooltip[a_, ___] :> a},
DynamicModule[{pt = {0, 0}, ij, xy, label, direction},
direction[mxy_] := 1 - 2 Boole[Thread[mxy > dim/2]];
LocatorPane[Dynamic[pt],
Dynamic[
xy = Floor[pt];
ij = {dim[], 1} + Cross[xy];
label = If[And @@ Thread[1 <= ij <= dim],
{{FaceForm[], EdgeForm[{Thick, LightGray}], Rectangle[xy]},
Text[
Framed[Replace[
Extract[matWithTooltips, ij], {Tooltip[a_, b_] :> b,
Tooltip[a_] :> a}], Background -> White],
direction[xy] + xy,
-1.2 direction[xy]]},
{}];
MatrixPlot[mat, Epilog -> label, opts]],
AutoAction -> True,
Appearance -> None]]]


The main improvement is that it can receive a matrix with its own tooltips in the data.

Thanks to all for the help.

This is just an elaboration of faleichik's answer. To create a MatrixPlot with tooltip labelling and highlighting of the selected square similar to for example BarChart or BubbleChart you could do something like

matPlot[mat_, opts : OptionsPattern[]] :=
With[{dim = Dimensions[mat]},
DynamicModule[{pt = {0, 0}, ij, xy, label, direction},
direction = 1 - 2 Boole[Thread[# > dim/2]] &;
LocatorPane[Dynamic[pt],
Dynamic[xy = Floor[pt];
ij = {dim[], 1} + Cross[xy];
label = If[Nand @@ Thread[1 <= ij <= dim], {},
(* else *)
{{FaceForm[], EdgeForm[{Thick, LightGray}], Rectangle[xy]},
Text[Framed[mat ~Extract~ ij, Background -> White],
direction[xy] + xy, -1.2 direction[xy]]}];
MatrixPlot[mat, Epilog -> label, opts]],
AutoAction -> True,
Appearance -> None]
]]


Screenshot

mat = RandomReal[1, {30, 40}];
matPlot[mat, ColorFunction -> "DeepSeaColors"] • Very nice! Looking to the code: is there any particular reason to use With[] wrapping here? Why not include dim = Dimensions[mat] directly to DynamicModule? Am I missing something? Mar 2 '12 at 14:37
• @faleichik No particular reason other than that With is usually more efficient for localizing constants than DynamicModule (although I don't think it would make any noticeable difference in this case). Mar 2 '12 at 14:53
• I like this a lot, but something I don't like is that when I changed the tooltip for something more complex, it got cut by the borders, maybe it could be fix to change the position of the tooltip towards the center of the image. I will try it. Thanks!
– FJRA
Mar 2 '12 at 15:51
• I inserted a simple direction function instead of 1+xy and worked very nice! direction := 1 - 2 Boole[Thread[# > dim/2]] & and changed 1+xy -> direction[xy]+xy, {-1.2,-1.2} -> -1.2 direction[xy].
– FJRA
Mar 2 '12 at 17:48
• Why do I even bother to answer Graphics questions? +1 :-) Mar 2 '12 at 19:16

My variant is without tooltips but is fast. You need to click on the desired cell to get the value. One more advantage is that you have the generic MatrixPlot, not a substitute.

A = Table[Sin[x y/10 + x], {x, 1, 50}, {y, 1, 50}] // N;
{n, m} = Dimensions@A;
DynamicModule[{pt = {1, 1}/2, trans, ij},
trans[{x_, y_}] := {Max[1, Min[n, Floor[n - y] + 1]],
Max[1, Min[m, Floor@x + 1]]};
Column@{
LocatorPane[Dynamic[pt], MatrixPlot[A, ImageSize -> 500]],
Dynamic[(ij = trans@pt) -> A[[Sequence @@ ij]]]
}
] EDIT: more dynamic version without LocatorPane (no need to click) + using Clip as Mr.Wizard kindly adviced.

   A = Table[Sin[x y/10 + x], {x, 1, 50}, {y, 1, 50}] // N;
{n, m} = Dimensions@A;
DynamicModule[{pt = {1, 1}/2, trans, ij},
trans[{x_, y_}] := {Clip[Floor[n - y] + 1, {1, n}],
Clip[Floor@x + 1, {1, m}]};
Column@{MatrixPlot[A, ImageSize -> 500],
Dynamic[(ij = trans@MousePosition["Graphics", {0, 0}]) ->
A[[Sequence @@ ij]]]}
]


EDIT 2: using Appearance->None and Epilog, creating a stylish Tooltip in the right place, with the right alignment (you can probably do more to style it better if you want to spend the time).

A = Table[Sin[x y/10 + x], {x, 1, 50}, {y, 1, 50}] // N;
{n, m} = Dimensions@A;
DynamicModule[{pt = {1, 1}/2, trans, ij},
trans[{x_, y_}] := {Max[1, Min[n, Floor[n - y] + 1]],
Max[1, Min[m, Floor@x + 1]]};
gLoc[{x_, y_}] := {First@#, 1 + n - Last@#} &@Reverse@trans@{x, y};
Column@{LocatorPane[Dynamic[pt],
MatrixPlot[A, ImageSize -> 500,
Epilog ->
Dynamic@{EdgeForm[Red], FaceForm[None],
Rectangle[gLoc@pt, gLoc@pt - 1], EdgeForm[Black],
FaceForm[{Opacity[.7], RGBColor[1, 1, .6]}],
If[First@gLoc@pt < n - 12,
{Rectangle[gLoc@pt + {6, 2}, gLoc@pt + {-1, 0}],
Text[A[[Sequence @@ (trans@pt)]], gLoc@pt + {2, 1}]},
{Rectangle[gLoc@pt + {-7, 2}, gLoc@pt],
Text[A[[Sequence @@ (trans@pt)]], gLoc@pt + {-3, 1}]}]}],
Appearance -> None, AutoAction -> True],
Dynamic[(ij = trans@pt) -> A[[Sequence @@ ij]]]}]

• Technically not tooltips, but quite possibly the better alternative. +1 Mar 2 '12 at 7:53
• Noted. You may care to know there is a built-in function for the Max[ Min [ ] ] thing: Clip[. . ., {1, m}] Mar 2 '12 at 8:21
• I like this approach. You could set AutoAction -> True in DynamicModule if you want the locator position to be continuously updated. Also, to mimic Tooltip, you could play around with Appearance in LocatorPane, or use Epilog to dynamically plot a label with the current value on top of the matrix plot. Mar 2 '12 at 9:17
• This is a very good alternative, since I can locate the "tooltip" above and use it as title comment. Thanks!
– FJRA
Mar 2 '12 at 15:53

EDIT: y-axis corrected

You could do something like this:

a = RandomInteger[99, {7, 5}];

minmax = {Min@a, Max@a};
cf = ColorData["SunsetColors"];
ticks = Table[{i, # - i + 1}, {i, #}] & @ Length[a]

Graphics[
{cf[1 - Rescale[#2, minmax]],
Tooltip[Rectangle[# - 0.5], #2]} & @@@
Most @ ArrayRules @ Reverse[a\[Transpose], {2}],
Frame -> True,
FrameTicks -> {All, ticks}
] • +1. It is VERY hard to make something faster than you guys. Although this Tooltip aproach becomes very slow for large matrices. Mar 2 '12 at 7:22
• @faleichik it is slow, but unless there is a specialized option for Raster I am overlooking I don't know of a better way. Mar 2 '12 at 7:28
• I thought also about doing my own matrix plot, anyway I wanted to know if MatrixPlot could be adapted to have tooltips. Here would be necessary to add the MatrixPlot behavior for non numeric cases (like Indeterminate). Thanks!
– FJRA
Mar 2 '12 at 15:58

One can also use the option CoordinatesToolOptions for MatrixPlot and make use of the Get Coordinates tool as follows:

 MatrixPlot[mat, ColorFunction -> "DeepSeaColors",
CoordinatesToolOptions ->
{"DisplayFunction" ->
Function[pt,
With[{rows = Dimensions[mat][], columns = Dimensions[mat][]},
indices = {Clip[Floor[rows - pt[]] + 1, {1, rows}],
Clip[Floor@pt[] + 1, {1, columns}]};
Row[{"mat[", Row[indices, ","], "]  =  ", Extract[mat, indices]},
Background -> White, ImageSize -> {150, 30},
Alignment -> Center]
]]}]


where I used faleichik's transformation.

Screenshot: Update: Generalizing, one can

• Embed the needed coordinate transformations into DisplayFunction option for tooltips, and into CopiedValuesFunction option for copy/paste,
• Use these user-specified functions as values for the CoordinatesToolOptions option in MatrixPlot, and
• Let the Get Coordinates tool manage the dynamics needed for tooltips and copy/paste

as in:

  mtrxPlot2[mat_, opts : OptionsPattern[]] :=
With[{dims = Dimensions[mat],
indx = {Clip[Floor[#1[] - #2[]] + 1, {1, #1[]}],
Clip[Floor[#2[]] + 1, {1, #1[]}]} &},
With[{copiedvalues = "CopiedValueFunction" -> Function[pt,
{indx[dims, pt], Extract[mat, indx[dims, pt]]}],
coordtooltips = "DisplayFunction" -> Function[pt,
Row[{"mat[[", Row[indx[dims, pt], ","], "]]  =  ",
Extract[mat, indx[dims, pt]]},
Background -> White, ImageSize -> {Automatic, 30},
ImageMargins -> {{5, 5}, {10, 10}}, Alignment -> Center]]},
MatrixPlot[mat, opts,
CoordinatesToolOptions -> {coordtooltips, copiedvalues}]]]

• This is really cool and a best answer IMO. Mar 4 '12 at 16:47
• @faleichik, thank you. I like your and Heikes LocatorPane approach better because it allows you to highlight the cells (which I do not know how to do with CoordinatesToolOptions)
– kglr
Mar 5 '12 at 4:56
• After trying it, I think it's very fast, but I had a problem, when using the output of this graphic into a GraphicsGrid, it looses the custom coordinates tooltips. Anyway this is the fastest one!
– FJRA
Mar 6 '12 at 16:45

One way to do this:

is = 150; rm = RandomInteger[100, {5, 5}]; m =  Map[Tooltip[#, #] &, rm, {2}];
A = GraphicsGrid[m, ImageSize -> is {1, 1}]; B =  MatrixPlot[rm, FrameTicks -> None,
Mesh -> All, PlotRangePadding -> 0, ImageSize -> is {1, 1}]; Overlay[{A, B}, All, 1] It'll be a bit more elaborate to add frame ticks.

• Good option, but tooltips only show up when you are in the center of the squares (if they are bigger than text numbers behind). I like that this is simple enough to be done without references once you know it :P.
– FJRA
Mar 2 '12 at 15:55
• @FJRA Yes, thanks. Overlay` is neat but often overlooked function - plus it preserves interactivity ;) Mar 2 '12 at 22:33