วิธีกำหนดสีให้กับตัวแปรเด็ดขาดใน 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

สำหรับสถานการณ์อย่างง่ายเช่นตัวอย่างที่ถูกต้องใน OP ฉันยอมรับว่าคำตอบของธีรี่ร์นั้นดีที่สุด อย่างไรก็ตามฉันคิดว่ามันมีประโยชน์ที่จะชี้ให้เห็นวิธีการอื่นที่ง่ายขึ้นเมื่อคุณพยายามรักษาโทนสีที่สอดคล้องกันในกรอบข้อมูลหลาย ๆ กรอบซึ่งไม่ได้รับทั้งหมดจากการย่อยเฟรมข้อมูลขนาดใหญ่เพียงเฟรมเดียว การจัดการระดับปัจจัยในหลาย ๆ เฟรมข้อมูลอาจกลายเป็นเรื่องน่าเบื่อหากถูกดึงออกมาจากไฟล์ที่แยกกันและไม่ใช่ระดับปัจจัยทั้งหมดที่ปรากฏในแต่ละไฟล์

วิธีหนึ่งในการแก้ไขปัญหานี้คือการสร้างมาตราส่วนสีที่กำหนดเองดังต่อไปนี้:

#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ที่พบได้ทั่วไปในทุกแปลง
Andrie

14
@Andrie - สำหรับเซตย่อยเดียวใช่ แต่ถ้าคุณเล่นกลชุดข้อมูลจำนวนมากที่ไม่ได้สร้างขึ้นทั้งหมดด้วยการเซ็ตอัพเฟรมข้อมูลดั้งเดิมหนึ่งเฟรมฉันพบว่ากลยุทธ์นี้ง่ายกว่ามาก
joran

2
@Joran ขอบคุณ Joran สิ่งนี้ได้ผลสำหรับฉัน! มันสร้างตำนานที่มีจำนวนปัจจัยที่เหมาะสม ฉันชอบวิธีการและการแมปสีในชุดข้อมูลที่แตกต่างกันนั้นคุ้มค่ากับสามบรรทัด
Wintour

3
ฉันต้องการ: ไลบรารี่ ("RColorBrewer")
PatrickT

4
ทำงานได้อย่างสมบูรณ์แบบ! ฉันเพิ่มในfillScale <- scale_fill_manual(name = "grp",values = myColors)การใช้สิ่งนี้กับบาร์แปลง
pentandrous

42

ฉันอยู่ในสถานการณ์เดียวกันชี้ให้เห็นโดยmalcookในความคิดเห็นของเขา : น่าเสียดายที่คำตอบของThierryไม่ทำงานกับ 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
คุณควรโพสต์คำถามนี้เป็นคำถามใหม่อ้างอิงคำถามนี้และแสดงว่าทำไมการแก้ปัญหาที่นี่ไม่ทำงาน
Brian Diggs

มีการถามคำถามที่คล้ายกันที่นี่แต่ฉันต้องการจะชี้ให้เห็นว่าคำตอบที่ยอมรับนั้นใช้ได้ดี
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 ละเว้นตัวแปรอักขระที่ไม่ได้ใช้เมื่อสร้างคำอธิบาย อย่างไรก็ตามปัจจัยที่ไม่ได้ใช้ยังคงมีอยู่ ถ้าฉันปล่อยพวกเขาโดยใช้: subdata $ category <- factor (หมวดหมู่ subdata $) [drop = TRUE] ดังนั้นคำอธิบายแผนภูมิมีจำนวนปัจจัยที่เหมาะสม แต่การสูญเสียการแมป
Wintour

11
@Thierry - ในมือของฉันโดยใช้ ggplot2_0.9.3.1 วิธีนี้ใช้ไม่ได้อีกต่อไปหรือไม่ สีที่กำหนดให้กับหมวดหมู่ fC นั้นแตกต่างกันระหว่างสองแปลง อย่างไรก็ตามอย่างมีความสุข @wintour ฉันคิดว่า @hadley จะบอกว่า+ scale_colour_discrete(drop=TRUE,limits = levels(dataset$fCategory))เพื่อรักษาสี | สมาคมปัจจัย แต่ที่ทำงานยกเว้นในมือของฉันลดลง = TRUEจะไม่ได้รับการเคารพนับถือ (ผมคาดหวังว่ามันจะลบระดับจาก ตำนาน). Drat ... หรือว่าฉัน
malcook

1
@malcook แทนการปล่อย = TRUE คุณต้องระบุระดับที่คุณต้องการให้ผ่าน "ตัวแบ่ง": github.com/hadley/ggplot2/issues/1433
Eric

17

นี่เป็นโพสต์เก่า แต่ฉันต้องการคำตอบสำหรับคำถามเดียวกันนี้

ทำไมไม่ลองอะไรเช่น:

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

หากคุณมีค่าที่เป็นหมวดหมู่ฉันไม่เห็นสาเหตุที่ทำให้สิ่งนี้ไม่ทำงาน


3
นี่เป็นคำตอบที่แท้จริงของ Joran แต่ใช้myColors <- brewer.pal(5,"Set1"); names(myColors) <- levels(dat$grp)เพื่อหลีกเลี่ยงการเขียนรหัสด้วยตนเอง
Axeman

อย่างไรก็ตามคำตอบของ Joran นั้นไม่ได้เขียนรหัสค่าสีอย่างหนัก มีหลายกรณีที่คุณต้องการค่าสีเฉพาะสำหรับปัจจัยที่กำหนด
René Nyffenegger

ในขณะที่ฉันได้รับข้อเสียของ "การเข้ารหัสอย่างหนัก" ในบางกรณีฉันคิดว่าบ่อยครั้งที่เลเยอร์ของนักพัฒนา / ผู้เขียนโค้ดที่เป็นนามธรรมทำให้การทำงานของพวกเขาเข้าถึงได้น้อยลงไม่มากขึ้น เจตนาชัดเจน 100% ในกรณีนี้ นอกจากนี้ยังง่ายพอที่จะคิดวิธีสร้างฟังก์ชั่นยูทิลิตี้ที่ขยายตัวอย่างนี้ที่ส่งคืนเวกเตอร์ที่ระบุชื่อของสีเฉพาะ
Matt Barstead

16

จากคำตอบที่มีประโยชน์มากโดย joran ฉันสามารถหาวิธีแก้ปัญหานี้สำหรับการวัดระดับสีที่เสถียรสำหรับปัจจัยแบบบูล ( 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 ()" กับคอลัมน์ สิ่งนี้จะทำให้มันเป็นคอลัมน์สตริงที่ทำงานได้ดีกับ scale _ * _ manual
Sahir Moosvi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.