使用 vistime 绘制甘特图(时光轴)

· 1660字 · 4分钟

vistime 包也可以绘制时间轴,此包主要有三个函数,分别对应不同效果。

  1. gg_vistime():基于 ggplot2 的静态时间轴。
  2. vistime():基于 plotly 的可交互时间轴。
  3. hc_vistime():基于 HighCharts 的可交互时间轴。

三个函数可使用的参数一致,如下:

  • data(数据框):数据框中若有以下列名称,将直接引用,若没有,可通过以下参数单独指定。
    • col.event(事件名称)
    • col.start(开始日期)
    • col.end(结束日期)
    • col.group(分组名称)
    • col.color(事件对应的长方形框或点的颜色)
    • col.fontcolor(事件内容的字体颜色)
  • optimize_y:默认 TRUE,时间上不重叠的事件会排布更紧凑(在同一行)。若选 FALSE,所有事件会排布在不同行。
  • linewidth:指定事件对应方框的宽度、点的大小。
  • title:时间轴的主标题。
  • show_labels:默认 TRUE,显示事件的名称。
  • background_lines:默认10,图形容器中背景里绘制的垂直线条数量。
折叠/展开官方网站提供的数据
data1 <- data.frame(
  content = rep(c("President", "Vice"), each = 3),
  group = c("Washington", rep(c(
    "Adams", "Jefferson"
  ), 2), "Burr"),
  start = c("1789-03-29", "1797-02-03", "1801-02-03"),
  end = c("1797-02-03", "1801-02-03", "1809-02-03"),
  color = c('#cbb69d', '#603913', '#c69c6e'),
  fontcolor = c("black", "white", "black"))

