Как отобразить две категориальные переменные на одной плитке тепловой карты - плитки треугольника

У меня есть набор данных, аналогичный приведенному ниже примеру

df <- structure(list(Species = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L,3L, 
1L, 2L, 3L), .Label = c("setosa", "versicolor", "virginica"), class = 
"factor"), flower_att = c("Sepal.Length", "Sepal.Length", "Sepal.Length", 
"Sepal.Width", "Sepal.Width", "Sepal.Width", "Petal.Length", "Petal.Length", 
"Petal.Length", "Petal.Width", "Petal.Width", "Petal.Width"), measurement = 
c(5.1, 7, 6.3, 3.5, 3.2, 3.3, 1.4, 4.7, 6, 0.2, 1.4, 2.5), month = 
c("January", "February", "January", "February", "January", "February", 
"January", "February", "January", "February", "January", "February")), 
row.names = c(NA,-12L), class = "data.frame")

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

Моя собственная попытка в настоящее время выглядит так, как показано ниже. Я не могу понять, как разбить клетки.

ggplot(df, aes(x=month, y=Species)) +   geom_tile(aes(fill=measurement), 
color="black") +   theme(axis.text.x = element_text(angle=45, hjust = .5)) +   
geom_text(aes(label = round(measurement, .1))) +   scale_fill_gradient(low = 
"white", high = "red")

Обновить

После серьезного рывка в Интернете я нашел потенциальный вариант с использованием geom_segment и geom_text_repel, см. Ниже. Может ли кто-нибудь сказать мне, является ли этот вариант жизнеспособным? Если да, то как я могу получить его в соответствии с вышеуказанными требованиями?

Я готов переключить scale_fill_gradient на scale_fill_manual или другую альтернативу, моя основная цель - отображать все данные рядом

ggplot(df, aes(x=month, y=Species)) +
geom_tile(aes(fill=measurement), color="black") +
theme(axis.text.x = element_text(angle=45, hjust = .5)) +
geom_text_repel(aes(label = round(measurement, .1))) +
scale_fill_gradient(low = "white", high = "red")

gb <- ggplot_build(p)

p + geom_segment(data=gb$data[[1]],
aes(x=xmin, xend=xmax, y=ymin, yend=ymax), color="black")

person AudileF    schedule 25.01.2021    source источник
comment
что ты уже испробовал?   -  person Mike    schedule 25.01.2021
comment
Привет, Майк ive до сих пор использовал следующее, но я не могу разобраться, как выполнять сплит ggplot(df, aes(x=month, y=Species)) + geom_tile(aes(fill=measurement), color="black") + theme(axis.text.x = element_text(angle=45, hjust = .5)) + geom_text(aes(label = round(measurement, .1))) + scale_fill_gradient(low = "white", high = "red")   -  person AudileF    schedule 25.01.2021
comment
хороший вопрос! Я не уверен, как это сделать, я бы также отредактировал ваш вопрос, чтобы поместить туда код ggplot, чтобы другие люди могли помочь в устранении неполадок.   -  person Mike    schedule 25.01.2021
comment
Похоже, что в этом направлении предпринимаются и другие усилия, например, в этот пост.   -  person Ben    schedule 25.01.2021
comment
Спасибо за ссылку @Ben. Я пробовал пример спрашивающих, и он не дает того же результата, что и они. Но я посмотрю, смогу ли я это обойти :)   -  person AudileF    schedule 26.01.2021
comment
Я обнаружил 2 попытки создать geom_triangle, один доступен на GitHub, другой только на исходный код на rdrr.io. Оба рисуют треугольники, но размер первого очень сложно изменить, а остальная эстетика последнего ломается - они превращаются в категориальные, и нет немедленного обходного пути, чтобы сделать его непрерывным.   -  person tjebo    schedule 27.01.2021


Ответы (1)


Это немного взломано, но, честно говоря, без создания выделенного geom, я не думаю, что вы можете сделать его менее хакерским - и создание geom также может быть несколько хакерским :)

  • Создание многоугольников треугольников для каждой координаты x / y с помощью sapply. Думаю, вы могли бы использовать этот подход для своего compute_group слоя в будущем StatSplitTile.
  • Неправильное использование факторов - необходимое зло, чтобы навести порядок. Если вам нужен определенный порядок на оси Y, вам также необходимо сначала разложить Species на множители.
  • Использование ggnewscale для очень простого способа иметь несколько шкал заливки.
  • установить одинаковые пределы для лучшей сопоставимости
  • corre_equal, чтобы он выглядел лучше
