11  소통(Communication)

11.1 소개

Chapter 10 에서 탐색을 위한 도구로 플롯을 사용하는 방법을 배웠습니다. 탐색적 플롯을 만들 때는 보기 전에도 플롯에 어떤 변수가 표시될지 알고 있습니다. 각 플롯을 목적에 맞게 만들었고, 빠르게 살펴본 다음, 다음 플롯으로 넘어갈 수 있었습니다. 대부분의 분석 과정에서 수십 또는 수백 개의 플롯을 생성하게 되며, 그중 대부분은 즉시 버려집니다.

이제 데이터를 이해했으므로 이해한 내용을 다른 사람들에게 소통해야 합니다. 청중은 아마도 여러분의 배경 지식을 공유하지 않을 것이며 데이터에 깊이 투자하지 않았을 것입니다. 다른 사람들이 데이터에 대한 좋은 멘탈 모델을 빠르게 구축하도록 돕기 위해 플롯을 가능한 한 설명이 필요 없도록 만드는 데 상당한 노력을 투자해야 합니다. 이 장에서는 ggplot2가 이를 위해 제공하는 도구 중 일부를 배울 것입니다.

이 장은 좋은 그래픽을 만드는 데 필요한 도구에 중점을 둡니다. 우리는 여러분이 무엇을 원하는지 알고 있으며 단지 그것을 수행하는 방법만 알면 된다고 가정합니다. 이러한 이유로 이 장을 좋은 일반적인 시각화 책과 함께 보는 것을 강력히 추천합니다. 우리는 특히 알버트 카이로(Albert Cairo)의 The Truthful Art를 좋아합니다. 이 책은 시각화를 만드는 메커니즘을 가르치지는 않지만 대신 효과적인 그래픽을 만들기 위해 무엇을 생각해야 하는지에 초점을 맞춥니다.

11.1.1 선수 지식

이 장에서는 다시 한 번 ggplot2에 초점을 맞출 것입니다. 또한 데이터 조작을 위해 약간의 dplyr을 사용하고, 기본 breaks, 레이블, 변환 및 팔레트를 재정의하기 위해 scales를 사용하며, Kamil Slowikowski의 ggrepel(https://ggrepel.slowkow.com)과 Thomas Lin Pedersen의 patchwork(https://patchwork.data-imaginist.com)를 포함한 몇 가지 ggplot2 확장 패키지를 사용할 것입니다. 아직 패키지가 없다면 install.packages()로 설치해야 한다는 것을 잊지 마세요.

library(tidyverse)
#> Warning: package 'ggplot2' was built under R version 4.5.2
#> Warning: package 'readr' was built under R version 4.5.2
library(scales)
library(ggrepel)
library(patchwork)

11.2 레이블

탐색적 그래픽을 설명적 그래픽으로 바꿀 때 가장 먼저 시작하기 쉬운 곳은 좋은 레이블입니다. labs() 함수로 레이블을 추가합니다.

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class)) +
  geom_smooth(se = FALSE) +
  labs(
    x = "Engine displacement (L)",
    y = "Highway fuel economy (mpg)",
    color = "Car type",
    title = "Fuel efficiency generally decreases with engine size",
    subtitle = "Two seaters (sports cars) are an exception because of their light weight",
    caption = "Data from fueleconomy.gov"
  )

자동차의 고속도로 연비 대 엔진 크기의 산점도, 여기서 점들은 자동차  클래스에 따라 색상이 지정됩니다. 고속도로 연비 대 엔진 크기 간 관계의  궤적을 따르는 매끄러운 곡선이 겹쳐져 있습니다. x축 레이블은 "Engine  displacement (L)"이고 y축 레이블은 "Highway fuel economy (mpg)"입니다.  범례 레이블은 "Car type"입니다. 플롯의 제목은 "Fuel efficiency  generally decreases with engine size"입니다. 부제는 "Two seaters  (sports cars) are an exception because of their light weight"이고  캡션은 "Data from fueleconomy.gov"입니다.

플롯 제목의 목적은 주요 결과를 요약하는 것입니다. “엔진 배기량 대 연비의 산점도”와 같이 플롯이 무엇인지만 설명하는 제목은 피하세요.

텍스트를 더 추가해야 하는 경우 유용한 두 가지 레이블이 더 있습니다. subtitle은 제목 아래에 더 작은 글꼴로 추가 세부 정보를 추가하고 caption은 플롯 오른쪽 하단에 텍스트를 추가하며 종종 데이터의 출처를 설명하는 데 사용됩니다. labs()를 사용하여 축 및 범례 제목을 바꿀 수도 있습니다. 일반적으로 짧은 변수 이름을 더 자세한 설명으로 바꾸고 단위를 포함하는 것이 좋습니다.

텍스트 문자열 대신 수식을 사용할 수 있습니다. ""quote()로 바꾸고 ?plotmath에서 사용 가능한 옵션에 대해 읽어보세요:

df <- tibble(
  x = 1:10,
  y = cumsum(x^2)
)

ggplot(df, aes(x, y)) +
  geom_point() +
  labs(
    x = quote(x[i]),
    y = quote(sum(x[i] ^ 2, i == 1, n))
  )

x축 및 y축 레이블에 수학 텍스트가 있는 산점도. X축 레이블은 x_i,  y축 레이블은 x_i 제곱의 합, i는 1에서 n까지입니다.

11.2.1 연습문제

  1. 연비 데이터에 대해 사용자 정의된 title, subtitle, caption, x, y, color 레이블이 있는 하나의 플롯을 만드세요.

  2. 연비 데이터를 사용하여 다음 플롯을 다시 만드세요. 점의 색상과 모양 모두 구동 방식 유형에 따라 달라집니다.

    고속도로 대 도시 연비의 산점도. 점의 모양과 색상은 구동 방식 유형에  의해 결정됩니다.

  3. 지난달에 만든 탐색적 그래픽을 가져와 다른 사람들이 더 쉽게 이해할 수 있도록 유익한 제목을 추가하세요.

11.3 주석(Annotations)

플롯의 주요 구성 요소에 레이블을 지정하는 것 외에도 개별 관측값이나 관측값 그룹에 레이블을 지정하는 것이 유용한 경우가 많습니다. 사용할 수 있는 첫 번째 도구는 geom_text()입니다. geom_text()geom_point()와 유사하지만 추가 심미성인 label이 있습니다. 이것은 플롯에 텍스트 레이블을 추가할 수 있게 해줍니다.

레이블의 소스는 두 가지가 있습니다. 첫째, 레이블을 제공하는 티블이 있을 수 있습니다. 다음 플롯에서는 각 구동 방식에서 엔진 크기가 가장 큰 자동차를 뽑아내어 정보를 label_info라는 새 데이터 프레임으로 저장합니다.

label_info <- mpg |>
  group_by(drv) |>
  arrange(desc(displ)) |>
  slice_head(n = 1) |>
  mutate(
    drive_type = case_when(
      drv == "f" ~ "front-wheel drive",
      drv == "r" ~ "rear-wheel drive",
      drv == "4" ~ "4-wheel drive"
    )
  ) |>
  select(displ, hwy, drv, drive_type)

