Як призначити кольори категоричним змінним у ggplot2, які мають стабільне відображення?


178

Я в останній місяць набирав швидкість з R.

Ось моє запитання:

Який хороший спосіб призначити кольори категоричним змінним в ggplot2, які мають стабільне відображення? Мені потрібні послідовні кольори в наборі графіків, які мають різні підмножини та різну кількість категоричних змінних.

Наприклад,

plot1 <- ggplot(data, aes(xData, yData,color=categoricaldData)) + geom_line()

де categoricalDataмає 5 рівнів.

І потім

plot2 <- ggplot(data.subset, aes(xData.subset, yData.subset, 
                                 color=categoricaldData.subset)) + geom_line()

де categoricalData.subsetмає 3 рівні.

Однак певний рівень, який знаходиться в обох наборах, закінчиться різним кольором, що ускладнює читання графіків разом.

Чи потрібно створити вектор кольорів у кадрі даних? Або є інший спосіб призначити певні кольори категоріям?

Відповіді:


187

Для простих ситуацій, таких як точний приклад в ОП, я погоджуюся, що відповідь Тьєррі найкраща. Однак я вважаю, що корисно вказати на інший підхід, який стає простішим, коли ви намагаєтеся підтримувати послідовні кольорові схеми у кількох кадрах даних, які не всі отримані шляхом підстановки одного великого кадру даних. Управління рівнями факторів у кількох кадрах даних може стати стомлюючим, якщо вони витягуються з окремих файлів, і не всі рівні факторів відображаються у кожному файлі.

Один із способів вирішити це - створити власну ручну кольорову шкалу таким чином:

#Some test data
dat <- data.frame(x=runif(10),y=runif(10),
        grp = rep(LETTERS[1:5],each = 2),stringsAsFactors = TRUE)

#Create a custom color scale
library(RColorBrewer)
myColors <- brewer.pal(5,"Set1")
names(myColors) <- levels(dat$grp)
colScale <- scale_colour_manual(name = "grp",values = myColors)

а потім додайте кольорову шкалу на графік за потребою:

#One plot with all the data
p <- ggplot(dat,aes(x,y,colour = grp)) + geom_point()
p1 <- p + colScale

#A second plot with only four of the levels
p2 <- p %+% droplevels(subset(dat[4:10,])) + colScale

Перший сюжет виглядає приблизно так:

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

а другий сюжет виглядає приблизно так:

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

Таким чином, вам не потрібно запам’ятовувати або перевіряти кожен кадр даних, щоб переконатися, що вони мають відповідні рівні.


1
Це спрацює, але, ймовірно, занадто складно. Я не думаю, що для цього не потрібно створювати вручну шкалу. Все, що вам потрібно factor, це спільне між усіма ділянками.
Андрі

14
@Andrie - для одного підмножини, так. Але якщо ви жонглюєте безліччю наборів даних, які були створені не всім підстановкою одного оригінального кадру даних, я вважаю цю стратегію набагато простішою.
joran

2
@joran Спасибі Джоран. Це працювало для мене! Створюється легенда з потрібною кількістю факторів. Мені подобається підхід і отримувати кольорові відображення в різних наборах даних цілком варто за три рядки.
зимовий

3
Мені потрібно: бібліотека ("RColorBrewer")
PatrickT

4
працював чудово! Я додав, fillScale <- scale_fill_manual(name = "grp",values = myColors)щоб використовувати це з барними ділянками.
п’ятирічний

42

Я перебуваю в такій же ситуації вказував malcook в своєму коментарі : на жаль, відповідь на Тьєррі не працює з ggplot2 версії 0.9.3.1.

png("figure_%d.png")
set.seed(2014)
library(ggplot2)
dataset <- data.frame(category = rep(LETTERS[1:5], 100),
    x = rnorm(500, mean = rep(1:5, 100)),
    y = rnorm(500, mean = rep(1:5, 100)))
dataset$fCategory <- factor(dataset$category)
subdata <- subset(dataset, category %in% c("A", "D", "E"))

ggplot(dataset, aes(x = x, y = y, colour = fCategory)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = fCategory)) + geom_point()

Ось це перша цифра:

ggplot AE, змішані кольори

і друга цифра:

ggplot ADE, змішаних кольорів

Як ми бачимо, кольори не залишаються фіксованими, наприклад, E перемикається з пурпурового на синій.

Як запропонував malcook у своєму коментарі та hadley у своєму коментарі, код, який використовує, limitsпрацює належним чином:

ggplot(subdata, aes(x = x, y = y, colour = fCategory)) +       
    geom_point() + 
    scale_colour_discrete(drop=TRUE,
        limits = levels(dataset$fCategory))

дає правильну цифру:

правильний ggplot

Це вихід із sessionInfo():

R version 3.0.2 (2013-09-25)
Platform: x86_64-pc-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] methods   stats     graphics  grDevices utils     datasets  base     

other attached packages:
[1] ggplot2_0.9.3.1

