Избегайте потери пространства при размещении нескольких выровненных графиков на одной странице
Я хотел бы разместить четыре сюжета на одной странице. Этикетки осей должны быть напечатаны только на самом ободе, то есть на осях оси X только для нижних диаграмм, и на оси y для левых диаграмм. Это происходит как для названия оси в целом, так и для отдельных меток. Я могу сгенерировать что-то в этих строках, используя следующий код:
pdf(file = "ExampleOutput.pdf",
width = 6.61,
height = 6.61,
pointsize = 10
)
set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
catB = rsample(catB),
valA = rnorm(samples, 150, 8),
valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))
par(mfrow = c(2,2))
for (i in 0:3) {
x <- Tab[[1 + i %% 2]]
plot(x, Tab[[3 + i %/% 2]],
xlab = if (i %/% 2 == 1) "Some Categories" else NULL,
ylab = if (i %% 2 == 0) "Some Values" else NULL,
axes = FALSE
)
axis(side = 1,
at=1:nlevels(x),
labels = if (i %/% 2 == 1) levels(x) else FALSE)
axis(side = 2, labels = (i %% 2 == 0))
box(which = "plot", bty = "l")
}
par(mfrow = c(1,1))
dev.off()
Я буду приветствовать предложения о том, как улучшить мои команды построения графиков, возможно, избегать опускания осей и L в левом нижнем углу вручную. Но это только кроме того.
Результат этой последовательности выглядит следующим образом:
![Current output]()
Проблема здесь в огромном количестве потраченных впустую пробелов. У меня сложилось впечатление, что R резервирует пространство для меток оси и тика, даже если они не используются. Вследствие этого потраченного пространства, для левой нижней диаграммы, только каждый второй x-тик фактически получает помеченную, что здесь действительно плохо.
Я бы хотел создать подобный сюжет без такого большого пробела. Фактические графики должны быть одинакового размера, поэтому они выравниваются правильно, но пространство для этикеток должно быть только снаружи. Я предполагаю, что такой макет (макет, созданный в GIMP):
![Desired output]()
Как я могу достичь такого макета?
Ответы
Ответ 1
Вот небольшая модификация общего сюжета, который вы показываете, предполагая, что метки оси y и x относятся ко всем графикам. Он использует внешний край, чтобы содержать метку оси, которую мы добавляем с помощью title()
, используя аргумент outer = TRUE
. Эффект несколько похож на маркировку в строках ggplot2 или решетки.
Ключевая строка здесь:
op <- par(mfrow = c(2,2),
oma = c(5,4,0,0) + 0.1,
mar = c(0,0,1,1) + 0.1)
который задает параметры графика (значения, находящиеся до вызова, сохраняются в op
). Мы используем строки 5
и 4
на сторонах 1 и 2 для внешнего поля, что является обычным числом для параметра mar
. Границы области участка (mar
) по 1 строке каждый добавляются в верхнюю и правую стороны, чтобы дать небольшую комнату между графиками.
Знаки оси добавляются после цикла for()
с помощью
title(xlab = "Some Categories",
ylab = "Some Values",
outer = TRUE, line = 3)
Весь script:
set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
catB = rsample(catB),
valA = rnorm(samples, 150, 8),
valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))
op <- par(mfrow = c(2,2),
oma = c(5,4,0,0) + 0.1,
mar = c(0,0,1,1) + 0.1)
for (i in 0:3) {
x <- Tab[[1 + i %% 2]]
plot(x, Tab[[3 + i %/% 2]], axes = FALSE)
axis(side = 1,
at=1:nlevels(x),
labels = if (i %/% 2 == 1) levels(x) else FALSE)
axis(side = 2, labels = (i %% 2 == 0))
box(which = "plot", bty = "l")
}
title(xlab = "Some Categories",
ylab = "Some Values",
outer = TRUE, line = 3)
par(op)
который производит
![enter image description here]()
Ответ 2
Просто манипулируйте своими параметрами в par
. Аргумент mar
управляет размером поля для отдельного участка. Измените par
на это:
par(mfrow = c(2,2), mar=c(1, 4, 1, 1) + 0.1)#it goes c(bottom, left, top, right)
Ответ 3
В ответ на большой ответ на от Gavin Simpson, теперь я использую следующее решение:
par(mfrow = c(2, 2), # 2x2 layout
oma = c(2, 2, 0, 0), # two rows of text at the outer left and bottom margin
mar = c(1, 1, 0, 0), # space for one row of text at ticks and to separate plots
mgp = c(2, 1, 0), # axis label at 2 rows distance, tick labels at 1 row
xpd = NA) # allow content to protrude into outer margin (and beyond)
Результат выглядит следующим образом:
![Resulting image]()
Как вы можете видеть, этого достаточно, чтобы разрешить печать всех ярлыков меток. Если бы это было не так, то согласно комментарий Gavin добавление cex.axis
со значением меньше 1 в список параметров должно помочь уменьшить размер шрифта там.
Ответ 4
Вам нужна условная оценка, которая присваивает значениям par('mar')
, которые соответствуют позиционированию; Вот пример кода (внутри вашего цикла), который проверяет "положение x-layout-position":
pdf(file = "ExampleOutput2.pdf",
width = 6.61,
height = 6.61,
pointsize = 10
)
set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
catB = rsample(catB),
valA = rnorm(samples, 150, 8),
valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))
par(mfrow = c(2,2), mar= c(3, 4, 1, 1) + 0.1)
for (i in 0:3) {
x <- Tab[[1 + i %% 2]]
plot(x, Tab[[3 + i %/% 2]], mar= if(i %/%2 == 0) {c(4, 4, 1, 1) + 0.1
}else{c(1, 1, 1, 1) + 0.1},
xlab = if (i %/% 2 == 1) "Some Categories" else NULL,
ylab = if (i %% 2 == 0) "Some Values" else NULL,
axes = FALSE
)
axis(side = 1,
at=1:nlevels(x),
labels = if (i %/% 2 == 1) levels(x) else FALSE)
axis(side = 2, labels = (i %% 2 == 0))
box(which = "plot", bty = "l")
}
par(mfrow = c(1,1))
dev.off()
Вам нужно будет отрегулировать это так, как вам нужно, поскольку оно обрабатывает только два крайних условия, и у вас действительно есть 4 отдельных условия (2 ниже обоих требуется больше нижнего пространства, а справа - меньшее левое пространство и два выше (также с различными требованиями). Если вы уменьшите значение "mar" во всем мире, оно отключит ваши метки x и y, как можно увидеть в потере значений xlab, когда вы просто отбрасываете этот код в свой цикл.