Barplot의 한계

막대 그래프는 가장 많이 사용되는 그래프 중 하나이다. car 패키지에 포함되어 있는 Salaries 데이타는 2008-9년 미국의 한 대학교의 직급과 연봉에 관한 데이타이다. 이 데이터에서 성별에 따른 직급 분포를 barplot으로 그려보면 다음과 같다.

require(car)
require(ggplot2)
require(ggiraph)
require(moonBook)

ggplot(Salaries,aes(x=sex,fill=rank))+geom_bar()

이를 proportional stacked bar plot을 그려보면 다음과 같이 할 수 있다.

ggplot(Salaries,aes(x=sex,fill=rank))+geom_bar(position="fill")

이 그래프의 단점은 Male과 Female의 전체 인원수 가 다른데 비율만을 보여주기 때문에 성별에 따른 분포를 표현할 수 없다는 점이다. R의 기본패키지인 graphics에 포함되어 있는 spineplot은 bar의 width가 각각 다른 proportional bar plot을 그려준다.

par(mfrow=c(1,2))
spineplot(rank~sex,data=Salaries)
spineplot(sex~rank,data=Salaries)

par(mfrow=c(1,1))

ggSpine() for interactive spinogram

저자는 ggplot2와 ggiraph 패키지를 이용하여 spine plot을 그려주는 ggSpine()함수를 만들어 보았다. spineplot과 유사하지만 Interaction이 가능한 것이 장점이다.

source("ggSpine.R")
ggSpine(data=Salaries,"rank","sex",interactive=TRUE)

addlabel=TRUE로 주면 label을 자동으로 붙여준다.

ggSpine(data=Salaries,"sex","rank",addlabel = TRUE,interactive=TRUE)

geom_bar()와 마찬가지로 position=“stack” 또는 position=“dodge”도 쓸수 있다.

ggSpine(data=Salaries,"sex","rank",position="stack",addlabel = TRUE,interactive=TRUE)

ggSpine(data=Salaries,"sex","rank",position="dodge",addlabel = TRUE,interactive=TRUE)

이 함수는 데이타를 집계하여 그래프를 그릴 수도 있고 이미 count되어 있는 데이타로 그래프를 그릴 수도 있다. 지난번 저자가 rose plot을 올릴 때 사용한 데이타로 Rose plot을 그리려면 다음과 같다.

rose=read.csv("rose.csv",stringsAsFactors = FALSE)
rose$Month=factor(rose$Month,levels=month.name)
rose$tooltip=paste0(rose$Month,"<br>",rose$group,"<br>",rose$value)
rose$data_id=as.character(1:nrow(rose))
p<-ggplot(rose,aes(x=Month,fill=group,y=value))+
    geom_bar_interactive(aes(data_id=data_id,tooltip=tooltip),stat="identity",width=1,color="black",size=0.1)+
    scale_fill_brewer(palette="Greens")+coord_polar()

tooltip_css <- "background-color:white;font-style:italic;padding:10px;border-radius:20px 20px 20px 20px;"
ggiraph(code={print(p)},tooltip_extra_css = tooltip_css)

이 그림은 각 월별로 A-G까지의 합계가 다른 점을 표현하지 못하고 있다. 이를 ggSpine()함수로 표현해보면 다음과 같다. count가 되어 있는 자료의 경우 stat=“identity”로 지정하고 count가 있는 열이름을 yvar로 지정하여야 한다. 또한 bar사이의 간격을 없애려면 width=1로 한다.

rose1=read.csv("rose.csv",stringsAsFactors = FALSE)
rose1
   group     Month value
