Come assegnare i colori alle variabili categoriali in ggplot2 che hanno una mappatura stabile?


178

Mi sono alzato per accelerare con R nell'ultimo mese.

Ecco la mia domanda:

Qual è un buon modo per assegnare i colori alle variabili categoriali in ggplot2 che hanno una mappatura stabile? Ho bisogno di colori coerenti in una serie di grafici che hanno diversi sottoinsiemi e un diverso numero di variabili categoriali.

Per esempio,

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

dove categoricalDataha 5 livelli.

E poi

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

dove categoricalData.subsetha 3 livelli.

Tuttavia, un livello particolare che si trova in entrambi i set finirà con un colore diverso, il che rende più difficile leggere i grafici insieme.

Devo creare un vettore di colori nella cornice dati? O c'è un altro modo per assegnare colori specifici alle categorie?

Risposte:


187

Per situazioni semplici come l'esatto esempio nel PO, concordo sul fatto che la risposta di Thierry sia la migliore. Tuttavia, penso che sia utile sottolineare un altro approccio che diventa più facile quando si tenta di mantenere combinazioni di colori coerenti tra più frame di dati che non sono tutti ottenuti sottoponendo a un singolo frame di dati di grandi dimensioni. La gestione dei livelli dei fattori in più frame di dati può diventare noiosa se vengono estratti da file separati e non tutti i livelli dei fattori vengono visualizzati in ciascun file.

Un modo per risolvere questo problema è creare una scala di colori manuale personalizzata come segue:

#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)

e quindi aggiungi la scala dei colori sulla trama secondo necessità:

#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

La prima trama è simile alla seguente:

inserisci qui la descrizione dell'immagine

e la seconda trama è simile alla seguente:

inserisci qui la descrizione dell'immagine

In questo modo non è necessario ricordare o controllare ciascun frame di dati per verificare che abbiano i livelli appropriati.


1
Funzionerà, ma probabilmente è troppo complicato. Non penso che sia necessario creare una scala manuale per questo. Tutto ciò che serve è un factorelemento comune tra tutte le trame.
Andrie,

14
@Andrie - Per un singolo sottoinsieme, sì. Ma se stai manipolando molti set di dati che non sono stati tutti creati sottoponendo un frame di dati originale, trovo questa strategia molto più semplice.
joran,

2
@joran Grazie Joran. Questo ha funzionato per me! Crea una legenda con il giusto numero di fattori. Mi piace l'approccio e ottenere mappature dei colori su diversi set di dati vale le tre linee.
mercoledì

3
Avevo bisogno di: biblioteca ("RColorBrewer")
PatrickT

4
ha funzionato perfettamente! Ho aggiunto fillScale <- scale_fill_manual(name = "grp",values = myColors)per usarlo con grafici a barre.
pentandrous,

42

Sono nella stessa situazione evidenziata da Malcook nel suo commento : purtroppo la risposta di Thierry non funziona con la versione 0.9.3.1 di ggplot2.

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()

Ecco la prima figura:

ggplot AE, colori misti

e la seconda cifra:

ggplot ADE, colori misti

Come possiamo vedere i colori non rimangono fissi, ad esempio E passa dal magenta al blu.

Come suggerito da Malcook nel suo commento e da Hadley nel suo commento, il codice che utilizza limitsfunziona correttamente:

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

fornisce la seguente figura, che è corretta:

ggplot corretto

Questo è l'output di 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
Dovresti pubblicare questo come una nuova domanda, facendo riferimento a questa domanda e mostrando perché le soluzioni qui non hanno funzionato.
Brian Diggs,

Una domanda simile è stata posta qui , ma vorrei sottolineare che la risposta accettata funziona bene.
tonytonov,

1
Quindi so che questo è vecchio ma mi chiedo se c'è un modo per farlo senza avere i colori extra nella leggenda.
Goryh

20

La soluzione più semplice è convertire la variabile categoriale in un fattore prima del sottoinsieme. In conclusione, hai bisogno di una variabile fattore con esattamente gli stessi livelli in tutti i tuoi sottoinsiemi.

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"))

Con una variabile di carattere

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

Con una variabile fattore

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

11
Il modo più semplice è usare i limiti
hadley,

1
Potrebbe fornire un esempio in questo contesto Hadley? Non sono sicuro di come utilizzare i limiti con un fattore.
Thierry,

@Thierry Grazie. Sono stato felice di ricevere risposte sul mio primo post. E grazie Thierry o l'aggiunta di codice riproducibile come avrei dovuto nel mio post ... Le mie variabili categoriali erano i giusti fattori di tipo. L'altro problema è che voglio che la legenda non mostri i fattori inutilizzati. R ignora le variabili di carattere non utilizzate durante la creazione della legenda. Tuttavia, persistono fattori inutilizzati. Se li faccio cadere usando: subdata $ category <- factor (subdata $ category) [drop = TRUE] allora la legenda ha il giusto numero di fattori MA perde la mappatura.
mercoledì

11
@Thierry - nelle mie mani, usando ggplot2_0.9.3.1, questo metodo non funziona (più?); i colori assegnati alla categoria f sono diversi tra i due grafici. Tuttavia, fortunatamente, @wintour, ho pensato che @hadley sta suggerendo che + scale_colour_discrete(drop=TRUE,limits = levels(dataset$fCategory))per conservare il colore | associazione fattore, ma, che funziona, tranne che, nelle mie mani, la goccia = TRUE è non essere rispettati (mi aspetto che per rimuovere il livello da la leggenda). Drat ... o sono io?
Malcook,

1
@malcook, invece di drop = TRUE, devi specificare quali livelli vuoi mantenere tramite le "pause": github.com/hadley/ggplot2/issues/1433
Eric

17

Questo è un vecchio post, ma stavo cercando una risposta a questa stessa domanda,

Perché non provare qualcosa di simile:

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

Se hai valori categorici, non vedo un motivo per cui questo non dovrebbe funzionare.


3
Questa è in realtà la risposta di Joran, ma usando myColors <- brewer.pal(5,"Set1"); names(myColors) <- levels(dat$grp)per evitare di dover codificare manualmente i livelli.
Axeman

Tuttavia, la risposta di Joran non codifica duramente i valori dei colori. Ci sono casi in cui è necessario un valore di colore specifico per un dato fattore.
René Nyffenegger

Mentre in alcuni casi ottengo il rovescio della medaglia del "hard coding", penso che troppo spesso gli strati di astrazione che gli sviluppatori / programmatori aggiungono rendono il loro lavoro meno accessibile, non di più. L'intenzione è chiara al 100% in questo caso. Inoltre è abbastanza facile pensare a come realizzare una funzione di utilità che si espande in questo esempio che restituisce un vettore con nome di colori specifici.
Matt Barstead,

16

Sulla base della risposta molto utile di joran sono stato in grado di trovare questa soluzione per una scala cromatica stabile per un fattore booleano ( 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

Poiché ColorBrewer non è molto utile con le scale di colori binarie, i due colori necessari vengono definiti manualmente.

Ecco mybooleanil nome della colonna che contiene il myDataFramefattore VERO / FALSO. datee durationsono i nomi delle colonne da mappare sull'asse xey del grafico in questo esempio.


Un altro approccio è applicare "as.character ()" alla colonna. Questo renderà una colonna di stringhe che funziona bene con il manuale scala _ * _
Sahir Moosvi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.