챗GPT 데이터 시각화

데이터 시각화 어디까지 보고 오셨어요?

이광춘

한국 R 사용자회

2024년 6월 25일

목차

  1. 데이터 시각화 (이광춘, 2018)

  2. 데이터 시각화 + 저널리즘

  3. 데이터 시각화 + 저널리즘 + 챗GPT

  4. ggplot 데이터 시각화

  5. 질의응답!

2023년 챗GPT 데이터 사이언스



서울 R 미트업 (2023년)

참여와 연대

  • 서울R미트업 meetup.com: link
    • 23년 4월 서울 R 미트업: link
    • 23년 5월 서울 R 미트업: link
    • 23년 6월 서울 R 미트업: link
    • 23년 7월 서울 R 미트업: link
    • 23년 8월 서울 R 미트업: link
    • 23년 9월 서울 R 미트업: link
  • 세계 R 미트업 현황 (Global R Meetup Dashboard): link
  • 한국 R 사용자회 (Korea R User Group): link
  • 한국 R 컨퍼런스 (Korea R Conference): link
  • 유튜브 채널 (Youtube Channel): link
  • 페이스북 그룹 (Facebook Group): link

2024년 인공지능 데이터 사이언스



서울 R 미트업

참여와 연대

  • 서울R미트업 meetup.com: link
    • 23년 4월 서울 R 미트업: link
    • 23년 5월 서울 R 미트업: link
    • 23년 6월 서울 R 미트업: link
    • 23년 7월 서울 R 미트업: link
    • 23년 8월 서울 R 미트업: link
    • 23년 9월 서울 R 미트업: link
  • Resources for General Help with R - Regional R communities link
  • 세계 R 미트업 현황 (Global R Meetup Dashboard): link
  • 한국 R 사용자회 (Korea R User Group): link
  • 한국 R 컨퍼런스 (Korea R Conference): link
  • 유튜브 채널 (Youtube Channel): link
  • 페이스북 그룹 (Facebook Group): link

데이터 시각화

정적 그래프


library(tidyverse)
library(plotly)
library(gapminder)
library(crosstalk)
library(leaflet)
library(flipbookr)

gapminder %>% 
  ggplot(aes(x=year, 
             y=lifeExp, 
             group=country)) + 
    geom_line()
그림 1

인터랙티브 그래프

p <- gapminder %>% 
  ggplot(aes(x=year, 
             y=lifeExp, 
             group=country)) + 
    geom_line()

ggplotly(p)

인터랙티브 그래프 - 툴팁(Tooltip) 기능

p <- gapminder %>% 
  ggplot(aes(
    x = year, 
    y = lifeExp, 
    group = country, 
    text = paste0("대륙: ", continent, "\n",  
                  "국가: ", country))) + 
  geom_line()

ggplotly(p, tooltip = "text")

강조(Highlight) 기능

gm_highlight <- highlight_key(gapminder, 
                              ~country)

life_g <- gm_highlight %>% 
  ggplot(aes(
    x=year, 
    y=lifeExp, 
    group=country, 
    text=paste0("대륙: ", continent, "\n",
               "국가: ", country))) + 
  geom_line()

life_gg <- ggplotly(life_g, tooltip = "text")
highlight(life_gg, on = "plotly_click", 
          selectize = TRUE, 
          dynamic = TRUE, 
          persistent = TRUE)

연결뷰(Linked View) 기능

gapminder_cjk <- gapminder %>% 
  filter(country %in% c("China", "Japan", 
                        "Korea, Rep."))

gapminder_sd <- SharedData$new(gapminder_cjk, 
                               ~country)

life_g <- gapminder_sd %>% 
  ggplot(aes(
    x = year, 
    y = lifeExp, 
    group = country,
    text = paste0("대륙: ", continent, "\n", 
                  "국가: ", country))) + 
  geom_line() +
  geom_point() +
  facet_wrap(~country)

ggplotly(life_g, tooltip = "text")

삼국지

