Làm thế nào để vẽ hai biểu đồ với nhau trong R?


221

Tôi đang sử dụng R và tôi có hai khung dữ liệu: cà rốt và dưa chuột. Mỗi khung dữ liệu có một cột số duy nhất liệt kê chiều dài của tất cả cà rốt được đo (tổng cộng: 100k cà rốt) và dưa chuột (tổng cộng: 50k dưa chuột).

Tôi muốn vẽ hai biểu đồ - chiều dài cà rốt và chiều dài dưa chuột - trên cùng một âm mưu. Chúng chồng chéo lên nhau, vì vậy tôi đoán tôi cũng cần một chút minh bạch. Tôi cũng cần sử dụng tần số tương đối chứ không phải số tuyệt đối vì số lượng phiên bản trong mỗi nhóm là khác nhau.

một cái gì đó như thế này sẽ rất tuyệt nhưng tôi không hiểu cách tạo ra nó từ hai bảng của mình:

mật độ chồng chéo


Btw, phần mềm nào bạn định sử dụng? Đối với nguồn mở, tôi khuyên dùng gnuplot.info [gnuplot]. Trong tài liệu của nó, tôi tin rằng bạn sẽ tìm thấy các kịch bản mẫu và kỹ thuật nhất định để làm những gì bạn muốn.
noel aye

1
Tôi đang sử dụng R như thẻ gợi ý (bài đăng đã được chỉnh sửa để làm rõ điều này)
David B

1
ai đó đã đăng một số đoạn mã để làm điều đó trong chuỗi này: stackoverflow.com/questions/3485456/iêu
nico

Câu trả lời:


194

Hình ảnh mà bạn liên kết đến là cho các đường cong mật độ, không phải biểu đồ.

Nếu bạn đã đọc trên ggplot thì có lẽ điều duy nhất bạn thiếu là kết hợp hai khung dữ liệu của bạn thành một khung dài.

Vì vậy, hãy bắt đầu với một cái gì đó giống như những gì bạn có, hai bộ dữ liệu riêng biệt và kết hợp chúng.

carrots <- data.frame(length = rnorm(100000, 6, 2))
cukes <- data.frame(length = rnorm(50000, 7, 2.5))

# Now, combine your two dataframes into one.  
# First make a new column in each that will be 
# a variable to identify where they came from later.
carrots$veg <- 'carrot'
cukes$veg <- 'cuke'

# and combine into your new data frame vegLengths
vegLengths <- rbind(carrots, cukes)

Sau đó, điều này là không cần thiết nếu dữ liệu của bạn đã ở định dạng dài, bạn chỉ cần một dòng để tạo cốt truyện.

ggplot(vegLengths, aes(length, fill = veg)) + geom_density(alpha = 0.2)

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

Bây giờ, nếu bạn thực sự muốn biểu đồ sau đây sẽ hoạt động. Lưu ý rằng bạn phải thay đổi vị trí từ đối số "ngăn xếp" mặc định. Bạn có thể bỏ lỡ điều đó nếu bạn không thực sự có ý tưởng về dữ liệu của mình sẽ như thế nào. Một alpha cao hơn có vẻ tốt hơn ở đó. Cũng lưu ý rằng tôi đã làm cho nó biểu đồ mật độ. Thật dễ dàng để loại bỏ y = ..density..để đưa nó trở lại đếm.

ggplot(vegLengths, aes(length, fill = veg)) + 
   geom_histogram(alpha = 0.5, aes(y = ..density..), position = 'identity')

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


8
Nếu bạn muốn ở lại với biểu đồ, sử dụng ggplot(vegLengths, aes(length, fill = veg)) + geom_bar(pos="dodge"). Điều này sẽ tạo ra các biểu đồ xen kẽ, như trong MATLAB.
mbq

1
Thx cho câu trả lời! Phần 'vị trí = "danh tính" thực sự quan trọng vì nếu không các thanh được xếp chồng lên nhau gây hiểu lầm khi kết hợp với mật độ mà theo mặc định dường như là "danh tính", nghĩa là được phủ chồng lên nhau so với xếp chồng lên nhau.
Bóng tối

265

Đây là một giải pháp thậm chí đơn giản hơn bằng cách sử dụng đồ họa cơ bản và trộn alpha (không hoạt động trên tất cả các thiết bị đồ họa):

