ggplot dotplot: What is the proper use of geom_dotplot?

后端 未结 3 1373
小鲜肉
小鲜肉 2021-02-20 13:51

My purpose is to reproduce this figure [ref] with ggplot2 (author: Hadley Wickham).

Here is my effort based on geom_point and some ugl

3条回答
  •  北海茫月
    2021-02-20 14:17

    This question was somewhat a small inspiration for an answer to a recent bounty. I decided to add this approach to this thread too.

    You can mimic the geom_dotplot with another geom - I chose ggforce::geom_ellipse for full size control of your points. It shows the count on the y axis. I have added some lines to make it more programmatic - and tried to reproduce Hadley's look.

    This is the final result: (Code see below)

    First the undderlying data modifications and geoms

    library(tidyverse)
    library(ggforce)
    
    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))
    
    bin_width <- 1
    pt_width <- bin_width / 3 # so that they don't touch horizontally
    pt_height <- bin_width / 2 # 2 so that they will touch vertically
    
    count_data <- 
      data.frame(x = rep(df$x, df$y)) %>%
      mutate(x = plyr::round_any(x, bin_width)) %>%
      group_by(x) %>%
      mutate(y = seq_along(x))
    
    ggplot(count_data) +
      geom_ellipse(aes(
        x0 = x,
        y0 = y,
        a = pt_width / bin_width,
        b = pt_height / bin_width,
        angle = 0
      )) +
      coord_equal((1 / pt_height) * pt_width)# to make the dot
    

    Setting bin width is flexible!

    bin_width <- 2 
    # etc (same code as above)
    

    Now, it was actually quite fun to reproduce Hadley's graphic a bit more in detail. (Although I somehow seriously doubt that he has created it with ggplot!). A lot of it is not possible without some hack. Most notably the "cross" axis ticks and of course the background gradient (Baptiste helped).

    library(tidyverse)
    library(grid)
    library(ggforce)
    
    p <- 
      ggplot(count_data) +
        annotate(x= seq(80,104,4), y = -Inf, geom = 'text', label = '|') +
      geom_ellipse(aes(
        x0 = x,
        y0 = y,
        a = pt_width / bin_width,
        b = pt_height / bin_width,
        angle = 0
      ),
      fill = "#E67D62",
      size = 0
      ) +
        scale_x_continuous(breaks = seq(80,104,4)) +
        scale_y_continuous(expand = c(0,0.1)) +
      theme_void() +
      theme(axis.line.x = element_line(color = "black"),
            axis.text.x = element_text(color = "black", 
                                       margin = margin(8,0,0,0, unit = 'pt'))) +
      coord_equal((1 / pt_height) * pt_width, clip = 'off')
    
    oranges <- c("#FEEAA9", "#FFFBE1")
    g <- rasterGrob(oranges, width = unit(1, "npc"), height = unit(0.7, "npc"), interpolate = TRUE)
    
    grid.newpage()
    grid.draw(g)
    print(p, newpage = FALSE)
    

    Created on 2020-05-01 by the reprex package (v0.3.0)

提交回复
热议问题