library(crosstalk); library(DT)
### 1. 공유 데이터
general_sd_df <- general_df %>% select(삼국, 무장, 무력, 지력, 통솔, 생년)
sam_sd <- SharedData$new(general_sd_df)

### 2. 제어
sam_ctrl <- filter_checkbox("삼국", "위촉오", sam_sd, ~삼국, inline = TRUE)
year_ctrl <- filter_slider("생년", "출생년도", sam_sd, ~생년, width = "50%")

### 3. 표
sam_tbl <- sam_sd |> 
  datatable( extensions="Scroller", style="bootstrap", class="compact", width="100%",
             options=list(deferRender=TRUE, scrollY=300, scroller=TRUE))

### 4. 시각화
force_g <- ggplot(sam_sd, aes(x=무력, y=통솔, color=삼국,
                              text = paste('이름 :', 무장, "\n",
                                           '무력:', 무력, "\n",
                                           '지력:', 지력, "\n",
                                           '통솔:', 통솔, "\n"))) +
  geom_point() +
  theme(legend.position = "none") +
  labs(x="무력", y="통솔") +
  scale_color_manual(values = c("red", "green", "blue"))

force_gg <- ggplotly(force_g, tooltip = "text")

### 5. 인터랙티브 시각화
bscols(widths = c(2, 5, 5),
       list(year_ctrl, sam_ctrl),
       sam_tbl, force_gg)

삼국지

애니메이션

library(tidyverse)
library(gapminder)
library(plotly)

life_g <- gapminder %>% 
  ggplot(aes(
    x = gdpPercap, 
    y = lifeExp, 
    group = country, color=country,
    text=paste0("대륙: ", continent, "\n", 
                 "국가: ", country))) + 
    geom_point(alpha = 0.2) +
    geom_point() +
    facet_wrap(~continent, ncol = 2) +
    scale_x_sqrt() +
    theme(legend.position = "none")

ggplotly(life_g, tooltip="text")

애니메이션

frame= 매개변수만 넣으면 됨.

library(tidyverse)
library(gapminder)
library(plotly)

life_g <- gapminder %>% 
  ggplot(aes(
    x = gdpPercap, 
    y = lifeExp, 
    group = country, color=country,
    text=paste0("대륙: ", continent, "\n", 
                 "국가: ", country))) + 
    geom_point(alpha = 0.2) +
    geom_point(aes(frame = year), color="red") +
    facet_wrap(~continent, ncol = 2) +
    scale_x_sqrt() +
    theme(legend.position = "none")

ggplotly(life_g, tooltip="text")

애니메이션 - 2017년 버전

crosstalk

library(crosstalk); library(plotly); library(leaflet); library(palmerpenguins)
penguins <- na.omit(penguins)  # Remove missing data for simplicity

penguins$longitude <- rnorm(nrow(penguins), mean = -64, sd = 0.1)
penguins$latitude <- rnorm(nrow(penguins), mean = -64, sd = 0.1)

# Create a shared data object
sd_penguins <- SharedData$new(penguins)

# Plot with plotly
penguin_plot <- plot_ly(sd_penguins, x = ~bill_length_mm, y = ~flipper_length_mm, 
    color = ~species, 
    text = ~paste("Body Mass:", body_mass_g), 
    type = 'scatter', mode = 'markers') %>% 
    add_markers() %>% highlight("plotly_selected")

# Map with leaflet
penguin_map <- leaflet(sd_penguins) %>% addTiles() %>% 
    addCircles(lng = ~longitude, lat = ~latitude, 
    weight = 1, radius = 40, popup = ~species)

# Combine both using crosstalk
bscols(widths = c(6, 6), penguin_plot, penguin_map)

crosstalk

지도 - BitSpatial

library(tidyverse);library(sf);library(bitSpatial);library(ggiraph)

start_gg <- bitSpatial::admi |> 
  ggplot(aes(geometry = geometry)) +
    geom_sf(
      data = bitSpatial::mega,
      aes(fill = mega_nm), color = 'black', linewidth = 0.5
    ) +
    geom_sf(fill = NA, color = 'black', linewidth = 0.1)

