Làm cách nào để gán màu cho các biến phân loại trong ggplot2 có ánh xạ ổn định?


176

Tôi đã tăng tốc với R trong tháng trước.

Đây là câu hỏi của tôi:

Một cách tốt để gán màu cho các biến phân loại trong ggplot2 có ánh xạ ổn định là gì? Tôi cần các màu nhất quán trên một tập các biểu đồ có các tập con khác nhau và số lượng biến phân loại khác nhau.

Ví dụ,

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

nơi categoricalDatacó 5 cấp độ.

Và sau đó

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

nơi categoricalData.subsetcó 3 cấp độ.

Tuy nhiên, một mức cụ thể trong cả hai bộ sẽ kết thúc bằng một màu khác nhau, khiến cho việc đọc các biểu đồ cùng nhau trở nên khó khăn hơn.

Tôi có cần tạo một vectơ màu trong khung dữ liệu không? Hoặc có một cách khác để gán màu cụ thể cho các danh mục?

Câu trả lời:


186

Đối với các tình huống đơn giản như ví dụ chính xác trong OP, tôi đồng ý rằng câu trả lời của Thierry là tốt nhất. Tuy nhiên, tôi nghĩ thật hữu ích khi chỉ ra một cách tiếp cận khác trở nên dễ dàng hơn khi bạn đang cố gắng duy trì các bảng màu nhất quán trên nhiều khung dữ liệu mà không phải tất cả đều có được bằng cách đặt một khung dữ liệu lớn duy nhất. Việc quản lý các mức yếu tố trong nhiều khung dữ liệu có thể trở nên tẻ nhạt nếu chúng được kéo từ các tệp riêng biệt và không phải tất cả các cấp yếu tố đều xuất hiện trong mỗi tệp.

Một cách để giải quyết vấn đề này là tạo thang màu thủ công tùy chỉnh như sau:

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

và sau đó thêm thang màu vào ô nếu cần:

#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

Cốt truyện đầu tiên trông như thế này:

nhập mô tả hình ảnh ở đây

và cốt truyện thứ hai trông như thế này:

nhập mô tả hình ảnh ở đây

Bằng cách này, bạn không cần phải nhớ hoặc kiểm tra từng khung dữ liệu để thấy rằng chúng có các mức phù hợp.


1
Điều này sẽ làm việc, nhưng có lẽ là quá phức tạp. Tôi không nghĩ bạn cần tạo một thang đo thủ công cho việc này. Tất cả bạn cần là một factorphổ biến giữa tất cả các lô.
Andrie

14
@Andrie - Đối với một tập hợp con duy nhất, yeah. Nhưng nếu bạn tung hứng nhiều bộ dữ liệu mà tất cả không được tạo bằng cách đặt lại một khung dữ liệu gốc, tôi thấy chiến lược này đơn giản hơn nhiều.
Joran

2
@joran Cảm ơn Joran. Điều này làm việc cho tôi! Nó tạo ra một huyền thoại với đúng số lượng các yếu tố. Tôi thích cách tiếp cận và để có được ánh xạ màu trên các tập dữ liệu khác nhau rất xứng đáng với ba dòng.
mùa đông

3
Tôi cần: thư viện ("RColorBrewer")
PatrickT

4
làm việc hoàn hảo Tôi đã thêm vào fillScale <- scale_fill_manual(name = "grp",values = myColors)để sử dụng điều này với các ô thanh.
pentandrous

42

Tôi đang ở trong tình huống tương tự được malcook chỉ ra trong bình luận của mình : thật không may, câu trả lời của Thierry không hoạt động với ggplot2 phiên bản 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()

Đây là con số đầu tiên:

ggplot AE, màu sắc hỗn hợp

và hình thứ hai:

ggplot ADE, màu sắc hỗn hợp

Như chúng ta có thể thấy các màu không cố định, ví dụ E chuyển từ màu đỏ tươi sang màu xanh.

Theo đề xuất của malcook trong bình luận của anh ấy và bởi hadley trong bình luận của anh ấy , mã sử dụng limitshoạt động đúng:

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

đưa ra con số sau đây, đúng:

ggplot đúng

Đây là đầu ra từ 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
Bạn nên đăng câu hỏi này dưới dạng câu hỏi mới, tham khảo câu hỏi này và cho biết lý do tại sao các giải pháp ở đây không hoạt động.
Brian Diggs

Một câu hỏi tương tự đã được hỏi ở đây , nhưng tôi muốn chỉ ra rằng câu trả lời được chấp nhận hoạt động tốt.
tonytonov 6/03/2015