label_info
#> # A tibble: 3 × 4
#> # Groups:   drv [3]
#>   displ   hwy drv   drive_type       
#>   <dbl> <int> <chr> <chr>            
#> 1   6.5    17 4     4-wheel drive    
#> 2   5.3    25 f     front-wheel drive
#> 3   7      24 r     rear-wheel drive

그런 다음 이 새 데이터 프레임을 사용하여 세 그룹에 직접 레이블을 지정하여 범례를 플롯에 직접 배치된 레이블로 바꿉니다. fontfacesize 인수를 사용하여 텍스트 레이블의 모양을 사용자 정의할 수 있습니다. 플롯의 나머지 텍스트보다 크고 굵게 표시됩니다. (theme(legend.position = "none")은 모든 범례를 끕니다. 잠시 후에 더 자세히 이야기하겠습니다.)

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(alpha = 0.3) +
  geom_smooth(se = FALSE) +
  geom_text(
    data = label_info, 
    aes(x = displ, y = hwy, label = drive_type),
    fontface = "bold", size = 5, hjust = "right", vjust = "bottom"
  ) +
  theme(legend.position = "none")
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

고속도로 마일리지 대 엔진 크기의 산점도로, 점들은 구동 유형에 따라  색상이 지정됩니다. 각 구동 유형에 대한 매끄러운 곡선이 겹쳐져 있습니다.  텍스트 레이블은 곡선을 전륜, 후륜, 4륜으로 식별합니다.

hjust(수평 정렬) 및 vjust(수직 정렬)를 사용하여 레이블의 정렬을 제어하는 것에 유의하세요.

그러나 위에서 만든 주석이 달린 플롯은 레이블이 서로 겹치고 점과 겹치기 때문에 읽기 어렵습니다. ggprepel 패키지의 geom_label_repel() 함수를 사용하여 두 문제를 모두 해결할 수 있습니다. 이 유용한 패키지는 레이블이 겹치지 않도록 자동으로 조정합니다:

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(alpha = 0.3) +
  geom_smooth(se = FALSE) +
  geom_label_repel(
    data = label_info, 
    aes(x = displ, y = hwy, label = drive_type),
    fontface = "bold", size = 5, nudge_y = 2
  ) +
  theme(legend.position = "none")
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

고속도로 마일리지 대 엔진 크기의 산점도로, 점들은 구동 유형에 따라  색상이 지정됩니다. 각 구동 유형에 대한 매끄러운 곡선이 겹쳐져 있습니다.  텍스트 레이블은 곡선을 전륜, 후륜, 4륜으로 식별합니다.  레이블은 흰색 배경의 상자이며 겹치지 않도록 배치됩니다.

또한 ggrepel 패키지의 geom_text_repel()을 사용하여 플롯의 특정 점을 강조 표시하는 데 동일한 아이디어를 사용할 수 있습니다. 여기서 사용된 또 다른 편리한 기술에 주목하세요: 레이블이 지정된 점을 더욱 강조하기 위해 크고 빈 점 레이어를 추가했습니다.

potential_outliers <- mpg |>
  filter(hwy > 40 | (hwy > 20 & displ > 5))
  
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_text_repel(data = potential_outliers, aes(label = model)) +
  geom_point(data = potential_outliers, color = "red") +
  geom_point(
    data = potential_outliers,
    color = "red", size = 3, shape = "circle open"
  )

자동차의 고속도로 연비 대 엔진 크기의 산점도. 고속도로 마일리지가  40 이상이거나 엔진 크기가 5 이상이면서 20 이상인 점은 빨간색 빈  원이며 자동차 모델 이름으로 레이블이 지정되어 있습니다.

geom_text()geom_label() 외에도 ggplot2에는 플롯에 주석을 추가하는 데 도움이 되는 다른 많은 지옴이 있다는 것을 기억하세요. 몇 가지 아이디어:

  • geom_hline()geom_vline()을 사용하여 참조선을 추가하세요. 우리는 종종 두껍게(linewidth = 2) 흰색(color = white)으로 만들고 기본 데이터 레이어 아래에 그립니다. 그렇게 하면 데이터에서 주의를 뺏지 않으면서도 보기 쉽습니다.

  • geom_rect()를 사용하여 관심 지점 주위에 사각형을 그립니다. 사각형의 경계는 xmin, xmax, ymin, ymax 심미성에 의해 정의됩니다. 또는 ggforce 패키지, 구체적으로 geom_mark_hull()을 살펴보세요. 이를 통해 헐(hulls)로 점의 하위 집합에 주석을 달 수 있습니다.

  • geom_segment()arrow 인수를 사용하여 화살표로 점에 주의를 끕니다. xy 심미성을 사용하여 시작 위치를 정의하고 xendyend를 사용하여 끝 위치를 정의하세요.

플롯에 주석을 추가하는 또 다른 편리한 함수는 annotate()입니다. 경험적으로 지옴은 일반적으로 데이터의 하위 집합을 강조 표시하는 데 유용한 반면 annotate()는 플롯에 하나 또는 소수의 주석 요소를 추가하는 데 유용합니다.

annotate() 사용을 보여주기 위해 플롯에 추가할 텍스트를 만들어 보겠습니다. 텍스트가 조금 길기 때문에 stringr::str_wrap()을 사용하여 한 줄에 원하는 문자 수에 따라 자동으로 줄 바꿈을 추가합니다:

trend_text <- "Larger engine sizes tend to have lower fuel economy." |>
  str_wrap(width = 30)
trend_text
#> [1] "Larger engine sizes tend to\nhave lower fuel economy."

그런 다음 두 개의 주석 레이어를 추가합니다. 하나는 레이블 지옴이고 다른 하나는 세그먼트 지옴입니다. 두 경우 모두 xy 심미성은 주석이 시작될 위치를 정의하고 세그먼트 주석의 xendyend 심미성은 세그먼트의 끝 위치를 정의합니다. 또한 세그먼트가 화살표로 스타일링되어 있음에 유의하세요.

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  annotate(
    geom = "label", x = 3.5, y = 38,
    label = trend_text,
    hjust = "left", color = "red"
  ) +
  annotate(
    geom = "segment",
    x = 3, y = 35, xend = 5, yend = 25, color = "red",
    arrow = arrow(type = "closed")
  )

자동차의 고속도로 연비 대 엔진 크기의 산점도. 아래쪽을 가리키는 빨간  화살표는 점들의 추세를 따르며 화살표 옆에 배치된 주석은 "Larger engine  sizes tend to have lower fuel economy"라고 읽습니다. 화살표와 주석  텍스트는 빨간색입니다.

주석은 시각화의 주요 시사점과 흥미로운 특징을 전달하기 위한 강력한 도구입니다. 유일한 한계는 상상력(그리고 주석을 미적으로 즐겁게 배치하는 인내심)뿐입니다!