# 인터랙티브 지도
map_gg <- bitSpatial::admi |> 
  ggplot(aes(geometry = geometry)) +
    geom_sf(
      data = bitSpatial::mega,
      aes(fill = mega_nm), color = 'black', linewidth = 0.5 ) +
    geom_sf(fill = NA, color = 'black', linewidth = 0.1 ) +
    geom_sf_interactive(fill = NA,   
      aes(data_id = cty_cd, tooltip = glue::glue('{mega_nm}<br>{cty_nm}')),
      linewidth = 0.1
    ) +
    theme_void() +
    theme(legend.position = 'none') +
    scale_fill_manual(
        values = c("#A0CBE8FF", "#F28E2BFF", "#FFBE7DFF", "#59A14FFF", "#8CD17DFF", "#B6992DFF", "#F1CE63FF", "#499894FF", "#86BCB6FF", "#E15759FF", "#FF9D9AFF", "#79706EFF", "#BAB0ACFF", "#D37295FF", "#B07AA1FF", "#D4A6C8FF", "#9D7660FF") )  

girafe(ggobj = map_gg,
  options = list(opts_hover(
      css = girafe_css(css = '', area = 'stroke: black; fill: black;'))))

지도 - BitSpatial

그림 2

로고 + 막대그래프

library(tidyverse)

dat <- tribble( ~neo_bank, ~market_cap_bn, ~logo_url,
  "Nubank", 45, "https://upload.wikimedia.org/wikipedia/commons/f/f7/Nubank_logo_2021.svg",
  "Revolut", 33, "https://upload.wikimedia.org/wikipedia/commons/d/d6/Revolut.svg",
  "Chime", 25, "https://upload.wikimedia.org/wikipedia/commons/f/f6/Chime_company_logo.svg",
  "WeBank", 21, "https://upload.wikimedia.org/wikipedia/en/e/eb/WeBank_Logo.svg",
  "Kakaobank", 19, "https://upload.wikimedia.org/wikipedia/commons/4/48/KakaoBank_logo.svg",
  "Robinhood", 10, "https://upload.wikimedia.org/wikipedia/commons/d/da/Robinhood_%28company%29_logo.svg",
  "SoFi", 10, "https://upload.wikimedia.org/wikipedia/commons/1/16/SoFi_logo.svg",
  "Tinkoff", 9, "https://upload.wikimedia.org/wikipedia/commons/1/19/Tinkoff_logo_2024.svg",
  "N26", 9, "https://upload.wikimedia.org/wikipedia/commons/b/bf/N26_logo_2019.svg",
  "K Bank", 7, "https://upload.wikimedia.org/wikipedia/commons/2/26/Kbank_logo.svg"
) 

map(dat$logo_url, magick::image_read_svg) |>
  walk2(
    dat$neo_bank,
    \(x, y) magick::image_write(x, path = paste0("img/logos/", y, ".png"))
  )

dat |> 
  mutate(neo_bank = fct_reorder(neo_bank, market_cap_bn)) |>
  ggplot(aes(x = market_cap_bn, y = neo_bank))  +
  geom_col() +
  scale_y_discrete(
    labels = \(x) glue::glue("<img src='img/logos/{x}.png' height=20 />")
  ) +
  theme_minimal(base_size = 12,  base_family = 'Source Sans Pro') +
  labs(
    title = 'Top 10 neobanks worldwide by market capitalization 2022',
    y = element_blank()) +
  theme(axis.text.y = ggtext::element_markdown())

로고 + 막대그래프

인터랙티브 그래프

library(tidyverse); library(palmerpenguins); library(ggiraph); library(patchwork)
color_palette <- thematic::okabe_ito(3)

