I am trying to show a BarLegend for a MatrixPlot. I am aware that doing MatrixPlot[ ... PlotLegends -> Automatic] should work, but for some reason it isn't. The function I'm using to specify the colour coding is somewhere inside myfunction, and even when plotting it alone I can't get the full thing to show.

This code snippet reproduces the problem. I think that if I get this to work I may be able to have MatrixPlot working with the legend.

myfunction[range_] := Block[{bar, something},
  bar = (Blend[{{range[[1]], 
        Lighter@Cyan}, {range[[1]] - range[[3]]/2, 
        Orange}, {range[[2]], Darker@Red}}, #] &);
  BarLegend[{bar[#] &, {range[[1]], range[[2]]}}]
myfunction[{-3, 10, 13}]

enter image description here


1 Answer 1


I had initially intended to make this as a comment, but I think expanding on what is happening would be very useful. There are two issues here, and it is helpful to look at the InputForm of what myfunction produces:

InputForm@myfunction[{-3, 10, 13}]
(* BarLegend[{bar[#1] & , {-3, 10}}] *)

The first issue is that BarLegend does not evaluate; it, and the other legend functions, have no transformative DownValues. Their DownValues only check validity, but otherwise leave them unevaluated. They are then handled during markup, in much the same way that Graphics is. Second, bar will not evaluate outside of the Block, unless it has DownValues/UpValues in the enclosing scope. Taken together, when BarLegend is marked up, there is no function for it to operate on.

The solution is to use either Module or With. Using Module, though,

mfModule[range_] := 
 Module[{bar, something}, 
  bar = (Blend[{{range[[1]], 
        Lighter@Cyan}, {range[[1]] - range[[3]]/2, 
        Orange}, {range[[2]], Darker@Red}}, #] &);
  BarLegend[{bar[#] &, {range[[1]], range[[2]]}}]]

results in an evaluation leak

InputForm@mfModule[{-3, 10, 13}]
(* BarLegend[{bar$3604[#1] & , {-3, 10}}] *)

as the internal variable, bar$, will not be released until all references to it are gone. So, I prefer using With,

mfWith[range_] := 
 With[{bar = (Blend[{{range[[1]], 
         Lighter@Cyan}, {range[[1]] - range[[3]]/2, 
         Orange}, {range[[2]], Darker@Red}}, #] &)},
  BarLegend[{bar[#] &, {range[[1]], range[[2]]}}]]

as it places the function directly into the result:

InputForm@mfWith[{-3, 10, 13}]
(* BarLegend[{(Blend[{{{-3, 10, 13}[[1]], Lighter[Cyan]}, 
  {{-3, 10, 13}[[1]] - {-3, 10, 13}[[3]]/2, Orange}, 
  {{-3, 10, 13}[[2]], Darker[Red]}}, #1] & )[#1] & , {-3, 10}}]*)
  • $\begingroup$ BarLegend does have down values, though mainly for argument checking purposes. $\endgroup$ Nov 9, 2016 at 14:57
  • $\begingroup$ @BrettChampion yep, I see that now, and how they work. Will figure out how to rephrase ... $\endgroup$
    – rcollyer
    Nov 9, 2016 at 15:01

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.