Тепловая карта R с расходящейся цветовой палитрой

Я пытаюсь создать простую тепловую карту в R, используя расходящуюся цветовую палитру. Я хочу использовать градиент, чтобы все числа ниже порога N были обозначены цветом (скажем, фиолетовым), а все числа выше порога обозначены другим цветом (скажем, оранжевым). Чем дальше число от порога, тем темнее должен быть цвет.

Вот примерный набор данных:

Division,COL1,COL2,COL3,COL4,COL5,COL6,COL7
Division 1,31.9221884012222,75.8181694429368,97.0480443444103,96.295954938978,70.5677134916186,63.0451830103993,93.0396212730557
Division 2,85.7012346852571,29.0621076244861,16.9130333233625,94.6443660184741,19.9103083927184,61.9562198873609,72.3791105207056
Division 3,47.1665125340223,99.4153356179595,8.51091076619923,79.1276383213699,41.915355855599,7.45079894550145,24.6946100145578
Division 4,66.0743870772421,24.6163331903517,78.694460215047,42.04714265652,50.2694897353649,73.0409651994705,87.3745442833751
Division 5,29.6664374880493,35.4036891367286,19.2967326845974,5.48460693098605,32.4517334811389,15.5926876701415,76.0523204226047
Division 6,95.4969164915383,8.63230894319713,61.7535551078618,24.5590241160244,25.5453423131257,56.397921172902,44.4693325087428
Division 7,87.5015622004867,28.7770316936076,56.5095080062747,34.6680747810751,28.1923673115671,65.0204187724739,13.795713102445
Division 8,70.1077231671661,72.4712177179754,38.4903231170028,36.1821102909744,97.0875509083271,17.184783378616,78.2292529474944
Division 9,47.3570406902581,90.2257485780865,65.6037972308695,77.0234781783074,25.6294377148151,84.900529962033,82.5080851092935
Division 10,58.0811711959541,0.493217632174492,58.5604055318981,53.5780876874924,9.12552657537162,20.313960686326,78.1371118500829
Division 11,34.6708688884974,76.711881859228,22.6064443588257,22.1724311355501,5.48891355283558,79.1159523651004,56.8405059166253
Division 12,33.6812808644027,44.1363711375743,70.6362190190703,3.78900407813489,16.6075889021158,9.12654218263924,39.9711143691093

Вот простой фрагмент для создания тепловой карты из приведенных выше данных

data <- read.csv("dataset.csv", sep=",")
row.names(data) <- data$Division
data <- data[,2:7]
data_matrix <- data.matrix(data) 
heatmap(data_matrix, Rowv=NA, Colv=NA, col = heat.colors(256), scale="column", margins=c(5,10))

Как я могу изменить приведенный выше код для получения:

a color gradient (orange) for all numbers ABOVE 50 (darker the further the number is from 50) a color gradient (purple) for all numbers BELOW 50 (darker the further the number is from 50) Nice to have (but optional) write the number value in the grid cell Nice to have (but optional), use a different color for grid cell that is EXACTLY the threshold number (50 in this case)

[[Edit]]

Я только что видел этовопрос по ТАчто, похоже, очень похоже. В ответе используется ggplot (с которым у меня нет опыта), и я до сих пор не смог адаптировать решение ggplot к своим немного более сложным данным.

 tim riffe12 июн. 2012 г., 01:44
@ JoshO 'Brien точно. способ интерполировать над лабораторным пространством!
 Josh O'Brien11 июн. 2012 г., 21:23
@timriffe - Хорошее предложение. Я украл вашу цветовую схему для моего ответа ниже - надеюсь, вы не возражаете;)
 tim riffe11 июн. 2012 г., 20:58
RColorBrewer пакет имеет хорошие паллеты: попробуйтеRColorBrewer:::brewer.pal(11,"PuOr"), затем укажите аргумент breaks, хотя вам может потребоваться сделать это черезimage() функция вместо

Ответы на вопрос(2)

Вот, но для моих целей мне нужно было обобщить некоторые вещи и я хотел использовать пакет RColorBrewer. Пока я работал над этим, доктор Бревер (из известной компании Color Brewer) остановился в моем офисе и сказал мне, что мне нужно интерполировать внутри меньших цветовых разрывов, а не просто выбирать конечные точки. Я думал, что другие могут найти это полезным, поэтому я публикую свою функцию здесь для потомков.

Функция принимает ваш вектор данных, имя расходящейся палитры colorBrewer и центральную точку для вашей цветовой схемы (по умолчанию 0). Он выводит список, содержащий 2 объекта: объект classIntervals и вектор цветов: функция настроена на интерполяцию в общей сложности 100 цветов, но ее можно изменить с некоторой осторожностью.

