Я пытаюсь создать ggplot со следующей эстетикой (см. Ниже) на относительно небольшом наборе данных (x = номер случая, y1, y2, y3 и т. д. = несколько переменных, относящихся к различным характеристикам случаев)
Case <- c("Case 1", "Case 2", "Case 3", "Case 4", "Case 5")
Age <- c(53, 46, 72, 68, 45)
Tumor_Stage <- c(1, 2, 3, 1, 2)
Tumor_Grade <- c(3, 1, 2, 2, 1)
Smoking_Status <- c(0,1 ,1 ,0 ,1)
CD3 <- c(0,1,0,0,1)
df <- tibble(Case, Age, Tumor_Stage, Tumor_Grade, Smoking_Status, CD3)
df1 <- df %>% pivot_longer(cols = c(Age, Tumor_Stage, Tumor_Grade, Smoking_Status,CD3),
names_to = "Variables")
ggplot(df1,aes(x = Case,
y = Variables,
col = value,
fill = value)) +
geom_tile()
Я получаю следующий сюжет:
НО проблема в том, что для ВСЕХ переменных создается одна шкала, и я хочу сделать другую цветовую шкалу для каждой отдельной переменной y. Как лучше всего это сделать? Большое вам спасибо за вашу помощь!
Моя цель, что-то похожее на это
Я просто застрял здесь и не знаю, как продолжить... Я видел примеры с использованием
scale_color_gradient()
new_scale_color() +
но я не знаю, как интегрировать эту функцию для каждой переменной y
РЕДАКТИРОВАТЬ
Вот мой окончательный результат благодаря ответу Стефана!
Одним из вариантов получения индивидуальной шкалы заливки и легенды для каждой переменной с помощью ggnewscale
было бы использование нескольких слоев geom_tile
, по одному для каждой переменной. Для этого разделите свой фрейм данных на Variable
, затем используйте, например. purrr::imap
чтобы добавить отдельные слои:
library(ggplot2)
library(ggnewscale)
df1_split <- split(df1, df1$Variables)
legend_order <- rev(seq_along(df1_split))
names(legend_order) <- names(df1_split)
ggplot(df1, aes(
x = Case,
y = Variables
)) +
purrr::imap(df1_split, function(x, y) {
order <- legend_order[[y]]
list(
geom_tile(aes(fill = value), data = x),
scale_fill_gradient(
name = y,
guide = guide_colorbar(direction = "horizontal", title.position = "top", order = order)
),
new_scale_fill()
)
})
Второй вариант для достижения желаемого результата - создать отдельные графики для каждой переменной и склеить их вместе, используя, например. patchwork
. Хотя этот подход требует дополнительных усилий, чтобы патч выглядел как один график, т. е. установка полей графика и удаление оси, одним из преимуществ является то, что легенды хорошо выровнены с категориями оси Y. И я предполагаю, что этот подход был использован для примера сюжета, который вы добавили в качестве изображения.
library(patchwork)
plot_fun <- function(x, y) {
theme_adjust <- if (y != "Tumor_Stage") {
theme(
axis.line.x = element_blank(),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.length.x = unit(0, "pt")
)
}
plot_margin <- if (y == "Tumor_Stage") {
theme(plot.margin = margin(0, 5.5, 5.5, 5.5))
} else if (y == "Age") {
theme(plot.margin = margin(5.5, 5.5, 0, 5.5))
} else {
theme(plot.margin = margin(0, 5.5, 0, 5.5))
}
ggplot(df1, aes(
x = Case,
y = Variables
)) +
geom_tile(aes(fill = value), data = x) +
scale_fill_gradient(
name = y,
guide = guide_colorbar(direction = "horizontal", title.position = "top")
) +
scale_y_discrete(expand = c(0, 0)) +
theme_adjust +
plot_margin +
labs(y = NULL)
}
purrr::imap(df1_split, plot_fun) |>
wrap_plots(ncol = 1)
РЕДАКТИРОВАТЬ Относительно вашего второго вопроса. Если у вас есть сочетание категориальных и числовых переменных, я бы предложил использовать данные в широком формате. Для приведенного ниже примера я немного изменил данные примера и преобразовал Smoking_Status
и Tumor_Stage
в коэффициенты. По поводу шкалы заполнения. Есть вообще различный подход. Простым, но, вероятно, не самым элегантным подходом было бы создание списка шкал заполнения, то есть списка, содержащего желаемую шкалу заполнения для каждой переменной. Я также выбрал подход patchwork
. Обратите внимание, что, поскольку теперь я использую широкий набор данных, больше нет необходимости разделять набор данных. Вместо этого мы должны перебрать имена столбцов.
Case <- c("Case 1", "Case 2", "Case 3", "Case 4", "Case 5")
Age <- c(53, 46, 72, 68, 45)
Tumor_Stage <- c(1, 2, 3, 1, 2)
Tumor_Grade <- c(3, 1, 2, 2, 1)
Smoking_Status <- c(0, 1, 1, 0, 1)
CD3 <- c(0, 1, 0, 0, 1)
df <- data.frame(Case, Age, Tumor_Stage, Tumor_Grade, Smoking_Status, CD3)
df$Smoking_Status <- factor(df$Smoking_Status)
df$Tumor_Stage <- factor(df$Tumor_Stage)
library(ggplot2)
library(patchwork)
cols <- c("Age", "Tumor_Stage", "Tumor_Grade", "Smoking_Status", "CD3")
cols <- sort(cols)
scale_fill <- lapply(cols, function(x) {
if (x == "Smoking_Status") {
scale_fill_brewer(type = "div", name = x, palette = "BrBG",
guide = guide_legend(direction = "horizontal", title.position = "top"))
} else if (x == "Tumor_Stage") {
scale_fill_brewer(type = "div", name = x, palette = "PiYG",
guide = guide_legend(direction = "horizontal", title.position = "top"))
} else if (x == "Age") {
scale_fill_gradient(name = x, low = "lightgreen", high = "darkgreen",
guide = guide_colorbar(direction = "horizontal", title.position = "top")
)
} else {
scale_fill_gradient(name = x,
guide = guide_colorbar(direction = "horizontal", title.position = "top")
)
}
})
names(scale_fill) <- cols
plot_fun <- function(x) {
theme_adjust <- if (x != "Tumor_Stage") {
theme(
axis.line.x = element_blank(),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.length.x = unit(0, "pt")
)
}
plot_margin <- if (x == "Tumor_Stage") {
theme(plot.margin = margin(0, 5.5, 5.5, 5.5))
} else if (x == "Age") {
theme(plot.margin = margin(5.5, 5.5, 0, 5.5))
} else {
theme(plot.margin = margin(0, 5.5, 0, 5.5))
}
scale_fill <- scale_fill[[x]]
ggplot(df, aes(
x = Case,
y = x
)) +
geom_tile(aes(fill = .data[[x]])) +
scale_fill +
scale_y_discrete(expand = c(0, 0)) +
theme_adjust +
plot_margin +
labs(y = NULL)
}
purrr::map(cols, plot_fun) |>
wrap_plots(ncol = 1)
Привет Альфонсо. Я только что внес изменения и добавил один возможный подход к ответу на ваши дополнительные вопросы.
Большое спасибо @stefan, я более чем благодарен за ваше удивительно структурированное предложение! У моего разочарованного «я» есть два дополнительных вопроса, если вы не возражаете. 1- Как можно изменить цветовые шкалы для каждой переменной? (как в опубликованном примере) И 2- Если я хочу ввести категориальную переменную во фрейм данных: например. CD1 <- c ("присутствует", "отсутствует", "присутствует", "отсутствует", "отсутствует"), как его можно объединить с остальными числовыми/непрерывными переменными?