ggplot dotplot: Как правильно использовать geom_dotplot? - PullRequest
0 голосов
/ 10 декабря 2018

Моя цель - воспроизвести эту цифру [ref] с ggplot2 (автор: Хэдли Уикхем).

enter image description here

Вот мои усилия, основанные на geom_point и некрасивой подготовке данных (см. Код ниже):

enter image description here

Как я мог это сделатьчто с 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" сделает это, но не смог заставить его работать).

enter image description here

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

По совпадению, я также провел прошлый день, борясь с geom_dotplot() и пытаясь заставить его показать счет.Я не придумал, как заставить ось 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 не будет достаточно усечена.


Отредактировано с помощью метода объединения графиков

Как я уже упоминал в комментарии ниже, использование пэчворка для объединения графиков с coord_fixed() не работает должным образом.Однако, если вы вручную установите высоту (или ширину) комбинированных графиков на те же значения, что и соотношение в coord_fixed() и , убедитесь, что каждый график имеет одинаковую ось x, вы можете получить psuedo-facetedучастки

# Make a subset of df
df2 <- df %>% slice(1:25)

plot1 <- ggplot(df, aes(x)) +
  geom_dotplot(method = 'histodot', binwidth = 1) +
  scale_y_continuous(NULL, breaks = NULL) + 
  # Make this as high as the tallest column
  # Make xlim the same on both plots
  coord_fixed(ratio = 15, xlim = c(75, 110))

plot2 <- ggplot(df2, aes(x)) +
  geom_dotplot(method = 'histodot', binwidth = 1) +
  scale_y_continuous(NULL, breaks = NULL) + 
  coord_fixed(ratio = 7, xlim = c(75, 110))

# Combine both plots in a single column, with each sized incorrectly
library(patchwork)
plot1 + plot2 +
  plot_layout(ncol = 1)

# Combine both plots in a single column, with each sized appropriately
library(patchwork)
plot1 + plot2 +
  plot_layout(ncol = 1, heights = c(15, 7) / (15 + 7))

0 голосов
/ 10 декабря 2018

Достаточно ли близко для воспроизведения?

enter image description here

Чтобы добраться, поскольку первый график действительно является гистограммой, разверните данные вашего примера обратнов одну строку для каждой формы наблюдения, из итоговых сумм.

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

Затем с помощью method = 'histodot' и bindwidth=1 введите geom_dotplot() в форму гистограммы-y.

Иудаляя ось Y для эстетики, потому что это дробная тарабарщина, и даже доктора говорят, что это «не очень важно, так что скрывайте это».

ggplot(df, aes(x)) +
  geom_dotplot(method = 'histodot', binwidth = 1) +
  scale_y_continuous(NULL, breaks = NULL)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...