Wie ordne ich kategorialen Variablen in ggplot2 Farben zu, die eine stabile Zuordnung haben?

176

Ich habe mich im letzten Monat mit R vertraut gemacht.

Hier ist meine Frage:

Was ist eine gute Möglichkeit, kategorialen Variablen in ggplot2 Farben zuzuweisen, die eine stabile Zuordnung haben? Ich benötige konsistente Farben für eine Reihe von Diagrammen mit unterschiedlichen Teilmengen und unterschiedlicher Anzahl kategorialer Variablen.

Beispielsweise,

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

wo categoricalDatahat 5 Ebenen.

Und dann

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

wo categoricalData.subsethat 3 Ebenen.

Eine bestimmte Ebene in beiden Sätzen hat jedoch eine andere Farbe, was das gemeinsame Lesen der Diagramme erschwert.

Muss ich im Datenrahmen einen Farbvektor erstellen? Oder gibt es eine andere Möglichkeit, Kategorien bestimmte Farben zuzuweisen?

Winter
quelle

Antworten:

186

Für einfache Situationen wie das genaue Beispiel im OP stimme ich zu, dass Thierrys Antwort die beste ist. Ich halte es jedoch für nützlich, auf einen anderen Ansatz hinzuweisen, der einfacher wird, wenn Sie versuchen, konsistente Farbschemata über mehrere Datenrahmen hinweg beizubehalten, die nicht alle durch Unterteilen eines einzelnen großen Datenrahmens erhalten werden. Das Verwalten der Faktorebenen in mehreren Datenrahmen kann mühsam werden, wenn sie aus separaten Dateien abgerufen werden und nicht alle Faktorebenen in jeder Datei angezeigt werden.

Eine Möglichkeit, dies zu beheben, besteht darin, eine benutzerdefinierte manuelle Farbskala wie folgt zu erstellen:

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

und fügen Sie dann die Farbskala nach Bedarf zum Plot hinzu:

#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

Die erste Handlung sieht folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein

und die zweite Handlung sieht so aus:

Geben Sie hier die Bildbeschreibung ein

Auf diese Weise müssen Sie sich nicht jeden Datenrahmen merken oder überprüfen, um festzustellen, ob er die entsprechenden Ebenen hat.

Joran
quelle
1
Dies wird funktionieren, ist aber wahrscheinlich zu kompliziert. Ich glaube nicht, dass Sie dafür eine manuelle Skala erstellen müssen. Alles, was Sie brauchen, ist eine factor, die allen Parzellen gemeinsam ist.
Andrie
14
@Andrie - Für eine einzelne Teilmenge, ja. Wenn Sie jedoch viele Datensätze jonglieren, die nicht alle durch Unterteilen eines ursprünglichen Datenrahmens erstellt wurden, finde ich diese Strategie viel einfacher.
Joran
2
@joran Danke Joran. Das hat bei mir funktioniert! Es wird eine Legende mit der richtigen Anzahl von Faktoren erstellt. Ich mag den Ansatz und es lohnt sich, Farbzuordnungen über verschiedene Datensätze hinweg zu erhalten.
Winter
3
Ich brauchte: Bibliothek ("RColorBrewer")
PatrickT
4
hat perfekt funktioniert! Ich habe hinzugefügt fillScale <- scale_fill_manual(name = "grp",values = myColors), um dies mit Balkendiagrammen zu verwenden.
Pentandrous
42

Ich bin in der gleichen Situation, auf die Malcook in seinem Kommentar hingewiesen hat : Leider funktioniert die Antwort von Thierry nicht mit ggplot2 Version 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()

Hier ist es die erste Figur:

ggplot AE, gemischte Farben

und die zweite Figur:

ggplot ADE, gemischte Farben

Wie wir sehen können, bleiben die Farben nicht fest, zum Beispiel wechselt E von Magenta zu Blau.

Wie von Malcook in seinem Kommentar und von Hadley in seinem Kommentar vorgeschlagen,limits funktioniert der verwendete Code ordnungsgemäß:

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

gibt die folgende Zahl an, die richtig ist:

richtiges ggplot

Dies ist die Ausgabe von 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 
Alessandro Jacopson
quelle
3
Sie sollten dies als neue Frage posten, auf diese Frage verweisen und zeigen, warum die Lösungen hier nicht funktionierten.
Brian Diggs
Eine ähnliche Frage wurde hier gestellt , aber ich möchte darauf hinweisen, dass die akzeptierte Antwort gut funktioniert.
Tonytonov
1
Ich weiß, dass dies alt ist, aber ich frage mich, ob es eine Möglichkeit gibt, dies zu tun, ohne die zusätzlichen Farben in der Legende zu haben.
Goryh
20

