Подтвердить что ты не робот

Ggplot2 heatmaps: использование разных градиентов для категорий

Это сообщение в блоге Learning R показывает, как сделать карту памяти баскетбола с помощью ggplot2. Готовая тепловая карта выглядит следующим образом:

enter image description here

Мой вопрос (вдохновленный Джейк, который прокомментировал сообщение в блоге Learning R): возможно ли использовать разные цвета градиента для разных категории статистики (наступательные, оборонительные, другие)?

4b9b3361

Ответ 1

Во-первых, воссоздайте график из сообщения, обновив его для новой версии ggplot2 (0.9.2.1), которая имеет другую систему тем и прикрепляет меньшее количество пакетов:

nba <- read.csv("http://datasets.flowingdata.com/ppg2008.csv")
nba$Name <- with(nba, reorder(Name, PTS))

library("ggplot2")
library("plyr")
library("reshape2")
library("scales")

nba.m <- melt(nba)
nba.s <- ddply(nba.m, .(variable), transform,
               rescale = scale(value))

ggplot(nba.s, aes(variable, Name)) + 
  geom_tile(aes(fill = rescale), colour = "white") + 
  scale_fill_gradient(low = "white", high = "steelblue") + 
  scale_x_discrete("", expand = c(0, 0)) + 
  scale_y_discrete("", expand = c(0, 0)) + 
  theme_grey(base_size = 9) + 
  theme(legend.position = "none",
        axis.ticks = element_blank(), 
        axis.text.x = element_text(angle = 330, hjust = 0))

enter image description here

Использование разных цветов градиента для разных категорий не так просто. Концептуальный подход, чтобы отобразить fill to interaction(rescale, Category) (где Category - атакующий/защитный/другой, см. Ниже) не работает, потому что взаимодействие фактора и непрерывной переменной дает дискретную переменную, которая fill не может для отображения.

Чтобы обойти это, искусственно выполнить это взаимодействие, сопоставляя rescale с неперекрывающимися диапазонами для разных значений Category, а затем используйте scale_fill_gradientn для сопоставления каждой из этих областей с разными цветовыми градиентами.

Сначала создайте категории. Я думаю, что эти карты относятся к комментариям, но я не уверен; изменение этой переменной в какой категории легко.

nba.s$Category <- nba.s$variable
levels(nba.s$Category) <- 
  list("Offensive" = c("PTS", "FGM", "FGA", "X3PM", "X3PA", "AST"),
       "Defensive" = c("DRB", "ORB", "STL"),
       "Other" = c("G", "MIN", "FGP", "FTM", "FTA", "FTP", "X3PP", 
                   "TRB", "BLK", "TO", "PF"))

Так как rescale находится в пределах нескольких (3 или 4) из 0, разные категории могут быть смещены на сто, чтобы их разделить. В то же время определите, где конечные точки каждого градиента цвета должны быть как с точки зрения масштабирования, так и с цветами.

nba.s$rescaleoffset <- nba.s$rescale + 100*(as.numeric(nba.s$Category)-1)
scalerange <- range(nba.s$rescale)
gradientends <- scalerange + rep(c(0,100,200), each=2)
colorends <- c("white", "red", "white", "green", "white", "blue")

Теперь замените переменную fill на rescaleoffset и измените масштаб fill, чтобы использовать scale_fill_gradientn (помня, чтобы перемасштабировать значения):

ggplot(nba.s, aes(variable, Name)) + 
  geom_tile(aes(fill = rescaleoffset), colour = "white") + 
  scale_fill_gradientn(colours = colorends, values = rescale(gradientends)) + 
  scale_x_discrete("", expand = c(0, 0)) + 
  scale_y_discrete("", expand = c(0, 0)) + 
  theme_grey(base_size = 9) + 
  theme(legend.position = "none",
        axis.ticks = element_blank(), 
        axis.text.x = element_text(angle = 330, hjust = 0))

enter image description here

Переупорядочение для получения связанных статистических данных является еще одним применением функции reorder для различных переменных:

nba.s$variable2 <- reorder(nba.s$variable, as.numeric(nba.s$Category))

ggplot(nba.s, aes(variable2, Name)) + 
  geom_tile(aes(fill = rescaleoffset), colour = "white") + 
  scale_fill_gradientn(colours = colorends, values = rescale(gradientends)) + 
  scale_x_discrete("", expand = c(0, 0)) + 
  scale_y_discrete("", expand = c(0, 0)) + 
  theme_grey(base_size = 9) + 
  theme(legend.position = "none",
        axis.ticks = element_blank(), 
        axis.text.x = element_text(angle = 330, hjust = 0))

enter image description here

Ответ 2

Здесь приведено более простое предложение, которое использует ggplot2-эстетику для отображения как градиентов, так и цветовых категорий. Просто используйте альфа-эстетику для создания градиента, а также эстетику заполнения для этой категории.

Вот код для этого, рефакторинг ответа Брайана Диггса:

nba <- read.csv("http://datasets.flowingdata.com/ppg2008.csv")
nba$Name <- with(nba, reorder(Name, PTS))

library("ggplot2")
library("plyr")
library("reshape2")
library("scales")

nba.m <- melt(nba)
nba.s <- ddply(nba.m, .(variable), transform,
           rescale = scale(value))

nba.s$Category <- nba.s$variable
levels(nba.s$Category) <- list("Offensive" = c("PTS", "FGM", "FGA", "X3PM", "X3PA", "AST"),
   "Defensive" = c("DRB", "ORB", "STL"),
   "Other" = c("G", "MIN", "FGP", "FTM", "FTA", "FTP", "X3PP", "TRB", "BLK", "TO", "PF"))

Затем нормализуем переменную rescale в диапазоне от 0 до 1:

nba.s$rescale = (nba.s$rescale-min(nba.s$rescale))/(max(nba.s$rescale)-min(nba.s$rescale))

И теперь сделайте следующее:

ggplot(nba.s, aes(variable, Name)) + 
  geom_tile(aes(alpha = rescale, fill=Category), colour = "white") + 
  scale_alpha(range=c(0,1)) +
  scale_x_discrete("", expand = c(0, 0)) + 
  scale_y_discrete("", expand = c(0, 0)) + 
  theme_grey(base_size = 9) + 
  theme(legend.position = "none",
        axis.ticks = element_blank(), 
        axis.text.x = element_text(angle = 330, hjust = 0)) +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())

ggplot2 heatmap с использованием альфа-эстетики

Обратите внимание на использование alpha=rescale, а затем масштабирование альфа-диапазона с помощью scale_alpha(range=c(0,1)), которое может быть адаптировано для изменения диапазона, подходящего для вашего графика.