Приведение аргументов пространства и ширины к барплоту для выравнивания окна графика 2x1 - PullRequest
0 голосов
/ 03 мая 2018

Я хотел бы выровнять нижнюю barplot в следующем, чтобы группы располагались вертикально между двумя графиками:

par(mfrow = c(2, 1))
n = 1:5
barplot(-2:2, width = n, space = .2)

barplot(matrix(-10:9, nrow = 4L, ncol = 5L), beside = TRUE,
        width = rep(n/4, each = 5L), space = c(0, .8))

poorly aligned

Я некоторое время смотрел на определение аргументов space и width для barplot (от ?barplot), и я действительно ожидал, что вышеприведенное сработает (но, очевидно, это не сработало) :

width - необязательный вектор ширины стержня. Повторно циклически повторяйте количество нарисованных баров. Указание одного значения не будет иметь видимого эффекта ...

space - количество места (в виде доли от средней ширины бара), оставшегося перед каждым баром. Может быть дано как одно число или одно число за бар. Если height - это матрица, а beside - это TRUE, space может быть задано двумя числами, где первое - это пробел между столбцами в одной группе, а второе - пробел между группами. Если не указано явно, по умолчанию используется c(0,1), если height - матрица, а beside - TRUE, и 0.2 в противном случае.

Насколько я понимаю, это означает, что мы должны иметь возможность сопоставить ширину группы на верхнем графике, разделив каждую группу на 4 (следовательно, n/4). Для space, так как мы делим ширину каждого бара на 4, средняя ширина также будет; следовательно, мы должны умножить дробь на 4, чтобы компенсировать это (следовательно, space = c(0, 4*.2)).

Однако, похоже, это игнорируется. На самом деле, кажется, что все коробки имеют одинаковую ширину! Работая вокруг, я смог изменить относительную ширину внутри группы .

Можно ли будет выполнить то, что я имею в виду с barplot? Если нет, может кто-нибудь сказать, как это сделать, например, ggplot2

Ответы [ 4 ]

0 голосов
/ 03 мая 2018

Другой способ, использующий только base R и все еще использующий barplot (не опускаясь до rect), состоит в том, чтобы сделать это за несколько barplot вызовов, с add=TRUE, играя с space до поместите группы баров в нужное место.

Как уже отмечалось, проблема в том, что space пропорционально среднему значению width. Поэтому вам нужно исправить это.

Вот мой путь:

# draw first barplot, getting back the value
bp <- barplot(-2:2, width = n, space = .2)

# get the xlim
x_rg <- par("usr")[1:2]

# plot the "frame"
plot(0, 0, type="n", axes=FALSE, xlab="", ylab="", xlim=x_rg, xaxs="i", ylim=range(as.vector(pr_bp2)))

# plot the groups of bars, one at a time, specifying space, with a correction according to width, so that each group start where it should
sapply(1:5, function(i) barplot(pr_bp2[, i, drop=FALSE], beside = TRUE, width = n[i]/4, space = c((bp[i, 1]-n[i]/2)/(n[i]/4), rep(0, 3)), add=TRUE))

enter image description here

0 голосов
/ 03 мая 2018

Это можно сделать и с базовым графиком, но это помогает передать матрицу в качестве вектора для второго графика. Впоследствии вам нужно понять, что аргумент пробела является частью средней ширины бара. Я сделал это следующим образом:

par(mfrow = c(2, 1))
widthsbarplot1 <- 1:5
spacesbarplot1 <- c(0, rep(.2, 4))

barplot(-2:2, width = widthsbarplot1, space = spacesbarplot1)

widthsbarplot2 <- rep(widthsbarplot1/4, each = 4)
spacesbetweengroupsbarplot2 <- mean(widthsbarplot2)

allspacesbarplot2 <- c(rep(0,4), rep(c(spacesbetweengroupsbarplot2, rep(0,3)), 4))

matrix2 <- matrix(-10:9, nrow = 4L, ncol = 5L)

barplot(c(matrix2),
    width = widthsbarplot2,
    space = allspacesbarplot2,
    col = c("red", "yellow", "green", "blue"))

Base plot

0 голосов
/ 03 мая 2018

Вы также можете передавать ширину в ggplot как векторы. Вам понадобится dev-версия ggplot2, чтобы получить правильное уклонение:

library(dplyr)
library(ggplot2)

df1 <- data.frame(n = 1:5, y = -2:2)
df1$x <- cumsum(df1$n)
df2 <- data.frame(n = rep(1:5, each = 4), y2 = -10:9)
df2$id <- 1:4                                                    # just for the colors

df3 <- full_join(df1, df2)

p1 <- ggplot(df1, aes(x, y)) + geom_col(width = df1$n, col = 1)
p2 <- ggplot(df3, aes(x, y2, group = y2, fill = factor(id))) + 
  geom_col(width = df3$n, position = 'dodge2', col = 1) +
  scale_fill_grey(guide = 'none')

cowplot::plot_grid(p1, p2, ncol = 1, align = 'v')

enter image description here

0 голосов
/ 03 мая 2018

Вы можете сделать это в ggplot2, явно указав расположение осей абсцисс баров и используя geom_rect для построения графика. Вот пример, который, вероятно, сложнее, чем нужно, но, надеюсь, он продемонстрирует основную идею:

library(tidyverse)

sp = 0.4

d1 = data.frame(value=-2:2) %>% 
  mutate(key=paste0("V", 1:n()),
         width=1:n(),
         spacer = cumsum(rep(sp, n())) - sp,
         xpos = cumsum(width) - 0.5*width + spacer)

d2 = matrix(-10:9, nrow = 4L, ncol = 5L) %>% 
  as.tibble %>% 
  gather(key, value) %>%
  mutate(width = as.numeric(gsub("V","",key))) %>% 
  group_by(key) %>% 
  mutate(width = width/n()) %>% 
  ungroup %>% 
  mutate(spacer = rep(cumsum(rep(sp, length(unique(key)))) - sp, each=4),
         xpos = cumsum(width) - 0.5*width + spacer)

d = bind_rows(list(d1=d1, d2=d2), .id='source') %>% 
  group_by(source, key) %>% 
  mutate(group = LETTERS[1:n()])

ggplot(d, aes(fill=group, colour=group)) +
  geom_rect(aes(xmin=xpos-0.5*width, xmax=xpos+0.5*width, ymin=0, ymax=value)) +
  facet_grid(source ~ ., scales="free_y") +
  theme_bw() +
  guides(fill=FALSE, colour=FALSE) +
  scale_x_continuous(breaks = d1$xpos, labels=d1$key)

enter image description here

...