17  표 테마

문서에 표를 삽입하면 정보를 효율적으로 요약하고 가독성을 높이는 데 큰 역할을 한다. 표를 작성할 수 있는 도구로 마크다운(Markdown), gt 패키지, 라텍 모두 각각의 특장점이 있다. 마크다운은 사용하기 쉬우며 복잡한 설치나 추가 패키지 없이도 기본적인 표를 빠르게 작성할 수 있다. 라텍은 논문이나 학술 자료에 적합하게 고품질의 표를 제작할 수 있는 전문적인 도구다.

웹과 PDF 출력, 테마 지정 등에서 gt 패키지가 뛰어나고 gt 패키지는 그래프 문법에 기초하여 고급 표제작도 수월히하게 작성가능하고, 특히, 데이터 중심 표를 작성할 때 필요한 다양한 기능을 제공하기 때문에 탄탄한 표문법에 기반한 gt 패키지가 여러가지 장점이 많다.

표제작 세가지 방식

17.1 gt 표 작성하기

gt 패키지는 R Tidyverse 생태계에 속한 표 제작 목적으로 특별히 제작된 패키지로 그래프 문법에 기반한 ggplot2 패키지에 친숙하신 저자는 쉽게 표도 gt 패키지를 사용해서 다양한 표 제작이 가능하다. 다음 예시에서는 palmerpenguins 데이터 패키지 penguins 데이터셋을 활용하여 “남극 펭귄 서식섬과 종 빈도표”를 제작한다.

  1. 라이브러리 가져오기: tidyverse, palmerpenguins, gt, gtExtras, magick.
  2. penguins 데이터를 사용하여 종(species)과 서식섬(island)에 따른 빈도를 집계하고 표제작에 맞춰 피벗 테이블을 생성한다.
  3. gt() 함수를 이용하여 gt 표를 초기화하고, rowname_col 인자로 “species”를 지정하여 행 이름을 설정한다.
  4. tab_header() 함수로 표 제목과 부제목을 지정한다.
  5. grand_summary_rows() 함수를 사용하여 각 서식섬(Biscoe, Dream, Torgersen) 합계를 계산한다.
  6. cols_align("center")을 통해 텍스트를 가운데 정렬한다.
  7. opt_row_striping() 함수로 행에 스트라이핑을 추가하여 가독성을 높인다.
  8. tab_source_note() 함수로 표 출처를 표기한다.

penguins_gt 변수에 저장된 gt 표를 저장한다. gt 패키지의 다양한 기능을 활용하여 복잡한 표도 손쉽게 작성할 수 있다는 것을 다시 확인할 수 있다.

library(tidyverse)
library(palmerpenguins)
library(gt)
library(gtExtras)
library(magick)

penguins_gt <- penguins |> 
  count(species, island) |> 
  pivot_wider(names_from = island, values_from = n, values_fill = 0) |> 
  as_tibble() |> 
  gt(rowname_col = "species") |> 
    tab_header(
      title = md("남극 펭귄 **서식섬과 종** 빈도표"),
      subtitle = md("`palmerpenguins` 데이터 패키지")
    ) |> 
    grand_summary_rows(
      columns = c(Biscoe, Dream, Torgersen),
      fns = list(
        '합계' = ~sum(.) 
      ),
      fmt = ~ fmt_number(., use_seps = FALSE, decimals = 0),
      missing_text = '-'
    )  |> 
    cols_align("center") |> 
    opt_row_striping() |> 
    tab_source_note(
      source_note = md("자료출처: `penguins` 데이터셋")
  )

penguins_gt
남극 펭귄 서식섬과 종 빈도표
palmerpenguins 데이터 패키지
Biscoe Dream Torgersen
Adelie 44 56 52
Chinstrap 0 68 0
Gentoo 124 0 0
합계 168 124 52
자료출처: penguins 데이터셋

17.1.1 기본 색상과 스타일

웹 프로그램을 제작할 때 HTML로 콘텐츠를 제작하고 CSS/SCSS 파일로 스타일을 적용하는 것처럼 유지보수성이 뛰어나고 가독성이 좋은 표를 제작하기 위해 저자가 익혀야 되는 필수적인 기본기 중 하나다. penguins_gt 표는 핵심 정보가 잘 요약되어 있지만, 색상이나 다른 외양 관련 설정은 기본설정값만 따르고 있다.