scatter_gg <- penguins |> drop_na() |>
  ggplot(aes(x = flipper_length_mm, y = body_mass_g, color = species, data_id = species)) +
  geom_point_interactive(size = 1) +
  labs(title = "펭귄의 지느러미 길이와 몸무게",
       x = "지느러미 길이 (mm)", y = "몸무게 (g)", color = "종") +
  theme_minimal(base_size = 5) +
  theme(legend.position = "top") +
  scale_color_manual(values = color_palette) +
  scale_y_continuous(labels = scales::comma) 

boxplot_gg <- penguins |> drop_na() |> 
  ggplot(aes(x = species, y = body_mass_g, fill = species,  data_id = species)) +
  geom_boxplot_interactive() +  
  geom_jitter_interactive(aes(col = species)) +
  labs(title = "펭귄 종별 몸무게",
       x = "펭귄 종명", y = "몸무게 (g)", color = "종") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none") +
  scale_fill_manual(values = color_palette) +
  scale_color_manual(values = color_palette) +
  scale_y_continuous(labels = scales::comma) +
  coord_flip()

girafe(
  ggobj = boxplot_gg + plot_spacer() + scatter_gg + plot_layout(widths = c(0.45, 0.1, 0.45)),
  options = list(
    opts_hover(css = ''), opts_hover_inv(css = "opacity:0.1;"), 
    opts_sizing(rescale = FALSE)
  ))

인터랙티브 그래프

그림 4: 산점도와 상자그림

데이터 시각화 + 저널리즘

문 대통령 해외순방

library(tidyverse)
library(rvest)

moon_html <- read_html("https://ko.wikipedia.org/wiki/문재인의_대통령_순방_목록")

moon_raw <- moon_html |> 
  html_elements("table") |> 
  html_table()

moon_h3 <- moon_html |> 
  html_elements("h3") |> 
  html_text()

names(moon_raw) <- moon_h3[1:6]

moon_tbl <- moon_h3 |> 
  enframe() |> 
  mutate(연도 = str_remove(value, "년\\[편집\\]")) |> 
  filter(str_detect(연도, "\\d{4}")) |> 
  mutate(data = moon_raw[c(1:5)]) |> 
  unnest(data) |> 
  select(연도, 나라, 장소, 일자, 세부내용=`세부 내용`) |>
  separate(일자, into = c("출국", "도착"), sep = "~") |> 
  mutate(도착 = ifelse(is.na(도착), 출국, 도착)) |> 
  mutate(출국일 = str_glue("{연도}-{출국}"),
         도착일 = str_glue("{연도}-{도착}")) |> 
  mutate(출국일 = parse_date(출국일, "%Y-%m월 %d일"),
         도착일 = parse_date(도착일, "%Y-%m월 %d일")) |> 
  select(출국일, 도착일, 국가 = 나라, 장소) |> 
  mutate(기간 = (출국일 %--% 도착일) / ddays(1) +1)

moon_tbl |> slice(1:5) |>  gt::gt()
출국일 도착일 국가 장소 기간
2017-06-28 2017-07-03 미국 워싱턴 D.C. 6
2017-07-05 2017-07-08 독일 베를린, 함부르크 4
2017-09-06 2017-09-07 러시아 블라디보스토크 2
2017-09-19 2017-09-21 미국 뉴욕 3
2017-11-08 2017-11-10 인도네시아 자카르타 3
library(countrycode)
library(gt)
library(gtExtras)

