39 Biểu đồ tương tác

Trực quan hóa dữ liệu ngày càng đòi hỏi có khả năng truy vấn được bởi người đọc. Hệ quả là, các biểu đồ tương tác ngày càng được tạo ra nhiều hơn. Có nhiều cách để tạo biểu đồ tương tác, nhưng hai cách phổ biến nhất là sử dụng package plotlyshiny.

Trong chương này chúng ta sẽ tập trung vào việc chuyển đổi một biểu đồ có sẵn được tạo bởi ggplot() thành một biểu đồ tương tác với plotly. Bạn có thể đọc thêm về shiny trong chương Dashboards với Shiny. Cũng cần nhấn mạnh là biểu đồ tương tác chỉ sử dụng được ở định dạng HTML trong tệp R markdown và không dùng được với tệp PDF hoặc Word.

Dưới đây là một đường cong dịch bệnh đơn giản đã được biến đổi thành thành biểu đồ tương tác với sự kết hợp của ggplot2plotly (hover trỏ chuột phía trên biểu đồ, phóng to, hoặc nhấp vào một item trong chú thích).

39.1 Chuẩn bị

Gọi packages

Đoạn code này hiển thị việc gọi các package cần thiết cho các phân tích. Trong cuốn sách này, chúng tôi nhấn mạnh việc sử dụng hàm p_load() từ package pacman, giúp cài đặt các package cần thiết gọi chúng ra để sử dụng. Bạn cũng có thể gọi các packages đã cài đặt với hàm library() của base R. Xem thêm chương R cơ bản để có thêm thông tin về các packages trong R.

pacman::p_load(
  rio,       # import/export
  here,      # filepaths
  lubridate, # working with dates
  plotly,    # interactive plots
  scales,    # quick percents
  tidyverse  # data management and visualization
  ) 

Bắt đầu với ggplot()

Trong chương này chúng ta giả định rằng bạn đang bắt đầu với một biểu đồ tạo bởi ggplot() và muốn chuyển đổi nó thành biểu đồ tương tác. Chúng ta sẽ xây dựng một số biểu đồ như vậy trong chương này, sử dụng bộ dữ liệu linelist đã được đề cập ở rất nhiều chương trong cuốn sổ tay này.

Nhập dữ liệu

Để bắt đầu, chúng ta nhập bộ dữ liệu có tên linelist đã làm sạch bao gồm các trường hợp từ vụ dịch Ebola mô phỏng. Để tiện theo dõi, bấm để tải dữ liệu linelist “đã được làm sạch” (dưới dạng tệp .rds). Nhập dữ liệu bằng hàm import() từ package rio (nó xử lý nhiều loại tệp như .xlsx, .csv, .rds - xem thêm chương Nhập xuất dữ liệu để biết thêm chi tiết).

# import case linelist 
linelist <- import("linelist_cleaned.rds")

50 hàng đầu tiên của bộ dữ liệu được hiển thị như bên dưới.

39.2 Vẽ biểu đồ với ggplotly()

Hàm ggplotly() thuộc package plotly hỗ trợ chuyển đổi dễ dàng một biểu đồ ggplot() thành có tính tương tác. Đơn giản chỉ cần lưu biểu đồ ggplot() và sau đó pipe nó tới hàm ggplotly().

Dưới đây, chúng ta biểu diễn một đường đơn giản đại diện cho tỷ lệ các trường hợp tử vong trong một tuần xác định:

Chúng ta bắt đầu bằng cách tạo một bộ dữ liệu tổng hợp cho từng tuần dịch tễ học, và phần trăm các trường hợp có outcome là tử vong.

weekly_deaths <- linelist %>%
  group_by(epiweek = floor_date(date_onset, "week")) %>%  # create and group data by epiweek column
  summarise(                                              # create new summary data frame:
    n_known_outcome = sum(!is.na(outcome), na.rm=T),      # number of cases per group with known outcome
    n_death  = sum(outcome == "Death", na.rm=T),          # number of cases per group who died
    pct_death = 100*(n_death / n_known_outcome)           # percent of cases with known outcome who died
  )

Đây là 50 hàng đầu tiên của bộ dữ liệu weekly_deaths.

Sau đó chúng ta vẽ biểu đồ với hàm geom_line() thuộc ggplot2.

deaths_plot <- ggplot(data = weekly_deaths)+            # begin with weekly deaths data
  geom_line(mapping = aes(x = epiweek, y = pct_death))  # make line 

deaths_plot   # print

Chúng ta có thể tạo tính tương tác cho biểu đồ bằng cách chuyển nó tới hàm ggplotly() như dưới đây. Di chuyển trỏ chuột của bạn tới vị trí các đường để hiện thị giá trị x và y. Bạn có thể phóng to và kéo thả trong biểu đồ. Bạn cũng sẽ thấy các biểu tượng ở góc phải trên của biểu đồ. Theo thứ tự, chúng cho phép bạn:

  • Tải xuống trạng thái hiện tại của biểu đồ dưới dạng ảnh PNG
  • Phóng to với hộp thoại lựa chọn
  • “Pan”, hay còn gọi là di chuyển biểu đồ bằng cách nhấp và kéo thả biểu đồ
  • Phóng to, thu nhỏ, hoặc quay trở về mặc định
  • Reset trục về mặc định
  • Bật/tắt “spike lines - đường vnah đai”, là các đường chấm chấm mở rộng theo trục x và y từ các điểm tương tác
  • Điều chỉnh hiển thị dữ liệu ngay cả khi bạn không rê chuột tới đường thẳng