11.3.1 연습문제

  1. geom_text()와 무한 위치(infinite positions)를 사용하여 플롯의 네 모서리에 텍스트를 배치하세요.

  2. annotate()를 사용하여 티블을 생성하지 않고 마지막 플롯의 가운데에 점 지옴을 추가하세요. 점의 모양, 크기 또는 색상을 사용자 정의하세요.

  3. geom_text()를 사용한 레이블은 패싯과 어떻게 상호 작용합니까? 단일 패싯에 레이블을 어떻게 추가할 수 있습니까? 각 패싯에 다른 레이블을 어떻게 넣을 수 있습니까? (힌트: geom_text()에 전달되는 데이터셋에 대해 생각해 보세요.)

  4. geom_label()의 어떤 인수가 배경 상자의 모양을 제어합니까?

  5. arrow()의 네 가지 인수는 무엇입니까? 어떻게 작동합니까? 가장 중요한 옵션을 보여주는 일련의 플롯을 만드세요.

11.4 척도(Scales)

소통을 위해 플롯을 더 좋게 만드는 세 번째 방법은 척도를 조정하는 것입니다. 척도는 심미적 매핑이 시각적으로 나타나는 방식을 제어합니다.

11.4.1 기본 척도

일반적으로 ggplot2는 자동으로 척도를 추가합니다. 예를 들어 다음과 같이 입력할 때:

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class))

ggplot2는 뒤에서 자동으로 기본 척도를 추가합니다:

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class)) +
  scale_x_continuous() +
  scale_y_continuous() +
  scale_color_discrete()

척도의 명명 체계에 유의하세요: scale_ 뒤에 심미성 이름, 그 다음 _, 그 다음 척도 이름이 옵니다. 기본 척도는 일치하는 변수 유형에 따라 이름이 지정됩니다: 연속형(continuous), 이산형(discrete), 날짜-시간(datetime) 또는 날짜(date). scale_x_continuous()displ의 숫자 값을 x축의 연속 숫자 라인에 놓고, scale_color_discrete()는 각 자동차 class에 대한 색상을 선택하는 식입니다. 아래에서 배우게 될 기본값이 아닌 척도가 많이 있습니다.

기본 척도는 광범위한 입력에 대해 잘 수행되도록 신중하게 선택되었습니다. 그럼에도 불구하고 두 가지 이유로 기본값을 재정의하고 싶을 수 있습니다:

  • 기본 척도의 일부 매개변수를 조정하고 싶을 수 있습니다. 이를 통해 축의 나누기(breaks) 또는 범례의 키 레이블을 변경하는 것과 같은 작업을 수행할 수 있습니다.

  • 척도를 완전히 교체하고 완전히 다른 알고리즘을 사용하고 싶을 수 있습니다. 종종 데이터에 대해 더 많이 알고 있기 때문에 기본값보다 더 잘할 수 있습니다.

11.4.2 축 눈금 및 범례 키

집합적으로 축과 범례를 가이드(guides) 라고 합니다. 축은 x 및 y 심미성에 사용되고 범례는 다른 모든 것에 사용됩니다.

축의 눈금과 범례의 키 모양에 영향을 미치는 두 가지 주요 인수는 breakslabels입니다. breaks는 눈금의 위치 또는 키와 관련된 값을 제어합니다. Labels는 각 눈금/키와 관련된 텍스트 레이블을 제어합니다. breaks의 가장 일반적인 용도는 기본 선택을 재정의하는 것입니다:

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  scale_y_continuous(breaks = seq(15, 40, by = 5)) 

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 구동 방식별로 색상이  지정됩니다. y축에는 15에서 시작하여 40으로 끝나고 5씩 증가하는  나누기(breaks)가 있습니다.

labels도 같은 방식으로 사용할 수 있지만(breaks와 길이가 같은 문자 벡터), NULL로 설정하여 레이블을 완전히 억제할 수도 있습니다. 이것은 지도나 절대 숫자를 공유할 수 없는 플롯을 게시하는 데 유용할 수 있습니다. breakslabels를 사용하여 범례의 모양을 제어할 수도 있습니다. 범주형 변수의 이산 척도의 경우 labels는 기존 수준 이름과 원하는 레이블의 명명된 리스트일 수 있습니다.

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  scale_x_continuous(labels = NULL) +
  scale_y_continuous(labels = NULL) +
  scale_color_discrete(labels = c("4" = "4-wheel", "f" = "front", "r" = "rear"))

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 구동 방식별로 색상이  지정됩니다. x축과 y축에는 축 눈금에 레이블이 없습니다. 범례에는 사용자  정의 레이블이 있습니다: 4-wheel, front, rear.

labels 인수는 scales 패키지의 라벨링 함수와 결합하여 숫자를 통화, 백분율 등으로 포맷하는 데에도 유용합니다. 왼쪽 플롯은 달러 기호와 천 단위 구분 기호 쉼표를 추가하는 label_dollar()를 사용한 기본 라벨링을 보여줍니다. 오른쪽 플롯은 달러 값을 1,000으로 나누고 접미사 “K”(“천”을 의미)를 추가하고 사용자 정의 나누기를 추가하여 사용자 정의를 더 추가합니다. breaks는 데이터의 원래 척도에 있다는 점에 유의하세요.

# 왼쪽
ggplot(diamonds, aes(x = price, y = cut)) +
  geom_boxplot(alpha = 0.05) +
  scale_x_continuous(labels = label_dollar())

# 오른쪽
ggplot(diamonds, aes(x = price, y = cut)) +
  geom_boxplot(alpha = 0.05) +
  scale_x_continuous(
    labels = label_dollar(scale = 1/1000, suffix = "K"), 
    breaks = seq(1000, 19000, by = 6000)
  )

다이아몬드 가격 대 컷의 두 개의 나란히 놓인 상자 그림. 이상치는  투명합니다. 두 플롯 모두 x축 레이블이 달러로 포맷되어 있습니다. 왼쪽  플롯의 x축 레이블은 $0에서 시작하여 $15,000까지 가며 $5,000씩  증가합니다. 오른쪽 플롯의 x축 레이블은 $1K에서 시작하여 $19K까지  가며 $6K씩 증가합니다.

다이아몬드 가격 대 컷의 두 개의 나란히 놓인 상자 그림. 이상치는  투명합니다. 두 플롯 모두 x축 레이블이 달러로 포맷되어 있습니다. 왼쪽  플롯의 x축 레이블은 $0에서 시작하여 $15,000까지 가며 $5,000씩  증가합니다. 오른쪽 플롯의 x축 레이블은 $1K에서 시작하여 $19K까지  가며 $6K씩 증가합니다.

또 다른 편리한 레이블 함수는 label_percent()입니다:

ggplot(diamonds, aes(x = cut, fill = clarity)) +
  geom_bar(position = "fill") +
  scale_y_continuous(name = "Percentage", labels = label_percent())

컷의 분할 막대 플롯으로, 투명도 수준으로 채워져 있습니다. y축 레이블은  0%에서 시작하여 100%까지 가며 25%씩 증가합니다. y축 레이블 이름은  "Percentage"입니다.

breaks의 또 다른 용도는 데이터 포인트가 비교적 적고 관측값이 정확히 어디에서 발생하는지 강조하고 싶을 때입니다. 예를 들어 각 미국 대통령이 임기를 시작하고 마친 시기를 보여주는 이 플롯을 가져와 보겠습니다.

presidential |>
  mutate(id = 33 + row_number()) |>
  ggplot(aes(x = start, y = id)) +
  geom_point() +
  geom_segment(aes(xend = end, yend = id)) +
  scale_x_date(name = NULL, breaks = presidential$start, date_labels = "'%y")

