11  표 테마

이전 장에서 우리는 적절한 글꼴, 색상, 테마를 사용한 그래프가 데이터 시각화에서 얼마나 중요한지 살펴봤다. 이번 장에서는 문서를 구성하는 또 다른 중요한 요소인 ‘표(table)’, 특히 ‘gt’ (grammar of tables) 테마를 중심으로 살펴볼 것이다. 표는 복잡한 데이터를 정리하고 분석하는 데 없어서는 안 될 도구다. ’gt’는 표 구성과 디자인에 대한 체계적인 접근 방법을 제공함으로써 표를 통해 효과적으로 정보를 전달할 수 있을 뿐만 아니라 시각적으로 미려한 표를 만들 수 있다는 점에서 매우 유용하다.

문서에 표를 넣으면 정보를 효과적으로 요약하고 가독성을 크게 높일 수 있다. 표를 만들 때 사용할 수 있는 도구로는 마크다운(Markdown), gt 패키지, \(\LaTeX\)이 있는데, 각각 독특한 장점이 있다. 마크다운은 사용하기 쉽고 복잡한 설치나 추가 패키지 없이 기본적인 표를 신속하게 만들 수 있다. 반면 \(\LaTeX\)은 논문이나 학술 자료에 적합하도록 고급 품질의 표를 만들 수 있는 전문적인 도구다. 그래프 문법이 정립된 이후 가장 최근에 소개된 gt는 마크다운의 간편함과 \(\LaTeX\)과 같은 전문적인 표를 만들 수 있는 기능을 모두 갖추고 있다.

그림 11.1: 표제작 세가지 방식

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

11.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)

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 데이터셋
표 11.1: gt 패키지 활용 표 제작 사례

11.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"))
}
그림 11.2: 색상별 gt

11.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"))
}
그림 11.3: 스타일별 gt

11.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"))
}
그림 11.4: gtExtras 테마 적용 표

11.3 사용자 정의 테마

사용자 정의 테마의 필요성은 다양하며 주로 보고서나 PPT 발표에서 중요한 역할을 한다. 동일한 스타일과 구성을 가진 표를 사용하면 데이터를 쉽고 빠르게 이해할 수 있고, 일관된 스타일은 전문성을 강조하고, 독자에게 깊은 인상을 남길 수 있다.

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

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

11.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(
    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")
표 11.2: gt 사용자 정의 테마 적용 표

11.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(
      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 데이터셋
그림 11.5: 사용자 정의 gt 테마 적용 사례

11.4 .Rprofile 설정작업

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

graph LR;

  A["테마 스크립트 <br>생성"] --> B["테마 함수<br> 작성"];
  B --> C[".Rprofile <br> 파일 반영"];
  C --> D["테마 자동 <br> 로딩"];
  D --> E["프로젝트 <br> 테마 적용"];
그림 11.6: 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")
그림 11.7: gt_theme_hangul() 테마 적용 전

 

그림 11.8: gt_theme_hangul() 테마 적용 후

연습문제

객관식

  1. gt 패키지는 어떤 프로그래밍 언어의 생태계에 속해 있나요?
    1. Python
    2. R
    3. JavaScript
    4. C++
  1. gtExtras 패키지의 주요 기능은 무엇인가요?
    1. 데이터 처리 속도 향상
    2. 표 시각화 향상
    3. 통계 분석 기능 추가
    4. 자동 코드 생성
  1. 사용자 정의 테마를 개발하는 이유는 무엇인가요?
    1. 속도 최적화
    2. 보안 강화
    3. 개성과 전문성 반영
    4. 호환성 향상

서술형

  1. gt 패키지를 사용하여 표를 제작할 때 고려해야 할 디자인 요소들은 무엇인가요?
  1. gtExtras 패키지를 사용하여 표에 적용할 수 있는 다양한 테마의 예시를 들어보세요.