vis.js 是一个 JavaScript 可视化库,其中的 vis-network 模块被封装成了 R 中的 visNetwork 包,而 vis-timeline 模块被封装成了 R 中的 timevis 包。
本文参考了三部分:
- timevis 包的官方。
- vis.js 的官方文档
- miscosoft copilot 的答案。
基础时间轴(timevis) 🔗
timevis 绘制时间轴的方式非常简单,加载包以后执行timevis(data)就可以得到一个配置了许多默认选项的时间轴。数据中可输入以下字段,仅 start 和 content 为必选项。
- id:条目唯一 id,数据框中每一行称为一个条目(item),对应时间轴上一个时点或一个时期。
- start:开始日期,必须是合法的日期格式,如
'yyyy-mm-dd',如果仅写年份的数字会被默认为秒数。 - end:结束日期,若有则展示时期,没有则展示时点。
- content:每行数据展示的内容标签,支持纯文本或 HTML 编码。
- title:鼠标悬停在每个条目时的提示内容,仅支持纯文本。
- type:条目的类型。可以是“box”(默认)、“point”、“range”或“background”。“box”和“point”类型只需要开始日期,“range”和“background”类型需要开始日期和结束日期。
- editable:如果为 TRUE,则可以使用鼠标操作项目。如果设置了全局 editable 配置选项,则此设置会覆盖全局设置。可编辑的项目可以通过单击来删除或修改其开始/结束日期。
- group:组的 id。vis.js 仅支持横向时间轴,组相当于在基础时间轴的基础上增加了一个纵向轴,所有相同组 id 的条目将放在同一行上。更多细节在另一个数据框 groups 中设置。
时点时间轴 🔗
只有开始日期、没有结束日期的条目在时间轴上显示为一个时点,默认类型为“box”。
library(timevis)
df1 <- data.frame(
id = 1:3,
start = c("1587-01-01", "1768-01-01", "1984-01-01"),
content = c('黄仁宇《万历十五年》', '孔飞力《叫魂:1768年中国妖术大恐慌》', '乔治·奥威尔《1984》'),
title = c('英文原版1981年出版', '英文原版1976年出版', '英文原版1949年出版'),
type = c('box', 'box', 'point')
)
timevis(
df1,
options = list(format = list(
minorLabels = list(year = "YYYY年"),
majorLabels = list(year = "YYYY年")
))
)
时期时间轴 🔗
既有开始日期、也有结束日期的条目在时间轴上显示为一个时期,默认类型为“默认为range”。
时期时间轴有一个问题,如果某个条目的时期范围相对于时间轴的当前展示范围太小,那么条目的内容会显示不全。
df2 <- data.frame(
id = 1:5,
start = c(
"2025-06-20",
"2025-08-01",
"2025-10-01",
"2025-12-30",
"2026-02-07"
),
end = c(
"2025-06-30",
"2025-08-17",
"2025-10-08",
"2026-01-04",
"2026-02-08"
),
content = c('A事件', 'B事件', 'C事件', "D事件", "E事件")
)
timevis(df2, options = list(format = list(
minorLabels = list(month = "M月", day = "D日"),
majorLabels = list(month = "YYYY年MM月")
)))
分组时间轴 🔗
- 单一分组
df1$group <- c(1, 2, 2)
timevis(df1, groups = data.frame(
id = 1:2,
content = c("第一组", "第二组"),
title = c('第一组的提示', '第二组的提示')
))
- 嵌套分组
df2$group <- 1:5
timevis(
df2,
groups = data.frame(
id = 1:5,
content = c("第一大组", "第二大组", "第一大组:小组1", "第一大组:小组2", "第二大组:1"),
nestedGroups = I(list(c(3, 4), 5, NA, NA, NA))
),
option = list(locale = 'en')
)
可选参数(options) 🔗
vis.js支持的可选参数(options),下面薅几个感兴趣一点的了解一下。关于交互的部分等猴年马月学了 shiny 再看。
- height 高度/width 宽度/maxHeight 最大高度/minHeight 最小高度
timevis(df1, width = '100%', height = '150px')
日期格式 🔗
- format:时间轴的标签格式。
- majorLabels:大刻度标签,在图形容器最下方。
- minorLabels:小刻度标签,作为时间轴的具体刻度标签。
查看默认的日期格式
日期的格式化语法详见moment.js
{
minorLabels: {
millisecond:'SSS',
second: 's',
minute: 'HH:mm',
hour: 'HH:mm',
weekday: 'ddd D',
day: 'D',
week: 'w',
month: 'MMM',
year: 'YYYY'
},
majorLabels: {
millisecond:'HH:mm:ss',
second: 'D MMMM HH:mm',
minute: 'ddd D MMMM',
hour: 'ddd D MMMM',
weekday: 'MMMM YYYY',
day: 'MMMM YYYY',
week: 'MMMM YYYY',
month: 'YYYY',
year: ''
}
}
timevis(df2, options = list(
format = list(
minorLabels = list(month = "M月", day = "D日"),
majorLabels = list(month = "YYYY年MM月 -大刻度-")
)
))
时间轴范围 🔗
- timeAxis:时间轴的固定刻度
- scale:固定刻度的单位,可选项有
'millisecond'(毫秒), 'second'(秒), 'minute'(分钟), 'hour'(小时), 'weekday', 'week', 'day'(日), 'month'(月), 'year'(年)。 - step:固定刻度的步长。
- scale:固定刻度的单位,可选项有
timevis(df1, options = list(timeAxis = list(scale = 'year', step = 100)))
-
设定时间轴整体范围
- max/min:固定时间轴的最大日期/最小日期,无法通过缩放改变。
- start/end:设定初始的时间范围,可以通过缩放改变。
-
hiddenDates:隐藏特定时间段。 -start/end:指定需要隐藏的时间起点和终点。 -repeat:指定需要隐藏的时间的重复方式,可选的有 daily(按天), weekly(按周), monthly(按月), yearly(按年)。
timevis(df2, options = list(
locale = 'en',
hiddenDates = list(
start = '2025-06-15',
end = '2025-06-30',
`repeat` = 'monthly'
)
))
布局 🔗
- orientation:时间轴的相对位置
- orientation.axis:时间轴轴线相对条目的位置,默认 “bottom” (时间轴轴线在条目下方),可选有 “top”(时间轴轴线在条目上方)、“both”(时间轴轴线在条目上下两边)、 “none”(去掉时间轴轴线)
- orientation.item:默认 “bottom”,改成 “top” 时条目会更靠近轴线。
timevis(df2, options = list(orientation = list(axis = 'both')))
timevis(df2, options = list(orientation = list(axis = 'top')))
timevis(df2)
timevis(df2, options = list(orientation = list(item = 'top')))
- stack(堆叠):控制在同一时点或时段有重叠的条目是否自动换行堆叠。
stack = TRUE(默认):重叠的事件会自动上下堆叠,减少互相遮挡。stack = FALSE:重叠的内容会被压缩到同一行,可能会互相遮挡。
df <- data.frame(
id = 1:2,
start = c(Sys.Date(), Sys.Date()),
content = c('xxxxx', 'bbbbb')
)
timevis(df, option = list(stack = FALSE))
- margin:间距
- axis:条目与时间轴之间的最小间距(像素),默认20。
- item 条目之间水平和垂直方向的最小间距(像素),默认10。
- horizontal:条目之间最小水平间距(像素),默认10。
- vertical:条目之间最小垂直间距(像素),默认10。
自定义样式(HTML/CSS) 🔗
按条目 🔗
- content:支持引入 HTML 编码。
- 支持 HTML 的 UNICODE 编码。
- 支持 JS 的 UNICODE 编码。
- 不默认引入 font awesome。
- 支持
<b>``<i>这类不改变 CSS 样式的 HTML 元素。 - 不支持
<span>``<div>这类改变 CSS 样式的 HTML 元素。
df <- data.frame(
id = 1:5,
start = c(
Sys.Date(),
Sys.Date(),
Sys.Date() + 1,
Sys.Date() + 2,
Sys.Date() + 3
),
content = c(
'A["❤"]',
'B["\u2764"]',
'C["❤"]',
"<b>D1</b><br><i>D2</i>",
"<span style='color:blue'>E1</span>"
)
)
timevis(df, option = list(locale = 'en'))
- className/style:支持引入 CSS 样式,且 className 类的优先级更高。
df$style <- c(rep(NA, 3), 'color:blue;', 'color:red;font-size:30px')
timevis(df, option = list(locale = 'en'))
library(htmltools)
df$className <- "myItem"
tagList(
tags$style(HTML("
/* 去掉 item 边框 */
.vis-item.myItem {
border: none !important;
}
.vis-item.myItem .vis-item-content {
color: green;
font-size: 20px;
background: white;
}
/* 隐藏竖着的刻度线(grid lines) */
.vis-time-axis .vis-grid {
display: none !important;
}
")),
timevis(df, option = list(locale = 'en'))
)
按组别 🔗
组标签的样式修改方式与按条目一样,这里不展开。
timevis(df1, groups = data.frame(
id = 1:2,
content = c("第一组", "第二组"),
style = c('color:blue;', 'color:red;font-size:30px')
))