# How to get contour levels of picked automatically by ContourPlot?

ContourPlot picks a nice set of curves as level curves by default. I'm trying to use the set of curves as mesh curves for corresponding 3D plot, can anyone suggest how I can get those levels extracted out of contour plot?

f[x_, y_] := Log[(1 - x)^2 + 100 (y - x^2)^2];
ContourPlot[f[x, y], {x, -2, 0.5}, {y, -2, 2},
ContourStyle -> {{Gray, Thick}}, PlotPoints -> 100,
ColorFunction -> Function[GrayLevel[1 - .45 #]], Frame -> None]
Plot3D[f[x, y], {x, -2, 0.5}, {y, -2, 2}, PlotPoints -> 100,
MeshFunctions -> {#3 &}, Mesh -> {{0, 1, 2, 3, 4}}, Ticks -> None]


• You can hunt through for Tooltips Commented Dec 13, 2017 at 17:49
• Hm...tooltips says the curves are 0,1,2,3,4,5,6,7,8....but using those as Mesh values doesn't give me same curves Commented Dec 13, 2017 at 17:56
• I can't reproduce that - if I change the code you posted, and add in the 5,6,7, and 8, it looks the same as below Commented Dec 13, 2017 at 18:04
• ok looks like I was plotting 2 different functions, thanks for the Tooltip extractor code Commented Dec 13, 2017 at 19:05
• Duplicates: (31858), (66487) Commented Dec 14, 2017 at 12:36

By default, contours generated by ContourPlot have Tooltips with their numerical value as the label. You can use Cases to grab the values programmatically.

f[x_, y_] := Log[(1 - x)^2 + 100 (y - x^2)^2];
plot = ContourPlot[f[x, y], {x, -2, 0.5}, {y, -2, 2},
ContourStyle -> {{Gray, Thick}}, PlotPoints -> 100,
ColorFunction -> Function[GrayLevel[1 - .45 #]], Frame -> None]

levels = Union@Cases[plot, Tooltip[_, label_] :> label, Infinity];

Plot3D[f[x, y], {x, -2, 0.5}, {y, -2, 2}, PlotPoints -> 100,
MeshFunctions -> {#3 &}, Mesh -> {levels}, Ticks -> None]


ContourPlot[f[x, y], {x, -2, .5}, {y, -2, 2},
Contours -> ((contours = FindDivisions[{#, #2}, #3, Method -> {}]) &)];
Plot3D[f[x, y], {x, -2, .5}, {y, -2, 2}, PlotPoints -> 100,
MeshFunctions -> {#3 &}, Mesh -> {contours}, Ticks -> None]


Jason's approach, extracting Tooltip labels form ContourPlot output, is straightforward and convenient.

For the curious, how ContourPlot picks a nice set of curves as level curves by default remains a puzzle.

Speaking of "nice", searching for "nice numbers" in the Documentation Center gives:

After a few trials, we find that the function FindDivisions[{#, #2}, #3, Method -> {}]& (where the first two arguments are $z_{min}$ and $z_{max}$ and the last argument is the number of divisions which is fixed at 10) as the setting for Contours gives the same output as the default setting for this option.

Some examples:

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}] ==
ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi},
Contours -> (FindDivisions[{#, #2}, #3, Method -> {}] &)] ==
ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi},
Contours -> (FindDivisions[{#, #2}, 10, Method -> {}] &)]


True

rr = RandomReal[5, 2];
ContourPlot[Evaluate[Sum[Sin[rr.{x, y}], {5}]], {x, 0, 5}, {y, 0, 5}] ==
ContourPlot[Evaluate[Sum[Sin[rr.{x, y}], {5}]], {x, 0, 5}, {y, 0, 5},
Contours -> (FindDivisions[{#, #2}, #3, Method -> {}] &)]


True

So for OP's example, we can extract the default contour levels using this function as follows:

f[x_, y_] := Log[(1 - x)^2 + 100 (y - x^2)^2];
cp1 = ContourPlot[f[x, y], {x, -2, .5}, {y, -2, 2}];
levels = Cases[cp1, Tooltip[_, t_]:>t, Infinity];

cp2 = ContourPlot[f[x, y], {x, -2, .5}, {y, -2, 2},
Contours -> ((contours = FindDivisions[{#, #2}, #3, Method -> {}]) &)];

cp1 === cp2


True

levels == Reverse@contours


True