country_codes <- data.frame(
  "국가" = c("노르웨이", "뉴질랜드", "덴마크", "독일", "라오스", "러시아", "말레이시아", "미국", "미얀마", "바티칸 시국", "베트남", "벨기에", "브루나이", "사우디아라비아", "스웨덴", "스페인", "싱가포르", "아랍에미리트", "아르헨티나", "영국", "오스트레일리아", "오스트리아", "우즈베키스탄", "이집트", "이탈리아", "인도", "인도네시아", "일본", "조선민주주의인민공화국", "중화인민공화국", "체코", "카자흐스탄", "캄보디아", "태국", "투르크메니스탄", "파푸아뉴기니", "프랑스", "핀란드", "필리핀", "헝가리"),
  "영문_국가명" = c("Norway", "New Zealand", "Denmark", "Germany", "Laos", "Russia", "Malaysia", "United States", "Myanmar", "Vatican City", "Vietnam", "Belgium", "Brunei", "Saudi Arabia", "Sweden", "Spain", "Singapore", "United Arab Emirates", "Argentina", "United Kingdom", "Australia", "Austria", "Uzbekistan", "Egypt", "Italy", "India", "Indonesia", "Japan", "North Korea", "China", "Czech Republic", "Kazakhstan", "Cambodia", "Thailand", "Turkmenistan", "Papua New Guinea", "France", "Finland", "Philippines", "Hungary"),
  "iso2c" = c("NO", "NZ", "DK", "DE", "LA", "RU", "MY", "US", "MM", "VA", "VN", "BE", "BN", "SA", "SE", "ES", "SG", "AE", "AR", "GB", "AU", "AT", "UZ", "EG", "IT", "IN", "ID", "JP", "KP", "CN", "CZ", "KZ", "KH", "TH", "TM", "PG", "FR", "FI", "PH", "HU")
)

moon_tbl |> 
  group_by(국가) |> 
  summarise(방문수 = n(),
            연도 = str_c(str_glue("{lubridate::year(출국일)}"), collapse = ",")) |> 
  left_join(country_codes, by = "국가") |> 
  mutate(대륙 = countrycode(iso2c, "iso2c", "continent")) |>
  arrange(desc(방문수)) |>
  select(-영문_국가명) |> 
  select(iso2c, everything()) |> 
  filter(대륙 %in% c("Americas", "Oceania")) |> 
  gt(groupname_col = "대륙") |> 
  fmt_flag(columns = iso2c) |> 
  cols_label(
    iso2c = ""
  ) |> 
  cols_align("center") |> 
  tab_header(
    title = md("문재인 대통령 해외 순방"),
    subtitle = md("2017년 5월 10일 ~ 2021년 5월 9일")
  ) |>
tab_footnote(
  footnote = md("데이터 출처: [위키백과](https://ko.wikipedia.org/wiki/문재인의_대통령_순방_목록)")
) |>   
  gt_theme_538() |> 
  ## 표 전체 합계 -------------------------------------
  grand_summary_rows(
    columns = 방문수,
    fns =  list(label = "", fn = "sum"),
    fmt = ~ fmt_integer(.),
    side = "bottom"
  )
문재인 대통령 해외 순방
2017년 5월 10일 ~ 2021년 5월 9일
국가 방문수 연도
Americas
미국 8 2017,2017,2018,2018,2019,2019,2021,2021
아르헨티나 1 2018
Oceania
뉴질랜드 1 2018
오스트레일리아 1 2021
파푸아뉴기니 1 2018
12
데이터 출처: 위키백과
library(viridis); library(sf); sf_use_s2(FALSE)

moon_tour <- moon_tbl |> group_by(국가) |> 
  summarise(방문수 = n(),
            연도 = str_c(str_glue("{lubridate::year(출국일)}"), collapse = ",")) |> 
  left_join(country_codes, by = "국가")

world_map <- rnaturalearth::ne_countries(scale = 50, returnclass = "sf")
country_centroid <- inner_join(st_centroid(world_map), moon_tour, 
                              by = c("iso_a2" = "iso2c"))

country_centroid <- bind_cols(country_centroid,
          st_coordinates(country_centroid) |> 
          as_tibble() |> set_names(c("lon", "lat")))

moon_map <- left_join(world_map, moon_tour, by = c("iso_a2" = "iso2c"))

