Package Information
- Last Updated
- Authors
- Amelia Mowers
1. Get the package
Download the package using the TPIX CLI:
tpix get @preview/tabut:1.0.22. Import in your Typst file
Add this to your .typ file:
#import "@preview/tabut:1.0.2": *#let ex(input) = {
set align(center);
block(
fill: luma(97%),
inset: 8pt,
radius: 4pt,
breakable: false,
[
#set align(left);
#input
])
}
#let snippet(filename) = {[
#let version = toml("typst.toml").package.version;
#let snippet-code-path = "doc/example-snippets/" + filename + ".typ"
#let snippet-image-path = "doc/compiled-snippets/" + filename + ".svg"
#let data = xml(snippet-image-path).first();
#let size = (
height: float(data.attrs.height) * 1pt ,
width: float(data.attrs.width) * 1pt,
);
#let content = read(snippet-code-path).replace("\r", "").replace("<
#ex(raw(content, block: true, lang: "typ"))
#ex(image(snippet-image-path, ..size))
]}
#let snippet-quiet(filename) = {[
#let version = toml("typst.toml").package.version;
#let snippet-code-path = "doc/example-snippets/" + filename + ".typ"
#let content = read(snippet-code-path).replace("\r", "").replace("<
#ex(raw(content, block: true, lang: "typ"))
]}
#let no-break(content) = {
block(breakable: false, width:100%, content)
}
#let subsection(name) = {
[== #name ]
}
#let label-text(content) = {
label(lower(content.text.replace(" ", "-")))
}
#let section(name) = {
[= #name #label-text(name)]
}
#let subsection(name) = {
[== #name #label-text(name)]
}
#no-break([
= Tabut
Powerful, Simple, Concise
A Typst plugin for turning data into tables.
== Outline
#set list(marker: ([•], [◦]))
#let sections = (
(name: [Examples], subs: (
[Input Format and Creation],
[Basic Table],
[Table Styling],
[Header Formatting],
[Remove Headers],
[Cell Expressions and Formatting],
[Index],
[Transpose],
[Alignment],
[Column Width],
[Get Cells Only],
[Use with Tablex],
)),
(name: [Data Operation Examples], subs: (
[CSV Data],
[Slice],
[Sorting and Reversing],
[Filter],
[Aggregation using Map and Sum],
[Grouping]
)),
(name: [Function Definitions], subs: (
[tabut],
[tabut-cells],
[rows-to-records],
[records-from-csv],
[group],
)),
)
#{
let items = ();
for s in sections {
let s-items = ();
for ss in s.subs {
s-items.push(link(label-text(ss), ss));
}
items.push([
#link(label-text(s.name), s.name)
#list(..s-items)
])
}
list(..items, tight: true)
}
])
#pagebreak(weak: true)
#no-break([
#section([Examples])
]) #no-break([
#subsection([Input Format and Creation])
The tabut function takes input in "record" format, an array of dictionaries, with each dictionary representing a single "object" or "record".
In the example below, each record is a listing for an office supply product.
#snippet-quiet("example-data/supplies")
]) #no-break([
#subsection([Basic Table])
Now create a basic table from the data.
#snippet("basic")
funct takes a function which generates content for a given cell corrosponding to the defined column for each record.
r is the record, so r => r.name returns the name property of each record in the input data if it has one.
]) #no-break([
The philosphy of tabut is that the display of data should be simple and clearly defined,
therefore each column and it's content and formatting should be defined within a single clear column defintion.
One consequence is you can comment out, remove or move, any column easily, for example:
#snippet("rearrange")
]) #no-break([
#subsection([Table Styling])
Any default Table style options can be tacked on and are passed to the final table function.
#snippet("styling")
]) #no-break([
#subsection([Header Formatting])
You can pass any content or expression into the header property.
#snippet("title")
]) #no-break([
#subsection([Remove Headers])
You can prevent from being generated with the headers paramater. This is useful with the tabut-cells function as demonstrated in it's section.
#snippet("no-headers")
]) #no-break([
#subsection([Cell Expressions and Formatting])
Just like the headers, cell contents can be modified and formatted like any content in Typst.
#snippet("format")
]) #no-break([
You can have the cell content function do calculations on a record property.
#snippet("calculation")
]) #no-break([
Or even combine multiple record properties, go wild.
#snippet("combine")
]) #no-break([
#subsection([Index])
tabut automatically adds an _index property to each record.
#snippet("index")
You can also prevent the index property being generated by setting it to none,
or you can also set an alternate name of the index property as shown below.
#snippet("index-alternate")
]) #no-break([
#subsection([Transpose])
This was annoying to implement, and I don't know when you'd actually use this, but here.
#snippet("transpose")
]) #no-break([
#subsection([Alignment])
#snippet("align")
You can also define Alignment manually as in the the standard Table Function.
#snippet("align-manual")
]) #no-break([
#subsection([Column Width])
#snippet("width")
You can also define Columns manually as in the the standard Table Function.
#snippet("width-manual")
]) #no-break([
#subsection([Get Cells Only])
#snippet("only-cells")
]) #no-break([
#subsection([Use with Tablex])
#snippet("tablex")
])
#pagebreak(weak: true)
#no-break([
#section([Data Operation Examples])
While technically seperate from table display, the following are examples of how to perform operations on data before it is displayed with tabut.
Since tabut assumes an "array of dictionaries" format, then most data operations can be performed easily with Typst's native array functions. tabut also provides several functions to provide additional functionality.
]) #no-break([
#subsection([CSV Data])
By default, imported CSV gives a "rows" or "array of arrays" data format, which can not be directly used by tabut.
To convert, tabut includes a function rows-to-records demonstrated below.
#snippet-quiet("import-csv-raw")
Imported CSV data are all strings, so it's usefull to convert them to int or float when possible.
#snippet-quiet("import-csv")
tabut includes a function, records-from-csv, to automatically perform this process.
#snippet-quiet("import-csv-easy")
]) #no-break([
#subsection([Slice])
#snippet("slice")
]) #no-break([
#subsection([Sorting and Reversing])
#snippet("sort")
]) #no-break([
#subsection([Filter])
#snippet("filter")
]) #no-break([
#subsection([Aggregation using Map and Sum])
#snippet("aggregation")
]) #no-break([
#subsection([Grouping])
#snippet("group")
#snippet("group-aggregation")
])
#pagebreak(weak: true)
#no-break([
#section([Function Definitions])
]) #no-break([
#subsection([tabut])
Takes data and column definitions and outputs a table.
#ex(```typc
tabut(
data-raw,
colDefs,
columns: auto,
align: auto,
index: "_index",
transpose: false,
headers: true,
..tableArgs
) -> content
=== Parameters
/ `data-raw`: This is the raw data that will be used to generate the table. The data is expected to be in an array of dictionaries, where each dictionary represents a single record or object.
/ `colDefs`: These are the column definitions. An array of dictionaries, each representing column definition. Must include the properties `header` and a `func`. `header` expects content, and specifies the label of the column. `func` expects a function, the function takes a record dictionary as input and returns the value to be displayed in the cell corresponding to that record and column. There are also two optional properties; `align` sets the alignment of the content within the cells of the column, `width` sets the width of the column.
/ `columns`: (optional, default: `auto`) Specifies the column widths. If set to `auto`, the function automatically generates column widths by each column's column definition. Otherwise functions exactly the `columns` paramater of the standard Typst `table` function. Unlike the `tabut-cells` setting this to `none` will break.
/ `align`: (optional, default: `auto`) Specifies the column alignment. If set to `auto`, the function automatically generates column alignment by each column's column definition. If set to `none` no `align` property is added to the output arg. Otherwise functions exactly the `align` paramater of the standard Typst `table` function.
/ `index`: (optional, default: `"_index"`) Specifies the property name for the index of each record. By default, an `_index` property is automatically added to each record. If set to `none`, no index property is added.
/ `transpose`: (optional, default: `false`) If set to `true`, transposes the table, swapping rows and columns.
/ `headers`: (optional, default: `true`) Determines whether headers should be included in the output. If set to `false`, headers are not generated.
/ `tableArgs`: (optional) Any additional arguments are passed to the `table` function, can be used for styling or anything else.
]) #no-break([
#subsection([`tabut-cells`])
The `tabut-cells` function functions as `tabut`, but returns `arguments` for use in either the standard `table` function or other tools such as `tablex`. If you just want the array of cells, use the `pos` function on the returned value, ex `tabut-cells(...).pos`.
`tabut-cells` is particularly useful when you need to generate only the cell contents of a table or when these cells need to be passed to another function for further processing or customization.
=== Function Signature
#ex(```typc
tabut-cells(
data-raw,
colDefs,
columns: auto,
align: auto,
index: "_index",
transpose: false,
headers: true,
) -> arguments
```)
=== Parameters
/ `data-raw`: This is the raw data that will be used to generate the table. The data is expected to be in an array of dictionaries, where each dictionary represents a single record or object.
/ `colDefs`: These are the column definitions. An array of dictionaries, each representing column definition. Must include the properties `header` and a `func`. `header` expects content, and specifies the label of the column. `func` expects a function, the function takes a record dictionary as input and returns the value to be displayed in the cell corresponding to that record and column. There are also two optional properties; `align` sets the alignment of the content within the cells of the column, `width` sets the width of the column.
/ `columns`: (optional, default: `auto`) Specifies the column widths. If set to `auto`, the function automatically generates column widths by each column's column definition. If set to `none` no `column` property is added to the output arg. Otherwise functions exactly the `columns` paramater of the standard typst `table` function.
/ `align`: (optional, default: `auto`) Specifies the column alignment. If set to `auto`, the function automatically generates column alignment by each column's column definition. If set to `none` no `align` property is added to the output arg. Otherwise functions exactly the `align` paramater of the standard typst `table` function.
/ `index`: (optional, default: `"_index"`) Specifies the property name for the index of each record. By default, an `_index` property is automatically added to each record. If set to `none`, no index property is added.
/ `transpose`: (optional, default: `false`) If set to `true`, transposes the table, swapping rows and columns.
/ `headers`: (optional, default: `true`) Determines whether headers should be included in the output. If set to `false`, headers are not generated.
]) #no-break([
#subsection([`records-from-csv`])
Automatically converts a CSV data into an array of records.
#ex(```typc
records-from-csv(
data
) -> array
```)
=== Parameters
/ `data`: The CSV data that needs to be converted, this can be obtained using the native `csv` function, like `records-from-csv(csv(file-path))`.
This function simplifies the process of converting CSV data into a format compatible with `tabut`. It reads the CSV data, extracts the headers, and converts each row into a dictionary, using the headers as keys.
It also automatically converts data into floats or integers when possible.
]) #no-break([
#subsection([`rows-to-records`])
Converts rows of data into an array of records based on specified headers.
This function is useful for converting data in a "rows" format (commonly found in CSV files) into an array of dictionaries format, which is required for `tabut` and allows easy data processing using the built in array functions.
#ex(```typc
rows-to-records(
headers,
rows,
default: none
) -> array
```)
=== Parameters
/ `headers`: An array representing the headers of the table. Each item in this array corresponds to a column header.
/ `rows`: An array of arrays, each representing a row of data. Each sub-array contains the cell data for a corresponding row.
/ `default`: (optional, default: `none`) A default value to use when a cell is empty or there is an error.
]) #no-break([
#subsection([`group`])
Groups data based on a specified function and returns an array of grouped records.
#ex(```typc
group(
data,
function
) -> array
```)
=== Parameters
/ `data`: An array of dictionaries. Each dictionary represents a single record or object.
/ `function`: A function that takes a record as input and returns a value based on which the grouping is to be performed.
This function iterates over each record in the `data`, applies the `function` to determine the grouping value, and organizes the records into groups based on this value. Each group record is represented as a dictionary with two properties: `value` (the result of the grouping function) and `group` (an array of records belonging to this group).
In the context of `tabut`, the `group` function is particularly useful for creating summary tables where records need to be categorized and aggregated based on certain criteria, such as calculating total or average values for each group.
])