R에서 두 개의 히스토그램을 함께 플롯하는 방법은 무엇입니까?


221

R을 사용하고 있으며 당근과 오이라는 두 가지 데이터 프레임이 있습니다. 각 데이터 프레임에는 측정 된 모든 당근 (총 : 100k 당근)과 오이 (총 : 50k 오이)의 길이가 나열된 단일 숫자 열이 있습니다.

나는 같은 줄거리에 두 개의 막대 그래프-당근 길이와 오이 길이를 그려보고 싶습니다. 그것들이 겹치기 때문에 투명성이 필요하다고 생각합니다. 각 그룹의 인스턴스 수가 다르기 때문에 절대 숫자가 아닌 상대 주파수를 사용해야합니다.

이 같은 것이 좋을 것이지만 두 테이블에서 그것을 만드는 방법을 이해하지 못합니다.

중복 밀도


Btw, 어떤 소프트웨어를 사용할 계획입니까? 오픈 소스의 경우 gnuplot.info [gnuplot]을 권장 합니다. 그 문서에는 원하는 기술을 수행하기위한 특정 기술과 샘플 스크립트가 있습니다.
noel aye

1
태그에서 알 수 있듯이 R을 사용하고 있습니다 (이를 명확하게하기 위해 편집 된 게시물)
David B

답변:


194

연결 한 이미지는 히스토그램이 아니라 밀도 곡선을위한 것입니다.

ggplot을 읽고 있다면 누락 된 유일한 것은 두 개의 데이터 프레임을 하나의 긴 프레임으로 결합하는 것입니다.

자, 당신이 가진 것, 두 개의 분리 된 데이터 세트로 시작해서 그것들을 결합합시다.

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)

그 후에는 데이터가 이미 긴 형식 인 경우 불필요합니다. 플롯을 만들려면 한 줄만 필요합니다.

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

여기에 이미지 설명을 입력하십시오

이제 히스토그램을 정말로 원한다면 다음과 같이 작동합니다. 기본 "스택"인수에서 위치를 변경해야합니다. 데이터의 모양이 무엇인지 모른다면 놓칠 수 있습니다. 알파가 높을수록 더 좋아 보입니다. 또한 밀도 히스토그램으로 만들었습니다. 를 y = ..density..다시 계산하기 위해를 쉽게 제거 할 수 있습니다.

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

여기에 이미지 설명을 입력하십시오


8
히스토그램을 유지하려면을 사용하십시오 ggplot(vegLengths, aes(length, fill = veg)) + geom_bar(pos="dodge"). 이렇게하면 MATLAB과 같이 인터레이스 히스토그램이 만들어집니다.
mbq

1
답변을위한 Thx! 'position = "identity"'부분은 실제로 막대가 쌓여 있기 때문에 실제로 중요합니다. 이는 기본적으로 "identity"인 것처럼 보이는 밀도와 결합 될 때 오해의 소지가 있습니다.
Shadow

265

기본 그래픽 및 알파 블렌딩을 사용하는 훨씬 간단한 솔루션은 다음과 같습니다 (일부 그래픽 장치에서는 작동하지 않음).

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

열쇠는 색상이 반투명하다는 것입니다.

2 년이 지난 후 편집 : 이것은 방금 공언을 얻었으므로 알파 블렌딩이 너무 유용하기 때문에 코드가 생성하는 것을 시각적으로 추가 할 수 있다고 생각합니다.

여기에 이미지 설명을 입력하십시오


6
+1 모두 감사합니다. 이는 더 부드러운 지 스토 그램으로 변환 될 수 있습니까 (예 : had.co.nz/ggplot2/graphics/55078149a733dd1a0b42a57faf847036.png )?
David B

3
plot명령 을 분리 했 습니까? 이러한 옵션을 모두 hist명령에 넣고 두 줄에 두 개만 둘 수 있습니다.
John

@John 어떻게 하시겠습니까?
HelloWorld

plot내가 말했듯 이 명령 의 옵션을 hist 명령에 직접 넣으십시오 . 코드를 게시하는 것은 주석이 아닙니다.
John

44

