Ch 01. ggplot2의 레이어 개념
차트를 만드는 방법은 두 가지가 있습니다. 하나는 "이 데이터로 막대그래프 그려줘"라고 명령하는 방식이고, 다른 하나는 "이 데이터를 X축에 놓고, 저 데이터를 Y축에 놓고, 막대 모양으로 표현하고, 색은 이렇게 해줘"라고 쌓아 올리는 방식입니다.
ggplot2는 후자입니다. 차트를 레이어(layer)의 조합으로 봅니다. 이 철학을 이해하면 어떤 복잡한 차트도 만들 수 있습니다.
Grammar of Graphics란
ggplot2는 Leland Wilkinson의 책 "The Grammar of Graphics"에서 영감을 받아 Hadley Wickham이 만들었습니다. 문법(grammar)이라는 단어가 핵심입니다. 언어에 문법이 있듯이, 시각화에도 규칙이 있다는 생각입니다.
이 문법은 차트를 몇 가지 구성 요소로 분해합니다.
| 구성 요소 | 역할 | 예시 |
|---|---|---|
| data | 사용할 데이터 | mpg, iris |
| aes() | 미적 속성 매핑 | x, y, color, size |
| geom | 기하학적 표현 | 점, 선, 막대 |
| stat | 통계 변환 | count, mean, density |
| coord | 좌표 시스템 | 직교, 극좌표 |
| facet | 패널 분할 | 그룹별 소 차트 |
| theme | 시각적 스타일 | 글자 크기, 배경색 |
이 요소들을 + 연산자로 차례로 더해가며 차트를 만듭니다. 레이어를 쌓는 것입니다.
첫 번째 ggplot2 차트
ggplot2는 tidyverse에 포함되어 있습니다.
library(tidyverse)
# mpg 데이터셋 확인
glimpse(mpg)
Rows: 234
Columns: 11
$ manufacturer <chr> "audi", "audi", "audi", "audi", "audi", "audi", "audi", …
$ model <chr> "a4", "a4", "a4", "a4", "a4", "a4", "a4", "a4 quattro",…
$ displ <dbl> 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 1.8, 1.8, 2.0, 2.0,…
$ year <int> 1999, 1999, 2008, 2008, 1999, 1999, 2008, 1999, 1999, 20…
$ cyl <int> 4, 4, 4, 4, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 8, …
$ trans <chr> "auto(l5)", "manual(m5)", "manual(m6)", "auto(av)", "aut…
$ drv <chr> "f", "f", "f", "f", "f", "f", "f", "4", "4", "4", "4",…
$ cty <int> 18, 21, 20, 21, 16, 18, 18, 18, 16, 20, 19, 15, 17, 17,…
$ hwy <int> 29, 29, 31, 30, 26, 26, 27, 26, 25, 28, 27, 25, 25, 25,…
$ fl <chr> "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p",…
$ class <chr> "compact", "compact", "compact", "compact", "compact", "…
mpg는 1999~2008년 자동차 연비 데이터입니다. displ은 엔진 배기량, hwy는 고속도로 연비입니다. 배기량이 클수록 연비가 나쁠까요? 산점도로 확인해봅니다.
ggplot(data = mpg, aes(x = displ, y = hwy)) +
geom_point()
세 줄짜리 코드로 차트가 만들어집니다. 하나씩 뜯어봅니다.
ggplot(data = mpg)— mpg 데이터를 사용한다고 선언합니다. 아직 아무것도 그리지 않습니다. 빈 캔버스입니다.aes(x = displ, y = hwy)— X축에displ, Y축에hwy를 매핑합니다. "이 변수를 저 위치에 표현하겠다"는 약속입니다.+ geom_point()— 점(point) 모양으로 그립니다.
배기량이 커질수록 연비가 낮아지는 경향이 보입니다. 예상과 맞습니다.
aes() — 미적 속성 매핑
aes()는 aesthetic의 약자입니다. 데이터의 변수를 차트의 시각적 속성에 연결하는 역할을 합니다.
x, y 외에도 다양한 속성을 매핑할 수 있습니다.
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point()
color = class를 추가하면 차량 클래스별로 색이 달라집니다. 범례도 자동으로 생성됩니다. SUV 계열이 배기량이 크고 연비가 낮은 오른쪽 아래에 몰려 있습니다.
크기도 변수에 연결할 수 있습니다.
ggplot(mpg, aes(x = displ, y = hwy, color = class, size = cyl)) +
geom_point(alpha = 0.6)
alpha = 0.6은 투명도를 60%로 설정합니다. 점이 겹쳐도 아래 점이 보입니다. alpha는 aes() 안이 아니라 geom_point() 안에 넣었습니다. 데이터 변수가 아니라 고정값이기 때문입니다.
aes() 안 vs 밖의 차이를 꼭 기억합니다.
# 데이터 변수에 따라 색 결정 — aes() 안
aes(color = class)
# 모든 점을 파란색으로 고정 — aes() 밖
geom_point(color = "blue")
geom — 기하학적 표현
geom_*() 함수는 데이터를 어떤 모양으로 그릴지 결정합니다. 자주 쓰는 geom을 정리합니다.
| 함수 | 용도 |
|---|---|
geom_point() |
산점도 |
geom_line() |
꺾은선 그래프 |
geom_bar() |
빈도 막대 (자동 집계) |
geom_col() |
값 막대 (직접 지정) |
geom_histogram() |
히스토그램 |
geom_boxplot() |
박스플롯 |
geom_violin() |
바이올린 플롯 |
geom_density() |
밀도 그래프 |
geom_smooth() |
추세선 |
geom_text() |
텍스트 레이블 |
하나의 차트에 여러 geom을 함께 쓸 수 있습니다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(color = "steelblue", alpha = 0.5) +
geom_smooth(method = "lm", se = TRUE)
산점도 위에 선형 회귀 추세선과 신뢰 구간(se)이 덧그려집니다. method = "lm"은 선형 모델(linear model)을 뜻합니다.
stat — 통계 변환
geom 뒤에서 조용히 작동하는 것이 stat입니다. 예를 들어 geom_bar()는 기본적으로 stat = "count"를 사용합니다. 데이터를 받아 빈도를 계산한 다음 막대를 그립니다.
ggplot(mpg, aes(x = class)) +
geom_bar()
mpg 데이터에 클래스별 빈도를 계산하는 코드가 없지만, geom_bar가 알아서 셉니다. 이것이 stat의 역할입니다.
직접 계산한 값을 막대로 그리려면 stat = "identity"를 쓰거나, geom_col()을 사용합니다.
coord — 좌표 시스템
기본은 데카르트 좌표계(coord_cartesian)입니다. 필요에 따라 바꿀 수 있습니다.
# 가로 막대그래프 — 축 뒤집기
ggplot(mpg, aes(x = class)) +
geom_bar() +
coord_flip()
coord_flip()은 X축과 Y축을 맞바꿉니다. 세로 막대그래프가 가로 막대그래프로 바뀝니다. 클래스 이름이 Y축에 표시되어 읽기 편해집니다.
facet — 패널 분할
데이터를 그룹별로 나누어 소 차트를 만듭니다. 비교 시각화에 강력합니다. 자세한 내용은 Ch 05에서 다룹니다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
facet_wrap(~ class)
차량 클래스별로 별도 패널이 생성됩니다. 각 그룹의 분포를 한눈에 비교할 수 있습니다.
theme — 시각적 스타일
theme_*()으로 차트의 전체 스타일을 한 번에 바꿉니다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(color = "steelblue") +
theme_minimal()
자주 쓰는 테마는 다음과 같습니다.
| 테마 함수 | 느낌 |
|---|---|
theme_gray() |
기본 (회색 배경) |
theme_bw() |
흑백, 그리드 있음 |
theme_minimal() |
깔끔, 그리드 최소 |
theme_classic() |
고전적, 테두리선 |
theme_void() |
배경 없음 |
레이어를 쌓는 전체 구조
ggplot2 차트의 기본 틀을 정리합니다.
ggplot(data = <데이터>, aes(<매핑>)) + # 캔버스와 매핑
geom_<함수>(<옵션>) + # 무엇을 그릴까
scale_<속성>_<유형>(<옵션>) + # 스케일 조정
coord_<함수>() + # 좌표계
facet_<함수>(<공식>) + # 패널 분할
labs(title = "", x = "", y = "") + # 제목과 축 이름
theme_<함수>() # 스타일
모두 필요한 것은 아닙니다. data와 aes, geom만 있어도 차트가 만들어집니다. 나머지는 차트를 더 잘 표현하고 싶을 때 덧붙입니다.
labs()로 제목과 축 이름 붙이기
완성도 있는 차트에는 제목과 축 설명이 있어야 합니다.
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point(alpha = 0.7) +
labs(
title = "배기량과 고속도로 연비의 관계",
subtitle = "차량 클래스별 색상 구분",
x = "엔진 배기량 (리터)",
y = "고속도로 연비 (mpg)",
color = "차량 클래스",
caption = "출처: ggplot2 내장 데이터 mpg"
) +
theme_minimal()
title은 상단 제목, subtitle은 부제목, caption은 하단 각주입니다. color = "차량 클래스"는 범례 제목을 바꿉니다.
이렇게 레이어를 하나씩 쌓아가는 방식이 ggplot2의 핵심입니다. 처음에는 geom 하나로 시작하고, 필요할 때 레이어를 추가합니다. 다음 챕터부터 각 geom을 구체적으로 살펴봅니다.