Bratt Swan
Bratt Swan

Reputation: 1146

How to put the actual data points on the contour plot with ggplot?

The code below produces a contour plot using ggplot.

xgrid <-  seq(min(mtcars$wt), max(mtcars$wt), 0.3)
ygrid <-  seq(min(mtcars$hp), max(mtcars$hp), 0.3)

data.fit <-  expand.grid(wt = xgrid, hp = ygrid)

data.loess <- loess(qsec ~ wt * hp, data = mtcars)
mtrx3d <-  predict(data.loess, newdata = data.fit)

mtrx3d[1:4, 1:4]

require(reshape)
mtrx.melt <- melt(mtrx3d, id.vars = c("wt", "hp"), measure.vars = "qsec")
names(mtrx.melt) <- c("wt", "hp", "qsec")

require(stringr)
mtrx.melt$wt <- as.numeric(str_sub(mtrx.melt$wt, str_locate(mtrx.melt$wt, "=")[1,1] + 1))
mtrx.melt$hp <- as.numeric(str_sub(mtrx.melt$hp, str_locate(mtrx.melt$hp, "=")[1,1] + 1))

ggplot(mtrx.melt, aes(x = wt, y = hp, z = qsec)) + stat_contour()

enter image description here

I wonder how to show all acutal data points with the contour lines. I have tried

ggplot(mtrx.melt, aes(x = wt, y = hp, z = qsec)) + 
  stat_contour() + geom_point(mtrx.melt, aes(x = wt, y = hp, z = qsec))

but this returned an error message said

Error: ggplot2 doesn't know how to deal with data of class uneval

This is similar to this question how-can-i-overlay-points-and-lines-onto-a-contour-plot-with-ggplot2 but is based on different situation. In that question, op wants to annotate a contour plot with particular points that he wants to highlight (where these points are stored in a different data set). My case is to highlight all original data points in mtrx.melt. I tried the method in that question but failed to work.

This is the plot that I expected

The plot above is not based on the dataset, it is just what I expect to have, I want to have a contour plot with its original data points.

Upvotes: 1

Views: 2708

Answers (1)

Uwe
Uwe

Reputation: 42564

There are several issues which prevent to produce the desired result. Some of which are already mentioned in comments.

However, the OP wants to show the actual data points but is trying to plot the regular grid mtrx.melt which is used to interpolate the data, instead.

The follwing code

library(ggplot2)
ggplot(mtrx.melt, aes(x = wt, y = hp, z = qsec))+ 
  geom_point(aes(colour = qsec), mtcars) +
  stat_contour(aes(colour = ..level..))

creates

enter image description here

which is probably what the OP is looking for.

Please, note

  • the contour levels are color coded now.
  • the actual data points from the mtcars data set are shown.
  • the order of parameters in calls to geom_point() and the like is different from ggplot. The geoms and stats expect the aesthetic mapping as first parameter and data as second.
  • geom_point() is called before stat_contour() to ensure that the legend title is qsec instead of level. Beware when replacing stat_contour() by geom_tile(). Then the tiles have to be plotted as first layer and the points on top.

EDIT In response to this comment by the OP, the code could have been written as well as

ggplot(mapping = aes(x = wt, y = hp, z = qsec)) + 
  geom_point(aes(colour = qsec), mtcars) +
  geom_contour(aes(colour = ..level..), mtrx.melt)

This makes it more explicit that two layers, i.e., geom_point() and geom_contour(), are being used to display data of two different data sources. The aesthetics which are shared between both layers are placed in the initial ggplot() call (which is possible here because mtcars and mtrx.melt use the same column names). The colour aesthetic is different, so each layer uses its own definition.

In the call to ggplot(), it's now required to specify the parameter name mapping = aes(...) because ggplot() expects data as first parameter if unnamed.

geom_contour() is used here as the code appears more consistent and it seems to be preferred over stat_contour() following the examples on the ggplot2 documentation site.

Upvotes: 1

Related Questions