대통령의 ID 번호 대 대통령직을 시작한 연도의 선 플롯. 시작 연도는 점과  거기서 시작하여 대통령직이 끝날 때 끝나는 세그먼트로 표시됩니다. x축  레이블은 아포스트로피로 시작하는 두 자리 연도로 포맷되어 있습니다. 예:  '53.

breaks 인수에 대해 이 인수에 대한 심미적 매핑을 할 수 없기 때문에 presidential$start를 사용하여 벡터로 start 변수를 뽑아냈다는 점에 유의하세요. 또한 날짜 및 날짜 시간 척도에 대한 나누기 및 레이블 지정은 약간 다릅니다:

  • date_labelsparse_datetime()과 같은 형식의 형식 사양을 취합니다.

  • date_breaks(여기에는 표시되지 않음)는 “2 days” 또는 “1 month”와 같은 문자열을 취합니다.

11.4.3 범례 레이아웃

축을 조정하기 위해 breakslabels를 가장 자주 사용할 것입니다. 둘 다 범례에도 작동하지만 더 많이 사용할 가능성이 있는 몇 가지 다른 기술이 있습니다.

범례의 전체 위치를 제어하려면 theme() 설정을 사용해야 합니다. 이 장의 마지막 부분에서 테마에 대해 다시 다루겠지만, 간단히 말해 테마는 플롯의 데이터가 아닌 부분을 제어합니다. 테마 설정 legend.position은 범례가 그려지는 위치를 제어합니다:

base <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class))

base + theme(legend.position = "right") # 기본값
base + theme(legend.position = "left")
base + 
  theme(legend.position = "top") +
  guides(color = guide_legend(nrow = 3))
base + 
  theme(legend.position = "bottom") +
  guides(color = guide_legend(nrow = 3))

자동차의 고속도로 연비 대 엔진 크기의 네 개의 산점도로, 점들은 자동차  클래스에 따라 색상이 지정됩니다. 시계 방향으로 범례는 플롯의 오른쪽,  왼쪽, 아래쪽, 위쪽에 배치됩니다.

자동차의 고속도로 연비 대 엔진 크기의 네 개의 산점도로, 점들은 자동차  클래스에 따라 색상이 지정됩니다. 시계 방향으로 범례는 플롯의 오른쪽,  왼쪽, 아래쪽, 위쪽에 배치됩니다.

자동차의 고속도로 연비 대 엔진 크기의 네 개의 산점도로, 점들은 자동차  클래스에 따라 색상이 지정됩니다. 시계 방향으로 범례는 플롯의 오른쪽,  왼쪽, 아래쪽, 위쪽에 배치됩니다.

자동차의 고속도로 연비 대 엔진 크기의 네 개의 산점도로, 점들은 자동차  클래스에 따라 색상이 지정됩니다. 시계 방향으로 범례는 플롯의 오른쪽,  왼쪽, 아래쪽, 위쪽에 배치됩니다.

플롯이 짧고 넓으면 범례를 위나 아래에 놓고, 키가 크고 좁으면 범례를 왼쪽이나 오른쪽에 놓으세요. legend.position = "none"을 사용하여 범례 표시를 완전히 억제할 수도 있습니다.

개별 범례의 표시를 제어하려면 guides()guide_legend() 또는 guide_colorbar()와 함께 사용하세요. 다음 예제는 두 가지 중요한 설정을 보여줍니다. nrow로 범례가 사용하는 행 수를 제어하고, 심미성 중 하나를 재정의하여 점을 더 크게 만듭니다. 이것은 플롯에 많은 점을 표시하기 위해 낮은 alpha를 사용한 경우에 특히 유용합니다.

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class)) +
  geom_smooth(se = FALSE) +
  theme(legend.position = "bottom") +
  guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 점들은 자동차 클래스에  따라 색상이 지정됩니다. 플롯 위에 매끄러운 곡선이 겹쳐져 있습니다.  범례는 바닥에 있고 클래스는 두 줄로 가로로 나열됩니다. 범례의 점은  플롯의 점보다 큽니다.

guides()의 인수 이름이 labs()에서와 마찬가지로 심미성의 이름과 일치한다는 점에 유의하세요.

11.4.4 척도 교체

세부 사항을 조금만 조정하는 대신 척도를 완전히 교체할 수도 있습니다. 교체하고 싶을 가능성이 가장 높은 척도는 연속 위치 척도와 색상 척도의 두 가지 유형입니다. 다행히도 다른 모든 심미성에도 동일한 원칙이 적용되므로 위치와 색상을 마스터하면 다른 척도 교체를 빠르게 익힐 수 있습니다.

변수의 변환을 플롯하는 것은 매우 유용합니다. 예를 들어 caratprice를 로그 변환하면 그들 사이의 정확한 관계를 보기가 더 쉽습니다:

# 왼쪽
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_bin2d()
#> `stat_bin2d()` using `bins = 30`. Pick better value `binwidth`.

# 오른쪽
ggplot(diamonds, aes(x = log10(carat), y = log10(price))) +
  geom_bin2d()
#> `stat_bin2d()` using `bins = 30`. Pick better value `binwidth`.

다이아몬드 가격 대 캐럿의 두 플롯. 데이터는 비닝되었으며 각 빈을  나타내는 사각형의 색상은 해당 빈에 속하는 포인트 수를 기반으로 합니다.  오른쪽 플롯에서 가격과 캐럿 값은 로그 변환되었으며 축 레이블은 로그  변환된 값을 보여줍니다.

다이아몬드 가격 대 캐럿의 두 플롯. 데이터는 비닝되었으며 각 빈을  나타내는 사각형의 색상은 해당 빈에 속하는 포인트 수를 기반으로 합니다.  오른쪽 플롯에서 가격과 캐럿 값은 로그 변환되었으며 축 레이블은 로그  변환된 값을 보여줍니다.

그러나 이 변환의 단점은 축이 이제 변환된 값으로 레이블이 지정되어 플롯을 해석하기 어렵다는 것입니다. 심미적 매핑에서 변환을 수행하는 대신 척도에서 수행할 수 있습니다. 축이 원래 데이터 척도로 레이블이 지정된다는 점을 제외하면 시각적으로 동일합니다.

ggplot(diamonds, aes(x = carat, y = price)) +
  geom_bin2d() + 
  scale_x_log10() + 
  scale_y_log10()
#> `stat_bin2d()` using `bins = 30`. Pick better value `binwidth`.

다이아몬드 가격 대 캐럿의 플롯. 데이터는 비닝되었으며 각 빈을 나타내는  사각형의 색상은 해당 빈에 속하는 포인트 수를 기반으로 합니다. 축 레이블은  원래 데이터 척도에 있습니다.

자주 사용자 정의되는 또 다른 척도는 색상입니다. 기본 범주형 척도는 색상환 주위에 균등하게 간격을 둔 색상을 선택합니다. 유용한 대안은 일반적인 유형의 색맹을 가진 사람들에게 더 잘 작동하도록 수동으로 조정된 ColorBrewer 척도입니다. 아래의 두 플롯은 비슷해 보이지만 빨간색과 녹색 음영의 차이가 충분하여 적록색맹이 있는 사람들도 오른쪽의 점을 구별할 수 있습니다.1

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv))

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv)) +
  scale_color_brewer(palette = "Set1")

