ggplot2 изменить пределы оси для каждой отдельной панели фасетов

avatar
stackinator
7 августа 2018 в 21:10
15097
3
14
library(tidyverse)
ggplot(mpg, aes(displ, cty)) + 
  geom_point() + 
  facet_grid(rows = vars(drv), scales = "free")

Приведенный выше код ggplot состоит из трех панелей: 4, f и r. Я бы хотел, чтобы пределы оси Y были следующими для каждой панели:

Panel y-min y-max breaks
----- ----- ----- ------
4     5     25    5
f     0     40    10
r     10    20    2

Как мне изменить свой код для этого? Не уверен, имеет ли смысл scale_y_continuous больше смысла, или coord_cartesian, или какую-то их комбинацию.

Источник
aosmith
7 августа 2018 в 21:23
2

Я думаю, что общий подход состоит в том, чтобы создавать отдельные графики, а затем сшивать их вместе, а не использовать грани. Некоторые идеи о том, как это сделать, показаны здесь и здесь

Ben Bolker
7 августа 2018 в 21:24
1

Я думаю, что ни одно из ваших предложений (scale_y_continuous или coord_cartesian) не применимо по частям. Если это расширения шкалы данных, я также сделал это, добавив поддельные данные в набор данных (и сделав все необходимое, чтобы убедиться, что они учитываются при определении масштабов, но не отображаются на графике). Также можно использовать функцию breaks(), чтобы взломать это, определив, какой подзаговор в настоящее время рассматривается ...

Calum You
7 августа 2018 в 22:03
1

@BenBolker OP использует mpg, который является встроенным набором данных для ggplot2

Ben Bolker
7 августа 2018 в 22:32
0

ох! ..........

pengchy
15 августа 2019 в 04:06
0

Эта проблема может быть решена установкой scale_y_continuous(breaks=my_breaks,expand=expand_scale(mult= c(0,.1))), с помощью которой функция my_break устанавливает разрывы, а expand_scale устанавливает пределы.

Ответы (3)

avatar
Ben Bolker
7 августа 2018 в 22:40
13

предварительные мероприятия

Определите исходный график и желаемые параметры для осей Y каждого фасета:

library(ggplot2)
g0 <- ggplot(mpg, aes(displ, cty)) + 
    geom_point() + 
    facet_grid(rows = vars(drv), scales = "free")

facet_bounds <- read.table(header=TRUE,
text=                           
"drv ymin ymax breaks
4     5     25    5
f     0     40    10
r     10    20    2",
stringsAsFactors=FALSE)

версия 1: подставить поддельные точки данных

Это не соответствует спецификации breaks, но дает правильные границы:

Определите новый фрейм данных, который включает минимальные / максимальные значения для каждого drv:

ff <- with(facet_bounds,
           data.frame(cty=c(ymin,ymax),
                      drv=c(drv,drv)))

Добавьте их к графикам (они не будут построены, поскольку x равно NA, но они все еще используются при определении масштабов)

g0 + geom_point(data=ff,x=NA)

Это похоже на то, что делает expand_limits(), за исключением того, что эта функция применяется «для всех панелей или всех графиков».

версия 2: определить, на какой панели вы находитесь

Это уродливо и зависит от каждой группы, имеющей уникальный диапазон.

library(dplyr)
## compute limits for each group
lims <- (mpg
    %>% group_by(drv)
    %>% summarise(ymin=min(cty),ymax=max(cty))
)

Функция разрывов: определяет, какая группа соответствует заданному набору ограничений ...

bfun <- function(limits) {
    grp <- which(lims$ymin==limits[1] & lims$ymax==limits[2])
    bb <- facet_bounds[grp,]
    pp <- pretty(c(bb$ymin,bb$ymax),n=bb$breaks)
    return(pp)
}
g0 + scale_y_continuous(breaks=bfun, expand=expand_scale(0,0))

Другое уродство здесь заключается в том, что мы должны установить expand_scale(0,0), чтобы сделать пределы точно равными ограничениям группы, что может быть не таким, каким вы хотите сюжет ...

Было бы неплохо, если бы в функцию breaks() можно было каким-то образом передать некоторую информацию о том, какая панель в настоящее время вычисляется ...

crsh
23 января 2020 в 14:05
1

«Более чистый» подход к нанесению невидимых точек в качестве средства управления масштабами может заключаться в использовании geom_blank().

avatar
Johanna
6 марта 2019 в 16:16
5

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

Оказалось, что мне нужно указать log10 в двух позициях:

scales_x <- list(
  "B" = scale_x_log10(limits=c(0.1, 10), breaks=c(0.1, 1, 10)),
  "C" = scale_x_log10(limits=c(0.008, 1), breaks=c(0.01, 0.1, 1)),
  "E" = scale_x_log10(limits=c(0.01, 1), breaks=c(0.01, 0.1, 1)),
  "R" = scale_x_log10(limits=c(0.01, 1), breaks=c(0.01, 0.1, 1))
)

и в сюжете

ggplot(...) + facet_grid_sc(...) +  scale_x_log10()
avatar
Uwe
7 января 2019 в 12:18
30

Это давний запрос функции (см., Например, 2009, 2011, 2016), который обрабатывается отдельным пакетом <6345698615964 facetscales> .

devtools::install_github("zeehio/facetscales")
library(g)
library(facetscales)
scales_y <- list(
  `4` = scale_y_continuous(limits = c(5, 25), breaks = seq(5, 25, 5)),
  `f` = scale_y_continuous(limits = c(0, 40), breaks = seq(0, 40, 10)),
  `r` = scale_y_continuous(limits = c(10, 20), breaks = seq(10, 20, 2))
)
ggplot(mpg, aes(displ, cty)) + 
  geom_point() + 
  facet_grid_sc(rows = vars(drv), scales = list(y = scales_y))

enter image description here

Если параметры для каждого аспекта хранятся в кадре данных facet_params, мы можем вычислить на языке для создания scale_y:

library(tidyverse)
facet_params <- read_table("drv y_min y_max breaks
4     5     25    5
f     0     40    10
r     10    20    2")

scales_y <- facet_params %>% 
  str_glue_data(
    "`{drv}` = scale_y_continuous(limits = c({y_min}, {y_max}), ", 
                "breaks = seq({y_min}, {y_max}, {breaks}))") %>%
  str_flatten(", ") %>% 
  str_c("list(", .  ")") %>% 
  parse(text = .) %>% 
  eval()
qdread
6 ноября 2020 в 02:41
1

Теперь это должен быть принятый ответ ... хотя Бен Болкер довольно умен.

qdread
6 ноября 2020 в 13:05
0

Если подумать, я думаю, что, возможно, geom_blank() - более гибкий подход, поскольку кажется, что пакет facetscales не поддерживает facet_wrap, только facet_grid

Markm0705
7 августа 2021 в 10:25
1

Получение сообщения о том, что для текущей версии R4.1.0 доступно масштабное отображение ... позор

Stephen Henderson
30 августа 2021 в 08:31
0

Большое спасибо за это. Погуглив в поисках решения окончательных требований рецензентов, я нашел это и сэкономил часы и часы рефакторинга кода. Купель простых правок моего исходного кода и фига по мере необходимости. Огромный палец вверх!