1      A   January  10.0
2      B   January   9.0
3      C   January   8.0
4      D   January   7.0
5      E   January   6.0
6      F   January   5.0
7      G   January   4.0
8      A  February   5.0
9      B  February   4.5
10     C  February   4.0
11     D  February   3.5
12     E  February   3.0
13     F  February   2.5
14     G  February   2.0
15     A     March   7.0
16     B     March   6.0
17     C     March   5.0
18     D     March   4.0
19     E     March   3.0
20     F     March   2.0
21     G     March   2.0
22     A     April   9.0
23     B     April   7.0
24     C     April   8.0
25     D     April   7.0
26     E     April   6.0
27     F     April   5.0
28     G     April   4.0
29     A       May  11.0
30     B       May   8.0
31     C       May   4.0
32     D       May   3.5
33     E       May   3.0
34     F       May   2.5
35     G       May   2.0
36     A      June  13.0
37     B      June   9.0
38     C      June   5.0
39     D      June   4.0
40     E      June   3.0
41     F      June   2.0
42     G      June   2.0
43     A      July  15.0
44     B      July  10.0
45     C      July   8.0
46     D      July   7.0
47     E      July   6.0
48     F      July   5.0
49     G      July   4.0
50     A    August  17.0
51     B    August  11.0
52     C    August   4.0
53     D    August   3.5
54     E    August   3.0
55     F    August   2.5
56     G    August   2.0
57     A September  19.0
58     B September  12.0
59     C September   5.0
60     D September   4.0
61     E September   3.0
62     F September   2.0
63     G September   2.0
64     A   October  21.0
65     B   October  13.0
66     C   October   8.0
67     D   October   7.0
68     E   October   6.0
69     F   October   5.0
70     G   October   4.0
71     A  November  23.0
72     B  November  14.0
73     C  November   4.0
74     D  November   3.5
75     E  November   3.0
76     F  November   2.5
77     G  November   2.0
78     A  December  25.0
79     B  December  15.0
80     C  December   5.0
81     D  December   4.0
82     E  December   3.0
83     F  December   2.0
84     G  December   2.0
rose1$Month=factor(rose1$Month,levels=month.name)
p<-ggSpine(rose1,"group","Month",yvar="value",stat="identity",width=1)
ggiraph(code={print(p)})

이것을 polar map으로 바꾸려면 polar=TRUE를 지정해주면 된다.

p<-p+coord_polar()
ggiraph(code={print(p)})

위의 코드는 다음의 코드와 동일하다.

ggSpine(rose1,"group","Month",yvar="value",stat="identity",
        width=1,polar=TRUE,interactive=TRUE)

geom_bar()와 유사하게 position=“stack” 으로 바꾸어주면 varaible width의 stacked bar plot을 얻을 수 있다.

ggSpine(rose1,"group","Month",yvar="value",stat="identity",
        position="stack",width=1,interactive=TRUE)

이 때도 polar=TRUE를 주면 variable width의 rose plot을 얻을 수 있다.

ggSpine(rose1,"group","Month",yvar="value",stat="identity",polar=TRUE,
        position="stack",width=1,interactive=TRUE)

stat=“identity”를 쓰지 않으면 각각의 자료의 갯수를 count하므로 다음과 같은 plot을 얻는다.

ggSpine(rose1,"group","Month",yvar="value",
        width=1,polar=TRUE,interactive=TRUE)

ggSpine() application to continuous variable

사실 ggSpine() 함수의 강력함은 연속형변수에 적용할 때 histogram과 비슷한 기능을 한다는 점이다. 이때 x축 라벨이 겹치지 않게 하기 위해 열합계가 전체의 4%가 되지 않는 열은 출력하지 않는다.

ggSpine(Salaries,"rank","yrs.service",interactive=TRUE)

addlabel= TRUE 로 하면 라벨을 붙여주는데 겹치는 것을 막기 위해 열합계가 전체의 4%가 되지 않는 열은 라벨을 출력하지 않는다.

ggSpine(Salaries,"rank","yrs.service",addlabel=TRUE,interactive=TRUE)

또 다른 예로써 ggSpine()함수를 그냥 호출하면 moonBook패키지의 acs데이타 중에서 smoking과 age의 관계를 보여준다.

ggSpine(addlabel=TRUE,interactive=TRUE)

smoking과 콜레스테롤의 관계를 보려면 다음과 같이 할 수 있다. 이 때 팔레트를 바꾸고 싶은 경우 다음과 같이 할수 있다.

ggSpine(data=acs,"smoking","TC",addlabel=TRUE,palette="Reds",interactive=TRUE)

이와 같이 ggplot2와 ggiraph패키지를 만들어 사용한 함수들은 htmlwidgets패키지의 saveWidget()함수를 사용하여 html파일로 만들어 local computer에 저장할 수도 있고 그 ㅊ파일을 파워포인트 파일 내에서 링크를 걸어 프리젠테이션에도 사용할 수 있다. 다음과 같이 하면 된다.

require(htmlwidgets)
p<-ggSpine(data=acs,"smoking","TC",addlabel=TRUE,palette="Reds",interactive=TRUE)
saveWidget(p,"ggSpine.html")

ggSpine()함수를 만드는데 꼬박 48시간이 걸렸다. ggSpine()함수의 소스는 시간이 허락하는대로 패키지로 만들어 공개할 예정이며 web-r.org에서 클릭만으로 사용하고 다운로드받을 수 있도록 할 예정이다.