gt 패키지 opt_stylize() 함수는 표 스타일링에 다양한 선택지를 제공한다. 미리 정의된 배경색, 선 색상, 선 스타일 등을 다르게 적용할 수 있어 스타일은 총 36개에 이른다. 표 테두리, 표 요약 부분과 스텁(stub)에 더 어두운 색상을 적용, 수직선 반영여부가 포함된다.

R 코드 opt_colors 벡터에 총 6가지 색상(파란색, 청록색, 분홍색, 녹색, 붉은색, 회색) 중 5개 색상을 지정하고, draw_color_gt 함수를 이용하여 이 색상들을 penguins_gt 표에 opt_stylize 함수를 호출하여 표 색상을 적용한다.

opt_colors <- c("blue", "cyan", "green", "red", "gray")

draw_color_gt <- function(gt_color = "blue") {
  penguins_gt |> 
    opt_stylize(style = 1, color = gt_color)
}                

gt_colors_list <- map(opt_colors, draw_color_gt)


for(i in 1:length(opt_colors)) {
  gtsave(gt_colors_list[[i]], str_glue("images/gt_theme_{opt_colors[i]}.png"))
}

17.1.2 스타일

gt 패키지는 opt_stylize() 함수를 통해서 색상뿐만 아니라 스타일도 달리해서 표를 제작할 수 있다. gt 패키지 1 ~ 6까지 번호 총6가지 스타일 선택이 가능하고, 기본값은 1 로 설정되어 있고, 저자가 복잡한 설정 없이 번호를 지정함으로써 표 디자인을 빠르게 변경할 수 있다. 번호로 스타일을 선택하게 되면, 데이터 분석과정에서 다양한 표 스타일을 빠르게 시험하고 가장 적절한 표를 신속히 제작하는데 도움이 된다.

opt_styles <- 1:5

draw_style_gt <- function(opt_sytle, gt_color = "blue") {
  penguins_gt |> 
    opt_stylize(style = opt_sytle, color = gt_color)
}                

gt_styles_list <- map(opt_sytles, draw_style_gt)


for(i in 1:length(opt_styles)) {
  gtsave(gt_styles_list[[i]], str_glue("images/gt_theme_style_{opt_styles[i]}.png"))
}

17.2 gtExtra

gtExtras 패키지는 gt 패키지를 보완하여 더 아름다운 표를 생성할 수 있도록 도와주는 목적으로 개발되었다. gt 패키지에서 구현되지 않은 기능을 추가하거나, 반복되는 코드를 줄이기 위한 래퍼(wrapper) 함수로 작성되었다. gt 패키지를 확장한 다양한 기능이 있지만 테마와 관련된 사항을 집중적으로 살펴보자.

ggplot2 패키지를 활용하여 그래프 문법에 맞춰 그래프를 제작한 경험이 있다면, 자주 theme_*() 함수를 사용했을 것이다. 마찬가지로 ggplot2 그래프 테마 theme_minimal(), theme_grey()에 대응되는 테마가 gtExtras 패키지에 gt_theme_538(), gt_theme_espn(), gt_theme_nytimes(), gt_theme_guardian(), gt_theme_dot_matrix(), gt_theme_dark(), gt_theme_excel(), gt_theme_pff() 포함되어 있다. 주목할 점은 언론사와 단체에서 사용되는 스타일이 대거 포함되어 있다는 점이다.

gt_theme_espn() 함수는 gt 패키지로 생성된 표에 ESPN 테마를 적용한다. 이 함수는 gt 테이블 객체(gt_tbl 클래스)를 인자로 받으며, 선택적으로 gt::table_options()에 전달할 추가 인자를 받을 수 있다. 반환 값은 gt_tbl 클래스의 객체이다.

다음은 다른 테마 함수들에 대한 간략한 설명이다:

테마명 테마 설명
gt_theme_538() FiveThirtyEight 스타일 테마 적용
gt_theme_espn() ESPN 스타일 테마 적용
gt_theme_nytimes() New York Times 스타일 테마 적용
gt_theme_guardian() 가디언진(The Guardian) 스타일 테마 적용
gt_theme_dot_matrix() 도트 매트릭스 스타일 테마 적용
gt_theme_dark() 어두운 배경 테마 적용
gt_theme_excel() 마이크로소프트 엑셀 스타일 테마 적용
gt_theme_pff() PFF(Pro Football Focus, 스포츠 분석회사) 스타일 테마 적용

언론사와 미국 풋볼 리그 스포츠 분석에 특화된 PFF 스타일을 표에 적용해보자.