diverge.color <- function(data,pal_choice="RdGy",centeredOn=0){
  nHalf=50
  Min <- min(data,na.rm=TRUE)
  Max <- max(data,na.rm=TRUE)
  Thresh <- centeredOn
  pal<-brewer.pal(n=11,pal_choice)
  rc1<-colorRampPalette(colors=c(pal[1],pal[2]),space="Lab")(10)
  for(i in 2:10){
    tmp<-colorRampPalette(colors=c(pal[i],pal[i+1]),space="Lab")(10)
    rc1<-c(rc1,tmp)
  }
  rb1 <- seq(Min, Thresh, length.out=nHalf+1)
  rb2 <- seq(Thresh, Max, length.out=nHalf+1)[-1]
  rampbreaks <- c(rb1, rb2)
  cuts <- classIntervals(data, style="fixed",fixedBreaks=rampbreaks)
  return(list(cuts,rc1))
}

В своей работе я использую эту схему для построения растрового слоя (rs), используя spplot, вот так:

brks<-diverge.color(values(rs))
spplot(rs,col.regions=brks[[2]],at=brks[[1]]$brks,colorkey=TRUE))
Решение Вопроса

что вам нужно установитьscale="none" если вы хотите, чтобы отображаемые цвета соответствовали фактическим (а не масштабированным) значениям ячеек).

ncol <- 100

## Make a vector with n colors
cols <- RColorBrewer:::brewer.pal(11,"PuOr")  # OR c("purple","white","orange")  
rampcols <- colorRampPalette(colors = cols, space="Lab")(ncol)
rampcols[(n/2) + 1] <- rgb(t(col2rgb("green")), maxColorValue=256) 

## Make a vector with n+1 breaks
rampbreaks <- seq(0, 100, length.out = ncol+1)

## Try it out
heatmap(data_matrix, Rowv = NA, Colv = NA, scale="none",
        col = rampcols, breaks = rampbreaks)

enter image description here

EDIT

Для более точного управления размещением порога я предлагаю создать две отдельные палитры - одну для значений, меньших порога, и одну для значений выше порога, а затем "наложение швов". их вместе. Попробуйте что-то вроде этого, поиграв с разными значениями дляMin, Max, Thresh, так далее.:

nHalf <- 50

Min <- 0
Max <- 100
Thresh <- 50

## Make vector of colors for values below threshold
rc1 <- colorRampPalette(colors = c("purple", "white"), space="Lab")(nHalf)    
## Make vector of colors for values above threshold
rc2 <- colorRampPalette(colors = c("white", "orange"), space="Lab")(nHalf)
rampcols <- c(rc1, rc2)
## In your example, this line sets the color for values between 49 and 51. 
rampcols[c(nHalf, nHalf+1)] <- rgb(t(col2rgb("green")), maxColorValue=256) 

rb1 <- seq(Min, Thresh, length.out=nHalf+1)
rb2 <- seq(Thresh, Max, length.out=nHalf+1)[-1]
rampbreaks <- c(rb1, rb2)

heatmap(data_matrix, Rowv = NA, Colv = NA, scale="none",
        col = rampcols, breaks = rampbreaks)
 Homunculus Reticulli11 июн. 2012 г., 23:18
@JoshOBrien: Последнее, но не менее важное, если я хочу записать значения в ячейку (как в этом примере:stackoverflow.com/questions/8161014/custom-heat-map-in-r/…) как я могу это сделать? Спасибо
 Homunculus Reticulli11 июн. 2012 г., 23:17
Спасибо, Джош! Я не могу поверить, что вам удалось создать это с таким количеством строк кода! Я довольно новичок во всем этом (R, RColorBrewer и т. Д.), И я изо всех сил пытаюсь понять, как вы используете «магические числа». (например,100, 11 и т. д.) и как они соотносятся с моими исходными данными и пороговым значением «50» (как используется в моем примере). Не могли бы вы пролить свет на:1. откуда приходят цифры, которые вы используете?2. Как я могу установить пороговое число?3. Непонятно, как (или где) вы устанавливаете критерии зеленого фона, если значение ячейки приблизительно = пороговое значение.
 12 июн. 2012 г., 00:12
@HomunculusReticulli - Слишком много для меня, чтобы хотеть объяснить там. Вы должны быть в состоянии узнать, как работает код, играя с ним и делая много?xxx гдеxxx = someFunctionMysteriousToMe, Что касаетсяRColorBrewerэто интерфейс R к палитрам, разработаннымthis project, Попробуйте это, чтобы узнать немного больше:library(RColorBrewer); display.brewer.all(); display.brewer.pal(n=3, "PuOr"); display.brewer.pal(n=7, "PuOr")и т.д ... Удачи! (Обратите внимание, что я отредактировал свой ответ, чтобы привести пример более гибкого определения порогового значения.)
 Homunculus Reticulli11 июн. 2012 г., 23:36
@JoshOBrien: причина, по которой я спрашивал о том, как установить порог, заключается в том, чтобы я мог, например, использовать разные цвета для положительных и отрицательных чисел (установив для порогового числа значение 0). Я не могу понять, как это сделать из фрагмента ...

Ваш ответ на вопрос