# 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 – Jason B. Dec 13 '17 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 – Yaroslav Bulatov Dec 13 '17 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 – Jason B. Dec 13 '17 at 18:04
• ok looks like I was plotting 2 different functions, thanks for the Tooltip extractor code – Yaroslav Bulatov Dec 13 '17 at 19:05
• Duplicates: (31858), (66487) – Michael E2 Dec 14 '17 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