moon_map |> 
  filter(continent != "Antarctica") |> 
  mutate(방문수 = factor(방문수, levels = c(1, 2, 8),
                      labels = c("1회", "2회", "8회"))) |>
  ggplot() +
    geom_sf(aes(fill = 방문수)) +
    scale_fill_manual(values = c("gray50", "skyblue", "blue"), 
                      na.value = "transparent",
                      breaks = c("1회", "2회", "8회", NA),
                      labels = c("1회", "2회", "8회", "방문 없음")) +
    labs(title = "문재인 대통령 해외순방") +
    theme_void(base_family = "NanumGothic") +
    theme(legend.position = "bottom") +
    ggrepel::geom_text_repel(
      data = country_centroid |> select(국가, lon, lat) |> st_drop_geometry(),
          aes(label = 국가, x = lon, y = lat), size = 3, segment.size = 0.2)

offset <- 180 - 150

polygon <- st_polygon(x = list(rbind(
  c(-0.0001 - offset, 90), c(0 - offset, 90),
  c(0 - offset, -90), c(-0.0001 - offset, -90),
  c(-0.0001 - offset, 90) ))) %>%
  st_sfc() %>% st_set_crs(4326)

world_pacific <- world_map |> 
  st_difference(polygon) |> st_transform(crs = "+proj=eqc +x_0=0 +y_0=0 +lat_0=0 +lon_0=150")

moon_pacific_map <- left_join(world_pacific, moon_tour, by = c("iso_a2" = "iso2c"))

pacific_centroid <- inner_join(st_centroid(moon_pacific_map), moon_tour, by = c("iso_a2" = "iso2c"))

pacific_country_centroid <- bind_cols(pacific_centroid,
    st_coordinates(pacific_centroid) |> as_tibble() |> set_names(c("lon", "lat")))


moon_pacific_map |> 
  mutate(방문수 = factor(방문수, levels = c(1, 2, 8),  labels = c("1회", "2회", "8회"))) |>
  ggplot() +
    geom_sf(aes(fill = 방문수)) +
    scale_fill_manual(values = c("gray50", "skyblue", "blue"), 
                      na.value = "transparent",
                      breaks = c("1회", "2회", "8회", NA),
                      labels = c("1회", "2회", "8회", "방문 없음")) +
    theme_void(base_family = "NanumGothic") +
    theme(legend.position = "bottom") +
    ggrepel::geom_text_repel(
      data = pacific_country_centroid |> select(국가.x, lon, lat) |> st_drop_geometry(),
          aes(label = 국가.x, x = lon, y = lat), size = 3, segment.size = 0.2)

K-POP 빌보드 HOT 100

graph TD
    A[나무위키 <br> 크롤링]
    A --> C[데이터 전처리<br>데이터프레임]
    C --> E[Billboard API]
    C --> F[데이터 시각화<br> ggplot + gt]
    F --> G[대시보드<br>Quarto 문서 작성]
    E --> G
    G --> I[gh-pages 배포]

데이터 시각화 + 저널리즘 +
챗GPT

OpenAI Advanced Data Analysis


Open AI Code Interpreter → Advanced Data Analysis → 챗GPT4


RStudio Copilot

Tools -> Global Options -> Copilot -> Enable Github Copilot

웹앱(Shiny App) 개발 사례

광명시 보좌관

RTutor & PandasAI

ggplot 데이터 시각화

더블 다이아몬드

워드 클라우드

library(ggwordcloud)

yoon_tbl |> 
  ggplot(aes(label = 키워드, size = n, color = I("red"))) +
    geom_text_wordcloud_area(rm_outside = TRUE) +
    scale_size_area(max_size = 80) +
    facet_wrap(~ 연도) +
    theme_minimal() +
    labs(title = "윤석열 대통령 연도별 워드 클라우드")

지도

library(bitSpatial)

bitSpatial::admi |> 
  select(base_ym, mega_nm, cty_nm, admi_nm, geometry)