고속도로 마일리지 대 엔진 크기의 두 산점도로, 점들은 구동 방식 유형에  따라 색상이 지정됩니다. 왼쪽 플롯은 기본 ggplot2 색상 팔레트를 사용하고  오른쪽 플롯은 다른 색상 팔레트를 사용합니다.

고속도로 마일리지 대 엔진 크기의 두 산점도로, 점들은 구동 방식 유형에  따라 색상이 지정됩니다. 왼쪽 플롯은 기본 ggplot2 색상 팔레트를 사용하고  오른쪽 플롯은 다른 색상 팔레트를 사용합니다.

접근성을 개선하기 위한 더 간단한 기술을 잊지 마세요. 색상이 몇 개뿐인 경우 중복된 모양 매핑을 추가할 수 있습니다. 이렇게 하면 플롯을 흑백으로 해석할 수 있도록 하는 데에도 도움이 됩니다.

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv, shape = drv)) +
  scale_color_brewer(palette = "Set1")

고속도로 마일리지 대 엔진 크기의 산점도로, 점의 색상과 모양 모두 구동  방식 유형에 따라 결정됩니다. 색상 팔레트는 기본 ggplot2 팔레트가  아닙니다.

ColorBrewer 척도는 https://colorbrewer2.org/에 온라인으로 문서화되어 있으며 Erich Neuwirth의 RColorBrewer 패키지를 통해 R에서 사용할 수 있습니다. Figure 11.1 는 모든 팔레트의 전체 목록을 보여줍니다. 순차적(위쪽) 및 발산(아래쪽) 팔레트는 범주형 값이 순서가 있거나 “중간”이 있는 경우 특히 유용합니다. 이는 cut()을 사용하여 연속형 변수를 범주형 변수로 만든 경우 자주 발생합니다.

모든 colorBrewer 척도. 한 그룹은 밝은 색에서 어두운 색으로 이동합니다.  다른 그룹은 순서가 없는 색상 세트입니다. 그리고 마지막 그룹은 발산  척도(어두운 색에서 밝은 색으로 다시 어두운 색으로)를 가지고 있습니다.  각 세트 내에는 여러 팔레트가 있습니다.
Figure 11.1: 모든 colorBrewer 척도.

값과 색상 사이에 미리 정의된 매핑이 있는 경우 scale_color_manual()을 사용하세요. 예를 들어 대통령 정당을 색상에 매핑하는 경우 공화당은 빨간색, 민주당은 파란색이라는 표준 매핑을 사용하고 싶습니다. 이러한 색상을 할당하는 한 가지 접근 방식은 16진수 색상 코드를 사용하는 것입니다:

presidential |>
  mutate(id = 33 + row_number()) |>
  ggplot(aes(x = start, y = id, color = party)) +
  geom_point() +
  geom_segment(aes(xend = end, yend = id)) +
  scale_color_manual(values = c(Republican = "#E81B23", Democratic = "#00AEF3"))

대통령의 ID 번호 대 대통령직을 시작한 연도의 선 플롯. 시작 연도는 점과  거기서 시작하여 대통령직이 끝날 때 끝나는 세그먼트로 표시됩니다. 민주당  대통령은 파란색으로, 공화당은 빨간색으로 표시됩니다.

연속적인 색상의 경우 내장된 scale_color_gradient() 또는 scale_fill_gradient()를 사용할 수 있습니다. 발산 척도가 있는 경우 scale_color_gradient2()를 사용할 수 있습니다. 이를 통해 예를 들어 양수 값과 음수 값에 다른 색상을 부여할 수 있습니다. 이는 평균 위 또는 아래의 점을 구별하려는 경우에도 때때로 유용합니다.

또 다른 옵션은 viridis 색상 척도를 사용하는 것입니다. 디자이너인 Nathaniel Smith와 Stéfan van der Walt는 다양한 형태의 색맹을 가진 사람들이 인식할 수 있을 뿐만 아니라 색상과 흑백 모두에서 지각적으로 균일한 연속 색상 체계를 신중하게 맞춤화했습니다. 이 척도는 ggplot2에서 연속(c), 이산(d), 비닝된(b) 팔레트로 사용할 수 있습니다.

df <- tibble(
  x = rnorm(10000),
  y = rnorm(10000)
)

ggplot(df, aes(x, y)) +
  geom_hex() +
  coord_fixed() +
  labs(title = "Default, continuous", x = NULL, y = NULL)

ggplot(df, aes(x, y)) +
  geom_hex() +
  coord_fixed() +
  scale_fill_viridis_c() +
  labs(title = "Viridis, continuous", x = NULL, y = NULL)

ggplot(df, aes(x, y)) +
  geom_hex() +
  coord_fixed() +
  scale_fill_viridis_b() +
  labs(title = "Viridis, binned", x = NULL, y = NULL)

세 개의 육각형 플롯으로, 육각형의 색상은 해당 육각형 빈에 속하는  관측값의 수를 나타냅니다. 첫 번째 플롯은 기본 연속 ggplot2 척도를  사용합니다. 두 번째 플롯은 viridis 연속 척도를 사용하고 세 번째 플롯은  viridis 비닝된 척도를 사용합니다.

세 개의 육각형 플롯으로, 육각형의 색상은 해당 육각형 빈에 속하는  관측값의 수를 나타냅니다. 첫 번째 플롯은 기본 연속 ggplot2 척도를  사용합니다. 두 번째 플롯은 viridis 연속 척도를 사용하고 세 번째 플롯은  viridis 비닝된 척도를 사용합니다.

세 개의 육각형 플롯으로, 육각형의 색상은 해당 육각형 빈에 속하는  관측값의 수를 나타냅니다. 첫 번째 플롯은 기본 연속 ggplot2 척도를  사용합니다. 두 번째 플롯은 viridis 연속 척도를 사용하고 세 번째 플롯은  viridis 비닝된 척도를 사용합니다.

모든 색상 척도에는 두 가지 종류가 있습니다: colorfill 심미성에 대해 각각 scale_color_*()scale_fill_*()(색상 척도는 영국식 및 미국식 철자 모두 사용 가능).

11.4.5 줌(Zooming)

플롯 한계를 제어하는 세 가지 방법이 있습니다:

  1. 플롯되는 데이터를 조정합니다.
  2. 각 척도의 한계를 설정합니다.
  3. coord_cartesian()에서 xlimylim을 설정합니다.

일련의 플롯으로 이러한 옵션을 보여드리겠습니다. 왼쪽 플롯은 엔진 크기와 연비 사이의 관계를 보여주며 구동 방식 유형별로 색상이 지정되어 있습니다. 오른쪽 플롯은 동일한 변수를 보여주지만 플롯되는 데이터의 하위 집합을 만듭니다. 데이터의 하위 집합을 만들면 x 및 y 척도뿐만 아니라 매끄러운 곡선에도 영향을 미쳤습니다.

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv)) +
  geom_smooth()