set.seed(42)
p1 <- hist(rnorm(500,4))                     # centered at 4
p2 <- hist(rnorm(500,6))                     # centered at 6
plot( p1, col=rgb(0,0,1,1/4), xlim=c(0,10))  # first histogram
plot( p2, col=rgb(1,0,0,1/4), xlim=c(0,10), add=T)  # second

Điều quan trọng là màu sắc là trong suốt.

Chỉnh sửa, hơn hai năm sau : Vì điều này vừa có một upvote, tôi hình tôi cũng có thể thêm một hình ảnh về những gì mã tạo ra khi trộn alpha rất hữu ích:

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


6
+1 cảm ơn tất cả các bạn, điều này có thể được chuyển đổi thành một bản đồ chính mượt mà hơn (như had.co.nz/ggplot2/graphics/55078149a733dd1a0b42a57faf847036.png ) không?
David B

3
Tại sao bạn tách ra các plotlệnh? Bạn có thể đặt tất cả các tùy chọn đó vào các histlệnh và chỉ hai tùy chọn trong hai dòng.
John

@ John Bạn sẽ làm thế nào?
HelloWorld

Đặt các tùy chọn trong plotlệnh trực tiếp vào lệnh hist như tôi đã nói. Đăng mã không phải là những gì bình luận cho.
Giăng

44

Đây là một hàm tôi đã viết sử dụng giả trong suốt để biểu thị các biểu đồ chồng chéo

plotOverlappingHist <- function(a, b, colors=c("white","gray20","gray50"),
                                breaks=NULL, xlim=NULL, ylim=NULL){

  ahist=NULL
  bhist=NULL

  if(!(is.null(breaks))){
    ahist=hist(a,breaks=breaks,plot=F)
    bhist=hist(b,breaks=breaks,plot=F)
  } else {
    ahist=hist(a,plot=F)
    bhist=hist(b,plot=F)

    dist = ahist$breaks[2]-ahist$breaks[1]
    breaks = seq(min(ahist$breaks,bhist$breaks),max(ahist$breaks,bhist$breaks),dist)

    ahist=hist(a,breaks=breaks,plot=F)
    bhist=hist(b,breaks=breaks,plot=F)
  }

  if(is.null(xlim)){
    xlim = c(min(ahist$breaks,bhist$breaks),max(ahist$breaks,bhist$breaks))
  }

  if(is.null(ylim)){
    ylim = c(0,max(ahist$counts,bhist$counts))
  }

  overlap = ahist
  for(i in 1:length(overlap$counts)){
    if(ahist$counts[i] > 0 & bhist$counts[i] > 0){
      overlap$counts[i] = min(ahist$counts[i],bhist$counts[i])
    } else {
      overlap$counts[i] = 0
    }
  }

  plot(ahist, xlim=xlim, ylim=ylim, col=colors[1])
  plot(bhist, xlim=xlim, ylim=ylim, col=colors[2], add=T)
  plot(overlap, xlim=xlim, ylim=ylim, col=colors[3], add=T)
}

Đây là một cách khác để làm điều đó bằng cách sử dụng hỗ trợ của R cho màu trong suốt

a=rnorm(1000, 3, 1)
b=rnorm(1000, 6, 1)
hist(a, xlim=c(0,10), col="red")
hist(b, add=T, col=rgb(0, 1, 0, 0.5) )

Kết quả cuối cùng trông giống như thế này: văn bản thay thế


+1 cho một tùy chọn khả dụng trên tất cả các thiết bị đồ họa (ví dụ postscript)
Lenna

31

Đã có câu trả lời đẹp, nhưng tôi nghĩ thêm. Co vẻ tôt vơi tôi. (Sao chép số ngẫu nhiên từ @Dirk). library(scales)là cần thiết

set.seed(42)
hist(rnorm(500,4),xlim=c(0,10),col='skyblue',border=F)
hist(rnorm(500,6),add=T,col=scales::alpha('red',.5),border=F)

Kết quả là...

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

Cập nhật: này chồng chéo chức năng cũng có thể có ích cho một số người.

hist0 <- function(...,col='skyblue',border=T) hist(...,col=col,border=border) 

Tôi cảm thấy kết quả từ hist0là đẹp hơn để nhìn hơnhist

