🎯 小项目②:数据处理流水线
本章的知识,到这里该派上用场了。我们要动手搭一条完整的数据处理流水线:一个节点不断生成数据,一个节点把数据变换加工,最后一个节点把结果可视化(画出来)。
这是实战项目,小莫将实现 数据处理流水线——它不再只是原样复读,而是能对数据"动手加工"了。
前面我只会把数据原样传来传去。这次我要真正"处理"它们了——生成、加工、展示,像个小小的数据工厂!
项目目标
搭一条三节点的流水线:
- generator:每隔一小段时间生成一个数字(我们让它生成一条"正弦波",这样画出来是好看的波浪);
- transform:把收到的数字放大,并做平滑处理(体现"变换");
- plot:把数值画成字符条形图打印出来,让我们在终端里肉眼"看见"数据的形状。
学完你会得到一条从无到有、能看见效果的完整数据流。
你将综合运用
- 4.x:写节点、连数据流、定时器、参数;
- 5.1:Arrow 是数据的统一格式;
- 5.2:造和读数字、用 NumPy 计算;
- 5.3:(transform 里的平滑用到"记住上一个值"的缓存思想)。
前置要求
- 完成 5.1 - 5.3;
- 手边有能运行 DORA 的开发环境。
准备目录
新建一个放本项目代码的文件夹并进入它:
本项目所有文件都放这里。
第一步:generator(生成数据)
它每隔 100 毫秒生成一个正弦波数值。正弦波会平滑地上下起伏,画出来是漂亮的波浪,很适合观察"数据在流动"。
新建 generator.py:
math.sin(...)生成正弦值(-1 到 1 之间平滑起伏);step * 0.2控制波浪的"疏密",step每次加 1,波形就缓缓推进;- 用
pa.array([value])把这个数字发到value输出。
第二步:transform(变换数据)
它做两件"加工":
- 放大:把 -1
1 的小数值放大到 -1010(放大倍数用参数配置,体现第四章的参数化); - 平滑:把当前值和上一个值做个平均,让曲线更柔和(用到 5.3 的"记住上一个值"思想)。
新建 transform.py:
scale从环境变量读,默认 10;last缓存上一次的结果,第一次为None时特殊处理(呼应 5.3 的is not None防护);- 平滑就是"当前和上一个取平均",是最简单实用的平滑法。
第三步:plot(可视化数据)
在终端里,我们用字符条形图把数值"画"出来——数值越大,横条越长。这样不用任何图形界面,也能直观看到波浪。
新建 plot.py:
int(value + 10)把大约 -1010 的值平移成 020 的条长;max(0, min(20, ...))把条长限制在合理范围,防止负数或过长;"█" * bar_len用方块字符重复出条形;f"{value:6.2f}"把数值格式化成宽 6、保留 2 位小数,对齐好看。
第四步:连成数据流
新建 dataflow.yml,把三个节点串起来:
三处连线:generator/value → transform 的 value,transform/result → plot 的 result。名字层层对应(回顾 4.3 的"四处对应"表)。
第五步:跑起来!
如果一切顺利,你会在终端里看到一条上下起伏、缓缓流动的波浪:
方块条随着正弦波左右伸缩——这就是你亲手造的数据,经过加工,被"看见"了! 按 Ctrl+C 停止。
看那条波浪!数据从 generator 冒出来,被 transform 加工,最后被 plot 画出来——三个零件像流水线上的工人,各干一段,配合得天衣无缝。我会处理数据啦!🧮
玩一玩:改参数看变化
数据流的乐趣在于"改一点点,效果立刻不同"。试试:
- 把
transform的env: SCALE从10改成5或18,波浪的振幅会变; - 把
generator的定时器从millis/100改成millis/300,波浪会变"慢"; - 把
generator.py里的0.2改成0.5,波浪会变"密"。
每次改完重新 dora run,观察差异。代码几乎不用动,改配置就能调出不同效果——这正是数据流架构的魅力。
动手挑战
在 transform 和 plot 之间,插入一个新节点 abs_node,把负数变成正数(取绝对值)。这样波浪就只在上半部分起伏了。
提示:Python 的 abs(x) 求绝对值;记得改 dataflow.yml 的连线,让数据从 transform → abs_node → plot。
参考答案
abs_node.py:
dataflow.yml 中间插一段,并改 plot 的来源:
给 plot 加两路输入:一路来自 generator(原始),一路来自 transform(变换后),用不同符号画出来对比。
提示:这就是 5.3 的多输入!用 event["id"] 区分两路。
参考答案思路
plot 配两个输入:
plot 代码里用 event["id"] 区分,raw 用一种符号(如 ·)、result 用 █,各画各的。这样能直观看到"变换前 vs 变换后"的差异。
常见报错 FAQ
检查 generator 的定时器 tick 配了没。没有定时器,generator 不会持续生成数据。
正常现象——终端字符图分辨率有限,只能近似。想更平滑可减小 generator 里的相位步长(把 0.2 改小)。
检查 plot 里的 max(0, min(20, bar_len)) 有没有写对——它负责把条长限制在 0~20,防止越界。若你调大了 SCALE,可能需要相应调整映射范围。
小结
你完成了小项目②:数据处理流水线!在这个项目里,你:
- 搭出了一条 生成 → 变换 → 可视化 的完整数据流;
- 用 Arrow(
pa.array/as_py)在节点间传递数字; - 用参数(
env/os.getenv)让变换可配置; - 用"记住上一个值"的缓存思想做了平滑处理;
- 在终端里把抽象的数据画成了看得见的波浪。
从"只会传话"到"会加工数据",这是我很大的一步进步!下一章,我要学习节点之间更丰富的"对话方式"——不只是单向传数据,还能一问一答、边做边报呢!
本章回顾 🧮 会处理数据
第五章到此圆满。回顾一下这一章的收获:
- 5.1:懂了 Arrow 为什么是"黑板的统一书写规范",以及零拷贝为何快;
- 5.2:学会造和读数字、数组、图像三类数据;
- 5.3:掌握多输入的区分与"最新值缓存"合并模式;
- 小项目②:亲手搭出一条能看见效果的数据处理流水线。
下一章 第六章 · 节点如何对话,我们学习节点之间的四种通信模式,让小莫掌握更灵活的沟通方式。