在终端舒适地进行数据可视化

Lobsters Hottest 工具

摘要

xan 是一个用 Rust 编写的高性能命令行 CSV 处理工具,具备 SIMD 解析、并行计算和终端数据可视化功能。

<p><a href="https://lobste.rs/s/1shdvp/data_visualization_from_comfort_your">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/17 17:53

medialab/xan 源代码:https://github.com/medialab/xan 构建状态(https://github.com/medialab/xan/actions) DOI(https://doi.org/10.5281/zenodo.15310200) # xan,CSV 魔术师

xan 是一个命令行工具,可直接在 shell 中处理 CSV 文件。它用 Rust 编写,力求速度最快、内存占用最小,并能轻松处理大型 CSV 文件(数 GB 级别)。它采用了一种新颖的 SIMD(单指令多数据流)CSV 解析器(https://docs.rs/simd-csv),并且可以并行化某些计算(通过多线程),从而尽可能快地完成某些任务。它可以轻松预览、过滤、切片、聚合、排序、连接 CSV 文件,并提供大量可组合的命令,这些命令可以链接在一起以执行各种典型任务。xan 还提供了自己的表达式语言,因此你可以执行无法通过简单命令完成的复杂任务。这种极简的语言专为 CSV 数据定制,比评估典型的动态类型语言(如 Python、Lua、JavaScript 等)快得多

请注意,该工具最初是 BurntSushi(https://github.com/BurntSushi)的 xsv(https://github.com/BurntSushi/xsv)的一个分支,但到目前为止几乎完全重写,以适应 SciencesPo 的 médialab(https://github.com/medialab)的用例,其根源在于面向社会科学的网络数据收集和分析(你可能认为 CSV 现在已经过时,但在过于匆忙地评判之前,请阅读我们写给该格式的情书)。因此,xan 超越了典型的数据操作,并提供了与词汇计量、图论甚至爬取相关的实用程序。除了 CSV 数据,xan 还能处理来自许多不同学科的、与 CSV 相邻的多种数据格式,例如网络存档(.cdx)或生物信息学(.vcf.gtf.sam.bed 等)。xan 还能够使用 xan toxan from 与许多数据格式(如 json、Excel 文件、numpy 数组等)相互转换。有关详细信息,请参阅部分。

最后,xan 可用于在终端中显示 CSV 文件,便于探索,甚至可以用于绘制基本的数据可视化:

view 命令flatten 命令
viewflatten
分类直方图散点图
categ-histcorrelation
分类散点图直方图
scatterhist
并行处理时间序列
parallelseries
小倍数(面板网格)分组视图
small-multiplesview-grid
相关性矩阵热图热图
small-multiplesview-grid

目录

如何安装

Cargo

可以使用 cargo 安装 xan(它通常随 Rust(https://www.rust-lang.org/tools/install)一起提供):

cargo install xan --locked

可选功能 某些功能由于编译时间或可执行文件大小成本过高,默认不构建。以下是可选功能的列表:

  • parquet:启用 xan from -f parquet

你可以按如下方式指定要启用的可选功能:

# 启用所有可选功能
cargo install xan --locked --all-features

# 仅启用特定功能
cargo install xan --locked --features parquet

你还可以调整构建标志,以确保 Rust 编译器能够利用 CPU 的所有功能:

CARGO_BUILD_RUSTFLAGS='-C target-cpu=native' cargo install xan --locked

你也可以按如下方式安装最新的开发版本:

cargo install --git https://github.com/medialab/xan --locked

Scoop (Windows)

可以使用 Scoop(https://scoop.sh/)在 Windows 上安装 xan

scoop bucket add extras
scoop install xan

Homebrew (macOS)

可以使用 Homebrew(https://brew.sh/)在 macOS 上安装 xan,方法如下:

brew install xan

Arch Linux

你可以使用 pacman 从 extra 仓库(https://archlinux.org/packages/extra/x86_64/xan/)安装 xan

sudo pacman -S xan

NetBSD

官方仓库中提供了一个软件包。要安装 xan,只需运行:

pkgin install xan

Nix

xan 为 Nix 打包,自 25.05 版本起可在 Nixpkgs 中获得。要安装它,你可以将其作为 pkgs.xan 添加到 environment.systemPackages 中,或使用 nix-shell 进入临时 shell。

nix-shell -p xan

Pixi (Linux, macOS, Windows)

可以在 Linux、macOS 和 Windows 上使用 Pixi(https://pixi.sh/latest/)包管理器安装 xan

pixi global install xan

Conda Forge

可以通过 conda-forge(https://conda-forge.org/)安装 xan,方法如下:

conda install conda-forge::xan

预构建的二进制文件

预构建的二进制文件可以附加到每个 GitHub 发行版(https://github.com/medialab/xan/releases/latest)中找到。当前支持的目标包括:

  • x86_64-apple-darwin
  • x86_64-unknown-linux-gnu
  • x86_64-unknown-linux-musl
  • x86_64-pc-windows-msvc
  • aarch64-apple-darwin
  • aarch64-unknown-linux-gnu

CI 尚未构建 ppc64le 目标,但如果需要,仍然可以在 conda-forge 软件包的文件(https://anaconda.org/conda-forge/xan/files)中找到预构建的二进制文件。欢迎提交 PR 以通过添加相关目标来改进 CI。

安装补全

请注意,xan 还提供了方便的命令和头部/列名称的自动补全,你可以通过 xan completions 命令安装。运行以下命令了解如何安装这些补全:

xan completions -h

对于 zsh,你可以将补全文件添加到 ~/.zfunc

mkdir -p ~/.zfunc
xan completions zsh > ~/.zfunc/_xan

然后在 ~/.zshrc 中的 compinit 之前添加以下内容:

fpath=(~/.zfunc $fpath)
autoload -Uz compinit
compinit

快速入门

让我们通过探索一个法国媒体语料库来了解最常用的 xan 命令:

下载语料库

curl -LO https://github.com/medialab/corpora/raw/master/polarisation/medias.csv

显示文件的头部

xan headers medias.csv
0 webentity_id
1 name
2 prefixes
3 home_page
4 start_pages
5 indegree
6 hyphe_creation_timestamp
7 hyphe_last_modification_timestamp
8 outreach
9 foundation_year
10 batch
11 edito
12 parody
13 origin
14 digital_native
15 mediacloud_ids
16 wheel_category
17 wheel_subcategory
18 has_paywall
19 inactive

计算行数

xan count medias.csv
478

在终端中预览文件

xan view medias.csv
Displaying 5/20 cols from 10 first rows of medias.csv
┌───┬───────────────┬───────────────┬────────────┬───┬─────────────┬──────────┐
│ - │ name          │ prefixes      │ home_page  │ ... │ has_paywall │ inactive │
├───┼───────────────┼───────────────┼────────────┼───┼─────────────┼──────────┤
│ 0 │ Acrimed.org   │ http://acrim...│ http://ww...│ ... │ false       │          │
│ 1 │ 24matins.fr   │ http://24mat...│ https://w...│ ... │ false       │          │
│ 2 │ Actumag.info  │ http://actum...│ https://a...│ ... │ false       │          │
│ 3 │ 2012un-Nouve...│ http://2012u...│ http://ww...│ ... │ false       │          │
│ 4 │ 24heuresactu...│ http://24heu...│ http://24...│ ... │ false       │          │
│ 5 │ AgoraVox      │ http://agora...│ http://ww...│ ... │ false       │          │
│ 6 │ Al-Kanz.org   │ http://al-ka...│ https://w...│ ... │ false       │          │
│ 7 │ Alalumieredu...│ http://alalu...│ http://al...│ ... │ false       │          │
│ 8 │ Allodocteurs...│ http://allod...│ https://w...│ ... │ false       │          │
│ 9 │ Alterinfo.net │ http://alter...│ http://ww...│ ... │             │ true     │
│ ...│ ...           │ ...           │ ...        │ ... │ ...         │ ...      │
└───┴───────────────┴───────────────┴────────────┴───┴─────────────┴──────────┘

在 Unix 上,不要犹豫使用 -p 标志来自动将完整输出转发到合适的分页器,并浏览所有列。

读取第一行的扁平化表示

# 注意:使用 -c 以避免截断值
xan flatten -c medias.csv
Row n°0
───────────────────────────────────────────────────────────────────────────────
webentity_id                     1
name                             Acrimed.org
prefixes                         http://acrimed.org|http://acrimed69.blogspot...
home_page                        http://www.acrimed.org
start_pages                      http://acrimed.org|http://acrimed69.blogspot...
indegree                         61
hyphe_creation_timestamp         1560347020330
hyphe_last_modification_timestamp 1560526005389
outreach                         nationale
foundation_year                  2002
batch                            1
edito                            media
parody                           false
origin                           france
digital_native                   true
mediacloud_ids                   258269
wheel_category                   Opinion Journalism
wheel_subcategory                Left Wing
has_paywall                      false
inactive                         
Row n°1
───────────────────────────────────────────────────────────────────────────────
webentity_id                     2
...

搜索行

xan search -s outreach internationale medias.csv | xan view
Displaying 4/20 cols from 10 first rows of
┌───┬──────────────┬────────────────────┬───┬─────────────┬──────────┐
│ - │ webentity_id │ name               │ ... │ has_paywall │ inactive │
├───┼──────────────┼────────────────────┼───┼─────────────┼──────────┤
│ 0 │ 25           │ Businessinsider.fr │ ... │ false       │          │
│ 1 │ 59           │ Europe-Israel.org  │ ... │ false       │          │
│ 2 │ 66           │ France 24          │ ... │ false       │          │
│ 3 │ 220          │ RFI                │ ... │ false       │          │
│ 4 │ 231          │ fr.Sott.net        │ ... │ false       │          │
│ 5 │ 246          │ Voltairenet.org    │ ... │ true        │          │
│ 6 │ 254          │ Afp.com /fr        │ ... │ false       │          │
│ 7 │ 265          │ Euronews FR        │ ... │ false       │          │
│ 8 │ 333          │ Arte.tv            │ ... │ false       │          │
│ 9 │ 341          │ I24News.tv         │ ... │ false       │          │
│ ...│ ...          │ ...                │ ... │ ...         │ ...      │
└───┴──────────────┴────────────────────┴───┴─────────────┴──────────┘

选择某些列

xan select foundation_year,name medias.csv | xan view
Displaying 2 cols from 10 first rows of
┌───┬─────────────────┬───────────────────────────────────────┐
│ - │ foundation_year │ name                                  │
├───┼─────────────────┼───────────────────────────────────────┤
│ 0 │ 2002            │ Acrimed.org                           │
│ 1 │ 2006            │ 24matins.fr                           │
│ 2 │ 2013            │ Actumag.info                          │
│ 3 │ 2012            │ 2012un-Nouveau-Paradigme.com          │
│ 4 │ 2010            │ 24heuresactu.com                      │
│ 5 │ 2005            │ AgoraVox                              │
│ 6 │ 2008            │ Al-Kanz.org                           │
│ 7 │ 2012            │ Alalumieredunouveaumonde.blogspot.com │
│ 8 │ 2005            │ Allodocteurs.fr                       │
│ 9 │ 2005            │ Alterinfo.net                         │
│ ...│ ...             │ ...                                   │
└───┴─────────────────┴───────────────────────────────────────┘

排序文件

xan sort -s foundation_year medias.csv | xan view -s name,foundation_year
Displaying 2 cols from 10 first rows of
┌───┬────────────────────────────────────┬─────────────────┐
│ - │ name                               │ foundation_year │
├───┼────────────────────────────────────┼─────────────────┤
│ 0 │ Le Monde Numérique (Ouest France)  │                 │
│ 1 │ Le Figaro                          │ 1826            │
│ 2 │ Le journal de Saône-et-Loire       │ 1826            │
│ 3 │ L'Indépendant                      │ 1846            │
│ 4 │ Le Progrès                         │ 1859            │
│ 5 │ La Dépêche du Midi                 │ 1870            │
│ 6 │ Le Pélerin                         │ 1873            │
│ 7 │ Dernières Nouvelles d'Alsace (DNA) │ 1877            │
│ 8 │ La Croix                           │ 1883            │
│ 9 │ Le Chasseur Francais               │ 1885            │
│ ...│ ...                                │ ...             │
└───┴────────────────────────────────────┴─────────────────┘

根据某些列去重文件

# 我们语料库中的一些媒体在 mediacloud.org 上具有相同的 ID
xan dedup -s mediacloud_ids medias.csv | xan count && xan count medias.csv
457
478

去重也可以在排序时进行:

xan sort -s mediacloud_ids -u medias.csv

计算频率表

xan frequency -s edito medias.csv | xan view
Displaying 3 cols from 5 rows of
┌───┬───────┬────────────┬───────┐
│ - │ field │ value      │ count │
├───┼───────┼────────────┼───────┤
│ 0 │ edito │ media      │ 423   │
│ 1 │ edito │ individu   │ 30    │
│ 2 │ edito │ plateforme │ 14    │
│ 3 │ edito │ agrégateur │ 10    │
│ 4 │ edito │ agence     │ 1     │
└───┴───────┴────────────┴───────┘

打印直方图

xan frequency -s edito medias.csv | xan hist
Histogram for edito (bars: 5, sum: 478, max: 423):
media           |423 88.49%|━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━|
individu        | 30  6.28%|━━━╸                                                      |
plateforme      | 14  2.93%|━╸                                                       |
agrégateur      | 10  2.09%|━╸                                                       |
agence          |  1  0.21%|╸                                                         |

计算描述性统计

xan stats -s indegree,edito medias.csv | xan transpose | xan view -I
Displaying 2 cols from 14 rows of
┌─────────────┬───────────────────┬────────────┐
│ field       │ indegree          │ edito      │
├─────────────┼───────────────────┼────────────┤
│ count       │ 463               │ 478        │
│ count_empty │ 15                │ 0          │
│ type        │ int               │ string     │
│ types       │ int|empty         │ string     │
│ sum         │ 25987             │            │
│ mean        │ 56.12742980561554 │            │
│ variance    │ 4234.530197929737 │            │
│ stddev      │ 65.07326792108829 │            │
│ min         │ 0                 │            │
│ max         │ 424               │            │
│ lex_first   │ 0                 │ agence     │
│ lex_last    │ 99                │ plateforme │
│ min_length  │ 0                 │ 5          │
│ max_length  │ 3                 │ 11         │
└─────────────┴───────────────────┴────────────┘

评估表达式以过滤文件

xan filter 'batch > 1' medias.csv | xan count
130

要访问表达式语言的速查表,请运行 xan help cheatsheet。要显示可用函数的完整列表,请运行 xan help functions

评估表达式以基于其他列创建新列

xan map 'fmt("{} ({})", name, foundation_year) as key' medias.csv | xan select key | xan slice -l 10
key
Acrimed.org (2002)
24matins.fr (2006)
Actumag.info (2013)
2012un-Nouveau-Paradigme.com (2012)
24heuresactu.com (2010)
AgoraVox (2005)
Al-Kanz.org (2008)
Alalumieredunouveaumonde.blogspot.com (2012)
Allodocteurs.fr (2005)
Alterinfo.net (2005)

要访问表达式语言的速查表,请运行 xan help cheatsheet。要显示可用函数的完整列表,请运行 xan help functions

通过评估表达式转换列

xan transform name 'split(name, ".") | first | upper' medias.csv | xan select name | xan slice -l 10
name
ACRIMED
24MATINS
ACTUMAG
2012UN-NOUVEAU-PARADIGME
24HEURESACTU
AGORAVOX
AL-KANZ
ALALUMIEREDUNOUVEAUMONDE
ALLODOCTEURS
ALTERINFO

要访问表达式语言的速查表,请运行 xan help cheatsheet。要显示可用函数的完整列表,请运行 xan help functions

执行自定义聚合

xan agg 'sum(indegree) as total_indegree, mean(indegree) as mean_indegree' medias.csv | xan view -I
Displaying 1 col from 1 rows of
┌────────────────┬───────────────────┐
│ total_indegree │ mean_indegree     │
├────────────────┼───────────────────┤
│ 25987          │ 56.12742980561554 │
└────────────────┴───────────────────┘

要访问表达式语言的速查表,请运行 xan help cheatsheet。要显示可用函数的完整列表,请运行 xan help functions

最后,要显示可用聚合函数的完整列表,请运行 xan help aggregations

数据绘图

重要提示:当在终端中使用 xan 的命令(如 histscattercorrelationparallelseriessmall-multiplesview-grid)时,图表是渲染在 Unicode 点上的。因此,如果终端中的 Unicode 字形字体配置不佳,可能会显得很奇怪。xan 会尽力检测这一点,如果兼容性问题被检测到,可能会退回到一个简单的 ASCII 后备方案(使用 hist 时,使用 -a 标志以 ASCII 模式运行;其他命令也有 -a 标志)。请注意,在 Windows 上,PowerShell 可能需要修补字体支持。

xan scatter foundation_year indegree medias.csv
Scatterplot for foundation_year vs indegree
 424 │                                       ║
     │                                   ║   ║ ║
     │                                   ║ ║ ║ ║
     │                                 ║ ║ ║ ║ ║
     │                                 ║ ║ ║ ║ ║
     │                               ║ ║ ║ ║ ║ ║
     │                               ║ ║ ║ ║ ║ ║
     │                             ║ ║ ║ ║ ║ ║ ║
     │                             ║ ║ ║ ║ ║ ║ ║
     │                         ║ ║ ║ ║ ║ ║ ║ ║ ║               ║
     │                       ║ ║ ║ ║ ║ ║ ║ ║ ║ ║               ║ ║
     │                       ║ ║ ║ ║ ║ ║ ║ ║ ║ ║         ║     ║ ║
     │                     ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║     ║   ║ ║   ║ ║ ║
     │                     ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║   ║ ║ ║ ║ ║ ║ ║ ║ ║
     │                     ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
     │                   ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
     │               ║   ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
     │               ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
     │       ║       ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
   0 │ ──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──║──
         1826                                                  2018 (N=463)

请注意,在上面的散点图中,xan 添加了一个相关性的视觉提示:点的四个象限中的对角线点形成的形状可以让你大致了解相关性的方向和趋势(包括缺失值)。

有关更多信息,你可以阅读专用文档:docs/moonblade/plotting.md

使用小倍数绘制多个图形

xan 还有一个 small-multiples 命令,可以将一个绘图命令应用于数据的一个分组,并将结果渲染为小倍数网格。该命令可用作 xan small-multiples -g column command args,其中 commandxan 的另一个绘图命令。

以下是一个示例,按基础绘制年份分组显示 indegree 的直方图:

xan small-multiples -g foundation_year hist indegree medias.csv
Small multiples for foundation_year
╔══════════════════════════════════════════╦══════════════════════════════════════════╦══════════════════════════════════════════╗
║             1826-1859 (N=3)             ║             1870-1900 (N=9)             ║             1905-1930 (N=2)              ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║  422                                     ║
║                                          ║                                          ║  424    (6)                               ║
║                                          ║                                          ║  426                                     ║
║                                          ║                                          ║  422⇌426 (3)                             ║
╠══════════════════════════════════════════╬══════════════════════════════════════════╬══════════════════════════════════════════╣
║             1944-1967 (N=9)             ║             1972-1989 (N=10)            ║             1990-1995 (N=9)              ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
╠══════════════════════════════════════════╬══════════════════════════════════════════╬══════════════════════════════════════════╣
║             1996-1997 (N=10)            ║             1998 (N=9)                   ║             1999 (N=12)                  ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║                                          ║                                          ║
║                                          ║

相似文章

@ai_suxiaole: 终端里最不缺的就是数字 真正缺的是一眼就能看懂趋势 GitHub 上有个 chartli 小工具,可以直接把命令行输出的数据渲染成图表 不管是服务器监控、日志分析还是脚本统计,只需要一条命令,就能生成 ASCII 折线图、柱状图、热力图、…

X AI KOLs Timeline

介绍一个名为 chartli 的命令行工具,可以将命令行输出的数字数据直接渲染成 ASCII 图表(折线图、柱状图、热力图等),支持管道输入、文件读取和多种图表类型,适合服务器监控、日志分析等场景。

Tsplat – 在终端中运行高斯泼溅渲染

Hacker News Top

Tsplat 是一款基于 Rust 的命令行工具,仅使用 CPU 即可直接在终端中渲染 3D 高斯泼溅场景,甚至支持通过 SSH 运行。它支持 Unicode 半角块和图形协议,并具有导航和自动旋转控制。