library(tidyverse)

mydat <- structure(list(Species = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), .Label = c("setosa", "versicolor", "virginica"), class = "factor"), flower_att = c("Sepal.Length", "Sepal.Length", "Sepal.Length", "Sepal.Width", "Sepal.Width", "Sepal.Width", "Petal.Length", "Petal.Length", "Petal.Length", "Petal.Width", "Petal.Width", "Petal.Width"), measurement = c(5.1, 7, 6.3, 3.5, 3.2, 3.3, 1.4, 4.7, 6, 0.2, 1.4, 2.5), month = c("January", "February", "January", "February", "January", "February", "January", "February", "January", "February", "January", "February")),
  row.names = c(NA, -12L), class = "data.frame"
)

make_triangles <- function(x, y, point = "up") {
  x <- as.integer(as.factor((x)))
  y <- as.integer(as.factor((y)))

  if (point == "up") {
    newx <- sapply(x, function(x) {
      c(x - 0.5, x - 0.5, x + 0.5)
    }, simplify = FALSE)
    newy <- sapply(y, function(y) {
      c(y - 0.5, y + 0.5, y + 0.5)
    }, simplify = FALSE)
  } else if (point == "down") {
    newx <- sapply(x, function(x) {
      c(x - 0.5, x + 0.5, x + 0.5)
    }, simplify = FALSE)
    newy <- sapply(y, function(y) {
      c(y - 0.5, y - 0.5, y + 0.5)
    }, simplify = FALSE)
  }
  data.frame(x = unlist(newx), y = unlist(newy))
}

# required, otherwise you cannot use the values as fill
mydat_wide <- mydat %>% pivot_wider(names_from = "flower_att", values_from = "measurement")
# making your ordered months factor
mydat_wide$month <- droplevels(factor(mydat_wide$month, levels = month.name))
# The actual triangle computation
newcoord_up <- make_triangles(mydat_wide$month, mydat_wide$Species)
newcoord_down <- make_triangles(mydat_wide$month, mydat_wide$Species, point = "down")
# just a dirty trick for renaming
newcoord_down <- newcoord_down %>% select(xdown = x, ydown = y)
# you need to repeat each row of your previous data frame 3 times
repdata <- map_df(1:nrow(mydat_wide), function(i) mydat_wide[rep(i, 3), ])
newdata <- bind_cols(repdata, newcoord_up, newcoord_down)

ggplot(newdata) +
  geom_polygon(aes(x = x, y = y, fill = Sepal.Length, group = interaction(Species, month)), color = "black") +
  scale_fill_gradient(low = "white", high = "red", limits = c(0, 10)) +
  ggnewscale::new_scale_fill() +
  geom_polygon(aes(x = xdown, y = ydown, fill = Sepal.Width, group = interaction(Species, month)), color = "black") +
  scale_fill_gradient(low = "white", high = "red", limits = c(0, 10)) +
  scale_x_continuous(breaks = seq_along(unique(mydat_wide$month)), 
                     labels = unique(levels(mydat_wide$month))) +
  scale_y_continuous(breaks = seq_along(unique(mydat_wide$Species)),
                     labels = unique(mydat_wide$Species))+
  coord_equal()

Создано 27 января 2021 года пакетом REPEX (v0.3.0)

person tjebo    schedule 27.01.2021
comment
P.S. - серые треугольники - нет данных, это связано с предоставленными вами данными - person tjebo; 27.01.2021
comment
Также - я не уверен насчет вашей категоричности - возможно, я неправильно понял то, что вы хотели построить. - person tjebo; 27.01.2021
comment
Спасибо, это похоже на то, что я хочу. Однако я не понимаю, почему в данных должны быть NA. В идеале длина должна соответствовать верхнему треугольнику, а ширина - низу для каждой «ячейки» на тепловой карте, надеюсь, это проясняет ситуацию. - person AudileF; 27.01.2021
comment
@AudileF, например, проверьте, дали ли вы нам setosa, January, Sepal.Width (подсказка - вы этого не сделали) - person tjebo; 27.01.2021