본문 바로가기
R 프로그래밍/R 데이터 시각화

[R 그래픽스] 막대(Bar) 및 선(Line) 그래프 그리기

by 찐남 2021. 12. 30.
본 포스팅은 R Graphics Cookbook을 기반으로 작성하였습니다.

 

기본적인 막대(Bar) 또는 선(Lline) 그래프를 만들어 볼게요.

ggplot2로 그래프를 만들려면 데이터가 데이터 프레임(data frame)이어야 하고,

"긴(long)"(와이드(wide)와 반대) 형식이어야 해요.

그렇기 때문에 데이터를 재구성해야 하는 경우도 있어요.

이와 관련된 자세한 내용은 여기를 참고하세요.

 

 


 

이산형 변수를 가지는 x축이 있는 기본 그래프

 

막대그래프에는 막대의 높이가 일반적으로 나타내는 두 가지가 있어요.

 

1. 각 그룹의 케이스 수

    - 일반적으로 이산형 변수 각각의 x 값은 하나의 그룹을 나타냅니다. 이것은 각 그룹의 케이스 수를 계산하는 stat_bin으로 수행돼요. stat_bin은 x가 이산형 변수이면 각 x 값은 그룹이고, x가 연속형 변수이면 그룹화를 지정하지 않는 한(ex. group = xx), 모든 데이터는 자동적으로 하나의 그룹에 포함됩니다. 

 

2. 데이터 세트의 열(column) 값(value)

    - 이것은 stat_identity로 수행되며 y 값은 변경되지 않습니다. 

x 축 구분 막대 높이 명칭
연속형 건수(Count) 히스토그램(Histogram)
이산형 건수(Count) 막대 그래프(Bar graph)
연속형 값(Value) 막대 그래프(Bar graph)
이산형 값(Value) 막대 그래프(Bar graph)

 

참고로, ggplot2에서 기본값은 stat_bin을 사용하여 막대 높이가 케이스 수라고 보시면 되요.

 

< 값의 막대그래프 >

아래의 예시 데이터는 reshape2 패키지에 포함되어 있는 tips 데이터 세트에서 파생된 샘플이에요.

 

# reshape2 패키지에 포함되어 있는 tips 데이터 세트의 데이터 일부를 수기로 작성하여 dat 생성
dat <- data.frame(
time = factor(c("Lunch","Dinner"), levels=c("Lunch","Dinner")),
total_bill = c(14.89, 17.23)
)

dat
library(ggplot2)  # ggplot2 패키지 로드

이 예에서 막대의 높이는 데이터 프레임의 열에 있는 값이에요.

이것은 기본값인 stat="bin" 대신 stat="identity"를 사용하여 수행하게 돼요.

사용된 변수 매핑은 다음과 같아요.

time: x축과 가끔 막대그래프 안에 색상 채우기

total_bill: y축

# 매우 기본적인 막대 그래프
ggplot(data=dat, aes(x=time, y=total_bill)) +
  geom_bar(stat="identity")

# 시간을 다른 채우기 색상으로 매핑
ggplot(data=dat, aes(x=time, y=total_bill, fill=time)) +
  geom_bar(stat="identity")

## 아래 코드는 위와 같은 결과를 가지기 때문에 주석 처리함
# ggplot(data=dat, aes(x=time, y=total_bill)) +
# geom_bar(aes(fill=time), stat="identity")

# 검은색 윤곽선 추가
ggplot(data=dat, aes(x=time, y=total_bill, fill=time)) +
  geom_bar(colour="black", stat="identity")

# 정보가 중복되므로 범례 삭제
ggplot(data=dat, aes(x=time, y=total_bill, fill=time)) +
  geom_bar(colour="black", stat="identity") +
  guides(fill=FALSE)

 

최종적으로 원하는 막대그래프의 모습은 아래와 같지 않을까요?

# 제목 추가, 막대 축소, 색상 채우기, 축 레이블 변경
ggplot(data=dat, aes(x=time, y=total_bill, fill=time)) +
  geom_bar(colour="black", fill="#DD8888", width=.8, stat="identity") +
  guides(fill=FALSE) +
  xlab("Time of day") +
  ylab("Total bill") +
  ggtitle("Average bill for 2 people")

(색상에 대한 자세한 내용은 별도 포스팅으로 게시할게요.)

 

<카운트의 막대그래프>

이 예에서 막대의 높이는 케이스 수이고요, stat="bin"(기본값)을 사용하여 수행하게 돼요.

reshape2 패키지의 tips 데이터부터 시작할게요.

library(reshape2) # reshape2 패키지 로드
head(tips) # 데이터 몇 줄만 확인하기

 

카운트의 막대그래프를 얻으려면 변수를 y에 매핑하지 말고 stat="identity" 대신 stat="bin"(기본값)을 사용하세요.

# 카운트의 막대그래프
ggplot(data=tips, aes(x=day)) +
  geom_bar()  # stat = "bin"을 기본값으로 세팅

