如何在ggplot2中制作具有平滑密度的点图?

时间:2013-04-25 20:38:16

标签: r plot ggplot2

我在ggplot2中制作这个点图:

ggplot(mtcars, aes(x = mpg)) + geom_dotplot()

我希望显示某种平滑的密度适合点图顶部的观察点。这看起来不正确:

ggplot(mtcars, aes(x = mpg)) + geom_dotplot() + geom_density()

我尝试了stat_smooth(),但我收到错误:

> ggplot(mtcars, aes(x = mpg)) + geom_dotplot() + stat_smooth()
stat_bindot: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
Error: stat_smooth requires the following missing aesthetics: y

感谢。

2 个答案:

答案 0 :(得分:0)

stat_smooth函数中的平滑公式需要y值,并且由于您未指定值,因此您会看到错误。

如果您为y指定一系列值,则错误将消失,例如:

ggplot(mtcars, aes(x = hp, y = mpg)) + geom_dotplot() + stat_smooth()

修改

stat_smooth()与大多数其他功能完美配合。您可能需要的近似值(x上的mpg和y上的模型)将是:

qplot(mpg, row.names(mtcars), data=mtcars, group=1, color=mpg, xlab="Miles Per Gallon", ylab="Model")  + stat_smooth()

哪会导致:

enter image description here

答案 1 :(得分:0)

我自己遇到了这个问题(尽管我也想按组对点进行着色)。问题是geom_dotplot忽略了y缩放,只是根据x轴和点的宽度堆叠点。这意味着您可以自己设置y轴,然后调整绘图的纵横比,以使点神奇地对齐到正确的高度。

这是我写的一个实用函数:

# Function to generate a normal curve
make.normal.density = function( a, mn=median(a), stdev=sd(a), numpts=500 ) {
  x.grid = seq(min(a), max(a), length= numpts)
  dens.all = dnorm(x.grid,mean=mn, sd = stdev)
  data.frame( x = x.grid, y = dens.all )
}


make.densodot.plot = function( X, group = NULL, binwidth, bw = binwidth, normal.density = FALSE ) {
  df = data.frame( X = X )
  if ( !is.null( group ) ) {
    df$group=group
  }

  # Hand-bin our dots
  scl = 1 / binwidth
  mn = round( scl * (min( X ) - binwidth/2 ) ) / scl
  breaks = seq( mn - binwidth/2, max( df$X + binwidth), by=binwidth )
  df = mutate( df, bin = cut( X, breaks=breaks ) )

  mx = max( table(df$bin ) )

  # Get density curve to plot
  if ( normal.density ) {
    dd = make.normal.density( df$X )
  } else {
    dens = density( df$X, bw=bw )
    dd = data.frame( x=dens$x, y=dens$y )
  }
  dmax = max( dd$y )

  # What fraction of density is in tallest histogram bar?
  frac = mx / nrow( df )

  # How high should density line be through the peak (to get relatively same area
  # under density curve (integrate curve over binwidth) vs. histogram bin (# dots in
  # the bin over total number of dots)
  ratio = (binwidth * dmax) / frac

  # Each unit of height is what in terms of dots? (The dots will stack up
  # without regard of y-axis, so we want to fix aspect ratio so the dots
  # correspond to the density line.)
  scaling = binwidth / ( (dmax / ratio) / (mx) )

  y.max = max( dmax, mx * binwidth/scaling )

  if ( is.null( group ) ) {
    plt = ggplot( df )+
      geom_dotplot( aes(x=X), method="histodot",
                    binwidth = binwidth, stackgroups = TRUE)
  } else {
    plt = ggplot( df )+
      geom_dotplot( aes(x=X, fill=group, col=group), method="histodot",
                    binwidth = binwidth, stackgroups = TRUE)
  }
  plt = plt +
    geom_line( data=dd, aes( x = x, y = y ) ) +
    coord_fixed(ratio = scaling, ylim=c(0, y.max ) ) +
    scale_y_continuous(name="", breaks=seq(0,by=binwidth/scaling, length.out=(mx+1)), labels=c(0:mx) )

  plt
}


make.densodot.plot( X = mtcars$mpg, binwidth=3 )