목표

일반적으로 파이그래프는 자료를 표현하는데 있어 그리 좋은 방법은 아닌 것으로 알려져 있다. 특히 자료의 갯수가 많아 질 경우 파이그래프보다 donut 그래프가 더 좋은 것으로 알려져 있다. 이번 글의 목표는 파이그래프와 donut plot을 결합하여 보기 좋은 그래프를 만드는 것이다. 다음과 같은 자료가 있다고 하자.

browsers=read.csv("browsers.csv")
browsers
   browser     version share
1     MSIE    MSIE 6.0 10.85
2     MSIE    MSIE 7.0  7.35
3     MSIE    MSIE 8.0 33.06
4     MSIE    MSIE 9.0  2.81
5  Firefox Firefox 3.5  1.58
6  Firefox Firefox 3.6 13.12
7  Firefox Firefox 4.0  5.43
8   Chrome Chrome 10.0  9.91
9   Safari  Safari 4.0  1.42
10  Safari  Safari 5.0  4.55
11   Opera  Opera 11.x  1.65

이때 이 자료를 이용하여 다음과 같은 그래프를 그리고자 한다.

또는 필자가 만든 moonBook package에 있는 acs 데이타를 이용하여 진단명과 흡연여부를 나타내보면 다음과 같다.

Donut plot 의 구현

먼저 Pie plot과 Donut plot을 비교해보자. ggplot2의 geom_rect()및 coord_polar()를 이용하면 간단하게 그릴 수 있다. geom_rect()를 이용하려면 ymin, ymax, xmin, xmax 좌표를 지정해주어야 한다. 이를 위하여 먼저 다음과 같이 자료를 전처리한다.

dat1<-browsers
dat1$ymax<-cumsum(dat1$share)
dat1$ymin<-cumsum(dat1$share)-dat1$share
dat1$ypos<-dat1$ymin+dat1$share/2
dat1$ratio<-dat1$share*100/sum(dat1$share)
dat1
   browser     version share  ymax  ymin   ypos     ratio
1     MSIE    MSIE 6.0 10.85 10.85  0.00  5.425 11.828191
2     MSIE    MSIE 7.0  7.35 18.20 10.85 14.525  8.012646
3     MSIE    MSIE 8.0 33.06 51.26 18.20 34.730 36.040554
4     MSIE    MSIE 9.0  2.81 54.07 51.26 52.665  3.063338
5  Firefox Firefox 3.5  1.58 55.65 54.07 54.860  1.722446
6  Firefox Firefox 3.6 13.12 68.77 55.65 62.210 14.302845
7  Firefox Firefox 4.0  5.43 74.20 68.77 71.485  5.919546
8   Chrome Chrome 10.0  9.91 84.11 74.20 79.155 10.803445
9   Safari  Safari 4.0  1.42 85.53 84.11 84.820  1.548021
10  Safari  Safari 5.0  4.55 90.08 85.53 87.805  4.960209
11   Opera  Opera 11.x  1.65 91.73 90.08 90.905  1.798757

Pie Plot

먼저 geom_rect()를 이용하여 막대그래프를 만들어보자.

require(ggplot2)

p<-ggplot(dat1)+geom_rect(aes(xmin=3,xmax=4,ymin=ymin,ymax=ymax,fill=version))
p

이제 coord_polar()를 이용하여 좌표계를 원형좌표계로 변환한다. 양궁에서 쓰이는 과녁과 비슷한 Buul’s eye plot이 그려진다.

p+coord_polar()

이를 Pie plot으로 변환하려면 coord_polar의 theta옵션을 “y”로 주면 된다.

p+coord_polar(theta="y")

이 그래프를 Donut plot으로 바꾸는 것은 x축의 좌표의 범위만 바꾸어 주면 된다.

p+coord_polar(theta="y")+xlim(0,4)

범례를 없애고 대신 browser version을 각 모형에 표시하면 다음과 같다.

p<-p+coord_polar(theta="y")+xlim(0,4)+
        geom_text(aes(x=3.5,y=ypos,label=version))+
        guides(fill=FALSE)
p

좌표계 축 및 라벨을 제거하기 위해 다음과 같은 테마를 만들어 사용하였다.

theme_clean=function(base_size=12){
  theme_grey(base_size) %+replace%
    theme(
      axis.title=element_blank(),
      axis.text=element_blank(),
      panel.background=element_blank(),
      panel.grid=element_blank(),
      axis.ticks.length=unit(0,"cm"),
      axis.ticks.margin=unit(0,"cm"),
      panel.margin=unit(0,"lines"),
      plot.margin=unit(c(0,0,0,0),"lines"),
      complete=TRUE
    )
}

theme_axis_blank=function(){
  theme(axis.ticks=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank())
}

p<-p+theme_clean()
p

Donut plot과 pie plot의 결합

Donut plot에 Pie plot을 다음과 같이 결합할 수 있다. 먼저 pie plot을 그리기 위한 데이타 전처리가 필요하다.

dat1
   browser     version share  ymax  ymin   ypos     ratio
