Создайте отдельную цветовую шкалу для каждого столбца на гистограмме с накоплением ggplot2.

У меня есть столбчатая диаграмма с накоплением, которая выглядит так:

Количество пациентов, принимающих каждый препарат, по классам препаратов

Хотя цвета выглядят красиво, сбивает с толку то, что так много похожих цветов представляют разные наркотики. Я хотел бы иметь отдельную цветовую палитру для каждой полосы на графике, например, class1 может использовать палитру «Blues», а class2 может использовать палитру «BuGn» (имена цветовых палитр найдены здесь)

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

Код для создания приведенного выше графика:

library(ggplot2)
library(plyr)
library(RColorBrewer)

drug_name <- c("a", "a", "b", "b", "b", "c", "d", "e", "e", "e", "e", "e", "e",
           "f", "f", "g", "g", "g", "g", "h", "i", "j", "j", "j", "k", "k",
           "k", "k", "k", "k", "l", "l", "m", "m", "m", "n", "o")
df <- data.frame(drug_name)

#get the frequency of each drug name
df_count <- count(df, 'drug_name')

#add a column that specifies the drug class
df_count$drug_class <- vector(mode='character', length=nrow(df_count))

df_count$drug_class[df_count$drug_name %in% c("a", "c", "e", "f")] <- 'class1'

df_count$drug_class[df_count$drug_name %in% c("b", "o")] <- 'class2'

df_count$drug_class[df_count$drug_name %in% c("d", "h", "i")] <- 'class3'

df_count$drug_class[df_count$drug_name %in% c("g", "j", "k", "l", "m", "n")] <- 'class4'

#expand color palette (from http://novyden.blogspot.com/2013/09/how-to-expand-color-palette-with-ggplot.html)

colorCount = length(unique(df_count$drug_name))
getPalette = colorRampPalette(brewer.pal(9, "Set1"))

test_plot <- ggplot(data = df_count, aes(x=drug_class, y=freq, fill=drug_name) ) + geom_bar(stat="identity") + scale_fill_manual(values=getPalette(colorCount))

test_plot

person epi_n00b    schedule 11.03.2016    source источник
comment
Вы можете проверить Несколько цветовых шкал в одном наборе гистограмма с использованием ggplot. На первый взгляд, это похоже на похожий случай.   -  person Henrik    schedule 11.03.2016


Ответы (2)


Различные цветовые палитры выше не последовательно переносятся в разные классы - вместо этого они строятся в соответствии с названным вектором (a, b, c ...) и, таким образом, разделяются между различными классами. Подробнее см. ??scale_fill_manual.

Чтобы «сопоставить» их с каждым набором полос, нам нужно упорядочить data.frame по классам и соответствующим образом выровнять цветовые палитры с именами.

Создайте повторяющиеся палитры для проверки правильности (ожидаемого) порядка.

 repeating.pal = mapply(function(x,y) brewer.pal(x,y), ncol,        c("Set2","Set2","Set2","Set2"))

 repeating.pal[[2]] = repeating.pal[[2]][1:2]  # We only need 2 colors but brewer.pal creates 3 minimum

 repeating.pal = unname(unlist(repeating.pal))

Отсортируйте данные по классам (в том порядке, в котором мы хотим, чтобы цвета оставались!)

 df_count_sorted <- df_count[order(df_count$drug_class),]

Скопируйте исходный порядок названий лекарств.

 df_count_sorted$labOrder <- df_count$drug_name

Добавьте тестовую цветовую палитру.

 df_count$colours<-repeating.pal

Измените график с помощью fill = labOrder.

ggplot(data = df_sorted, aes(x=drug_class, y=freq, fill=labOrder) ) + 
geom_bar(stat="identity", colour="black", lwd=0.2) + 
geom_text(aes(label=paste0(drug_name,": ", freq), y=cum.freq),     colour="grey20") +
scale_fill_manual(values=df_sorted$colours) +
guides(fill=FALSE)

Палитра соответствует ожидаемому порядку

person danny_C_O_T_W    schedule 18.03.2016
comment
отлично. Я придумал (своего рода) обходной путь, который позволил добиться этого, но не решил проблему полностью. Я основывался на ответе @ eipi10, заменив pal <- colorRampPalette(brewer.pal(9,"Greens"))(41) на ранее определенный pal. - person epi_n00b; 20.03.2016

С таким количеством цветов ваш сюжет будет сбивать с толку. Вероятно, лучше просто пометить каждую секцию столбика названием препарата и количеством. В приведенном ниже коде показан один из способов создания отдельных палитр для каждой полосы, а также способ маркировки полос.

Сначала добавьте столбец, который мы будем использовать для размещения меток полос:

library(dplyr) # for the chaining (%>%) operator

## Add a column for positioning drug labels on graph
df_count = df_count %>% group_by(drug_class) %>%
  mutate(cum.freq = cumsum(freq) - 0.5*freq)

Во-вторых, создайте палитры. В приведенном ниже коде используются четыре разные палитры Colorbrewer, но вы можете использовать любую комбинацию функций или методов создания палитр для управления цветами так тонко, как вам нужно.

## Create separate palette for each drug class

# Count the number of colors we'll need for each bar
ncol = table(df_count$drug_class)

# Make the palettes
pal = mapply(function(x,y) brewer.pal(x,y), ncol, c("BrBG","OrRd","YlGn","Set2"))
pal[[2]] = pal[[2]][1:2]  # We only need 2 colors but brewer.pal creates 3 minimum
pal = unname(unlist(pal)) # Combine palettes into single vector of colors

ggplot(data = df_count, aes(x=drug_class, y=freq, fill=drug_name) ) + 
  geom_bar(stat="identity", colour="black", lwd=0.2) + 
  geom_text(aes(label=paste0(drug_name,": ", freq), y=cum.freq), colour="grey20") +
  scale_fill_manual(values=pal) +
  guides(fill=FALSE)

введите описание изображения здесь

Существует множество стратегий и функций для создания цветовых палитр. Вот еще один метод, использующий функцию hcl:

lum = seq(100, 50, length.out=4)    # Vary the luminance for each bar
shift = seq(20, 60, length.out=4)  # Shift the hues for each bar

pal2 = mapply(function(n, l, s) hcl(seq(0 + s, 360 + s, length.out=n+1)[1:n], 100, l), 
              ncol, lum, shift)
pal2 = unname(unlist(pal2))
person eipi10    schedule 11.03.2016