gtExtra_themes <- c(gt_theme_538, gt_theme_espn, gt_theme_nytimes, gt_theme_guardian, gt_theme_pff)

gtExtra_themes_names <- c("gt_theme_538", "gt_theme_espn", "gt_theme_nytimes",
                          "gt_theme_guardian","gt_theme_pff")

draw_gtExtras_theme <- function(gt_theme, gtExtra_themes_names) {
  penguins_gt |> 
    gt_theme() |> 
    tab_header(
      title = md("남극 펭귄 **서식섬과 종** 빈도표"),
      subtitle = gtExtra_themes_names)
}

# draw_gtExtras_theme(gtExtra_themes[5][[1]])
## gtExtras 테마적용 표 -------------------

gtExtra_styles_list <- vector(mode ="list", length = length(gtExtra_themes))

for(i in 1:length(gtExtra_themes)) {
  gtExtra_styles_list[[i]] <-  draw_gtExtras_theme(gtExtra_themes[i][[1]], gtExtra_themes_names[i])
}

## 테마 표 png 파일 저장 -------------------

gtExtras_path_filenames <- vector(mode = "character", length = length(gtExtra_themes))

for(i in 1:length(gtExtra_themes)) {
  gtExtras_path_filenames[i] <-  str_glue("images/gtExtras_theme_{gtExtra_themes_names[i]}.png")
}

for(i in 1:length(gtExtra_themes)) {
  gtsave(gtExtra_styles_list[[i]],
         str_glue("images/gtExtras_theme_{gtExtra_themes_names[i]}.png"))
}

17.3 사용자 정의 테마

사용자 정의 테마가 필요한 이유는 다양하지만, 보고서나 PPT 발표에서 동일한 스타일과 구성을 가진 표를 사용하면 데이터를 더 쉽고 빠르게 이해할 수 있고 동일한 일관성은 수작없이 반영할 수 있고 독자에게는 전문성을 각인시킬 수 있는 점이 크다.

gtExtras와 같은 패키지에서 제공되는 테마는 코드 한 줄로 빠르고 깔끔한 표를 만들 수 있어 시간을 절약할 수 있다는 큰 장점이 있지만, 특정 요구사항이나 브랜딩 지침을 완전히 맞춤화하기 쉽지 않고, 복잡한 데이터 구조나 특별한 시각화 요구사항을 충족시키는 데에도 한계가 있다.

사용자 정의 테마를 개발함으로써 gtExtras에서 제공하는 테마처럼 표 제작을 빠르고 편하게 지원할 수 있으면서도, 저자가 필요로 하는 브랜드나 스타일을 반영할 수 있다. 이렇게 하면 표가 더 전문적이면서도 개성있게 작성할 수 있다.

17.3.1 gtExtras 확장

penguins_gt라는 기존 gt 표 객체에 gt_theme_538() 테마를 선택하고 글꼴, 색상, 정렬 등 세부적인 작업을 진행하고 그 결과를 .png 파일로 저장한다. gt 패키지는 tidyverse 생태계 일원으로 파이프 연산자를 통해 세부적인 기능을 긴밀히 조합하여 단순한 코드로 제작되지만 최종 결과물로 상당히 높은 난이도를 갖는 표를 제작할 수 있다.

  1. gt_theme_538(): FiveThirtyEight 스타일 테마 적용

  2. tab_options(): 테이블의 글꼴, 제목 크기, 배경색 등 다양한 표 선택옵션 설정

  3. cols_align(): 숫자형 열은 가운데 정렬하고, 문자형 열은 자동 정렬

  4. tab_style(): “MaruBuri” 글꼴과 굵은 글씨체를 제목, 본문, 열에 적용

  5. gtsave(): 최종적으로 작업한 표를 PNG 이미지로 저장