# 오른쪽
mpg |>
  filter(displ >= 5 & displ <= 6 & hwy >= 10 & hwy <= 25) |>
  ggplot(aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv)) +
  geom_smooth()

왼쪽에는 고속도로 마일리지 대 배기량의 산점도로, 점들은 구동 방식에 따라  색상이 지정됩니다. 겹쳐진 매끄러운 곡선은 하키 스틱처럼 감소하다가 증가하는  추세를 보여줍니다. 오른쪽에는 배기량이 5에서 6까지, 고속도로 마일리지가  10에서 25까지만 범위가 지정된 동일한 변수가 플롯되어 있습니다. 겹쳐진  매끄러운 곡선은 처음에는 약간 증가하다가 감소하는 추세를 보여줍니다.

왼쪽에는 고속도로 마일리지 대 배기량의 산점도로, 점들은 구동 방식에 따라  색상이 지정됩니다. 겹쳐진 매끄러운 곡선은 하키 스틱처럼 감소하다가 증가하는  추세를 보여줍니다. 오른쪽에는 배기량이 5에서 6까지, 고속도로 마일리지가  10에서 25까지만 범위가 지정된 동일한 변수가 플롯되어 있습니다. 겹쳐진  매끄러운 곡선은 처음에는 약간 증가하다가 감소하는 추세를 보여줍니다.

이것을 아래의 두 플롯과 비교해 봅시다. 왼쪽 플롯은 개별 척도에 limits를 설정하고 오른쪽 플롯은 coord_cartesian()에 설정합니다. 한계를 줄이는 것은 데이터를 부분집합화하는 것과 동일함을 알 수 있습니다. 따라서 플롯의 영역을 줌인하려면 일반적으로 coord_cartesian()을 사용하는 것이 가장 좋습니다.

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv)) +
  geom_smooth() +
  scale_x_continuous(limits = c(5, 6)) +
  scale_y_continuous(limits = c(10, 25))

# 오른쪽
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = drv)) +
  geom_smooth() +
  coord_cartesian(xlim = c(5, 6), ylim = c(10, 25))

왼쪽에는 고속도로 마일리지 대 배기량의 산점도로, 배기량은 5에서 6까지,  고속도로 마일리지는 10에서 25까지입니다. 겹쳐진 매끄러운 곡선은  처음에는 약간 증가하다가 감소하는 추세를 보여줍니다. 오른쪽에는 동일한  변수가 동일한 한계로 플롯되어 있지만 겹쳐진 매끄러운 곡선은 끝에서  약간 증가하는 비교적 평평한 추세를 보여줍니다.

왼쪽에는 고속도로 마일리지 대 배기량의 산점도로, 배기량은 5에서 6까지,  고속도로 마일리지는 10에서 25까지입니다. 겹쳐진 매끄러운 곡선은  처음에는 약간 증가하다가 감소하는 추세를 보여줍니다. 오른쪽에는 동일한  변수가 동일한 한계로 플롯되어 있지만 겹쳐진 매끄러운 곡선은 끝에서  약간 증가하는 비교적 평평한 추세를 보여줍니다.

반면에 개별 척도에 limits를 설정하는 것은 한계를 확장하려는 경우, 예를 들어 다른 플롯 간에 척도를 일치시키려는 경우에 일반적으로 더 유용합니다. 예를 들어 두 클래스의 자동차를 추출하여 별도로 플롯하는 경우 세 가지 척도(x축, y축, 색상 심미성) 모두 범위가 다르기 때문에 플롯을 비교하기 어렵습니다.

suv <- mpg |> filter(class == "suv")
compact <- mpg |> filter(class == "compact")

# 왼쪽
ggplot(suv, aes(x = displ, y = hwy, color = drv)) +
  geom_point()

# 오른쪽
ggplot(compact, aes(x = displ, y = hwy, color = drv)) +
  geom_point()

왼쪽에는 SUV의 고속도로 마일리지 대 배기량의 산점도. 오른쪽에는  소형차에 대한 동일한 변수의 산점도. 두 플롯 모두 구동 방식별로 점의  색상이 지정됩니다. SUV 중에는 4륜 구동이 더 많고 나머지는 후륜  구동인 반면, 소형차 중에는 전륜 구동이 더 많고 나머지는 4륜  구동입니다. SUV 플롯은 고속도로 마일리지와 배기량 사이에 명확한 음의  관계를 보여주는 반면 소형차 플롯에서는 관계가 훨씬 평평합니다.

왼쪽에는 SUV의 고속도로 마일리지 대 배기량의 산점도. 오른쪽에는  소형차에 대한 동일한 변수의 산점도. 두 플롯 모두 구동 방식별로 점의  색상이 지정됩니다. SUV 중에는 4륜 구동이 더 많고 나머지는 후륜  구동인 반면, 소형차 중에는 전륜 구동이 더 많고 나머지는 4륜  구동입니다. SUV 플롯은 고속도로 마일리지와 배기량 사이에 명확한 음의  관계를 보여주는 반면 소형차 플롯에서는 관계가 훨씬 평평합니다.

이 문제를 극복하는 한 가지 방법은 전체 데이터의 limits로 척도를 훈련(training)하여 여러 플롯에서 척도를 공유하는 것입니다.

x_scale <- scale_x_continuous(limits = range(mpg$displ))
y_scale <- scale_y_continuous(limits = range(mpg$hwy))
col_scale <- scale_color_discrete(limits = unique(mpg$drv))

# 왼쪽
ggplot(suv, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  x_scale +
  y_scale +
  col_scale

# 오른쪽
ggplot(compact, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  x_scale +
  y_scale +
  col_scale

왼쪽에는 SUV의 고속도로 마일리지 대 배기량의 산점도. 오른쪽에는  소형차에 대한 동일한 변수의 산점도. 두 플롯 모두 구동 방식별로 점의  색상이 지정됩니다. 두 플롯 모두 고속도로 마일리지, 배기량, 구동 방식에  대해 동일한 척도로 플롯되어, 전륜 구동 SUV와 후륜 구동 소형차가  없음에도 불구하고 두 플롯 모두 범례에 세 가지 유형(전륜, 후륜, 4륜  구동)이 모두 표시됩니다. x 및 y 척도가 동일하고 최소 또는 최대  고속도로 마일리지 및 배기량을 훨씬 넘어서기 때문에 점들이 전체 플롯  영역을 차지하지 않습니다.

왼쪽에는 SUV의 고속도로 마일리지 대 배기량의 산점도. 오른쪽에는  소형차에 대한 동일한 변수의 산점도. 두 플롯 모두 구동 방식별로 점의  색상이 지정됩니다. 두 플롯 모두 고속도로 마일리지, 배기량, 구동 방식에  대해 동일한 척도로 플롯되어, 전륜 구동 SUV와 후륜 구동 소형차가  없음에도 불구하고 두 플롯 모두 범례에 세 가지 유형(전륜, 후륜, 4륜  구동)이 모두 표시됩니다. x 및 y 척도가 동일하고 최소 또는 최대  고속도로 마일리지 및 배기량을 훨씬 넘어서기 때문에 점들이 전체 플롯  영역을 차지하지 않습니다.

이 특별한 경우에는 단순히 패싯을 사용할 수 있었지만, 예를 들어 보고서의 여러 페이지에 플롯을 분산시키려는 경우와 같이 이 기술은 더 일반적으로 유용합니다.

11.4.6 연습문제

  1. 다음 코드가 기본 척도를 재정의하지 않는 이유는 무엇입니까?

    df <- tibble(
      x = rnorm(10000),
      y = rnorm(10000)
    )
    
    ggplot(df, aes(x, y)) +
      geom_hex() +
      scale_color_gradient(low = "white", high = "red") +
      coord_fixed()
  2. 모든 척도의 첫 번째 인수는 무엇입니까? labs()와 어떻게 비교됩니까?

  3. 다음을 수행하여 대통령 임기 표시를 변경하세요:

    1. 색상과 x축 나누기를 사용자 정의하는 두 가지 변형을 결합합니다.
    2. y축 표시를 개선합니다.
    3. 각 임기에 대통령 이름으로 레이블을 지정합니다.
    4. 유익한 플롯 레이블을 추가합니다.
    5. 4년마다 나누기를 배치합니다(생각보다 까다롭습니다!).
  4. 먼저 다음 플롯을 만드세요. 그런 다음 override.aes를 사용하여 코드를 수정하여 범례를 더 보기 쉽게 만드세요.

    ggplot(diamonds, aes(x = carat, y = price)) +
      geom_point(aes(color = cut), alpha = 1/20)

11.5 테마(Themes)

마지막으로 테마를 사용하여 플롯의 데이터가 아닌 요소를 사용자 정의할 수 있습니다:

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class)) +
  geom_smooth(se = FALSE) +
  theme_bw()

