Count the number of contours

I have plotted a ListContourPlot and have not specified the number of contours that are plotted, just the range. Is there a way to count how many contours have been automatically plotted by Mathematica?

EDIT

If I have contours representing different values, is there a way to select the contour relative to a specific value?

• I and J.M. interpreted the question differently. Are you trying to count the number of contours in his sense or in the sense that I counted them? Apr 5 '17 at 22:53
• @C.E. Let us assume I have a contour plot with 10 contours and their value ranges from 1 to 10. How can I select the contour which represents the value of 7 (without selecting the 7th contour)?
– GEF
Apr 5 '17 at 23:00
• What do you mean "select"? Apr 5 '17 at 23:21
• @C.E. I mean extracting all the points belonging to the contour representing the value of 7.
– GEF
Apr 5 '17 at 23:25
• You can use the same method that march uses in his answer. You apply Normal to the plot and then extract the lines using Cases. Select all lines such that if you take on of the coordinates in the line and apply your function then you get the number that you desire. Apr 5 '17 at 23:29

FindDivisions

The list of automatically selected contours can be obtained using FindDivisions[{#, #2}, #3, Method -> {}] as the setting for Contours.

SeedRandom
data = RandomReal[1, {10, 10}];
lcp1 = ListContourPlot[data, InterpolationOrder -> 3, ImageSize -> 300];

The default list of contours in lcp1 can also be obtained using FindDivisions in the option setting for Contours. (See this answer to a related question.)

lcp2 = ListContourPlot[data, InterpolationOrder -> 3,
Contours -> ((contoursFD = FindDivisions[{#, #2}, #3, Method -> {}]) &)];

The two graphics objects lcp1 and lcp2 are identical:

lcp1 == lcp2

True

And the list contoursFD captured in lcp2 is identical with the default list of contours in lcp1.

N @ contoursFD

{0., 0.2, 0.4, 0.6, 0.8, 1.}

These contours match the ones produced by @J.M.'s method using Tooltips:

contoursTT = Reverse[Cases[lcp1, Tooltip[a_ /; Not[FreeQ[a, _Line]], t_] :> t, ∞]]

{0, 0.2, 0.4, 0.6, 0.8, 1}

Row[{Show[lcp1, PlotLabel -> Style["contours : " <> ToString@contoursTT, 16]],
Show[lcp2, PlotLabel -> Style["contours : " <> ToString@N[contoursFD], 16]]}] Update: FindDivisions also works to find the contour levels for the setting Contours -> {Automatic, atmostn} using atmostn as the second argument of FindDivisions:

atmostn = 3;
lcp3a = ListContourPlot[data, InterpolationOrder -> 3, Contours -> {Automatic, atmostn}];
contoursTT = Reverse[Cases[lcp3a, Tooltip[a_ /; Not[FreeQ[a, _Line]], t_] :> t, ∞]];
lcp3b = ListContourPlot[data, InterpolationOrder -> 3,
Contours -> ((contoursFD = FindDivisions[{#, #2}, atmostn, Method -> {}]) &)];
contoursFD == contoursTT

True

Style[Row[{Show[lcp3a, PlotLabel ->
Pane[Style["contours : " <> ToString@N[contoursTT], 12],
ImageSize -> {200, Automatic}]],
Show[lcp3b, PlotLabel ->
Pane[Style["contours : " <> ToString@N[contoursFD], 12],
ImageSize -> {200, Automatic}]]}],
ImageSizeMultipliers -> {1, 1}] For atmostn = 25 we get

contoursFD == contoursTT

True Update 2: For the question added in the update:

assume I have a contour plot with 10 contours and their value ranges from 1 to 10. How can I select the contour which represents the value of 7 (without selecting the 7th contour)?

a contour plot with 10 contours and their value ranges from 1 to 10:

lcp10 = ListContourPlot[3 + data, InterpolationOrder -> 3,
Contours -> Range, ContourShading -> None,
ContourStyle -> (ColorData[63, "ColorList"][[;; 10]])] How can I select the contour which represents the value of 7?

lcpC7 = ListContourPlot[3 + data, InterpolationOrder -> 3,
Contours -> {7}, ContourStyle -> Directive[Red, Thick], lines = Cases[Normal@lcpC7, _Line, Infinity];
lines // Short

{Line[{{100., 3.55836}, {99.9841, 3.5646}, <<24>> ,{97.1146, 4.}}], <<29>>, <<1>>}

Show[lcp10, Epilog -> {Blue, Thick, lines}] If you're dealing with multiple contours corresponding to multiple heights, a hacky way is to count the number of Tooltip[] objects being used internally. For instance,

conts = ContourPlot[Cos[x] + Cos[y], {x, 0, 4 π}, {y, 0, 4 π}, ContourShading -> None] Then,

Count[conts, Tooltip[l : {__} /; MemberQ[l, Line[__]], v_?NumericQ], ∞]
7

Here, counting Line[] objects would result in a gross overestimate. This is confirmed when one uses the explicit setting Contours -> 7 in ContourPlot[].

Original interpretation of the question

cp = ContourPlot[Cos[x] + Cos[y] == 1/2, {x, 0, 4 π}, {y, 0, 4 π}] Count[cp, _Line, ∞]

9

To understand how this works you need to be familiar with how graphics is represented in Mathematica. Examining FullForm[cp] is a good start in case you don't know this yet.

Here is my take on the extra question using the same kind of approach:

cp = ContourPlot[{Abs[Sin[x] Sin[y]] == 0.5,
Abs[Cos[x] Cos[y]] == 0.5}, {x, -3, 3}, {y, -3, 3}] Cases[cp, {Directive[col_, __], lines__Line} :> {col, Length[{lines}]}, ∞] But I think you are better off plotting the levels one by one and then using the approach here above.

cps = ContourPlot[#, {x, -3, 3}, {y, -3, 3}] & /@ {Abs[
Sin[x] Sin[y]] == 0.5, Abs[Cos[x] Cos[y]] == 0.5} Count[#, _Line, ∞] & /@ cps

{4, 9}

Alternative interpretation of the question

J.M. interpreted the question a little differently than I. My version of his code would not count tooltip labels, but would count colors instead. The reason is that it's slightly easier.

cp = ContourPlot[
Cos[x] + Cos[y], {x, 0, 4 π}, {y, 0, 4 π},
ContourStyle -> (ColorData[#] & /@ Range)
];

Count[cp, _RGBColor, ∞]

7

Note that I did not need to know the number of levels in order to insert the colors, I only had to make sure to generate more colors than I had levels.

As mentioned by @JM, ContourPlot by default includes a tooltip for each contour value. The first element of each tooltip includes the Line objects making up the contour, using GraphicsComplex coordinates. So, if you want to have an association tying each contour value with the Line objects making up that contour, you can do the following:

assoc = Association @ Cases[
Normal @ ContourPlot[Cos[x] + Cos[y], {x, 0, 4 π}, {y, 0, 4 π}],
Tooltip[x_, y_] :> y -> Cases[x,_Line,Infinity],
Infinity
];

The total number of contours is:

Length @ assoc

7

and the Line objects associated with the contour 1.5 is:

assoc[1.5] //Short[#,10]&

{Line[{{0.,1.04642},{0.0360218,1.04582},{0.0790736,1.04292},{0.1122,1.03923},{0.137919,1.03552},{0.213951,1.02025},{0.224399,1.01775},{0.249554,1.0098},{0.315379,0.988578},{0.336599,0.980251},<<19>>,{0.980251,0.336599},{0.988578,0.315379},{1.0098,0.249554},{1.01775,0.224399},{1.02025,0.213951},{1.03552,0.137919},{1.03923,0.1122},{1.04292,0.0790736},{1.04582,0.0360218},{1.04642,0.}}],<<7>>,Line[{{<<19>>,<<18>>},<<163>>}]}

Expanding on C.E.'s answer to address the extra question, let's do the following. Taking the function

f[x_, y_] = Cos[x] + Cos[y];

as an example consider the contour plot:

cp = ContourPlot[f[x, y],
{x, 0, 4 Pi}, {y, 0, 4 Pi},
Contours -> {0.1, 0.5, 1}, ContourShading -> False] If we do

assoc = GroupBy[Cases[Normal@cp, Line[a_] :> a, Infinity], f @@ #[] &];

then we get an Association object that associates the value of the contour (as computed by f @@ #[] &) to the list of contours with that value. Unfortunately, because of numerical error in the contour values, there are more than just the three (0.1, 0.5, and 1):

Keys@assoc // FullForm
(* List[1., 1.0000000000000002, 0.9999999999999996, 1.0000438962964133, 0.4993229505918183, 0.4993229505918182, 0.4993229505918185, 0.4993229505918175, 0.5006924094447289, 0.09990244696130435, 0.09990244696130413, 0.09990244696130446, 0.10067337224158247`] *)

Maybe that's okay, because maybe we want to know the values on the contours to machine precision, but probably not. To get around this, we can use Round in our selector function, like so:

assoc = GroupBy[Cases[Normal@cp, Line[a_] :> a, Infinity], Round[f @@ #[], 0.01] &];

The choice of 0.01 is made after examining what we get. Then:

Keys@assoc
(* {1., 0.5, 0.1} *)

To get the contours for a particular value, do, for instance,

assoc[1.]

To see how it works:

ListLinePlot@assoc[1.] 