1
Vì vậy, tôi biết điều này là cũ nhưng tôi tự hỏi nếu có một cách để làm điều này mà không có thêm màu sắc trong truyền thuyết.
goryh

20

Giải pháp đơn giản nhất là chuyển đổi biến phân loại của bạn thành một yếu tố trước khi đặt lại. Điểm mấu chốt là bạn cần một biến nhân tố với các cấp chính xác giống nhau trong tất cả các tập con của bạn.

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

Với một biến ký tự

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

Với một biến nhân tố

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

11
Cách dễ nhất là sử dụng các giới hạn
hadley

1
Có thể cung cấp một ví dụ trong bối cảnh này Hadley? Tôi không chắc chắn làm thế nào để sử dụng giới hạn với một yếu tố.
Thierry

@Thierry Cảm ơn. Tôi rất vui khi nhận được phản hồi về bài viết đầu tiên của tôi. Và cảm ơn Thierry hoặc thêm mã có thể tái tạo như tôi nên có trong bài viết của mình ... Các biến phân loại của tôi là loại đúng - các yếu tố. Vấn đề khác là tôi muốn huyền thoại không thể hiện các yếu tố không sử dụng. R bỏ qua các biến ký tự không sử dụng khi xây dựng huyền thoại. Tuy nhiên, các yếu tố không được sử dụng vẫn tồn tại. Nếu tôi thả chúng bằng cách sử dụng: subsata $ category <- Fact (subata $ category) [drop = TRUE] thì chú giải có đúng số lượng yếu tố NHƯNG làm mất ánh xạ.
mùa đông

11
@Thierry - trong tay tôi, sử dụng ggplot2_0.9.3.1, phương pháp này không còn hoạt động nữa? màu sắc được gán cho fC Category khác nhau giữa hai ô. Tuy nhiên, hạnh phúc, @wintour, I figured rằng @hadley được gợi ý rằng + scale_colour_discrete(drop=TRUE,limits = levels(dataset$fCategory))để bảo vệ màu | Hội yếu tố nhưng, hoạt động, ngoại trừ, trong tay tôi, thả = TRUEKHÔNG được tôn trọng (Tôi hy vọng nó sẽ loại bỏ các mức từ huyền thoại). Drat ... hay là tôi?
malcook

1
@malcook, thay vì drop = TRUE, bạn cần chỉ định cấp độ nào bạn muốn giữ thông qua "break": github.com/hadley/ggplot2/issues/1433
Eric

17

Đây là một bài viết cũ, nhưng tôi đang tìm câu trả lời cho cùng câu hỏi này,

Tại sao không thử một cái gì đó như:

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

Nếu bạn có các giá trị phân loại, tôi không thấy lý do tại sao điều này không hoạt động.


3
Đây thực sự là những gì câu trả lời của Joran, nhưng sử dụng myColors <- brewer.pal(5,"Set1"); names(myColors) <- levels(dat$grp)để tránh phải tự mã hóa các cấp độ.
Axeman

Tuy nhiên, câu trả lời của Joran không làm khó mã hóa các giá trị của màu sắc. Có những trường hợp bạn cần một giá trị màu cụ thể cho một yếu tố nhất định.
René Nyffalanger

Mặc dù tôi gặp phải nhược điểm của "mã hóa cứng" trong một số trường hợp nhất định, tôi nghĩ rằng quá thường xuyên các lớp của các nhà phát triển / lập trình viên trừu tượng thêm vào làm cho công việc của họ ít truy cập hơn, không nhiều hơn. Ý định là rõ ràng 100% trong trường hợp này. Thêm vào đó, thật dễ dàng để nghĩ ra cách tạo một hàm tiện ích mở rộng trên ví dụ này trả về một vectơ có tên của các màu cụ thể.
Matt Barstead

16

Dựa trên câu trả lời rất hữu ích của joran, tôi đã có thể đưa ra giải pháp này cho thang màu ổn định cho hệ số boolean ( 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

Vì ColorBrewer không hữu ích với thang màu nhị phân, hai màu cần thiết được xác định thủ công.

Đây mybooleanlà tên của cột trong myDataFrameviệc giữ yếu tố TRUE / FALSE. datedurationlà các tên cột được ánh xạ tới trục x và y của âm mưu trong ví dụ này.


Một cách tiếp cận khác là áp dụng "as.character ()" cho cột. Điều này sẽ làm cho nó trở thành một cột chuỗi hoạt động tốt với quy mô _ * _ thủ công
Sahir Moosvi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.