Dựa trên câu trả lời @ Andrie ở đây là một nhiều hơn (nhưng không hoàn toàn) giải pháp chung để xử lý bóng trên hoặc dưới một đường thẳng cho trước trong hầu hết các trường hợp.
Tôi không sử dụng phương thức @Andrie đã tham chiếu here vì tôi gặp sự cố với xu hướng tự động mở rộng cốt truyện của ggplot
khi bạn thêm điểm gần các cạnh. Thay vào đó, việc này sẽ tạo các điểm đa giác theo cách thủ công bằng cách sử dụng Inf
và -Inf
khi cần. Một vài lưu ý:
Những điểm cần phải theo thứ tự chính xác 'trong khung dữ liệu, vì ggplot
lô đa giác theo thứ tự mà các điểm xuất hiện. Vì vậy, nó không đủ để có được các đỉnh của đa giác, họ phải được đặt hàng (hoặc là chiều kim đồng hồ hoặc ngược chiều kim đồng hồ) là tốt.
Giải pháp này giả định rằng dòng bạn đang vẽ không tự gây ra ggplot
để mở rộng phạm vi ô. Bạn sẽ thấy trong ví dụ của tôi rằng tôi chọn một dòng để vẽ bằng cách chọn ngẫu nhiên hai điểm trong dữ liệu và vẽ đường thẳng qua chúng. Nếu bạn cố gắng vẽ một đường quá xa các điểm còn lại của bạn, ggplot
sẽ tự động thay đổi phạm vi ô và sẽ khó đoán được chúng sẽ là gì.
Thứ nhất, đây là chức năng mà xây dựng các khung dữ liệu đa giác:
buildPoly <- function(xr, yr, slope = 1, intercept = 0, above = TRUE){
#Assumes ggplot default of expand = c(0.05,0)
xrTru <- xr + 0.05*diff(xr)*c(-1,1)
yrTru <- yr + 0.05*diff(yr)*c(-1,1)
#Find where the line crosses the plot edges
yCross <- (yrTru - intercept)/slope
xCross <- (slope * xrTru) + intercept
#Build polygon by cases
if (above & (slope >= 0)){
rs <- data.frame(x=-Inf,y=Inf)
if (xCross[1] < yrTru[1]){
rs <- rbind(rs,c(-Inf,-Inf),c(yCross[1],-Inf))
}
else{
rs <- rbind(rs,c(-Inf,xCross[1]))
}
if (xCross[2] < yrTru[2]){
rs <- rbind(rs,c(Inf,xCross[2]),c(Inf,Inf))
}
else{
rs <- rbind(rs,c(yCross[2],Inf))
}
}
if (!above & (slope >= 0)){
rs <- data.frame(x= Inf,y= -Inf)
if (xCross[1] > yrTru[1]){
rs <- rbind(rs,c(-Inf,-Inf),c(-Inf,xCross[1]))
}
else{
rs <- rbind(rs,c(yCross[1],-Inf))
}
if (xCross[2] > yrTru[2]){
rs <- rbind(rs,c(yCross[2],Inf),c(Inf,Inf))
}
else{
rs <- rbind(rs,c(Inf,xCross[2]))
}
}
if (above & (slope < 0)){
rs <- data.frame(x=Inf,y=Inf)
if (xCross[1] < yrTru[2]){
rs <- rbind(rs,c(-Inf,Inf),c(-Inf,xCross[1]))
}
else{
rs <- rbind(rs,c(yCross[2],Inf))
}
if (xCross[2] < yrTru[1]){
rs <- rbind(rs,c(yCross[1],-Inf),c(Inf,-Inf))
}
else{
rs <- rbind(rs,c(Inf,xCross[2]))
}
}
if (!above & (slope < 0)){
rs <- data.frame(x= -Inf,y= -Inf)
if (xCross[1] > yrTru[2]){
rs <- rbind(rs,c(-Inf,Inf),c(yCross[2],Inf))
}
else{
rs <- rbind(rs,c(-Inf,xCross[1]))
}
if (xCross[2] > yrTru[1]){
rs <- rbind(rs,c(Inf,xCross[2]),c(Inf,-Inf))
}
else{
rs <- rbind(rs,c(yCross[1],-Inf))
}
}
return(rs)
}
Nó hy vọng x và y dãy dữ liệu của bạn (như trong range()
), độ dốc và đánh chặn của dòng bạn sẽ âm mưu, và liệu bạn có muốn che bóng ở trên hay dưới dòng. Đây là mã tôi đã sử dụng để tạo bốn ví dụ sau:
#Generate some data
dat <- data.frame(x=runif(10),y=runif(10))
#Select two of the points to define the line
pts <- dat[sample(1:nrow(dat),size=2,replace=FALSE),]
#Slope and intercept of line through those points
sl <- diff(pts$y)/diff(pts$x)
int <- pts$y[1] - (sl*pts$x[1])
#Build the polygon
datPoly <- buildPoly(range(dat$x),range(dat$y),
slope=sl,intercept=int,above=FALSE)
#Make the plot
p <- ggplot(dat,aes(x=x,y=y)) +
geom_point() +
geom_abline(slope=sl,intercept = int) +
geom_polygon(data=datPoly,aes(x=x,y=y),alpha=0.2,fill="blue")
print(p)
Và đây là một số ví dụ về kết quả. Nếu bạn tìm thấy bất kỳ lỗi, tất nhiên, cho tôi biết để tôi có thể cập nhật câu trả lời này ...
EDIT
Đã cập nhật lên minh họa giải pháp sử dụng dữ liệu ví dụ OP của:
set.seed(1)
dat <- data.frame(x=runif(6,-2,2),y=runif(6,-2,2),
var1=rep(c("A","B"),3),var2=rep(c("C","D"),3))
#Create polygon data frame
df_poly <- buildPoly(range(dat$x),range(dat$y))
ggplot(data=dat,aes(x,y)) +
facet_wrap(~var2) +
geom_abline(slope=1,intercept=0,lwd=0.5)+
geom_point(aes(colour=var1),size=3) +
scale_color_manual(values=c("red","blue"))+
geom_polygon(data=df_poly,aes(x,y),fill="blue",alpha=0.2)
và điều này sẽ cho kết quả như sau:
điểm màu và đa giác điền được xử lý bởi hai thẩm mỹ khác nhau (màu sắc và điền vào) và không nên xung đột, vì vậy tôi nghi ngờ bạn có thể làm điều gì đó sai trái ở đó. Tôi rất sẵn lòng trợ giúp thêm một số nhưng tôi không thể không có một ví dụ tái tạo cụ thể về dữ liệu bạn đang cố gắng vẽ ... – joran
Xong. Tôi nghi ngờ điều này xuất phát từ sự không quen thuộc của tôi với cách ggplot2 xử lý những thứ như vậy. Cảm ơn một lần nữa vì sự giúp đỡ của bạn, tôi đánh giá cao nó rất nhiều. – jslefche
Di chuyển 'color = var1' thành' geom_point': 'geom_point (aes (color = var1), ...)'. Ngoài ra, nếu bạn muốn các đa giác khác nhau trong mỗi khía cạnh nhận thức được rằng bạn sẽ phải tạo một khung dữ liệu riêng biệt cho từng khía cạnh và kết hợp chúng thành một khung dữ liệu đơn bao gồm yếu tố 'var2', vì vậy' ggplot' biết cái nào áp dụng cho từng khía cạnh. – joran