Typst 目前最好用的表格库应该就是 Tablex 了,虽然官方文档还是很清楚的,但是不妨在这里逐步实现一个复杂的三线表。

在读完本文后,你将会实现如下的效果:

成品

配置

Typst 现在已经推出了包管理器功能。在 .typ 文件当中添加一行代码即可引入 Tablex 库:

#import "@preview/tablex:<version>": * // <version> 最好填最新版

如果只想引入需要的函数,可以把 * 换成对应的函数名称

使用

首先我们需要使用 Tablex 的 tablex() 函数显示出一个表格:

#tablex()

然后我们要进行一些配置,比如列数、居中等:

#tablex(
	columns: 11, // 通过查看成品图,可以发现总共有 11 列数据
	align: center + horizon, // 在每一个 cell 中上下左右都居中对齐
	auto-vlines: false, // 因为我们要做的是三线格,所以把垂直的线去掉
	repeat-header: true, // 在表格过长,需要两页展示时,会在显示内容的同时,重新加上表头
)

这是表格的配置部分,下面我们要来写表头。

在成品图当中,我们发现有一些表头横跨了三行,也有的表头横跨了十列。这是通过 colspanx()rowspanx() 实现的。colspanx() 指的是该表头横跨几列。rowspanx() 同理。在编写的时候,我们可以把这种横跨了几列或几行的元素看作一个单独的 cell,把它们当做普通的单元格来写,这样会好理解一点。也就是说我们的成品表格的表头应该有三行。

那我们可以写出以下代码:

#tablex(
	columns: 11,
	align: center + horizon,
	auto-vlines: false,
	repeat-header: true,
	
	// 第一行
	rowspanx(3)[*Sugar \ Concn. \ (g/mL)*], colspanx(10)[*Potato Mass (g)*], (), (), (), (), (), (), (), (), (),
	
	// 第二行
	(), colspanx(2)[*Potato 1*], (), colspanx(2)[*Potato 2*], (), colspanx(2)[*Potato 3*], (), colspanx(2)[*Potato 4*], (), colspanx(2)[*Potato 5*], (),
	
	// 第三行
	(), [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*],
)

可以发现,虽然我们使用了 colspanx()rowspanx(),但是我们的一行还是有 11 列。多余部分需要用 () 补上。也就是说 rowspanx()colspanx() 实际上是只算一个单元格。

这样表头就完成了,接下来我们需要导入数据。

Tablex 的导入数据和 Typst 原生表格一样,都可以用 .csv 文件进行导入:

// 导入数据
#let raw_data = csv("datas/raw_data.csv")

#tablex(
	columns: 11,
	align: center + horizon,
	auto-vlines: false,
	repeat-header: true,
	
	rowspanx(3)[*Sugar \ Concn. \ (g/mL)*], colspanx(10)[*Potato Mass (g)*], (), (), (), (), (), (), (), (), (),
	
	(), colspanx(2)[*Potato 1*], (), colspanx(2)[*Potato 2*], (), colspanx(2)[*Potato 3*], (), colspanx(2)[*Potato 4*], (), colspanx(2)[*Potato 5*], (),
	
	(), [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*],
	
	// 将读取到的 csv 数据解包
	..raw_data.flatten()
)

至此,表格就已经完成了。如果想要用 figure() 包裹,可以通过使用 kind 参数让 Typst 识别出它是 table 元素:

#let raw_data = csv("datas/raw_data.csv")

#figure(
  tablex(
    columns: 11,
    align: center + horizon,
    auto-vlines: false,
    repeat-header: true,

    rowspanx(3)[*Sugar \ Concn. \ (g/mL)*], colspanx(10)[*Potato Mass (g)*], (), (), (), (), (), (), (), (), (),

    (), colspanx(2)[*Potato 1*], (), colspanx(2)[*Potato 2*], (), colspanx(2)[*Potato 3*], (), colspanx(2)[*Potato 4*], (), colspanx(2)[*Potato 5*], (),

    (), [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*], [*Initial*], [*Final*],

    ..raw_data.flatten()
  ),
  caption: [Raw Data],
  kind: table
) <raw-data>