恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

VisiData 列系统深度指南:Column 计算引擎、类型系统与聚合器实战

  • 首页
  • 资讯中心
  • /
  • VisiData 列系统深度指南:Column 计算引擎、类型系统与聚合器实战

相关资讯

Plannotator External Annotations API:把外部工具的标注实时推送到活动评审会话 2026/9/25 6:04:52
pylibcudf 字符串 API 实战指南:capitalize / title / is_title 的用法与底层原理 2026/9/25 6:04:52
Kubebuilder 项目路线图全景解读:2024–2026 战略规划与源码落地 2026/9/25 6:04:52

最新资讯

STM32最小系统板实战详解:从晶振选型到时钟树配置
Atlas 300V 24G部署YOLOv5全流程:从PyTorch权重到OM模型推理
OpenChamber 1.6.4 深度解析:聊天选中文本引用功能的实现与配额追踪扩展
Apache DataFusion 语义规范解读:逻辑/物理平面不变量与输出字段名生成规则
RocketRide media_inspect 节点实战:流式媒体的探测、响度测量与 JPEG 截帧
六种调制仿真避坑指南:从QPSK星座图旋转到误码率对齐

今日推荐

AI元人文:从工具使用到思维重构的深度探索
Python+CNN车牌识别实战:从数据预处理到模型训练与部署
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

VisiData 列系统深度指南:Column 计算引擎、类型系统与聚合器实战