Die einfachste Lösung besteht darin, Ihre kategoriale Variable vor der Teilmenge in einen Faktor umzuwandeln. Unter dem Strich benötigen Sie eine Faktorvariable mit genau den gleichen Ebenen in allen Ihren Teilmengen.

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

Mit einer Zeichenvariablen

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

Mit einer Faktorvariablen

ggplot(dataset, aes(x = x, y = y, colour = fCategory)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = fCategory)) + geom_point()
Thierry
quelle
11
Der einfachste Weg ist, Limits zu verwenden
Hadley
1
Könnte Hadley in diesem Zusammenhang ein Beispiel geben? Ich bin mir nicht sicher, wie ich Limits mit einem Faktor verwenden soll.
Thierry
@ Thierry Danke. Ich freute mich über Antworten auf meinen ersten Beitrag. Und danke Thierry oder das Hinzufügen von reproduzierbarem Code, wie ich es in meinem Beitrag hätte tun sollen ... Meine kategorialen Variablen waren die richtigen Typfaktoren. Das andere Problem ist, dass die Legende keine unbenutzten Faktoren anzeigt. R ignoriert nicht verwendete Zeichenvariablen beim Erstellen der Legende. Nicht verwendete Faktoren bleiben jedoch bestehen. Wenn ich sie lösche mit: subdata $ category <- factor (subdata $ category) [drop = TRUE], dann hat die Legende die richtige Anzahl von Faktoren, ABER verliert das Mapping.
Winter
11
@ Thierry - In meinen Händen funktioniert diese Methode mit ggplot2_0.9.3.1 (nicht mehr?) Nicht mehr. Die der fCategory zugewiesenen Farben unterscheiden sich zwischen den beiden Plots. Doch glücklich, @wintour, ich dachte , dass @hadley dass schlägt + scale_colour_discrete(drop=TRUE,limits = levels(dataset$fCategory))die Farbe zu erhalten | Faktor Verein aber, was funktioniert, es sei denn, in der Hand, den Tropfen = TRUE wird nicht eingehalten werden (ich erwarte , dass es um den Pegel zu entfernen die Legende). Drat ... oder bin ich es?
Malcook
1
@malcook, anstelle von drop = TRUE, müssen Sie angeben, welche Ebenen Sie über "Pausen" behalten möchten: github.com/hadley/ggplot2/issues/1433
Eric
17

Dies ist ein alter Beitrag, aber ich habe nach einer Antwort auf dieselbe Frage gesucht.

Warum probieren Sie nicht so etwas wie:

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

Wenn Sie kategoriale Werte haben, sehe ich keinen Grund, warum dies nicht funktionieren sollte.

Pavlos Panteliadis
quelle
3
Dies ist eigentlich die Antwort von Joran, aber um myColors <- brewer.pal(5,"Set1"); names(myColors) <- levels(dat$grp)zu vermeiden, dass die Ebenen manuell codiert werden müssen.
Axeman
Jorans Antwort codiert die Werte der Farben jedoch nicht fest. Es gibt Fälle, in denen Sie einen bestimmten Farbwert für einen bestimmten Faktor benötigen.
René Nyffenegger
Obwohl ich in bestimmten Fällen den Nachteil der "harten Codierung" habe, denke ich, dass zu oft die Ebenen der Abstraktionsentwickler / -codierer ihre Arbeit weniger zugänglich machen, nicht mehr. Die Absicht ist in diesem Fall 100% klar. Außerdem ist es leicht zu überlegen, wie eine Dienstprogrammfunktion erstellt werden kann, die dieses Beispiel erweitert und einen benannten Vektor mit bestimmten Farben zurückgibt.
Matt Barstead
16

Basierend auf der sehr hilfreichen Antwort von Joran konnte ich diese Lösung für eine stabile Farbskala für einen Booleschen Faktor ( TRUE, FALSE) finden.

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

Da ColorBrewer bei binären Farbskalen nicht sehr hilfreich ist, werden die beiden benötigten Farben manuell definiert.

Hier mybooleanist der Name der Spalte, in myDataFrameder der TRUE / FALSE-Faktor enthalten ist. dateund durationsind die Spaltennamen, die in diesem Beispiel der x- und y-Achse des Diagramms zugeordnet werden sollen.

Marian
quelle
Ein anderer Ansatz besteht darin, "as.character ()" auf die Spalte anzuwenden. Dies macht es zu einer Zeichenfolgenspalte, die gut mit der Skala _ * _ manual
Sahir Moosvi