#> Simple feature collection with 3528 features and 4 fields
#> Geometry type: GEOMETRY
#> Dimension:     XY
#> Bounding box:  xmin: 124.6117 ymin: 33.11238 xmax: 130.9401 ymax: 38.61369
#> Geodetic CRS:  WGS 84
#> # A tibble: 3,528 × 5
#>    base_ym mega_nm    cty_nm admi_nm                                    geometry
#>    <chr>   <chr>      <chr>  <chr>                                 <POLYGON [°]>
#>  1 202306  서울특별시 종로구 사직동    ((126.9771 37.5758, 126.9744 37.57607, 1…
#>  2 202306  서울특별시 종로구 삼청동    ((126.9736 37.59327, 126.9756 37.58968, …
#>  3 202306  서울특별시 종로구 부암동    ((126.9772 37.59865, 126.9711 37.60078, …
#>  4 202306  서울특별시 종로구 평창동    ((126.98 37.62828, 126.975 37.62903, 126…
#>  5 202306  서울특별시 용산구 한남동    ((127.0057 37.5477, 127.0043 37.5502, 12…
#>  6 202306  서울특별시 성동구 왕십리2동 ((127.0336 37.56263, 127.0268 37.56496, …
#>  7 202306  서울특별시 성동구 마장동    ((127.0381 37.57227, 127.0322 37.57009, …
#>  8 202306  서울특별시 중구   중림동    ((126.9709 37.55937, 126.9695 37.56198, …
#>  9 202306  서울특별시 성동구 옥수동    ((127.0154 37.54825, 127.0131 37.55005, …
#> 10 202306  서울특별시 중구   장충동    ((127.0096 37.56303, 127.0012 37.56286, …
#> # ℹ 3,518 more rows
library(bitSpatial)
library(sf)

bitSpatial::admi |> 
  dplyr::select(base_ym, mega_nm, cty_nm, admi_nm, geometry) |> 
  dplyr::filter(mega_nm %in% c("부산광역시", "대구광역시", "울산광역시", "강원특별자치도", "경상북도", "경상남도")) |>
  group_by(mega_nm) |> 
  summarise(geometry = st_union(geometry)) |>
  st_geometry() |> 
  plot()

The webR Application 🔗 https://webr.r-wasm.org/v0.3.2/

WebR

shinylive-r

#| label: shinylive-esquisse
#| viewerWidth: 600
#| viewerHeight: 500
#| standalone: true

library(esquisse)
library(shiny)
library(ggplot2)
library(showtext)
showtext_auto()

ui <- fluidPage(
  titlePanel("Graph with esquisse"),
  sidebarLayout(
    sidebarPanel(
      fileInput("file", "Choose CSV File",
                accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")),
      radioButtons(
        inputId = "data",
        label = "Select data to use:",
        choices = c("mpg", "diamonds", "economics", "Uploaded Data" = "uploaded_data")
      )
    ),
    mainPanel(
      tabsetPanel(
        tabPanel(
          title = "esquisse",
          esquisse_ui(
            id = "esquisse",
            header = FALSE # dont display gadget title
          )
        ),
        tabPanel(
          title = "output",
          tags$b("Code:"),
          verbatimTextOutput("code"),
          tags$b("Filters:"),
          verbatimTextOutput("filters"),
          tags$b("Data:"),
          verbatimTextOutput("data")
        )
      )
    )
  )
)

server <- function(input, output, session) {
  data_r <- reactiveValues(data = iris, name = "iris")

  observeEvent(input$file, {
    req(input$file)
    data_r$data <- read.csv(input$file$datapath)
    data_r$name <- "uploaded_data"
  })

  observe({
    if (input$data != "uploaded_data") {
      data_r$data <- get(input$data)
      data_r$name <- input$data
    }
  })

  results <- esquisse_server(
    id = "esquisse",
    data_rv = data_r
  )

  output$code <- renderPrint({
    results$code_plot
  })

  output$filters <- renderPrint({
    results$code_filters
  })

  output$data <- renderPrint({
    str(results$data)
  })
}

shinyApp(ui, server)

참고문헌

이광춘. (2018). 데이터 과학자의 시각화. 데이터야 놀자 컨퍼런스. https://statkclee.github.io/ds-authoring/ds_data_scientist_visualization.html
이현진. (2024). 데이터 드리븐 디자인 (1판 ed). 출판 진행중.