首页 文章

ggplot dotplot:geom_dotplot的正确用法是什么?

提问于
浏览
5

我的目的是用 ggplot2 (作者:Hadley Wickham)重现这个图[ref] .

这是我基于 geom_point 的努力和一些丑陋的数据准备(参见下面的代码):

How could I do that with geom_dotplot()?

在我的尝试中,我遇到了几个问题:(1)将geom_dotplot生成的默认密度映射到计数,(2)将轴切断,(3)没有意外的漏洞 . 我放弃了并且砍掉了 geom_point() .

我期望(并且仍然希望)它会如此简单

ggplot(data, aes(x,y)) + geom_dotplot(stat = "identity")

但不是 . 所以这就是我尝试过的和输出:

# Data
df <- structure(list(x = c(79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105), y = c(1, 0, 0, 2, 1, 2, 7, 3, 7, 9, 11, 12, 15, 8, 10, 13, 11, 8, 9, 2, 3, 2, 1, 3, 0, 1, 1)), class = "data.frame", row.names = c(NA, -27L))

# dotplot based on geom_dotplot
geom_dots <- function(x, count, round = 10, breaks = NULL, ...) {
    require(ggplot2)
    n = sum(count) # total number of dots to be drawn
    b = round*round(n/round) # prettify breaks
    x = rep(x, count) # make x coordinates for dots
    if (is.null(breaks))  breaks = seq(0, 1, b/4/n)
    ggplot(data.frame(x = x), aes(x = x)) +
        geom_dotplot(method = "histodot", ...) +
        scale_y_continuous(breaks = breaks, 
                        #limits = c(0, max(count)+1), # doesn't work
                        labels = breaks * n) 
} 

geom_dots(x = df$x, count = df$y) 

# dotplot based on geom_point
ggplot_dot <- function(x, count, ...) {
    require(ggplot2)
    message("The count variable must be an integer")
    count = as.integer(count) # make sure these are counts
    n = sum(count) # total number of dots to be drawn
    x = rep(x, count) # make x coordinates for dots
    count = count[count > 0]  # drop zero cases 
    y = integer(0)  # initialize y coordinates for dots
    for (i in seq_along(count)) 
        y <- c(y, 1:(count[i]))  # compute y coordinates
    ggplot(data.frame(x = x, y = y), aes(x = x, y = y)) +
        geom_point(...)  # draw one dot per positive count
}

ggplot_dot(x = df$x, count = df$y, 
    size = 11, shape = 21, fill = "orange", color = "black") + theme_gray(base_size = 18)
# ggsave("dotplot.png") 
ggsave("dotplot.png", width = 12, height = 5.9)

简短随机评论:使用 geom_point() 解决方案,保存绘图包括调整尺寸恰好以确保点接触(点大小和绘图高度/宽度) . 使用 geom_dotplot() 解决方案,我将标签四舍五入以使它们更漂亮 . 不幸的是,我无法在大约100处切断轴:使用 limits()coord_cartesian() 会导致整个绘图的重新缩放而不是切割 . 另请注意,要使用 geom_dotplot() 我根据计数创建了一个数据向量,因为我无法直接使用count变量(我希望 stat="identity" 能够做到这一点,但我无法使其工作) .

2 回答

  • 1

    巧合的是,我也在过去的一天里与_27347战斗并试图让它显示出来 . 我还没有想出让y轴显示实际数字的方法,但我找到了截断y轴的方法 . 如你所述, coord_cartesian()limits 不起作用,但 coord_fixed() 确实有效,因为它强制执行x:y单位的比率:

    library(tidyverse)
    df <- structure(list(x = c(79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105), y = c(1, 0, 0, 2, 1, 2, 7, 3, 7, 9, 11, 12, 15, 8, 10, 13, 11, 8, 9, 2, 3, 2, 1, 3, 0, 1, 1)), class = "data.frame", row.names = c(NA, -27L))
    df <- tidyr::uncount(df, y) 
    
    ggplot(df, aes(x)) +
      geom_dotplot(method = 'histodot', binwidth = 1) +
      scale_y_continuous(NULL, breaks = NULL) + 
      # Make this as high as the tallest column
      coord_fixed(ratio = 15)
    

    这里使用15作为比率是有效的,因为x轴也是相同的单位(即单个整数) . 如果x轴是百分比或对数美元或日期或其他,你必须修改比率,直到y轴被截断到足够 .

  • 2

    这是否足够接近复制?

    为此,由于第一个绘图实际上是直方图,因此从计数摘要中将每个观察表单中的示例数据扩展回一行 .

    df <- tidyr::uncount(df, y)
    

    然后使用 method = 'histodot'bindwidth=1geom_dotplot() 转换为直方图-y形式 .

    并删除y轴的美学,因为它是分数的胡言乱语,甚至文档说它“不是真的有意义,所以隐藏它” .

    ggplot(df, aes(x)) +
      geom_dotplot(method = 'histodot', binwidth = 1) +
      scale_y_continuous(NULL, breaks = NULL)
    

相关问题