1     MSIE    MSIE 6.0 10.85 10.85  0.00  5.425 11.828191
2     MSIE    MSIE 7.0  7.35 18.20 10.85 14.525  8.012646
3     MSIE    MSIE 8.0 33.06 51.26 18.20 34.730 36.040554
4     MSIE    MSIE 9.0  2.81 54.07 51.26 52.665  3.063338
5  Firefox Firefox 3.5  1.58 55.65 54.07 54.860  1.722446
6  Firefox Firefox 3.6 13.12 68.77 55.65 62.210 14.302845
7  Firefox Firefox 4.0  5.43 74.20 68.77 71.485  5.919546
8   Chrome Chrome 10.0  9.91 84.11 74.20 79.155 10.803445
9   Safari  Safari 4.0  1.42 85.53 84.11 84.820  1.548021
10  Safari  Safari 5.0  4.55 90.08 85.53 87.805  4.960209
11   Opera  Opera 11.x  1.65 91.73 90.08 90.905  1.798757
data2=ddply(dat1,"browser",summarize,sum(share))
colnames(data2)[2]="sum"
data2=data2[order(data2$sum,decreasing=TRUE),]
data2$cumsum=cumsum(data2$sum)
data2$pos=data2$cumsum-data2$sum/2
data2$ymin=data2$cumsum-data2$sum
data2$ratio=data2$sum*100/sum(data2$sum)
data2
  browser   sum cumsum    pos  ymin     ratio
3    MSIE 54.07  54.07 27.035  0.00 58.944729
2 Firefox 20.13  74.20 64.135 54.07 21.944838
1  Chrome  9.91  84.11 79.155 74.20 10.803445
5  Safari  5.97  90.08 87.095 84.11  6.508231
4   Opera  1.65  91.73 90.905 90.08  1.798757

이제 이렇게 만들어진 data2를 이용하여 기존의 plot에 파이그래프를 덧그린다.

p<-p+geom_rect(data=data2,aes(xmin=0,xmax=3,ymin=ymin,ymax=cumsum,fill=browser))+
        geom_text(data=data2,aes(x=1.5,y=pos,label=browser))
p

Dount plot의 개선

이 그림과 실제 저자가 만들어 사용하는 그림은 몇가지 차이가 있다. 먼저 donut plot의 라벨이 plot의 밖에 있고 선으로 연결되어 있다. 이 그림을 위해 저자가 만든 함수는 다음과 같다.

ggDonut=function(data=acs,donuts="Dx",count=NULL,
                 addPieLabel=TRUE,addDonutLabel=TRUE,showRatio=TRUE,
                 polar=TRUE,labelposition=1){
        if(is.null(count)){
                dat1=ddply(data,donuts,nrow)
                colnames(dat1)[2]="n"
        } else{
                dat1=data
                colnames(dat1)[colnames(dat1)==count]="n"
        }        
                dat1$ymax=cumsum(dat1$n)
                dat1$ymin=cumsum(dat1$n)-dat1$n
                dat1$ypos=dat1$ymin+dat1$n/2
                dat1$ratio=dat1$n*100/sum(dat1$n)
                dat1$cumratio=dat1$ypos*100/sum(dat1$n)
                dat1$hjust=ifelse((dat1$cumratio>25 & dat1$cumratio<75),0,1)
                
        
        mainCol=rainbow(nrow(dat1))
        p<-ggplot(dat1) + 
                geom_rect(aes( ymax=ymax, ymin=ymin, xmax=4,xmin=3),fill=mainCol,
                          colour="white",alpha=0.7)+ 
                coord_polar(theta="y",start=3*pi/2)+
                xlim(0,4+labelposition)+
                theme_clean()
        
        label=dat1[[donuts]]
        if(showRatio) 
                label=paste0(label,"\n(",round(dat1$ratio,1),"%)")
        
        if(labelposition==1) {
                p<- p+ geom_text(aes(label=label,x=4.3,y=ypos,hjust=hjust),size=3)+
                                geom_segment(aes(x=4,xend=4.2,y=ypos,yend=ypos))      
        }  else{
                p<- p+ geom_text(aes(label=label,x=3.5,y=ypos),size=3)
        }      
        
        p
        
}

사용하는 방법은 아주 간단하다. browser 자료는 “share”라는 열에 데이타가 있다.

ggDonut(browsers,"version","share")
Warning: `axis.ticks.margin` is deprecated. Please set `margin` property of
`axis.text` instead

ggDonut(browsers,"version","share",labelposition=0)
Warning: `axis.ticks.margin` is deprecated. Please set `margin` property of
`axis.text` instead

mtcars데이타에서 엔진 수에 따른 분포를 보려면 다음과 같이 할 수 있다.

ggDonut(mtcars,"cyl")
Warning: `axis.ticks.margin` is deprecated. Please set `margin` property of
`axis.text` instead

PieDonut 의 개선

처음 저자가 목표로 보여준 plot은 먼저 browser의 종류에 따라 색깔이 정해지고 그색깔을 기준으로 version의 색깔이 바뀐다. 또한 원형좌표계의 시작이 0도 지점이 아니고 270도 지점이다. ggPieDonut()함수는 다음과 같이 쓸 수 있다.

ggPieDonut(browsers,"browser","version","share")

ggPieDonut(acs,"Dx","smoking")

ggPieDonut(mtcars,"cyl","carb")

ggPieDonut() 함수를 각자 만들어보시기 바란다. 제일 먼저 웹R의 게시판에 글 올려주신 분에게는 저자가 곧 출판할 신간(영문책)을 한권 보내드리도록 하겠다.