penguins_theme_gt <- penguins_gt |> 
  gt_theme_538() |> 
  tab_options(
    # column_labels.background.color = '#1E61B0', # R logo 파란색
    table.font.names ="NanumSquare",    
    heading.title.font.size = px(26),
    heading.subtitle.font.size = px(16),    
    heading.background.color = "transparent", 
    column_labels.font.weight = 'bold',
    table_body.hlines.width = px(0),
    data_row.padding = px(6),
    heading.align = 'center',
    stub.background.color = "#ffffff",
    stub.font.weight = "bold",
    source_notes.font.size = px(10),
    row.striping.include_table_body = TRUE
  ) |> 
  cols_align( align = "center", columns = where(is.numeric)) |> 
  cols_align( align = "auto", columns = where(is.character)) |> 
  ## 글꼴 달리 적용
  tab_style(
    style = cell_text(
      font = "MaruBuri",      
      weight = 'bold' 
    ),
    locations = cells_title(groups = 'subtitle')
  ) |> 
  tab_style(
    style = cell_text(
      font = "MaruBuri",      
      weight = 'bold' 
    ),
    locations = cells_body()
  ) |> 
  tab_style(
    style = cell_text(
      font = "MaruBuri",      
      weight = 'bold' 
    ),
    locations = cells_column_labels()
  ) |> 
  tab_style(
    style = cell_text(
      font = "MaruBuri",      
    ),
    locations = cells_source_notes()
  )

penguins_theme_gt |> 
  gtsave(filename = "images/penguins_theme_gt.png")

gt 사용자 정의 테마 적용 표

17.3.2 gt_theme_hangul() 테마

gt_theme_538() 함수처럼 사용자 정의 함수를 gt_theme_hangul() 테마명을 지정해 두면 모든 표에 통일성을 유지한 테마를 간편하게 적용시킬 수 있다.

gt_tbl 데이터프레임을 입력받아 gt_theme_538()을 기본표 테마로 지정하고, tab_options() 함수를 통해 글꼴, 제목 크기, 배경색 등을 설정하고, 나눔스퀘어(NanumSquare), 마루부리(MaruBuri) 글꼴을 사용하여 한글 표에 더 적합한 스타일을 적용하고, cols_align()tab_style() 함수를 사용해서 숫자형 열(칼럼)은 가운데 정렬시키고, 문자형 열은 자동 정렬토록 하고, 특정 셀에 굵은 글씨체와 각기 다른 글꼴을 적용하여 좀더 독특하고 전문적인 느낌을 심는다. tab_style() 기능을 이용해 표 홀수 번째 행에만 회색 배경(‘grey90’)을 적용하여 가독성을 높게 한다. 마지막으로 사용자 정의 테마 함수도 예를 들어 기억하기 좋게 gt_theme_hangul()으로 작명하여 문서에서 표가 필요한 부분에 별도 검색작업 없이 적용시킬 수 있도록 한다.

gt_theme_hangul <- function(gt_tbl) {
  
  # Grab number of rows of data from gt object
  n_rows <- nrow(gt_tbl$`_data`)
  
  gt_tbl |> 
    gt_theme_538() |> 
    tab_options(
      # column_labels.background.color = '#1E61B0', # R logo 파란색
      table.font.names ="NanumSquare",    
      heading.title.font.size = px(26),
      heading.subtitle.font.size = px(16),    
      heading.background.color = "transparent", 
      column_labels.font.weight = 'bold',
      table_body.hlines.width = px(0),
      data_row.padding = px(6),
      heading.align = 'center',
      stub.background.color = "#ffffff",
      stub.font.weight = "bold",
      source_notes.font.size = px(10),
      row.striping.include_table_body = FALSE
    ) |> 
    cols_align( align = "center", columns = where(is.numeric)) |> 
    cols_align( align = "auto", columns = where(is.character)) |> 
    ## 글꼴 달리 적용
    tab_style(
      style = cell_text(
        font = "MaruBuri",      
        weight = 'bold' 
      ),
      locations = cells_title(groups = 'subtitle')
    ) |> 
    tab_style(
      style = cell_text(
        font = "MaruBuri",      
        weight = 'bold' 
      ),
      locations = cells_body()
    ) |> 
    tab_style(
      style = cell_text(
        font = "MaruBuri",      
        weight = 'bold' 
      ),
      locations = cells_column_labels()
    ) |> 
    tab_style(
      style = cell_text(
        font = "MaruBuri",      
      ),
      locations = cells_source_notes()
    ) |> 
    tab_style(
      style = cell_fill(color = 'grey90'),
      locations = cells_body(rows = seq(1, n_rows, 2))
    )    
}

penguins_gt |> 
  gt_theme_hangul()
남극 펭귄 서식섬과 종 빈도표
palmerpenguins 데이터 패키지
Biscoe Dream Torgersen
Adelie 44 56 52
Chinstrap 0 68 0
Gentoo 124 0 0
합계 168 124 52
자료출처: penguins 데이터셋

17.4 .Rprofile 설정작업

