# Getting contour levels in BarLegend to match their tick location instead of being equally spaced

Currently, I have the following

BarLegend[{colourScheme, {0, 10}}, {0.1, 5, 5.5}]


The contours are evenly distributed across the colourbar. I want them to sit where the corresponding tick values are (so 0.1 should be very close to the bottom, 5 should be right in the middle, etc.). How do I do this?

Thanks!

• Welcome to the Mathematica Stack Exchange. What is the value at the top of the scale? Is this a compressed scale of some kind? Why is 5 sitting right in the middle? What is colourScheme?
– Syed
Commented Jan 20 at 2:20
• Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. Commented Jan 22 at 13:55

The following provides what appears to be requested.

BarChart[{10, 5.5, 5, 0.1}, ChartLayout -> "Overlapped",
ImageSize -> Tiny, Axes -> False, AspectRatio -> 4,
ColorFunction -> "Rainbow", ChartLabels ->
Placed[{"10.", "5.5", "5.0", "0.1"}, {{1, 1}, {-.5, .5}}]]


If eliminating the top label is desired, replace "10." by Null. Colors can be changed by replacing ColorFunction -> "Rainbow" by a custom ChartStyle, for instance ChartStyle -> {Red, Green, Cyan, Purple}.

• That does the trick. Quite surprising Mathematica doesn't have an inbuilt option to do this, but alas. Thanks! Commented Jan 22 at 13:19
ClearAll[contourLegend]


The function contourLegend takes Graphics options and options to control ticks, tick labels and legend orientation:

Options[contourLegend] = Join[
{"Ticks" -> Automatic,
"TickLabels" -> Automatic,
"TickLengths" -> Automatic,
"TickSide" -> Right,
"TickDirection" -> "Out",
"RotateLabel" -> False,
"Appearance" -> "Vertical"},
Options[Graphics]];


The first two arguments specify the color scheme and contour levels, which are used to construct rectangles with appropriate colors.