hist2 <- function(var1, var2,name1='',name2='',
              breaks = min(max(length(var1), length(var2)),20), 
              main0 = "", alpha0 = 0.5,grey=0,border=F,...) {    

library(scales)
  colh <- c(rgb(0, 1, 0, alpha0), rgb(1, 0, 0, alpha0))
  if(grey) colh <- c(alpha(grey(0.1,alpha0)), alpha(grey(0.9,alpha0)))

  max0 = max(var1, var2)
  min0 = min(var1, var2)

  den1_max <- hist(var1, breaks = breaks, plot = F)$density %>% max
  den2_max <- hist(var2, breaks = breaks, plot = F)$density %>% max
  den_max <- max(den2_max, den1_max)*1.2
  var1 %>% hist0(xlim = c(min0 , max0) , breaks = breaks,
                 freq = F, col = colh[1], ylim = c(0, den_max), main = main0,border=border,...)
  var2 %>% hist0(xlim = c(min0 , max0),  breaks = breaks,
                 freq = F, col = colh[2], ylim = c(0, den_max), add = T,border=border,...)
  legend(min0,den_max, legend = c(
    ifelse(nchar(name1)==0,substitute(var1) %>% deparse,name1),
    ifelse(nchar(name2)==0,substitute(var2) %>% deparse,name2),
    "Overlap"), fill = c('white','white', colh[1]), bty = "n", cex=1,ncol=3)

  legend(min0,den_max, legend = c(
    ifelse(nchar(name1)==0,substitute(var1) %>% deparse,name1),
    ifelse(nchar(name2)==0,substitute(var2) %>% deparse,name2),
    "Overlap"), fill = c(colh, colh[2]), bty = "n", cex=1,ncol=3) }

Kết quả của

par(mar=c(3, 4, 3, 2) + 0.1) 
set.seed(100) 
hist2(rnorm(10000,2),rnorm(10000,3),breaks = 50)

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


24

Dưới đây là một ví dụ về cách bạn có thể làm điều đó trong đồ họa R "cổ điển":

## generate some random data
carrotLengths <- rnorm(1000,15,5)
cucumberLengths <- rnorm(200,20,7)
## calculate the histograms - don't plot yet
histCarrot <- hist(carrotLengths,plot = FALSE)
histCucumber <- hist(cucumberLengths,plot = FALSE)
## calculate the range of the graph
xlim <- range(histCucumber$breaks,histCarrot$breaks)
ylim <- range(0,histCucumber$density,
              histCarrot$density)
## plot the first graph
plot(histCarrot,xlim = xlim, ylim = ylim,
     col = rgb(1,0,0,0.4),xlab = 'Lengths',
     freq = FALSE, ## relative, not absolute frequency
     main = 'Distribution of carrots and cucumbers')
## plot the second graph on top of this
opar <- par(new = FALSE)
plot(histCucumber,xlim = xlim, ylim = ylim,
     xaxt = 'n', yaxt = 'n', ## don't add axes
     col = rgb(0,0,1,0.4), add = TRUE,
     freq = FALSE) ## relative, not absolute frequency
## add a legend in the corner
legend('topleft',c('Carrots','Cucumbers'),
       fill = rgb(1:0,0,0:1,0.4), bty = 'n',
       border = NA)
par(opar)

Vấn đề duy nhất với điều này là nó có vẻ tốt hơn nhiều nếu các ngắt biểu đồ được căn chỉnh, có thể phải được thực hiện thủ công (trong các đối số được truyền cho hist).


Rất đẹp. Nó cũng nhắc nhở tôi về một stackoverflow.com/questions/3485456/ từ
George Dontas

Bỏ qua điều này bởi vì câu trả lời này là câu duy nhất (ngoài những câu hỏi trong ggplot) trực tiếp giải thích nếu hai biểu đồ của bạn có kích thước mẫu khác nhau đáng kể.
MichaelChirico

Tôi thích phương pháp này, lưu ý rằng bạn có thể đồng bộ hóa các ngắt bằng cách định nghĩa chúng với seq (). Ví dụ:breaks=seq(min(data$some_property), max(data$some_property), by=(max_prop - min_prop)/20)
Deruijter

17

Đây là phiên bản giống như ggplot2 mà tôi đã chỉ cung cấp trong cơ sở R. Tôi đã sao chép một số từ @nullglob.

tạo dữ liệu

carrots <- rnorm(100000,5,2)
cukes <- rnorm(50000,7,2.5)

Bạn không cần phải đặt nó vào một khung dữ liệu như với ggplot2. Hạn chế của phương pháp này là bạn phải viết ra rất nhiều chi tiết của cốt truyện. Ưu điểm là bạn có quyền kiểm soát nhiều chi tiết hơn của cốt truyện.