发布时间:2026/9/25 6:04:52
VisiData 列系统深度指南:Column 计算引擎、类型系统与聚合器实战 数据分析CLI数据可视化【免费下载链接】visidataA terminal spreadsheet multitool for discovering and arranging data项目地址https://gitcode.com/gh_mirrors/vi/visidata点击查看免费下载导读本文围绕 VisiData 的Column体系展开这是整个终端电子表格工具的计算核心。你将掌握calcValue/putValue与getValue/setValue的分层缓存机制、六种经典列类型与用户自定义类型的完整规范、null 值语义以及如何通过vd.aggregator扩展描述性统计聚合器。文中所有 API 均可直接用于插件开发或.visidatarc配置。一、ColumnVisiData 计算引擎的心脏VisiData 的官方 API 文档在 docs/api/columns.rst 中开门见山地写道Columns are the heart of the VisiData computation engine.列是 VisiData 计算引擎的心脏。每一列承担两项最基本的职责calculate计算从行对象row object中求出一个值put写入把一个不同的值写回行对象供后续的 calculate 重新推导。这两项职责分别由calcValue与putValue两个方法承载。在源码中基类Column定义于 visidata/column.pyclass Column(Extensible): Base class for all column types. - *name*: name of this column; if None, current sheet will assign a name - *type*: anytype str int float date or other type-like conversion function. - *cache*: cache behavior - False (default): getValue never caches; calcValue is always called. - True: getValue maintains a cache of options.col_cache_size. - async: getValue launches thread for every uncached result, returns invalid value until cache entry available. - *width*: 0 if hidden, None if auto-compute next time. - *height*: max height, None/0 to auto-compute for each row. - *fmtstr*: format string as applied by column type. - *getter*: default calcValue calls getter(col, row). - *setter*: default putValue calls setter(col, row, val). def __init__(self, nameNone, *, typeanytype, cacheFalse, **kwargs): ... self.getter lambda col, row: row self.setter None ... self.expr None # Column-type-dependent parameter从构造函数可以看到几个对插件开发者至关重要的默认行为name为空时会由当前 Sheet 通过incremented_colname()自动命名默认typeanytype即不做任何类型转换默认getter直接返回row本身setter为None意味着列默认是只读的readonly属性即由self.setter is None判定见 column.py通过**kwargs可以把任意额外属性如expr、fmtstr直接设置到列对象上。1.1 子类只需覆盖两个方法官方文档强调一个Column子类通常只需覆盖calcValue和putValue这是它唯一要做的事。文档给出的示例可以直接用于实际开发class SpecialColumn(Column): Column for special fields on special rows. def calcValue(self, row): return row.special()[self.expr] def putValue(self, row, val): row.special()[self.expr] val c SpecialColumn(field1, exprfield1_key) sheet.addColumn(c)其中addColumn把列挂载到 Sheet 上源码位于 visidata/sheets.pyindex为None时表示列由 loader 添加继承 Sheet 的 defer 状态由用户添加时则标记 Sheet 为已修改。1.2 不要直接调用 calcValue/putValue这是文档强调的第二个关键约定calcValue和putValue不应被应用代码直接调用应用与插件应当调用getValue与setValue因为后者提供了适当的缓存层appropriate layers of caching。这一点在源码中有非常清晰的体现。getValuecolumn.py会先检查defer延迟列模式下的待处理修改若未启用缓存_cachedValues is None直接执行calcValue若启用缓存先按sheet.rowid(row)查缓存命中即返回缓存模式为async时通过_calcIntoCacheAsync为每个未缓存的结果启动线程在缓存条目可用前返回INPROGRESS哨兵值普通缓存模式下超过options.col_cache_size默认 0即不限制时用OrderedDict.popitem(lastFalse)淘汰最旧条目。calcValue可能非常昂贵甚至异步如网络请求因此计算结果会一直缓存到Column.recalc()被调用。recalc()column.py负责清空缓存、把列挂到指定 Sheet 上并重新固化列名def recalc(self, sheetNone): Reset column cache, attach column to *sheet*, and reify column name. if self._cachedValues: self._cachedValues.clear() if sheet: self.sheet sheet self.name self._namesetValuecolumn.py则负责写路径非延迟列立即调用putValue延迟列先记入cellChanged等待后续putChanges统一提交同时弹出缓存中的过期条目并标记 Sheet 已修改。1.3 修改源数据的铁律必须显式 save文档特别警告putValue可能直接修改源数据例如行对象代表数据库表中的一行。因此 VisiData 有一条铁律——未经显式的save命令VisiData 永远不会修改源数据。任何应用代码要修改单元格都必须走setValue。这也解释了文档末尾的提示delete-cell实际上只是以None调用setValue。源码印证在 visidata/clipboard.py 中Sheet.addCommand(zd, delete-cell, cursorCol.setValues([cursorRow], options.null_value), delete current cell (set to None)) Sheet.addCommand(gzd, delete-cells, cursorCol.setValues(onlySelectedRows, options.null_value), delete contents of current column for selected rows (set to None))注意实际传入的是options.null_value而非字面None这与后文Nulls一节的语义保持一致。二、Column 常用属性与 API 速查结合源码可以确认以下核心属性定义见 column.py属性含义源码要点name列的显示名字符串setName会经sheet.maybeClean清洗并标记修改type列的解析/显示类型支持anytype/str/int/float/date或任意类型转换函数也可用字符串typestr赋值width列宽字符数0或负数表示隐藏None表示尚未自动计算visibleWidth可见宽度由movement.py的visibleWidth计算自 2.1 版加入fmtstr显示格式字符串空时回退到vd.getType(self.type).fmtstrhidden是否隐藏width 0即为隐藏readonly是否只读setter is None时只读常用方法均为Column.api可在插件中直接调用取值链getValue(row)→getTypedValue(row)→getDisplayValue(row)/getFullDisplayValue(row)。其中getTypedValue通过wrapply把getValue的结果套上类型转换任何一步出错都会产生TypedWrapper家族的值见下文用户自定义类型getDisplayValue返回的是按列宽截断的显示字符串getFullDisplayValue不做宽度截断。批量取值getValueRows(rows)生成(value, row)对自动排除 null 与错误值getValues(rows)只生成值序列。二者定义在 visidata/aggregators.py。写入链setValue(row, val)、setValues(rows, *values)值循环复用填满行集、setValuesTyped(rows, *values)先按列类型强转再写入遇到类型异常会中止、setValuesFromExpr(rows, expr)用 Python 表达式逐行求值写入见 visidata/expr.py。setValues/setValuesTyped均以asyncthread异步执行并注册 undo。错误检测Column.isError(row)判断某行取值是否出错配合TypedExceptionWrapper。表达式求值BaseSheet.evalExpr(expr, row, col)在(row, col)上下文中eval表达式上下文由vd.getGlobals()与LazyComputeRow提供sheets.pyTableSheet.recalc()则负责在行集变化后整体重算。三、内置 Column 子类家族文档列出的五个内置子类全部定义于 visidata/column.py覆盖了绝大多数数据访问模式子类用途底层访问方式ItemColumn按下标/键取值dict/list 行getitemdeep/setitemdeepexpr即 key 或 indexAttrColumn按属性名取值对象行getattrdeep/setattrdeepExprColumn按 Python 表达式求值sheet.evalExpr(compiledExpr, row)见 expr.pySettableColumn以行 id 为 key 的内部存储列self._store[rowid] valueSubColumnFunc列组合器先对行做subfunc预处理再转发给origcol配套工厂SubColumnAttr(attrname, c)与SubColumnItem(idx, c)几个值得注意的实现细节ItemColumn、AttrColumn都属于WritableColumnreadonly恒为FalseExprColumn在exprsetter 中即时compile(expr, expr, eval)并统计每次求值耗时ncalcs/totaltime/maxtimeSubColumnFunc.readonly跟随origcol其recalc会顺带重置origcol缓存SettableColumn的_store通过SettableColumn.init(_store, dict, copyTrue)声明为可复制的实例属性。3.1 交互命令中的列子类在终端里这些子类通过命令直接暴露给用户命令注册见 expr.pyaddcol-expr输入nameexpr创建ExprColumngsetcol-expr对选中行用表达式批量重算当前列zsetcell-expr对当前行求值并写入当前单元格gzsetcol-iter把 Python 序列表达式的元素逐个写入选中行。四、Key Columns键列与行标识键列Key Columns是 VisiData 中决定行身份的特殊列参与排序、分组、去重、聚合排名aggregate_groups中sheet.rowkey(r)即分组键等几乎所有需要行级标识的操作。相关 API 位于 visidata/sheets.pydef setKeys(self, cols): Make all *cols* into key columns. vd.addUndo(undoAttrFunc(cols, keycol)) lastkeycol 0 if self.keyCols: lastkeycol max(c.keycol for c in self.keyCols) for col in cols: if not col.keycol: col.keycol lastkeycol1 lastkeycol 1 def unsetKeys(self, cols): Make all *cols* non-key columns. vd.addUndo(undoAttrFunc(cols, keycol)) for col in cols: col.keycol 0 def rowkey(self, row): Return tuple of the key for *row*. return tuple(c.getTypedValue(row) for c in self.keyCols)配套属性与方法keyCols所有可见键列按keycol序号排序sheets.pynonKeyVisibleCols可见的非键列sheets.py常用于对除键列外的所有列批量操作例如ColumnsSheet的aggregate-cols命令keystr键列值的字符串形式用于状态栏、行跳转与日志回放命令层面键列可通过[/]之类交互命令或表达式设置键列的keycol属性在列复制时会丢失__copy__中ret.keycol 0。五、Types类型系统5.1 getValue 可能返回的值getValue的返回值是自由的文档列举了八种可能字符串数值类型list 或 dictNone按options.null_value判定的 null 值异常取值出错线程异步挂起中任意 Python 对象因此每个列都带一个type属性它影响该列如何解析、显示、分组、排序。type的默认值是anytype——让底层值原样通过这也是唯一允许getTypedValue返回任意类型的列类型。5.2 经典类型一览文档给出了七种经典列类型对应源码见 visidata/_types.py 与 type_date.py、type_currency.pytype说明numeric命令按键anytype原样透传type-anytypez~str字符串type-str~date日期/时间Ytype-dateint整数Ytype-int#float小数Ytype-float%currency带单位的货币小数Ytype-currency$vlen序列长度Ytype-vlenz#命令注册源码示例Sheet.addCommand(z~, type-any, cursorCol.type anytype, set type of current column to anytype) Sheet.addCommand(~, type-string, cursorCol.type str, set type of current column to str) Sheet.addCommand(#, type-int, cursorCol.type int, set type of current column to int) Sheet.addCommand(z#, type-len, cursorCol.type vlen, set type of current column to len) Sheet.addCommand(%, type-float, cursorCol.type float, set type of current column to float) Sheet.addCommand(, type-date, cursorCol.type date, set type of current column to date) Sheet.addCommand($, type-currency, cursorCol.typecurrency; cursorCol.displayercurrency, ...)文档还点出了一个易记的规律这些设置类型的默认按键全部落在美式键盘上方左移的按键上~ # % $ 等方便盲操作。在_types.py中可以看到类型注册表的实现vd.typemap是[vtype] - VisiDataType的映射每个VisiDataType携带typetype真实构造器、icon列头/单元格注释位的单字符标记如 int 为#、float 为%、str 为~、vlen 为♯、fmtstr与formatter。数值类型的默认格式串受两个选项控制disp_float_fmt默认{:.2f}与disp_int_fmt默认{:d}以%开头的 fmtstr 走locale.format_string其余走 Pythonstr.format。5.3 用户自定义类型User-defined Types文档对类型给出了一个本质定义一个类型就是一个函数它接收底层值并返回特定类型的对象就像 Python 内置的int和float那样既能把字符串合理地转换过来也能在无参或收到None时产生合理的基线零值算术恒等元。类型函数/构造器TYPE必须满足TYPE()返回TYPE的合理默认值TYPE(typedval)返回typedval的精确副本TYPE(str)从合理字符串表示转换为TYPETYPE.__name__必须设置为该类型的官方名称。TYPE(...)返回的对象必须可比较用于排序可哈希可格式化可四舍五入数值类型用于分箱 binning幂等TYPE(TYPE(v)) TYPE(v)这些约束与源码中VisiDataType的注释一一对应The resulting object o must be orderable and convertible to a string for display and certain outputs (like csv).5.4 Types API 与示例类型注册使用vd.addType2.1 版起推荐vd.isNumeric用于判断列是否为数值类型visidata.isNumeric在 2.1 版被标记为 deprecated应改用vd.isNumeric。源码中的isNumeric实现非常直白VisiData.api def isNumeric(vd, col): return col.type in vd.numericTypes # numericTypes [int, float] 及新增数值类型文档给出的自定义类型示例为列增加 IP 地址类型# Add an ip_address type. vd.addType(ipaddress.ip_address, icon:, formatterlambda fmt,ip: str(ip)) TableSheet.addCommand(None, type-ipaddr, cursorCol.typeipaddress.ip_address, set type of current column to IP address)注册后ipaddress.ip_address会被加入vd.typemap与全局命名空间从而可以在表达式如新增列中直接引用。六、TypedWrapper 与错误/空值语义getTypedValue永远不会裸抛异常或直接返回混乱类型而是返回TypedWrapper家族的包装值实现见 visidata/wrappers.py当底层值为None时得到TypedWrapper在比较/计算时表现为基线零值在显示时表现为底层值的字符串化版本。例如TypedWrapper(int, None)参与sum时按0计算但str()输出原始表示。当calcValue抛出异常或返回一个Exception时得到TypedExceptionWrapper行为与之类似并携带exception与stacktrace。wrapply像 apply但包装异常并透传 Wrapper是这一切的枢纽wrappers.pydef wrapply(func, *args, **kwargs): if args: val args[0] if val is None: # None 值传播为 TypedWrapper return TypedWrapper(func, None) elif isinstance(val, TypedExceptionWrapper): tew copy(val); tew.forwarded True # 前序异常透传并标记 forwarded return tew elif isinstance(val, TypedWrapper): return val elif isinstance(val, Exception): # 异常值变成 TypedWrapper return TypedWrapper(func, *args) try: return func(*args, **kwargs) except Exception as e: e.stacktrace stacktrace() return TypedExceptionWrapper(func, *args, exceptione)TypedWrapper的关键设计__lt__恒为True——包装对象在排序中永远排在最前wrapped objects are always least保证 null 不会干扰有序比较__add__/__radd__返回另一操作数——求和时 null 值不污染累加__eq__允许被包装的None与None相等__iter__/__next__为空迭代器便于某些场景下安全遍历。七、Nulls空值语义VisiData 对 null 的概念是粗糙但实用的。null 值就是 Python 的None外加若设置options.null_value。null 值会与以下功能交互聚合器a分母只统计非 null 值getValues已过滤 null/errorDescribe Sheetbnulls 列只统计 null 值fill-nulls命令c填充 nullmelt命令d只保留非 null 值prev-null/next-null命令e按键z和z在 null 单元格间跳转。options.null_value的一个易踩坑点文档以 note 形式特别说明CLI 只能把它设为字符串如空串或NA但在.visidatarc或其他代码中可以设为任意类型options.null_value 0.0 options.null_value date(1980-01-01)官方文档明确没有直接的isNull函数因为可能的 null 值会在运行时随上述选项变化而在批量操作中每次获取选项值非常昂贵。取而代之的是BaseSheet.isNullFuncwrappers.py它返回一个闭包函数BaseSheet.api def isNullFunc(sheet): Return func(value) which returns whether or not *value* is null. nullv sheet.options.null_value if nullv is None: return lambda v: v is None or isinstance(v, TypedWrapper) return lambda v, nullvnullv: v is None or v nullv or isinstance(v, TypedWrapper)注意它不仅判断None/null_value还把一切TypedWrapper视为 null——也就是说错误值、异步挂起值在 null 语义上同样被排除在有效数据之外。null_value选项的默认值与注册位于 aggregators.py。八、Aggregators描述性统计聚合8.1 聚合器的本质聚合器把单个列内的多行值收集起来用描述性统计解释它们。VisiData 预装了一组默认聚合器min、max、avg/mean、median、mode、sum、distinct、count、stdev、list以及p10~p99分位数与q3/q4/q5/q10分位组、keymin/keymax取极值所在行的键。完整注册表见 visidata/aggregators.py。8.2 注册自定义聚合器vd.aggregatorvd.aggregatoraggregators.py是扩展聚合器的官方入口VisiData.api def aggregator(vd, name, funcValues, helpstr, *, typeNone): Define simple aggregator *name* that calls funcValues(values) to aggregate *values*. Use *type* to force type of aggregated column (default to use type of source column). vd.aggregators[name] Aggregator(name, type, funcValuesfuncValues, helpstrhelpstr)funcValues(values)接收一列值、返回一个聚合结果type参数可选用于指定聚合结果列aggregated column的默认类型缺省时沿用源列类型。文档示例——为 numpy 的内部收益率函数注册聚合器import numpy as np vd.aggregator(irr, np.irr, typefloat)8.3 聚合器的完整生命周期一个聚合器在源码中是这样被使用和呈现的注册Aggregator对象存入vd.aggregatorsOrderedDict按名字索引。绑定到列TableSheet.addAggregators(cols, aggrnames)aggregators.py把聚合器名写入列的aggstr属性空格分隔的聚合器名列表并注册 undo。交互命令aggregate-col与gaggregate-cols通过chooseAggregators()弹出模糊匹配选择面板支持多选与 Tab 循环。执行Aggregator.aggregate(col, rows)内部调用col.getValues(rows)——即只对非 null、非错误值聚合空值列表返回Nonestdev对单元素列表返回TypedExceptionWrapper显示为错误字符串。展示与记忆memo_aggregatez把聚合结果vd.memory[k]存入内存并显示在状态栏aggregateTotal在底部状态栏异步展示全表聚合值带INPROGRESS占位。生成新列addcol-aggregateaggregate-col的兄弟命令见 aggregators.py按键列分组后为每组计算聚合SettableColumn承载结果列名形如col1_sumlist等ListAggregator则按组输出每行一个值的列表列。传播列的聚合器会随 Frequency频次与 Pivot透视表继承ColumnsSheet的aggregators列可直接编辑。分位数聚合器是类型化聚合的一个好例子PercentileAggregator把q4展开为 25/50/75 三个分位聚合器aggregator_choices面板会隐藏p10这类数字命名的分位聚合器引导用户使用q#系列。九、实战把文档 API 串起来把以上知识串成一个最小可运行的插件写入.visidatarc或插件文件即可from visidata import Column, vd, TableSheet, anytype # 1. 自定义类型IP 地址满足 TYPE()/TYPE(typedval)/TYPE(str)/__name__ 四要件 vd.addType(ipaddress.ip_address, icon:, formatterlambda fmt, ip: str(ip)) # 2. 自定义列从行对象的特殊字段取值 class SpecialColumn(Column): def calcValue(self, row): return row.special()[self.expr] def putValue(self, row, val): row.special()[self.expr] val # 3. 自定义聚合器numpy 内部收益率 import numpy as np vd.aggregator(irr, np.irr, typefloat) # 4. 新命令把当前列设为 IP 类型 TableSheet.addCommand(None, type-ipaddr, cursorCol.typeipaddress.ip_address, set type of current column to IP address)在终端中的对应操作路径用#/%//$快速把列设为 int / float / date / currency数值列参与排序与聚合时自动使用getTypedValue的一致类型用为当前列添加sum、avg等聚合器Frequency/Pivot 会自动继承用zd删除单元格——内部即setValues(..., options.null_value)并受isNullFunc语义约束用z/z在 null 单元格间跳转fill-nulls填充空值。延伸阅读API 文档全文docs/api/columns.rst列基类与内置子类实现visidata/column.py类型注册表与anytype/vlen等实现visidata/_types.py空值/错误包装器TypedWrapper、wrapply、isNullFuncvisidata/wrappers.py聚合器注册与内置集合visidata/aggregators.py表达式列与setValuesFromExprvisidata/expr.py键列/行键相关 APIvisidata/sheets.py类型格式化选项disp_float_fmt等visidata/_types.py赞分享数据分析CLI数据可视化【免费下载链接】visidataA terminal spreadsheet multitool for discovering and arranging data项目地址https://gitcode.com/gh_mirrors/vi/visidata点击查看免费下载相关推荐StatsD深度解析现代监控系统的核心聚合引擎StatsD深度解析现代监控系统的核心聚合引擎 StatsD作为现代监控体系中的核心聚合引擎最初由Etsy团队基于Flickr的设计理念开发采用Node.可观测性指标监控为什么选择multi.js5个让前端开发者爱不释手的核心特性为什么选择multi.js5个让前端开发者爱不释手的核心特性 multi.js是一款用户友好的多选框替代方案专为解决原生multiple select元素的Redis实时统计计数器与聚合计算Redis实时统计计数器与聚合计算 Redis作为高性能的键值对数据库Key Value Database在实时统计场景中展现出卓越的性能和灵活性。本文数据库缓存KV存储消息队列上一篇Steam游戏库管理大师解放你的硬盘空间下一篇CnosDB实战指南5个关键场景下的高性能时序数据库部署与优化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号