data2 <- read.csv(
  text = "content,group,start,end,color
Phase 1,Project,2016-12-22,2016-12-23,#c8e6c9
Phase 2,Project,2016-12-23,2016-12-29,#a5d6a7
Phase 3,Project,2016-12-29,2017-01-06,#fb8c00
Phase 4,Project,2017-01-06,2017-02-02,#DD4B39
Room 334,Team 1,2016-12-22,2016-12-28,#DEEBF7
Room 335,Team 1,2016-12-28,2017-01-05,#C6DBEF
Room 335,Team 1,2017-01-05,2017-01-23,#9ECAE1
Group 1,Team 2,2016-12-22,2016-12-28,#E5F5E0
Group 2,Team 2,2016-12-28,2017-01-23,#C7E9C0
3-200,category 1,2016-12-25,2016-12-25,#1565c0
3-330,category 1,2016-12-25,2016-12-25,#1565c0
3-223,category 1,2016-12-28,2016-12-28,#1565c0
3-225,category 1,2016-12-28,2016-12-28,#1565c0
3-226,category 1,2016-12-28,2016-12-28,#1565c0
3-226,category 1,2017-01-19,2017-01-19,#1565c0
3-330,category 1,2017-01-19,2017-01-19,#1565c0
1-217.0,category 2,2016-12-27,2016-12-27,#90caf9
4-399.7,moon rising,2017-01-13,2017-01-13,#f44336
8-831.0,sundowner drink,2017-01-17,2017-01-17,#8d6e63
9-984.1,birthday party,2016-12-22,2016-12-22,#90a4ae
F01.9,Meetings,2016-12-26,2016-12-26,#e8a735
Z71,Meetings,2017-01-12,2017-01-12,#e8a735
B95.7,Meetings,2017-01-15,2017-01-15,#e8a735
T82.7,Meetings,2017-01-15,2017-01-15,#e8a735")

栗子一 🔗

从本质上来讲,gg_vistime()是在一个直角坐标系中绘图,默认横轴(X轴)为日期、纵轴(Y轴)为分组的名称。每个事件(event,在 timevis 中称为条目 item)如果是时点值,那么图中显示为一个圆点,如果是时期值,那么图中显示为一个长方形框。其本身是一个 ggplot2 对象,因而也可以直接引用 ggplot2 中的函数,比如用labs()设置各类图形标题或标签,用coord_flip()来交换 X Y 轴,用 theme 一类函数配置主题。需要注意的是,gg_vistime()函数中 title 参数的优先级低于 labs()函数。

library(vistime)
library(ggplot2)

gg_vistime(
  data1,
  # 指定事件名称对应的列
  col.event = "content",
  # 指定线宽
  linewidth = 25,
  # 设置标题
  title = "Presidents of the USA"
) + labs(
  title = '图形主标题',
  subtitle = '图形副标题',
  caption = '图形备注',
  tag = '不知道干撒用的标签',
  x = 'x 轴标题',
  y = 'y 轴标题',
  fill = '图例标题'
) + coord_flip() + theme_gray()

栗子二 🔗

同理,也可以用 ggplot2 中的函数来修改X轴标签、Y轴标签、数据标注等。需要注意的是,调整数据标注的位置时,实际上是相对于每个时期的开始时间。

gg_vistime(
  data2,
  col.event = "content",
  linewidth = 3,
  show_labels = FALSE
) +
  # 设置 X 轴日期格式
  scale_x_datetime(date_labels = "%Y-%m-%d") +
  # 设置 Y 轴标签的字体大小、粗细
  theme(axis.text.y = element_text(face = "bold", size = 12)) +
  # 设置数据标注的位置、颜色
  geom_text(
    aes(label = label),
    size = 3,
    color = 'black',
    vjust = -0.5,
    hjust = 0.5
  )

对比 timevis 🔗

两个栗子 🔗

根据前面导入的 data1 数据集,需要做以下几步数据处理。

  1. vistime 函数中设置了几个颜色相关的参数,而 timevis 中的标签样式需要写入 style 字段中,且为 CSS 的写法。
  2. timevis 要求分组时必须写入 groups 数据集,且必有 id 和 content 两个字段。

timevis 源于 vis.js,虽然同样是横轴为日期、纵轴为组别,但是横轴固定为日期时间的缩放轴,所以两个轴不能交换。如果要修改图形容器的主题名称,需要用 htmltools 来引入。

library(timevis)

data1$style <-
  paste0("background-color:",
         data1$color,
         ";color:",
         data1$fontcolor,
         ";")

groups = data.frame(id = unique(data1$group),
                    content = unique(data1$group))

htmltools::tagList(
  h3("Presidents of the USA", style = "text-align:center; margin-bottom:10px;"),
  timevis(
    data = data1,
    groups = groups,
    options = list(
      # 设置数据标签居中
      align = 'center',
      # 设置同一组下,条目的水平间距为0
      margin = list(item = list(horizontal = 0))
      
    )
  )
)

根据前面导入的 data2 数据集,同样需要做一些数据处理,如下。

  1. 拼接生成 style 字段。
  2. vistime 是默认了时点和时期的样式,而 timevis 是在结束日期为空才默认为点,否则开始和结束日期相同的会展示位一条细线。此例中需要单独设置时点类型。
  3. 生成 groups 数据集。
data2$style <-
  ifelse(
    data2$start == data2$end,
    sprintf("color:%s;", data2$color),
    sprintf("background-color:%s;", data2$color)
  )

data2$type <- ifelse(data2$start == data2$end, "point", "range")

groups <-
  data.frame(id = unique(data2$group), content = unique(data2$group))

timevis(
  data = data2,
  groups = groups,
  options = list(
    locale = 'en',
    align = 'center',
    margin = list(item = list(horizontal = 0))
  )
)

更大数据量 🔗

受限于 ggplot2 的性能,数据量相对较大时,timevis 更快。

random_dates <- as.Date("2026-01-01") + sample(0:365, 100, replace = TRUE)

data <- data.frame(event = rep('a', 100),
                   start = random_dates)

timevis(data)
gg_vistime(data)

总结 🔗

- vistime timevis
来源 ggplot2 vis.js
样式设置 基于 ggplot2 更方便 使用 HTML、CSS 语法,更复杂
适用数据量 相对较少 相对较多
交互能力 转换 plotly、highchats vis.js 支持缩放、拖拽、可编辑等
事件或条目内容 仅支持纯文本 还支持 HTML
嵌套分组 ×
R