## stat = "count"로 명시하여도 결과는 동일
# ggplot(data=tips,aes(x=day)) +
# geom_bar(stat="count")

 

<선 그래프>

선 그래프의 경우 연결할 포인트를 알 수 있도록 데이터 포인트를 그룹화해야 하는데,

매우 간단하게 할 수 있어요.

모든 점이 연결되어야 하므로 group=1이고요.

더 많은 변수를 사용하고 여러 선을 그릴 때 선에 대한 그룹화는 일반적으로 변수별로 수행하게 돼요.

이건 예제에서 보여 드릴게요.

 

여기에 사용된 변수 매핑은 time: x 축, total_bill: y 축이에요.

# 기본적인 선 그래프
ggplot(data=dat, aes(x=time, y=total_bill, group=1)) +
  geom_line()

## 아래 코드는 위의 결과와 동일
# ggplot(data=dat, aes(x=time, y=total_bill)) +
# geom_line(aes(group=1))

# 포인트 추가
ggplot(data=dat, aes(x=time, y=total_bill, group=1)) +
  geom_line() +
  geom_point()

# 선과 점의 색상 변경

# 흰색 채우기가 있는 원으로 점 변경
ggplot(data=dat, aes(x=time, y=total_bill, group=1)) +
  geom_line(colour="red", linetype="dashed", size=1.5) + # 더 두꺼운 선으로 변경
  geom_point(colour="red", size=4, shape=21, fill="white") # 더 큰 포인트와 점 변경(흰색 채우기가 있는 원)

 

최종적으로 원하는 선 그래프의 모습은 아래와 같지 않을까요?

ggplot(data=dat, aes(x=time, y=total_bill, group=1)) +
  geom_line() +
  geom_point() +
  expand_limits(y=0) +  # total_bill 열의 0에서 최대 값으로 이동하도록 y 범위 변경
  xlab("Time of day") + # x 축 레이블 변경
  ylab("Total bill") +  # y 축 레이블 변경
  ggtitle("Average bill for 2 people")

(점 모양과 선 형태에 대한 자세한 내용은 별도 포스팅으로 게시할게요.)

 

 


더 많은 변수가 있는 그래프

아래 예시를 보시죠.

dat1 <- data.frame(
  sex = factor(c("Female","Female","Male","Male")),
  time = factor(c("Lunch","Dinner","Lunch","Dinner"), levels=c("Lunch","Dinner")),
  total_bill = c(13.53, 16.81, 16.24, 17.42)
)

dat1 

(※reshape2 패키지의 tips 데이터 세트에서 파생된 데이터예요)

 

<막대그래프>

예시 데이터에서 사용된 변수 매핑이에요.

time: x 축

sex: color fill

total_bill: y-axis

# 누적 막대그래프 -- 아마 이 그래프를 원하지는 않았을 걸로 생각됩니다 ㅎ
ggplot(data=dat1, aes(x=time, y=total_bill, fill=sex)) +
  geom_bar(stat="identity")

# 막대그래프, x축(시간, 성별)으로 그룹화된 색상 채우기 -- position_dodge() 사용
ggplot(data=dat1, aes(x=time, y=total_bill, fill=sex)) +
  geom_bar(stat="identity", position=position_dodge())

ggplot(data=dat1, aes(x=time, y=total_bill, fill=sex)) +
  geom_bar(stat="identity", position=position_dodge(), colour="black")

# 색상 변경
ggplot(data=dat1, aes(x=time, y=total_bill, fill=sex)) +
  geom_bar(stat="identity", position=position_dodge(), colour="black") +
  scale_fill_manual(values=c("#999999", "#E69F00"))

 

x축에 매핑되는 변수와 채우기에 매핑되는 변수를 쉽게 변경할 수 있어요.

# 막대그래프, x축 성별, 시간에 따른 색상 채우기-- position_dodge() 사용
ggplot(data=dat1, aes(x=sex, y=total_bill, fill=time)) +
  geom_bar(stat="identity", position=position_dodge(), colour="black")

 

<선 그래프>

예시 데이터에서 사용된 변수 매핑이에요.

time: x축

sex: 선 색상

total_bill: y축

여러 선을 그리려면 점을 변수로 그룹화하는 것이 필요해요.

그렇지 않으면 모든 점이 한 줄로 연결돼요.

예시에서는 성별로 그룹화 하를 할게요.

# 포인트를 가지는 기본적인 선 그래프
ggplot(data=dat1, aes(x=time, y=total_bill, group=sex)) +
  geom_line() +
  geom_point()

# 성별을 색상으로 구분
ggplot(data=dat1, aes(x=time, y=total_bill, group=sex, colour=sex)) +
  geom_line() +
  geom_point()

# 성별을 다른 포인트 형태로 구분
ggplot(data=dat1, aes(x=time, y=total_bill, group=sex, shape=sex)) +
  geom_line() +
  geom_point()