contourLegend[{cs_, range_ : {0, 1}}, contours_, opts : OptionsPattern[]] :=
Module[{$$rects,$$ticks, $$tvals,$$tlbls, $$tlngths,$$rot,
$$cl = Join[{range[[1]]}, contours, {range[[2]]}],$$wdth = -Subtract @@ range /15,
$$tr = OptionValue["Appearance"] /. {Automatic | "Vertical" | "Column" -> Identity, _ -> Reverse},$$tr2 = OptionValue["TickSide"] /.
{Right | After | Above | Top | Automatic -> Identity, _ -> Reverse},
$$clrs = ColorData[{cs, range}] /@ Join[{range[[1]]}, MovingAverage[contours, 2], {range[[2]]}]},$$tvals = OptionValue["Ticks"] /. Automatic -> $$cl;$$tlbls = OptionValue["TickLabels"] /. Automatic -> $$tvals;$$rot = OptionValue["RotateLabel"] /.
{False -> 0  Degree, True -> 90  Degree, x_ :> x};
$$tlbls = Map[Rotate[#,$$rot] &] @ $$tlbls;$$tlngths = OptionValue["TickLengths"] /. Automatic ->
(OptionValue["Appearance"] /.
{Automatic|"Vertical"|"Column" -> .15, _ -> .015});
$$tlngths = If[ListQ @ OptionValue["TickLengths"],$$tlngths,
OptionValue["TickDirection"] /.
{"In" -> {$$tlngths, 0}, "InOut" ->$$tlngths {1, 1}, _ -> {0, $$tlngths}}];$$rects = Map[Rectangle @@ Transpose[$$tr@{{0, wdth}, #}] &] @ Partition[$$cl, 2, 1];
$$ticks = Thread[{tvals, tlbls, tlngths}, List, 2]; Graphics[MapThread[{EdgeForm[], #, #2} &] @ {clrs, rects}, FilterRules[{opts}, Options[Graphics]], PlotRangePadding -> 0, AspectRatio -> Automatic, ImageSize -> {{50, All}, All}, ImagePadding -> All, Frame -> True, FrameTicks ->$$tr @ {$$tr2 @ {None,$$ticks}, {None, None}}]]


Examples:

Row[{contourLegend[{"Rainbow", {0, 1}}, {.2, .6, .7, .9}],
contourLegend[{"Rainbow", {0, 10}}, {2, 6, 7, 9}],
contourLegend[{"TemperatureMap", {0, 1}}, {.2, .6, .7, .9}],
contourLegend[{"TemperatureMap", {0, 100}}, {10, 30, 50, 90}],
contourLegend[{"TemperatureMap", {0, 100}}, {10, 30, 50, 90},
"Ticks" -> {10, 30, 50, 90},
"TickLabels" -> {"A", "BBBB", "CC", "label 4"},
FrameLabel -> {{Style["legend", 18], None}, {None, None}}],
contourLegend[{"TemperatureMap", {0, 100}}, {10, 30, 50, 90},
"Ticks" -> {10, 30, 50, 90},
"TickLabels" -> {"A", "BBBB", "CC", "label 4"},
"TickSide" -> Left, "TickDirection" -> "InOut",
"TickLengths" -> .25, FrameTicksStyle -> Thick,
PlotLabel -> Style["legend", 16]]
}, Spacer[20]] // Style[#, ImageSizeMultipliers -> {1, 1}] &


Column[{contourLegend[{"Rainbow", {0, 1}}, {.2, .6, .7, .9},
"Appearance" -> "Horizontal"],
contourLegend[{"Rainbow", {0, 10}}, {2, 6, 7, 9},
"Appearance" -> "Horizontal"],
contourLegend[{"TemperatureMap", {0, 1}}, {.2, .6, .7, .9},
"Appearance" -> "Horizontal"],
contourLegend[{"TemperatureMap", {0, 100}}, {10, 30, 50, 90},
"Appearance" -> "Horizontal"],
contourLegend[{"TemperatureMap", {0, 100}}, {10, 30, 50, 90},
"Ticks" -> {10, 30, 50, 90},
"TickLabels" -> {"A", "BBBB", "CC", "label 4"},
"Appearance" -> "Horizontal", "RotateLabel" -> True,
FrameLabel -> {{None, None}, {Style["legend", 18], None}}],
contourLegend[{"TemperatureMap", {0, 100}}, {10, 30, 50, 90},
"Ticks" -> {10, 30, 50, 90},
"TickLabels" -> {"A", "BBBB", "CC", "label 4"},
"TickSide" -> Left, "TickDirection" -> "InOut",
"TickLengths" -> .025, "Appearance" -> "Horizontal",
"RotateLabel" -> True, FrameTicksStyle -> Thick,
PlotLabel -> Style["legend", 16]]
}, Dividers -> All] // Style[#, ImageSizeMultipliers -> {1, 1}] &


With[{contours = {-1., -.8, .5, 1.25}},
ContourPlot[2 Sin[x  y], {x, 0, π}, {y, 0, π},
ColorFunction -> "Rainbow", Contours -> contours, ImageSize -> 300,
PlotLegends -> contourLegend[{"Rainbow", {-2, 2}}, contours]]]


With[{contours = {-1., -.8, .5, 1.25}},
ContourPlot[2  Sin[x   y], {x, 0, π}, {y, 0, π},
ColorFunction -> "Rainbow", Contours -> contours, ImageSize -> 300,
PlotLegends -> Placed[
contourLegend[{"Rainbow", {-2, 2}}, contours,
"Appearance" -> Row, ImageSize -> {250, 50}, "RotateLabel" -> True],
Top]]]


When the second argument is specified, BarLegend produces equally-spaced contours with shading determined by the value of color function at specified contour levels.

To get a bar legend that behaves like ContourPlot (that is, shaded areas are proportional to differences between successive contour values) we can use (what else?) ContourPlot as follows:

barLegend[{cs_, range_: Automatic}, contours_, ticks_ : Automatic,
opts : OptionsPattern[]] :=
Module[{rmin = First[range /. Automatic -> {0, 1}],
rmax = Last[range /. Automatic -> {0, 1}]},
ContourPlot[$$y, {x, 0, 1}, {$$y, rmin, rmax}, opts,
ColorFunction -> cs, Contours -> contours,
AspectRatio -> (rmax - rmin), PlotRangePadding -> None,
Frame -> {{False, True}, {False, False}}, ContourStyle -> None,
FrameTicks -> {{None, {#, #, {0, .1}} & /@ (ticks /.
Automatic -> Join[{rmin}, contours, {rmax}])}, {None, None}}]]


Examples:

Row[{BarLegend[{"Rainbow", {0, 10}}, {0.1, 5, 5.5},
LegendMarkerSize -> 400],
barLegend[{"Rainbow", {0, 10}},
{0.1, 5, 5.5},
{0.1, 5, 5.5, 10},
ContourStyle -> None,
ImageSize -> {100, 400},
AspectRatio -> 20,
LabelStyle -> 14]},
Spacer[30]]


Replace "Rainbow" with "TemperatureMap" to get

With[{contours = {-.8, -.9, 1, .75}},
Row[ContourPlot[Sin[x  y], {x, 0, π}, {y, 0, π},
ColorFunction -> "Rainbow", Contours -> contours,
ImageSize -> 300, PlotLegends -> #] & /@
{Automatic,
barLegend[{"Rainbow", {-1, 1}}, contours, AspectRatio -> 20,
ImageSize -> {80, 300}, ImagePadding -> All]}]]


• The barLegend function doesn't seem to work. The output just prints barLegend({"Rainbow", {-1, 1}}, {-0.8, -0.9, 1, 0.75}, AspectRatio -> 20, ImageSize -> {80, 300}, ImagePadding -> All). Commented Jan 22 at 13:17
• Thank you @Sharplie12321. I updated with a correction - replaced range:Automatic with range_:Automatic.
– kglr
Commented Jan 22 at 17:31