Удаление слоя из диаграммы ggplot2
Я хотел бы удалить layer
(в этом случае результаты geom_ribbon
) из созданного ggplot2 объекта сетки. Есть ли способ удалить его, когда он уже является частью объекта?
library(ggplot2)
dat <- data.frame(x=1:3, y=1:3, ymin=0:2, ymax=2:4)
p <- ggplot(dat, aes(x=x, y=y)) + geom_ribbon(aes(ymin=ymin, ymax=ymax), alpha=0.3)
+ geom_line()
# This has the geom_ribbon
p
# This overlays another ribbon on top
p + geom_ribbon(aes(ymin=ymin, ymax=ymax, fill=NA))
Я бы хотел, чтобы эта функциональность позволяла мне создавать более сложные сюжеты поверх менее сложных. Я использую функции, которые возвращают объект сетки, а затем распечатывают окончательный график после его полной сборки. На базовом участке имеется одна строка с соответствующей geom_ribbon
(geom_ribbon
). Более сложный сюжет будет иметь несколько линий, а многократные перекрывающиеся объекты geom_ribbon
отвлекают. Я хотел бы удалить их с участков с несколькими строками. Кроме того, я смогу быстро создавать альтернативные версии с использованием фасетов или других функций ggplot2.
Изменение: Принять ответ @mnel, поскольку он работает. Теперь мне нужно определить, как динамически обращаться к слою geom_ribbon
, который geom_ribbon
в вопросе SO здесь.
Изменить 2: Для полноты, это функция, которую я создал для решения этой проблемы:
remove_geom <- function(ggplot2_object, geom_type) {
layers <- lapply(ggplot2_object$layers, function(x) if(x$geom$objname == geom_type) NULL else x)
layers <- layers[!sapply(layers, is.null)]
ggplot2_object$layers <- layers
ggplot2_object
}
Изменить 3: см. Принятый ответ ниже для последних версий ggplot (> = 2.xy)
Ответы
Ответ 1
Для ggplot2 версии 2.2.1 мне пришлось изменить предлагаемую функцию remove_geom
следующим образом:
remove_geom <- function(ggplot2_object, geom_type) {
# Delete layers that match the requested type.
layers <- lapply(ggplot2_object$layers, function(x) {
if (class(x$geom)[1] == geom_type) {
NULL
} else {
x
}
})
# Delete the unwanted layers.
layers <- layers[!sapply(layers, is.null)]
ggplot2_object$layers <- layers
ggplot2_object
}
Вот пример того, как его использовать:
library(ggplot2)
set.seed(3000)
d <- data.frame(
x = runif(10),
y = runif(10),
label = sprintf("label%s", 1:10)
)
p <- ggplot(d, aes(x, y, label = label)) + geom_point() + geom_text()
Покажите исходный график:
p
![сюжет с текстовыми метками]()
Теперь удалим ярлыки и снова покажу график:
p <- remove_geom(p, "GeomText")
p
![график без текстовых меток]()
Ответ 2
Если вы посмотрите
p$layers
[[1]]
mapping: ymin = ymin, ymax = ymax
geom_ribbon: na.rm = FALSE, alpha = 0.3
stat_identity:
position_identity: (width = NULL, height = NULL)
[[2]]
geom_line:
stat_identity:
position_identity: (width = NULL, height = NULL)
Вы увидите, что вы хотите удалить первый слой
Вы можете сделать это, переопределив слои как только второй компонент в списке.
p$layer <- p$layer[2]
Теперь построим и построим p
p
Обратите внимание, что p$layer[[1]] <- NULL
будет работать. Я согласен с комментариями @Andrie и @Joran относительно тех случаев, когда это может быть полезно, и не ожидал бы, что это будет обязательно надежным.
![enter image description here]()
Ответ 3
Поскольку эта проблема выглядела интересной, я расширил свой пакет ggpmisc с функциями для управления слоями в объекте ggplot (в настоящее время в пакете "gginnards"). Функции - это более отполированные версии примера в моем предыдущем ответе на этот же вопрос. Однако имейте в виду, что в большинстве случаев это не лучший способ работы, поскольку он нарушает грамматику графики. В большинстве случаев можно обычным образом собирать различные варианты одного и того же рисунка с помощью оператора +
, возможно, "упаковывать" группы слоев в списки, чтобы иметь объединенные строительные блоки, которые могут упростить сборку сложных фигур. В исключительных случаях мы можем захотеть отредактировать существующий сюжет или вывод графика с помощью функции более высокого уровня, чье определение мы не можем изменить. В таких случаях эти функции манипулирования слоями могут быть полезны. Приведенный выше пример становится.
library(gginnards)
p1 <- delete_layers(p, match_type = "GeomText")
См. Документацию пакета для других примеров и информацию о вспомогательных функциях, полезных для изменения порядка слоев, а также для вставки новых слоев в произвольные позиции.
Ответ 4
@Kamil Slowikowski Спасибо! Очень полезно. Однако я не мог остановить себя от создания нового варианта по той же теме... надеюсь, легче понять, чем в оригинальном посте или обновленной версии Kamil, также избегая некоторых назначений.
remove_geoms <- function(x, geom_type) {
# Find layers that match the requested type.
selector <- sapply(x$layers,
function(y) {
class(y$geom)[1] == geom_type
})
# Delete the layers.
x$layers[selector] <- NULL
x
}
Эта версия функционально идентична функции Kamil, поэтому здесь не нужно повторять приведенный выше пример использования.
В стороне эта функция может быть легко адаптирована для выбора слоев на основе класса stat вместо класса геометрии.
remove_stats <- function(x, stat_type) {
# Find layers that match the requested type.
selector <- sapply(x$layers,
function(y) {
class(y$stat)[1] == stat_type
})
# Delete the layers.
x$layers[selector] <- NULL
x
}
Ответ 5
@Kamil и @Pedro Спасибо большое! Для тех, кто заинтересован, можно также увеличить функцию Pedro, чтобы выбрать только определенные слои, как показано здесь с аргументом last_only
:
remove_geoms <- function(x, geom_type, last_only = T) {
# Find layers that match the requested type.
selector <- sapply(x$layers,
function(y) {
class(y$geom)[1] == geom_type
})
if(last_only)
selector <- max(which(selector))
# Delete the layers.
x$layers[selector] <- NULL
x
}
Возвращаясь к примерному примеру @Kamil:
set.seed(3000)
d <- data.frame(
x = runif(10),
y = runif(10),
label = sprintf("label%s", 1:10)
)
p <- ggplot(d, aes(x, y, label = label)) + geom_point() + geom_point(color = "green") + geom_point(size = 5, color = "red")
p
![enter image description here]()
p %>% remove_geoms("GeomPoint")
![enter image description here]()
p %>% remove_geoms("GeomPoint") %>% remove_geoms("GeomPoint")
![enter image description here]()