# 더 두꺼운 선, 더 넓은 포인트, and 속이 빈 흰색 점
ggplot(data=dat1, aes(x=time, y=total_bill, group=sex, shape=sex)) +
  geom_line(size=1.5) +
  geom_point(size=3, fill="white") +
  scale_shape_manual(values=c(22,21))

 

x축에 매핑되는 변수와 색상이나 모양에 매핑되는 변수를 쉽게 변경할 수 있어요.

ggplot(data=dat1, aes(x=sex, y=total_bill, group=time, shape=time, color=time)) +
  geom_line() + geom_point()

 

< 마지막 예제들 >

완성된 그래프는 다음과 같아요.

# 막대그래프
ggplot(data=dat1, aes(x=time, y=total_bill, fill=sex)) +
  geom_bar(colour="black", stat="identity", position=position_dodge(), size=.3) + # 더 얇은 막대 굵기
  scale_fill_hue(name="Sex of payer") + # 범례 제목 세팅
  xlab("Time of day") + # x축 라벨 세팅
  ylab("Total bill") + # y축 라벨 세팅
  ggtitle("Average bill for 2 people") + # 그래프 제목 세팅
  theme_bw()

# 선 그래프
ggplot(data=dat1, aes(x=time, y=total_bill, group=sex, shape=sex, colour=sex)) +
  geom_line(aes(linetype=sex), size=1) + # 성별에 따른 선 형태 세팅
  geom_point(size=3, fill="white") + # 더 큰 포인트, 흰색 채우기
  expand_limits(y=0) + # 0을 포함하도록 y 범위 설정
  scale_colour_hue(name="Sex of payer", # Set legend title
                         l=30) + # 더 어두운 색상 사용(lightness=30)
  scale_shape_manual(name="Sex of payer", values=c(22,21)) + # 색상 채우기 포인트 사용
  scale_linetype_discrete(name="Sex of payer") +
  xlab("Time of day") + # x축 라벨 세팅
  ylab("Total bill") + # y축 라벨 세팅
  ggtitle("Average bill for 2 people") + # 그래프 제목 세팅
  theme_bw() +
  theme(legend.position=c(.7, .4)) # 범례 위치 지정(내부)
                                            # theme_bw 다음에 와야 해요!

선 그래프에서 범례 제목인 "Sex of payer"를 세 번 지정해야 하는 이유는

범례가 하나만 있기 때문인데요.

이와 관련해서는 별도 포스팅으로 설명할게요.

 

 


숫자 x축 사용

x축의 변수가 숫자일 때는 연속형으로 처리하는 것이 유용할 때도 있고,

범주형으로 처리하는 것이 유용할 때도 있습니다.

이 데이터 세트에서 용량(dose)은 0.5, 1.0 및 2.0 값을 갖는 숫자 변수예요.

그래프를 만들 때 이러한 값을 동일한 범주로 처리하는 것이 유용할 수 있어요.

datn <- read.table(header=TRUE, text='
supp dose length
OJ 0.5 13.23
OJ 1.0 22.70
OJ 2.0 26.06
VC 0.5 7.98
VC 1.0 16.77
VC 2.0 26.14
')

datn

(R에 포함된 ToothGrowth 데이터 세트에서 파생된 예시예요.)

 

<연속형으로 처리되는 x축>

간단한 그래프는 x축에 수치 값으로 용량(dose)을 표시할 수 있어요.

이런 방법으로 선 그래프를 만들 수는 있지만 막대그래프는 만들 수 없어요.

ggplot(data=datn, aes(x=dose, y=length, group=supp, colour=supp)) +
  geom_line() +
  geom_point()

 

<범주형으로 처리되는 x축>

숫자 변수 대신 범주형 변수로 처리하려면 factor로 변환해야 해요.

이러한 작업은 데이터 프레임을 수정하거나 그래프의 사양을 변경하여 수행할 수 있어요.

datn2 <- datn # 데이터 프레임 복사 
datn2$dose <- factor(datn2$dose) # dose를 factor로 변환
ggplot(data=datn2, aes(x=dose, y=length, group=supp, colour=supp)) +
  geom_line() +
  geom_point()

# 원래의 데이터 프레임을 사용하지만 factor()를 플롯 사양에 직접 삽입
ggplot(data=datn, aes(x=factor(dose), y=length, group=supp, colour=supp)) +
geom_line() +
geom_point()

 

변수가 숫자가 아닌 범주형으로 취급될 때는 막대그래프를 만드는 것도 가능해요.

# 위에 있는 datn2 사용
ggplot(data=datn2, aes(x=dose, y=length, fill=supp)) +
  geom_bar(stat="identity", position=position_dodge())

# 원래의 데이터 프레임을 사용하지만 factor()를 플롯 사양에 직접 삽입
ggplot(data=datn, aes(x=factor(dose), y=length, fill=supp)) +
  geom_bar(stat="identity", position=position_dodge())

 

반응형

댓글