Geom_contour and color



What is the difference among the following 2 ? The first one works and colors the contours but the second one does not. The variable level is the same for each value of density, so then why can I not do this in the second way ?

ggplot(faithfuld, aes(waiting,eruptions)) + 
  geom_contour(aes(z = density,color = ..level..))
ggplot(faithfuld, aes(waiting,eruptions)) + 
  geom_contour(aes(z = density,color = density))


density refers here to the raw variable. Those contour lines are estimates of equal value, but not the actual raw data points that are exactly equal. It is the computed variable, ..level.. that contains the information about the lines.

For example, the outer most contour has a value of 0.005, but there are no observed points with that actual value: any(faithfuld$density == 0.005) gives FALSE.

Indeed by running:

p2 <- ggplot(faithfuld, aes(waiting,eruptions )) + geom_contour(aes(z=density,color= density))

one can see that density isn’t even in the data table used for plotting! Since stat_contour has calculated a transformation of the data, the original raw data cannot be easily matched to the new data describing the contour lines.

The only way to directly use density as the color would be to not do a transformation on the data (i.e. use stat_identity) such as:

ggplot(faithfuld, aes(waiting, eruptions)) + 
  geom_raster(aes(fill = density))


Note that it didn’t have to be this way, the internally computed ..level.. could have been named as the original variable from which it was calculated. But the authors ggplot2 have made the design choice to make these computed variables not use the names of the aesthetic. This makes sense in other scenarios, such as stat_bin, where several computed variables (..count.., ..density.., ..ncount.. and ..ndensity..) are linked to the same y aesthetic.


Hi there, thank you for your reply. Can you show me how to override the default statistical transformation ?

How can I say that in :

ggplot(faithfuld, aes(waiting, eruptions)) + 
  geom_contour(aes(z = density,color = ..level..))

use stat_identity as the transformation of density and then draw the contours ? I have not understood how to change the default stat and keep the same geom or to change the geom and keep the default stat. Although, from the help I have understood that geom_raster uses stat = "identity" internally.


You can pass any statistical transformation to geom_contour, but most won’t make any sense. You can run

ggplot(faithfuld, aes(waiting, eruptions)) + 
  geom_contour(aes(z = density, color = density), stat = "identity")

but first it will tell you that the z aesthetic isn’t recognized by that stat. Secondly, geom_contour will now try and draw continuous lines per group, but there aren’t any groups, so it draws a single continuous line.

You could get close with

ggplot(faithfuld, aes(waiting, eruptions)) + 
  geom_contour(aes(color = density, group = cut(density, 5)), stat = "identity")

But really, why not just use ggplot as intended, and use color = ..level..?

Generally speaking, you can create any layer by either calling geom_*(stat = "") or by stat_*(geom = ""), where each geom has a default stat and each stat has a default geom. But there is no guarantee the result will be sensible.