## calculate the density - don't plot yet
densCarrot <- density(carrots)
densCuke <- density(cukes)
## calculate the range of the graph
xlim <- range(densCuke$x,densCarrot$x)
ylim <- range(0,densCuke$y, densCarrot$y)
#pick the colours
carrotCol <- rgb(1,0,0,0.2)
cukeCol <- rgb(0,0,1,0.2)
## plot the carrots and set up most of the plot parameters
plot(densCarrot, xlim = xlim, ylim = ylim, xlab = 'Lengths',
     main = 'Distribution of carrots and cucumbers', 
     panel.first = grid())
#put our density plots in
polygon(densCarrot, density = -1, col = carrotCol)
polygon(densCuke, density = -1, col = cukeCol)
## add a legend in the corner
legend('topleft',c('Carrots','Cucumbers'),
       fill = c(carrotCol, cukeCol), bty = 'n',
       border = NA)

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


9

@Dirk Eddelbuettel: Ý tưởng cơ bản là tuyệt vời nhưng mã như được hiển thị có thể được cải thiện. [Mất nhiều thời gian để giải thích, do đó, một câu trả lời riêng biệt và không phải là một nhận xét.]

Các hist()chức năng theo mặc định rút lô, vì vậy bạn cần phải thêm plot=FALSEtùy chọn. Hơn nữa, rõ ràng hơn để thiết lập khu vực cốt truyện bằng một plot(0,0,type="n",...)cuộc gọi trong đó bạn có thể thêm nhãn trục, tiêu đề cốt truyện, v.v ... Cuối cùng, tôi muốn đề cập rằng người ta cũng có thể sử dụng bóng để phân biệt giữa hai biểu đồ. Đây là mã:

set.seed(42)
p1 <- hist(rnorm(500,4),plot=FALSE)
p2 <- hist(rnorm(500,6),plot=FALSE)
plot(0,0,type="n",xlim=c(0,10),ylim=c(0,100),xlab="x",ylab="freq",main="Two histograms")
plot(p1,col="green",density=10,angle=135,add=TRUE)
plot(p2,col="blue",density=10,angle=45,add=TRUE)

Và đây là kết quả (hơi rộng vì RStudio :-)):

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


nâng cao điều này bởi vì đây là một tùy chọn rất đơn giản sử dụng cơ sở và khả thi trên postscriptcác thiết bị.
MichaelChirico

6

API R của Plotly có thể hữu ích cho bạn. Biểu đồ dưới đây là đây .

library(plotly)
#add username and key
p <- plotly(username="Username", key="API_KEY")
#generate data
x0 = rnorm(500)
x1 = rnorm(500)+1
#arrange your graph
data0 = list(x=x0,
         name = "Carrots",
         type='histogramx',
         opacity = 0.8)

data1 = list(x=x1,
         name = "Cukes",
         type='histogramx',
         opacity = 0.8)
#specify type as 'overlay'
layout <- list(barmode='overlay',
               plot_bgcolor = 'rgba(249,249,251,.85)')  
#format response, and use 'browseURL' to open graph tab in your browser.
response = p$plotly(data0, data1, kwargs=list(layout=layout))

url = response$url
filename = response$filename

browseURL(response$url)

Tiết lộ đầy đủ: Tôi ở trong đội.

Đồ thị


1

Rất nhiều câu trả lời tuyệt vời nhưng vì tôi vừa viết một hàm function ( plotMultipleHistograms()) để làm điều này, tôi nghĩ rằng tôi sẽ thêm một câu trả lời khác.

Ưu điểm của chức năng này là nó tự động đặt giới hạn trục X và Y thích hợp và xác định một bộ thùng chung mà nó sử dụng trên tất cả các bản phân phối.

Đây là cách sử dụng nó:

# Install the plotteR package
install.packages("devtools")
devtools::install_github("JosephCrispell/basicPlotteR")
library(basicPlotteR)

# Set the seed
set.seed(254534)

# Create random samples from a normal distribution
distributions <- list(rnorm(500, mean=5, sd=0.5), 
                      rnorm(500, mean=8, sd=5), 
                      rnorm(500, mean=20, sd=2))

# Plot overlapping histograms
plotMultipleHistograms(distributions, nBins=20, 
                       colours=c(rgb(1,0,0, 0.5), rgb(0,0,1, 0.5), rgb(0,1,0, 0.5)), 
                       las=1, main="Samples from normal distribution", xlab="Value")

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

Các plotMultipleHistograms()chức năng có thể mất bất kỳ số lượng các bản phân phối, và tất cả các thông số âm mưu chung nên làm việc với nó (ví dụ: las, main, vv).

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.