loaded via a namespace (and not attached):
 [1] colorspace_1.2-4   dichromat_2.0-0    digest_0.6.4       grid_3.0.2        
 [5] gtable_0.1.2       labeling_0.2       MASS_7.3-29        munsell_0.4.2     
 [9] plyr_1.8           proto_0.3-10       RColorBrewer_1.0-5 reshape2_1.2.2    
[13] scales_0.2.3       stringr_0.6.2 

3
Ви повинні опублікувати це як нове запитання, посилаючись на це питання та показуючи, чому рішення тут не спрацювали.
Брайан Діггс

Аналогічне питання було поставлене тут , але я хотів би відзначити, що прийнятий відповідь працює відмінно.
tonytonov

1
Тому я знаю, що це старе, але мені цікаво, чи є спосіб зробити це, не маючи зайвих кольорів в легенді.
goryh

20

Найпростіше рішення - перетворити вашу категоричну змінну у фактор до підмножини. Підсумок полягає в тому, що вам потрібна факторна змінна з точно однаковими рівнями у всіх ваших підмножинах.

library(ggplot2)
dataset <- data.frame(category = rep(LETTERS[1:5], 100), 
    x = rnorm(500, mean = rep(1:5, 100)), y = rnorm(500, mean = rep(1:5, 100)))
dataset$fCategory <- factor(dataset$category)
subdata <- subset(dataset, category %in% c("A", "D", "E"))

Із змінною символів

ggplot(dataset, aes(x = x, y = y, colour = category)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = category)) + geom_point()

З факторною змінною

ggplot(dataset, aes(x = x, y = y, colour = fCategory)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = fCategory)) + geom_point()

11
Найпростіший спосіб - використовувати ліміти
hadley

1
Чи могли б навести приклад у цьому контексті Хедлі? Я не впевнений, як використовувати обмеження з фактором.
Тьєррі

@Thierry Дякую Я був радий отримати відповіді на своє перше повідомлення. І дякую Тьєррі або додавши до відтворюваного коду, як я мав би бути у своєму дописі ... Мої категоричні змінні були правильним типом - чинниками. Інше питання - я хочу, щоб легенда не показувала невикористані фактори. R ігнорує невикористані змінні символи при побудові легенди. Однак невикористані фактори зберігаються. Якщо я скидаю їх, використовуючи: піддані $ категорія <- фактор (піддані $ категорія) [падіння = ІСТИНА], тоді легенда має правильну кількість факторів, АЛЕ втрачає відображення.
зимовий

11
@Thierry - в моїх руках, використовуючи ggplot2_0.9.3.1, цей метод не працює (вже не?); кольори, призначені для fCategory, відрізняються між двома графіками. Однак, до щастя, @wintour, я зрозумів , що @hadley передбачає , що + scale_colour_discrete(drop=TRUE,limits = levels(dataset$fCategory))для збереження кольору | коефіцієнт асоціації , але, який працює, за винятком того , в моїх руках, на падіння = TRUE є НЕ дотримується (я очікую , що це видалити рівень з легенда). Драт ... чи це я?
malcook

1
@malcook, замість drop = ІСТИНА, вам потрібно вказати, які рівні ви хочете зберегти через "перерви": github.com/hadley/ggplot2/isissue/1433
Eric

17

Це стара публікація, але я шукав відповідь на це саме запитання,

Чому б не спробувати щось на кшталт:

scale_color_manual(values = c("foo" = "#999999", "bar" = "#E69F00"))

Якщо у вас є категоричні значення, я не бачу причини, чому це не повинно працювати.


3
Це насправді те, що робить відповідь Джорана, але використовуючи, myColors <- brewer.pal(5,"Set1"); names(myColors) <- levels(dat$grp)щоб уникнути необхідності вручну кодувати рівні.
Axeman

Однак відповідь Джорану не важко кодує значення кольорів. Бувають випадки, коли потрібно певне значення кольору для даного фактора.
Рене Ніффенеггер

Хоча в деяких випадках я отримую недолік «жорсткого кодування», я думаю, що занадто часто шари розробників / кодерів абстракції додають, що робить їх роботу менш доступною, а не більшою. Намір у цьому випадку ясний на 100%. Крім того, досить просто придумати, як зробити функцію утиліти, яка розширюється на цьому прикладі, що повертає названий вектор певних кольорів.
Метт Барстед

16

На основі дуже корисної відповіді Джорана я зміг придумати це рішення для стабільної кольорової гами для булевого фактора ( TRUE, FALSE).

boolColors <- as.character(c("TRUE"="#5aae61", "FALSE"="#7b3294"))
boolScale <- scale_colour_manual(name="myboolean", values=boolColors)

ggplot(myDataFrame, aes(date, duration)) + 
  geom_point(aes(colour = myboolean)) +
  boolScale

Оскільки ColorBrewer не дуже корисний для двійкових кольорових шкал, два необхідні кольори визначаються вручну.

Ось mybooleanназва стовпця, що myDataFrameмістить коефіцієнт TRUE / FALSE. dateі durationє назви стовпців, які повинні бути відображені на осі x та y ділянки в цьому прикладі.


Інший підхід - застосувати "as.character ()" до стовпця. Це зробить колону з рядками, яка добре працює з масштабом _ * _ керівництво
Сахір Моосві
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.