다음 은 의사 투명도를 사용하여 겹치는 히스토그램을 나타내는 함수입니다.

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

여기 투명 색상 R의 지원을 사용하여 할 수있는 또 다른 방법은

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

결과는 다음과 같이 보입니다. 대체 텍스트


모든 그래픽 장치에서 사용할 수있는 옵션에 대한 +1 (예 postscript)
레나

31

이미 아름다운 답변이 있지만 이것을 추가 할 생각이었습니다. 나에게 좋아 보인다. (@Dirk에서 복사 한 난수). library(scales)필요하다`

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)

결과는 ...

여기에 이미지 설명을 입력하십시오

업데이트 :겹치는 기능은 일부에게 유용 할 수 있습니다.

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

hist0보다 결과 가 더 예쁘다고 느낀다hist

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

의 결과

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

이다

여기에 이미지 설명을 입력하십시오


24

다음은 "클래식"R 그래픽에서 수행 할 수있는 방법의 예입니다.

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

이것의 유일한 문제는 히스토그램 나누기가 정렬되어 있으면 수동으로 수행해야 할 수도 있습니다 (인수에 전달 된 인수에서 hist).


아주 좋아요 또한 하나의 stackoverflow.com/questions/3485456/…을
George Dontas

이 답변은 ggplot두 개의 히스토그램이 실질적으로 다른 샘플 크기를 갖는지 직접적으로 설명 하는 유일한 답변이기 때문 입니다.
MichaelChirico

이 방법이 마음에 듭니다. seq ()로 나누기를 정의하여 나누기를 동기화 할 수 있습니다. 예를 들면 :breaks=seq(min(data$some_property), max(data$some_property), by=(max_prop - min_prop)/20)
Deruijter

17

다음은 기본 R에서만 제공하는 ggplot2와 같은 버전입니다. @nullglob에서 일부를 복사했습니다.

데이터를 생성

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

ggplot2와 같은 데이터 프레임에 넣을 필요는 없습니다. 이 방법의 단점은 플롯의 세부 사항을 훨씬 더 많이 작성해야한다는 것입니다. 이점은 플롯에 대한 자세한 내용을 제어 할 수 있다는 것입니다.

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

여기에 이미지 설명을 입력하십시오


9

@ Dirk Eddelbuettel : 기본 아이디어는 훌륭하지만 표시된 코드를 향상시킬 수 있습니다. [설명하는 데 시간이 오래 걸리므로 별도의 답변이 필요합니다.]

hist()당신은 추가해야하므로 기본적으로 함수는 그래프를 그립니다 plot=FALSE옵션을 선택합니다. 또한 plot(0,0,type="n",...)축 레이블, 플롯 제목 등을 추가 할 수 있는 호출로 플롯 영역을 설정하는 것이 더 명확합니다 . 마지막으로 두 히스토그램을 구별하기 위해 음영을 사용할 수도 있습니다. 코드는 다음과 같습니다.

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)

그리고 결과는 다음과 같습니다 (RStudio :-) 때문에 너무 넓습니다).

여기에 이미지 설명을 입력하십시오


postscript장치 에서 기본 및 실행 가능을 사용하는 매우 간단한 옵션이기 때문에 이것을 업업 합니다.
MichaelChirico

6

Plotly의 R API 가 유용 할 수 있습니다. 아래 그래프는 여기에 있습니다 .

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)

전체 공개 : 저는 팀에 있습니다.

그래프


1

많은 훌륭한 답변이 있지만 방금 함수 ( plotMultipleHistograms()) 함수를 작성했기 때문에 다른 답변을 추가 할 것이라고 생각했습니다.

이 기능의 장점은 적절한 X 및 Y 축 제한을 자동으로 설정하고 모든 분포에서 사용하는 공통 구간 세트를 정의한다는 것입니다.

사용 방법은 다음과 같습니다.

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

여기에 이미지 설명을 입력하십시오

plotMultipleHistograms()함수 분포의 임의의 수를 취할 수 있으며, 모든 일반적인 플로팅 파라미터가 작동한다 (예를 들어 las, main등).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.