第 9 章 交互图形

plotly 包的函数使用起来还是比较复杂的,特别是需要打磨细节以打造数据产品时,此外,其依赖相当重,仅数据处理就包含两套方法 — dplyr 和 data.table,引起很多函数冲突,可谓「苦其久矣」!因此,准备另起炉灶,开发一个新的 R 包 qplotly,取意 quick plotly,以 qplot_ly() 替代 plot_ly()。类似简化 API 的工作有 simplevisautoplotlyggfortifyplotme

plotly 团队开发了 plotly.js 库,且维护了 R 接口文档 (https://plotly.com/r/),Carson Sievert 开发了 plotly 包,配套书 Interactive web-based data visualization with R, plotly, and shiny。 Paul C. Bauer 的书 Applied Data Visualization 介绍 plotly https://bookdown.org/paul/applied-data-visualization/what-is-plotly.html

echarts4r 包基于 Apache ECharts (incubating),ECharts 的 Python 接口 pyecharts 也非常受欢迎,基于 apexcharts.jsapexcharterECharts2Shiny 包将 ECharts 嵌入 shiny 框架中。

timevis 创建交互式的时间线的时序可视化,它基于 Visvis-timeline 模块,支持 shiny 集成。dygraphs 包基于 dygraphs 可视化库,将时序数据可视化,更多情况见 https://dygraphs.com/leaflet 提供 leaflet 的 R 接口。rAmCharts4 基于 amCharts 4 库, apexcharter 提供 apexcharts.js 的 R 接口。还有 billboarder 等。更完整地,请看 Etienne Bacher 维护的 R 包列表 r-js-adaptation

对于想了解 htmlwidgets 框架,JavaScript 响应式编程的读者,推荐 John Coene 新书 JavaScript for R

学习 plotlyhighcharter 为代表的 基于 JavaScript 的 R 包,共有四重境界:第一重是照着帮助文档的示例,示例有啥我们做啥;第二重是明白帮助文档中 R 函数和 JavaScript 函数的对应关系,能力达到 JS 库的功能边界;第三重是深度自定义一些扩展性的 JS 功能,放飞自我;第四重是重新造轮子,为所欲为。下面的介绍希望能帮助读者到达第二重境界。

plotly 是一个功能非常强大的绘制交互式图形的 R 包。它支持下载图片、添加水印、自定义背景图片、工具栏和注释34 等一系列细节的自定义控制。下面结合 JavaScript 库 plotly.js 一起介绍,帮助文档 ?config 没有太详细地介绍,所以我们看看 config() 函数中参数 ... 和 JavaScript 库 plot_config.js 中的功能函数是怎么对应的。图9.1 中图片下载按钮对应 toImageButtonOptions 参数, 看 toImageButtonOptions 源代码,可知,它接受任意数据类型,对应到 R 里面就是列表。 watermarkdisplaylogo 都是传递布尔值(TRUE/FALSE),具体根据 JavaScript 代码中的 valType (参数值类型)决定,其它参数类似。另一个函数 layout 和函数 config() 是类似的,怎么传递参数值是根据 JavaScript 代码来的。

toImageButtonOptions: {
    valType: 'any',
    dflt: {},
    description: [
        'Statically override options for toImage modebar button',
        'allowed keys are format, filename, width, height, scale',
        'see ../components/modebar/buttons.js'
    ].join(' ')
},
displaylogo: {
    valType: 'boolean',
    dflt: true,
    description: [
        'Determines whether or not the plotly logo is displayed',
        'on the end of the mode bar.'
    ].join(' ')
},
watermark: {
    valType: 'boolean',
    dflt: false,
    description: 'watermark the images with the company\'s logo'
},
library(plotly, warn.conflicts = FALSE)
plot_ly(diamonds,
  x = ~clarity, y = ~price,
  color = ~clarity, colors = "Set1", type = "box"
) %>%
  config(
    toImageButtonOptions = list(
      format = "svg", width = 450, height = 300,
      filename = paste("plot", Sys.Date(), sep = "_")
    ), 
    modeBarButtons = list(list("toImage")),
    watermark = FALSE,
    displaylogo = FALSE, 
    locale = "zh-CN", 
    staticPlot = TRUE,
    showLink = FALSE,
    modeBarButtonsToRemove = c(
      "hoverClosestCartesian", "hoverCompareCartesian", 
      "zoom2d", "zoomIn2d", "zoomOut2d", 
      "autoScale2d", "resetScale2d", "pan2d",
      "toggleSpikelines"
    )
  ) %>%
  layout(
    template = "plotly_dark",
    images = list(
      source = "https://images.plot.ly/language-icons/api-home/r-logo.png",
      xref = "paper",
      yref = "paper",
      x = 1.00,
      y = 0.25,
      sizex = 0.2,
      sizey = 0.2,
      opacity = 0.5
    ),
    annotations = list(
      text = "DRAFT",               # 水印文本
      textangle = -30,              # 逆时针旋转 30 度
      font = list(
        size = 40,                  # 字号
        color = "gray",             # 颜色
        family = "Times New Roman"  # 字族
      ),
      opacity = 0.2,                # 透明度
      xref = "paper",
      yref = "paper",
      x = 0.5,
      y = 0.5,
      showarrow = FALSE             # 去掉箭头指示
    )
  )

图 9.1: 自定义细节

表 9.1: 交互图形的设置函数 config() 各个参数及其作用(部分)
参数 作用
displayModeBar 是否显示交互图形上的工具条,默认显示 TRUE35
modeBarButtons 工具条上保留的工具,如下载 "toImage",缩放 "zoom2d"36
modeBarButtonsToRemove 工具条上要移除的工具,如下载和缩放图片 c("toImage", "zoom2d")
toImageButtonOptions 工具条上下载图片的选项设置,包括名称、类型、尺寸等。37
displaylogo 是否交显示互图形上 Plotly 的图标,默认显示 TRUE38
staticPlot 是否将交互图形转为静态图形,默认 FALSE
locale 本土化语言设置,比如 "zh-CN" 表示中文。

9.1 散点图

表 9.2: 散点图类型
类型 名称
scattercarpet 地毯图
scatterternary 三元图
scatter3d 三维散点图
scattergeo 地图散点图
scattermapbox 地图散点图 Mapbox
scatter 散点图
scattergl 散点图 GL
scatterpolar 极坐标散点图
scatterpolargl 极坐标散点图 GL

plotly.js 提供很多图层用于绘制各类图形 https://github.com/plotly/plotly.js/tree/master/src/traces

# 折线图
plot_ly(Orange,
  x = ~age, y = ~circumference, color = ~Tree,
  type = "scatter", mode = "markers"
)

图 9.2: 其它常见图形

9.2 条形图

日常使用最多的图形无外乎散点图、柱形图(分组、堆积、百分比堆积等)

# 简单条形图
library(data.table)
diamonds <- as.data.table(diamonds)

p11 <- diamonds[, .(cnt = .N), by = .(cut)] %>%
  plot_ly(x = ~cut, y = ~cnt, type = "bar") %>%
  add_text(
    text = ~ scales::comma(cnt), y = ~cnt,
    textposition = "top middle",
    cliponaxis = FALSE, showlegend = FALSE
  ) %>%
  config(displayModeBar = F)

# 分组条形图
p12 <- plot_ly(diamonds,
  x = ~cut, color = ~clarity,
  colors = "Accent", type = "histogram"
) %>%
  config(displayModeBar = F)

# 堆积条形图
p13 <- plot_ly(diamonds,
  x = ~cut, color = ~clarity,
  colors = "Accent", type = "histogram"
) %>%
  layout(barmode = "stack") %>%
  config(displayModeBar = F)

# 百分比堆积条形图
p14 <- plot_ly(diamonds,
  x = ~cut, color = ~clarity,
  colors = "Accent", type = "histogram"
) %>%
  layout(barmode = "stack", barnorm = "percent") %>%
  config(displayModeBar = F)

htmltools::tagList(p11, p12, p13, p14)