deaths_plot %>% plotly::ggplotly()

Dữ liệu được nhóm cũng hoạt động với hàm ggplotly(). Dưới đây đường cong dịch tễ theo tuần được tạo, nhóm theo outcome. Các cột chồng có tính tương tác. Hãy thử nhấp vào các items khác nhau trong phần chú giải (chúng sẽ xuất hiện/biến mất).

# Make epidemic curve with incidence2 pacakge
p <- incidence2::incidence(
  linelist,
  date_index = date_onset,
  interval = "weeks",
  groups = outcome) %>% plot(fill = outcome)
# Plot interactively  
p %>% plotly::ggplotly()

39.3 Điều chỉnh

Kích thước tệp

Khi xuất một tệp HTML sinh ra bởi một tệp R Markdown (như cuốn sách này!), bạn sẽ muốn dung lượng của biểu đồ nhỏ nhất có thể (mà không có các tác dụng phụ tiêu cực trong phần lớn trường hợp). Để làm điều này, chỉ cần pipe biểu đồ tương tác tới hàm partial_bundle(), cũng thuộc plotly.

p <- p %>% 
  plotly::ggplotly() %>%
  plotly::partial_bundle()

Nút bấm

Một số nút bẩm trong biểu đồ plotly khá thừa thải vã gây mất tập trung, vì vậy bạn có thể loại bỏ chúng. Đơn giản bạn chỉ cần piping đầu ra tới hàm config() thuộc plotly và cụ thể tên của nút bấm muốn loại bỏ. Trong ví dụ dưới đây, chúng ta cụ thể trước tên của nút bấm muốn loại bỏ vào một danh sách, sau đó cung cấp chúng tới đối số modeBarButtonsToRemove =. Chúng ta cũng thiết lập displaylogo = FALSE để loại bỏ logo của plotly.

## these buttons are distracting and we want to remove them
plotly_buttons_remove <- list('zoom2d','pan2d','lasso2d', 'select2d','zoomIn2d',
                              'zoomOut2d','autoScale2d','hoverClosestCartesian',
                              'toggleSpikelines','hoverCompareCartesian')

p <- p %>%          # re-define interactive plot without these buttons
  plotly::config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

39.4 Biểu đồ nhiệt

Bạn có thể khiến bất kỳ loại biểu đồ nào tạo bởi ggplot() có khả năng tương tác, bao gồm biểu đồ nhiệt. Trong chương [Biểu đò nhiệt], bạn có thể đọc thêm về cách tạo biểu đồ dưới đây để hiển thị tỷ lệ số ngày trong tuần mà các cơ sở y tế báo cáo dữ liệu lên tuyến tỉnh.

Sau đây là code, mặc dù chúng tôi sẽ không giải thích chi tiết tại đây.

# import data
facility_count_data <- rio::import(here::here("data", "malaria_facility_count_data.rds"))

# aggregate data into Weeks for Spring district
agg_weeks <- facility_count_data %>% 
  filter(District == "Spring",
         data_date < as.Date("2020-08-01")) %>% 
  mutate(week = aweek::date2week(
    data_date,
    start_date = "Monday",
    floor_day = TRUE,
    factor = TRUE)) %>% 
  group_by(location_name, week, .drop = F) %>%
  summarise(
    n_days          = 7,
    n_reports       = n(),
    malaria_tot     = sum(malaria_tot, na.rm = T),
    n_days_reported = length(unique(data_date)),
    p_days_reported = round(100*(n_days_reported / n_days))) %>% 
  right_join(tidyr::expand(., week, location_name)) %>% 
  mutate(week = aweek::week2date(week))

# create plot
metrics_plot <- ggplot(agg_weeks,
       aes(x = week,
           y = location_name,
           fill = p_days_reported))+
  geom_tile(colour="white")+
  scale_fill_gradient(low = "orange", high = "darkgreen", na.value = "grey80")+
  scale_x_date(expand = c(0,0),
               date_breaks = "2 weeks",
               date_labels = "%d\n%b")+
  theme_minimal()+ 
  theme(
    legend.title = element_text(size=12, face="bold"),
    legend.text  = element_text(size=10, face="bold"),
    legend.key.height = grid::unit(1,"cm"),
    legend.key.width  = grid::unit(0.6,"cm"),
    axis.text.x = element_text(size=12),
    axis.text.y = element_text(vjust=0.2),
    axis.ticks = element_line(size=0.4),
    axis.title = element_text(size=12, face="bold"),
    plot.title = element_text(hjust=0,size=14,face="bold"),
    plot.caption = element_text(hjust = 0, face = "italic")
    )+
  labs(x = "Week",
       y = "Facility name",
       fill = "Reporting\nperformance (%)",
       title = "Percent of days per week that facility reported data",
       subtitle = "District health facilities, April-May 2019",
       caption = "7-day weeks beginning on Mondays.")

metrics_plot # print

Sau đó, chúng tôi biến nó trở thành biểu đồ tương tác và điều chỉnh các nút bấm và dung lượng tệp.

metrics_plot %>% 
  plotly::ggplotly() %>% 
  plotly::partial_bundle() %>% 
  plotly::config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

–>

39.5 Tài nguyên học liệu

Plotly không chỉ dành riêng cho R mà còn hoạt động tốt với Python (và bất cứ ngôn ngữ khoa học dữ liệu nào khác bởi vì nó được xây dựng trên JavaScript). Bạn có thể tìm hiểu thêm về nở ở website của plotly