자동차의 고속도로 마일리지 대 배기량의 산점도로, 자동차 클래스별로  색상이 지정됩니다. 플롯 배경은 흰색이며 회색 격자선이 있습니다.

ggplot2에는 Figure 11.2 에 표시된 8가지 테마가 포함되어 있으며 theme_gray()가 기본값입니다.2 제프리 아놀드(Jeffrey Arnold)의 ggthemes(https://jrnold.github.io/ggthemes)와 같은 추가 패키지에는 더 많은 테마가 포함되어 있습니다. 특정 회사나 저널 스타일을 일치시키려는 경우 자신만의 테마를 만들 수도 있습니다.

ggplot2로 만든 8개의 막대 플롯, 각각 8개의 내장 테마 중 하나를 사용: theme_bw() - 격자선이 있는 흰색 배경, theme_light() - 밝은 축과 격자선, theme_classic() - 클래식 테마, 축은 있지만 격자선 없음, theme_linedraw() - 검은색 선만 있음,  theme_dark() - 대비를 위한 어두운 배경, theme_minimal() - 미니멀 테마, 배경 없음, theme_gray() - 회색 배경(기본 테마), theme_void() - 빈 테마, 지옴만 보임.
Figure 11.2: ggplot2에 내장된 8가지 테마.

y축에 사용되는 글꼴의 크기와 색상과 같은 각 테마의 개별 구성 요소를 제어하는 것도 가능합니다. legend.position이 범례가 그려지는 위치를 제어한다는 것을 이미 보았습니다. theme()으로 사용자 정의할 수 있는 범례의 다른 많은 측면이 있습니다. 예를 들어 아래 플롯에서는 범례의 방향을 변경하고 주위에 검은색 테두리를 넣습니다. 범례 상자 및 플롯 제목 요소의 사용자 정의는 element_*() 함수로 수행됩니다. 이러한 함수는 데이터가 아닌 구성 요소의 스타일을 지정합니다. 예를 들어 제목 텍스트는 element_text()face 인수에서 굵게 표시되고 범례 테두리 색상은 element_rect()color 인수에서 정의됩니다. 제목과 캡션의 위치를 제어하는 테마 요소는 각각 plot.title.positionplot.caption.position입니다. 다음 플롯에서 이들은 플롯 패널(기본값) 대신 전체 플롯 영역에 정렬됨을 나타내기 위해 “plot”으로 설정됩니다. 제목 및 캡션 텍스트의 형식을 위한 배치 변경에 몇 가지 다른 유용한 theme() 구성 요소가 사용됩니다.

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  labs(
    title = "Larger engine sizes tend to have lower fuel economy",
    caption = "Source: https://fueleconomy.gov."
  ) +
  theme(
    legend.position = c(0.6, 0.7),
    legend.direction = "horizontal",
    legend.box.background = element_rect(color = "black"),
    plot.title = element_text(face = "bold"),
    plot.title.position = "plot",
    plot.caption.position = "plot",
    plot.caption = element_text(hjust = 0)
  )

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 구동 방식별로 색상이  지정됩니다. 플롯 제목은 'Larger engine sizes tend to have lower fuel  economy'이고 캡션은 데이터 출처인 fueleconomy.gov를 가리킵니다.  캡션과 제목은 왼쪽 정렬되어 있고 범례는 플롯 내부에 검은색 테두리와  함께 있습니다.

모든 theme() 구성 요소에 대한 개요는 ?theme 도움말을 참조하세요. ggplot2 책은 테마 지정에 대한 전체 세부 정보를 얻을 수 있는 훌륭한 장소이기도 합니다.

11.5.1 연습문제

  1. ggthemes 패키지에서 제공하는 테마를 선택하여 마지막으로 만든 플롯에 적용하세요.
  2. 플롯의 축 레이블을 파란색과 굵게 만드세요.

11.6 레이아웃(Layout)

지금까지 단일 플롯을 만들고 수정하는 방법에 대해 이야기했습니다. 특정 방식으로 레이아웃하고 싶은 여러 플롯이 있다면 어떻게 해야 할까요? patchwork 패키지를 사용하면 별도의 플롯을 동일한 그래픽으로 결합할 수 있습니다. 이 장의 앞부분에서 이 패키지를 로드했습니다.

두 플롯을 나란히 배치하려면 단순히 서로 더하면 됩니다. 먼저 플롯을 만들고 객체로 저장해야 합니다(다음 예제에서는 p1p2라고 함). 그런 다음 +로 나란히 배치합니다.

p1 <- ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point() + 
  labs(title = "Plot 1")
p2 <- ggplot(mpg, aes(x = drv, y = hwy)) + 
  geom_boxplot() + 
  labs(title = "Plot 2")
p1 + p2

두 개의 플롯(고속도로 마일리지 대 엔진 크기의 산점도와 고속도로 마일리지  대 구동 방식의 나란히 놓인 상자 그림)이 서로 옆에 배치되어 있습니다.

위의 코드 청크에서 patchwork 패키지의 새로운 함수를 사용하지 않았다는 점에 유의하는 것이 중요합니다. 대신 패키지가 + 연산자에 새로운 기능을 추가했습니다.

patchwork로 복잡한 플롯 레이아웃을 만들 수도 있습니다. 다음에서 |p1p3를 나란히 배치하고 /p2를 다음 줄로 이동합니다.

p3 <- ggplot(mpg, aes(x = cty, y = hwy)) + 
  geom_point() + 
  labs(title = "Plot 3")
(p1 | p3) / p2

세 개의 플롯이 첫 번째와 세 번째 플롯이 나란히 있고 두 번째 플롯이  그 아래로 뻗어 있도록 배치되어 있습니다. 첫 번째 플롯은 고속도로 마일리지  대 엔진 크기의 산점도이고, 세 번째 플롯은 고속도로 마일리지 대 도시  마일리지의 산점도이며, 두 번째 플롯은 고속도로 마일리지 대 구동 방식의  나란히 놓인 상자 그림입니다.

또한 patchwork를 사용하면 여러 플롯의 범례를 하나의 공통 범례로 수집하고, 범례의 배치 및 플롯의 치수를 사용자 정의하고, 플롯에 공통 제목, 부제, 캡션 등을 추가할 수 있습니다. 아래에서 5개의 플롯을 만듭니다. 상자 그림과 산점도의 범례를 끄고 & theme(legend.position = "top")으로 밀도 플롯의 범례를 플롯 상단에 모았습니다. 여기서 일반적인 + 대신 & 연산자를 사용한 것에 주목하세요. 이는 개별 ggplot이 아니라 patchwork 플롯의 테마를 수정하기 때문입니다. 범례는 상단의 guide_area() 내부에 배치됩니다. 마지막으로 patchwork의 다양한 구성 요소 높이도 사용자 정의했습니다. 가이드는 높이가 1, 상자 그림은 3, 밀도 플롯은 2, 패싯된 산점도는 4입니다. Patchwork는 이 척도를 사용하여 플롯에 할당된 영역을 나누고 구성 요소를 그에 따라 배치합니다.

#   처음 두 플롯은 나란히 놓인 상자 그림입니다. 3번과 4번 플롯은 밀도 
#|   플롯입니다. 그리고 5번 플롯은 패싯된 산점도입니다.
#   이러한 각 플롯은 구동 방식별로 색상이 지정된 지옴을 
#|   보여주지만 패치워크된 플롯에는 플롯 위와 제목 아래에 모두 적용되는 
#|   하나의 범례만 있습니다.
p1 <- ggplot(mpg, aes(x = drv, y = cty, color = drv)) + 
  geom_boxplot(show.legend = FALSE) + 
  labs(title = "Plot 1")

p2 <- ggplot(mpg, aes(x = drv, y = hwy, color = drv)) + 
  geom_boxplot(show.legend = FALSE) + 
  labs(title = "Plot 2")

p3 <- ggplot(mpg, aes(x = cty, color = drv, fill = drv)) + 
  geom_density(alpha = 0.5) + 
  labs(title = "Plot 3")

p4 <- ggplot(mpg, aes(x = hwy, color = drv, fill = drv)) + 
  geom_density(alpha = 0.5) + 
  labs(title = "Plot 4")

p5 <- ggplot(mpg, aes(x = cty, y = hwy, color = drv)) + 
  geom_point(show.legend = FALSE) + 
  facet_wrap(~drv) +
  labs(title = "Plot 5")

(guide_area() / (p1 + p2) / (p3 + p4) / p5) +
  plot_annotation(
    title = "City and highway mileage for cars with different drive trains",
    caption = "Source: https://fueleconomy.gov."
  ) +
  plot_layout(
    guides = "collect",
    heights = c(1, 3, 2, 4)
    ) &
  theme(legend.position = "top")

처음 두 플롯이 나란히 있도록 배치된 5개의 플롯. 세 번째와 네 번째  플롯은 그 아래에 있습니다. 그리고 다섯 번째 플롯은 그 아래로 뻗어  있습니다. 패치워크된 플롯의 제목은 "City and highway mileage for cars  with different drive trains"이고 캡션은 "Source:  https://fueleconomy.gov"입니다.

patchwork로 여러 플롯을 결합하고 레이아웃하는 것에 대해 더 알고 싶다면 패키지 웹사이트의 가이드를 살펴보는 것을 추천합니다: https://patchwork.data-imaginist.com.

11.6.1 연습문제

  1. 다음 플롯 레이아웃에서 괄호를 생략하면 어떻게 됩니까? 왜 이런 일이 발생하는지 설명할 수 있습니까?

    p1 <- ggplot(mpg, aes(x = displ, y = hwy)) + 
      geom_point() + 
      labs(title = "Plot 1")
    p2 <- ggplot(mpg, aes(x = drv, y = hwy)) + 
      geom_boxplot() + 
      labs(title = "Plot 2")
    p3 <- ggplot(mpg, aes(x = cty, y = hwy)) + 
      geom_point() + 
      labs(title = "Plot 3")
    
    (p1 | p2) / p3
  2. 이전 연습문제의 세 플롯을 사용하여 다음 패치워크를 다시 만드세요.

    세 개의 플롯: 플롯 1은 고속도로 마일리지 대 엔진 크기의 산점도입니다.  플롯 2는 고속도로 마일리지 대 구동 방식의 나란히 놓인 상자  그림입니다. 플롯 3은 도시 마일리지 대 구동 방식의 나란히 놓인 상자  그림입니다. 플롯 1은 첫 번째 행에 있습니다. 플롯 2와 3은 다음 행에  있으며 각각 플롯 1 너비의 절반에 걸쳐 있습니다. 플롯 1은 "Fig. A",  플롯 2는 "Fig. B", 플롯 3은 "Fig. C"라고 레이블이 지정되어 있습니다.

11.7 요약

이 장에서는 제목, 부제, 캡션과 같은 플롯 레이블 추가, 기본 축 레이블 수정, 주석을 사용하여 플롯에 정보 텍스트를 추가하거나 특정 데이터 포인트를 강조 표시, 축 척도 사용자 정의, 플롯 테마 변경에 대해 배웠습니다. 또한 단순 및 복잡한 플롯 레이아웃을 모두 사용하여 여러 플롯을 단일 그래프로 결합하는 방법에 대해서도 배웠습니다.

지금까지 다양한 유형의 플롯을 만드는 방법과 다양한 기술을 사용하여 사용자 정의하는 방법에 대해 배웠지만, ggplot2로 만들 수 있는 것의 겉만 핥았을 뿐입니다. ggplot2에 대한 포괄적인 이해를 얻으려면 ggplot2: Elegant Graphics for Data Analysis 책을 읽는 것을 추천합니다. 다른 유용한 리소스는 Winston Chang의 R Graphics Cookbook과 Claus Wilke의 Fundamentals of Data Visualization입니다.


  1. SimDaltonism과 같은 도구를 사용하여 색맹을 시뮬레이션하여 이 이미지를 테스트할 수 있습니다.↩︎

  2. 많은 사람들이 기본 테마가 회색 배경인 이유를 궁금해합니다. 이것은 격자선을 여전히 볼 수 있게 하면서 데이터를 앞으로 내세우기 때문에 의도적인 선택이었습니다. 흰색 격자선이 보이지만(위치 판단에 상당히 도움이 되기 때문에 중요함) 시각적 영향이 적어 쉽게 무시할 수 있습니다. 회색 배경은 플롯에 텍스트와 유사한 인쇄 색상을 제공하여 그래픽이 밝은 흰색 배경으로 튀어나오지 않고 문서 흐름에 맞도록 합니다. 마지막으로 회색 배경은 플롯이 단일 시각적 개체로 인식되도록 하는 연속적인 색상 필드를 만듭니다.↩︎