24
$\begingroup$

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]], 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.

$\endgroup$

5 Answers 5

18
$\begingroup$

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]], 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"]

screenshot

$\endgroup$
8
  • $\begingroup$ 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? $\endgroup$
    – faleichik
    Mar 2, 2012 at 14:37
  • $\begingroup$ @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). $\endgroup$
    – Heike
    Mar 2, 2012 at 14:53
  • $\begingroup$ 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! $\endgroup$
    – FJRA
    Mar 2, 2012 at 15:51
  • 2
    $\begingroup$ 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]. $\endgroup$
    – FJRA
    Mar 2, 2012 at 17:48
  • 4
    $\begingroup$ Why do I even bother to answer Graphics questions? +1 :-) $\endgroup$
    – Mr.Wizard
    Mar 2, 2012 at 19:16
21
$\begingroup$

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]]]
   }
 ]

enter image description here


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]]]}] 
$\endgroup$
4
  • $\begingroup$ Technically not tooltips, but quite possibly the better alternative. +1 $\endgroup$
    – Mr.Wizard
    Mar 2, 2012 at 7:53
  • 3
    $\begingroup$ Noted. You may care to know there is a built-in function for the Max[ Min [ ] ] thing: Clip[. . ., {1, m}] $\endgroup$
    – Mr.Wizard
    Mar 2, 2012 at 8:21
  • 4
    $\begingroup$ 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. $\endgroup$
    – Heike
    Mar 2, 2012 at 9:17
  • $\begingroup$ This is a very good alternative, since I can locate the "tooltip" above and use it as title comment. Thanks! $\endgroup$
    – FJRA
    Mar 2, 2012 at 15:53
9
$\begingroup$

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}
]

Mathematica graphics

$\endgroup$
3
  • $\begingroup$ +1. It is VERY hard to make something faster than you guys. Although this Tooltip aproach becomes very slow for large matrices. $\endgroup$
    – faleichik
    Mar 2, 2012 at 7:22
  • $\begingroup$ @faleichik it is slow, but unless there is a specialized option for Raster I am overlooking I don't know of a better way. $\endgroup$
    – Mr.Wizard
    Mar 2, 2012 at 7:28
  • $\begingroup$ 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! $\endgroup$
    – FJRA
    Mar 2, 2012 at 15:58
9
$\begingroup$

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][[1]], columns = Dimensions[mat][[2]]},
 indices = {Clip[Floor[rows - pt[[2]]] + 1, {1, rows}], 
    Clip[Floor@pt[[1]] + 1, {1, columns}]};
  Row[{"mat[", Row[indices, ","], "]  =  ", Extract[mat, indices]},
   Background -> White, ImageSize -> {150, 30}, 
   Alignment -> Center]
  ]]}]

where I used faleichik's transformation.

Screenshot:

tooltip and get coordinates

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[[1]] - #2[[2]]] + 1, {1, #1[[1]]}], 
  Clip[Floor[#2[[1]]] + 1, {1, #1[[2]]}]} &}, 
  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}]]]
$\endgroup$
3
  • $\begingroup$ This is really cool and a best answer IMO. $\endgroup$
    – faleichik
    Mar 4, 2012 at 16:47
  • $\begingroup$ @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) $\endgroup$
    – kglr
    Mar 5, 2012 at 4:56
  • $\begingroup$ 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! $\endgroup$
    – FJRA
    Mar 6, 2012 at 16:45
6
$\begingroup$

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]

enter image description here

It'll be a bit more elaborate to add frame ticks.

$\endgroup$
2
  • $\begingroup$ 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. $\endgroup$
    – FJRA
    Mar 2, 2012 at 15:55
  • 1
    $\begingroup$ @FJRA Yes, thanks. Overlay is neat but often overlooked function - plus it preserves interactivity ;) $\endgroup$ Mar 2, 2012 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.