.Rprofile 파일에 테마 함수를 반영시키면 R 세션을 시작할 때마다 테마가 자동으로 로드되어 일일이 코드를 실행할 필요가 없어 작업 효율성을 크게 높여줌은 물론, 프로젝트 간 일관된 스타일과 브랜딩을 유지할 수 있다. 코드 작성 측면에서 테마 함수를 .Rprofile에 추가하여 코드 재사용성을 높이고, 테마 관련 설정을 한 곳에서 관리할 수 있게 함으로써 작업 일관성과 전문성이 높아져 시간과 노력을 크게 절약할 수 있다.

gt 표 테마 적용 작업흐름

작성한 테마를 매번 코드를 “복사하여 붙여넣기” 하여 사용하는 대신 .Rprofile 파일에 반영하여 매번 gt 표를 제작할 때마다 gt_theme_hangul() 테마를 적용하는 방법은 다음과 같다. 먼저, usethis 패키지 edit_r_profile() 함수를 호출하여 앞서 작성한 테마를 반영한다.

usethis::edit_r_profile()

gt_theme_hangul() 테마를 gt 표 객체에 반영한다. 스크립트에서부터 시작하여 작성한 함수를 .Rprofile 파일에 복사하여 붙여넣는 것으로 작업은 완료된다.

library(gt)
library(gtExtras)

gt_theme_hangul <- function(gt_tbl) {

  # Grab number of rows of data from gt object
  n_rows <- nrow(gt_tbl$`_data`)

  gt_tbl |>
    gt_theme_538() |>
    tab_options(
      # column_labels.background.color = '#1E61B0', # R logo 파란색
      table.font.names ="NanumSquare",
      heading.title.font.size = px(26),
      heading.subtitle.font.size = px(16),
      heading.background.color = "transparent",
      column_labels.font.weight = 'bold',
      table_body.hlines.width = px(0),
      data_row.padding = px(6),
      heading.align = 'center',
      stub.background.color = "#ffffff",
      stub.font.weight = "bold",
      source_notes.font.size = px(10),
      row.striping.include_table_body = FALSE
    ) |>
    cols_align( align = "center", columns = where(is.numeric)) |>
    cols_align( align = "auto", columns = where(is.character)) |>
    ## 글꼴 달리 적용
    tab_style(
      style = cell_text(
        font = "MaruBuri",
        weight = 'bold'
      ),
      locations = cells_title(groups = 'subtitle')
    ) |>
    tab_style(
      style = cell_text(
        font = "MaruBuri",
        weight = 'bold'
      ),
      locations = cells_body()
    ) |>
    tab_style(
      style = cell_text(
        font = "MaruBuri",
        weight = 'bold'
      ),
      locations = cells_column_labels()
    ) |>
    tab_style(
      style = cell_text(
        font = "MaruBuri",
      ),
      locations = cells_source_notes()
    ) |>
    tab_style(
      style = cell_fill(color = 'grey90'),
      locations = cells_body(rows = seq(1, n_rows, 2))
    )
}

.Rprofile 파일에 gt 사용자 정의 테마가 지정되어 있기 때문에 새로 R 세션을 시작하면 gt_theme_hangul() 테마를 프로젝트 어디에서든지 사용할 수 있다.

original_penguins_gt <- penguins |> 
  drop_na() |> 
  count(species, sex) |> 
  pivot_wider(names_from = sex, values_from = n, values_fill = 0) |> 
  janitor::adorn_totals(where = "col", name = "합계") |> 
  rename(펭귄종 = species, 암컷 = female, 수컷 = male) |> 
  as_tibble() |> 
  gt(rowname_col = "펭귄종") |> 
    tab_header(
      title = md("남극 펭귄 **암수와 종** 빈도표"),
      subtitle = md("`palmerpenguins` 데이터 패키지")
    ) |> 
    grand_summary_rows(
      columns = c(펭귄종, 암컷, 수컷),
      fns = list(
        '합계' = ~sum(.) 
      ),
      fmt = ~ fmt_number(., use_seps = FALSE, decimals = 0),
      missing_text = '-'
    )  |> 
    cols_align("center") |> 
    opt_row_striping() |> 
    tab_source_note(
      source_note = md("자료출처: `penguins` 데이터셋")
  )

original_penguins_gt |> 
  gtsave("images/rprofile_original.png")

theme_penguins_gt <- original_penguins_gt |> 
  gt_theme_hangul()

theme_penguins_gt |> 
  gtsave("images/rprofile_hangul_theme.png")

gt_theme_hangul() 테마 적용 전

 

gt_theme_hangul() 테마 적용 후