# BarLegend not showing full range when indicated inside a function

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


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

• BarLegend does have down values, though mainly for argument checking purposes. Nov 9 '16 at 14:57
• @BrettChampion yep, I see that now, and how they work. Will figure out how to rephrase ... Nov 9 '16 at 15:01