Vistrails
VisTrails
Juliana Freire, David Koop, Emanuele Santos, Carlos Scheidegger, Claudio Silva, and Huy T. Vo
VisTrail是一个支持数据检索和可视化开源系统. 它包括并大大扩展了科学工作流程和可视化系统的有用特性. 跟科学性工作流系统Kepler和Tavema一样, VISTrail允许从现有集成应用,松散耦合的资源以及一组根据规则设立的库的计算规范. 像AVS和ParaView这样的可视化系统, VISTrail做出了先进科学和信息可视化的技术来满足用户,让他们可以去探索和比较他们数据中不同的视觉表现. 因此,用户可以从数据的手机和处理复杂的分析和可视化, 来创建围绕科学发现的重要步骤的复杂工作流, 这些功能都集成在一个系统中.
VisTrail的一个显著特性是它的起源基础设施 http://aosabook.org/en/bib1.html#bib:freire:vistrails |[FSC+06 ]. VisTrail捕捉并保持了详细步骤的历史并在一个探索任务中导出数据. 工作流程被传统的用来自动重复任务, 但是对应用来说本质是探索性质的,例如数据分析和可视化, 很少重复——变化才是它的常态. 对用户来说生产和评估他们的数据,在不同系列但相关的工作流上来说, 是需要迭代地调整的.
VisTrail被设计来管理那些进化快速的工作流:他维护着传递了这些产品工作流的数据产品的起源(例如可视化,绘制). 这个系统还提供了注释功能使得用户可以丰富自动捕获的起源.
除了让结果可以重复利用, VisTrail还能通过一系列的操作和帮助用户写作分析数据的直觉判断用户接口来改善起源信息. 更显著的是这个系统支持通过存储临时的结果来反射性推理, 这让用户可以检验导致这个结果的动作来促成一个结果并遵循推理链的前溯和回溯. 用户还可以凭自己的直觉为工作流的版本导航,撤销更改而不会丢失结果,在视觉上比较多个工作流并且在可视的电子表格上显示他们的结果.
VisTrail专注于在广范围内被限制的工作流和可视化系统的重要的可用性问题.为了更广范围地迎合用户,甚至那些没有编程经验的,VisTrail提供了一系列的操作和用户接口能够简化工作流设计和使用 http://aosabook.org/en/bib1.html#bib:freire:vistrails|[FSC+06 ],包括能够通过分析来创建跟重定义工作流的能力,例如排列工作流的能力, 还有去为工作流的完成提出建议来让用户通过一个推荐的系统来交互性地构建他们的工作流 http://aosabook.org/en/bib1.html#bib:scheidegger:analogy|[SVK+07 ]. 我们也有开发了一个新的能允许创建自定义应用的框架,这使得能让非专业的用户更容易进行开发.
VisTrail的扩展性来自一个基础设施, 使得用户在整合工具和库得到简化,对快速原型的新功能也是一样. 这使得系统在广泛的应用领域,包括环境科学,精神病学,天文学,宇宙学,高能物理,量子物理,分子建模里很有帮助.
为了保持系统开源和免费, 我们建立了仅供VisTrail的免费,开源包.VisTrail被用Python编写并使用Qt来作为他的GUI工具包(通过PyQt Python绑定). 因为有着广泛的用户和应用, 我们在脑海里已经将系统设计成具有高移植性. VisTrail能在Windows, Mac和Linux上运行
Figure 23.1:VisTrail用户界面的组成
23.1 系统概述
数据探索是一个需要用户来定位他们相关数据的固有的创造性过程, 来整合和可视化这些数据、来在探索不同解决方案时与伙伴的合作、以及散布结果.由于数据在分析上的规模和复杂性于科学性探索是相通的, 所以需要更好支持创造力的工具.
这些工具有两个密切相关基本要求. 第一,能够使用形式化描述指定探索过程这一点很重要,在理想情况下可执行. 第二, 为了再现这些过程的结果并且论证这些解决一个问题的不同步骤, 这些工具必须有系统性捕捉到起源的能力. VisTrail是因为这些需求而被设计出来.
23.1.1 工作流个工作流基础下的系统
工作流系统支持结合多个工具的管道(工作流)创造. 因此他们使得自动化重复任务和结果重现性变为可能. 工作流正在广范围地迅速取代原始的shell脚本,这一点在许多不管是商业性(例如平果的 Mac OS X自动器,和雅虎的管道)还是学术性(e.g., NiPype, Kepler, and Taverna)的应用上都得到了证实.
与高级语言编写的程序相比,工作流有许多的优点. 他们提供了一个简单的编程模型因此一系列的任务是由连接一个任务的输出到一个任务的输入组成的. 图23.1 表示了一个读取包含天气观测的CSV文件工作流并创建了值得散点图.
大多数工作流系统是为一个特定的应用领域涉及的. 例如, Taverna面向于生物信息工作流, NiPype允许创建神经影像工作流. 然而VisTrail支持很多其他工作流系统提供的功能, 这被用来设计成支持一般的广泛的探索性任务, 集成多种工具, 库和服务.
23.1.2 数据和工作流起源
维持起源信息的重要性对结果(和数据产品)来说在科学界是被公认的. 数据产品的出处(也被称为查账索引,lineage,pedigree)包含了.用于传递数据产品的关于过程和数据的信息. 起源提供了关键的保存数据, 决定数据的质量和作者关系以及再现认证结果的重要文献 http://aosabook.org/en/bib1.html#bib:freire:provenance|[FKSS08 ].
一个起源的重要组成是关于因果关系的信息. 例如, 同输入数据和参数在一起的一个过程的描述(步骤序列),它能促成数据产品的创建. 因此, 起源的结构反映了工作流的结构(或者一组工作流)被用来派生一个给定的结果集.
事实上,工作流系统的广泛应用的一种催化剂已经变得更容易地自动捕获起源了. 尽管早期的工作流系统已经被拓展到用来捕获起源, 但VisTrail已经被设计成支持起源了.
Figure 23.2: 加强注释的起源探索
23.1.3 用户接口和基本功能
系统的不同用户接口的组成在Figure 23.1和Figure 23.2中已经描述了出来.用户使用工作流编辑器来创建和编辑工作流.
想要建立工作流图表的话,用户可以从注册模块(Module Registry)中抓取模块并将他们丢进工作流编辑器画布中.VisTrail提供了一系列的内置模块, 用户也能添加他们自己的(详情请看章节23.3). 如果一个模块被选择了, VisTrail就会显示出它的参数(在参数编辑区域), 用户也能设置和修改这些参数的值.
作为一个工作流规范是需要被细化的, 系统捕获这些变化并在下面描绘的版本树查看中展现给用户. 用户可以与工作流和他们VisTrail表格里的结果互动.表格里的每个小格展示了工作流现状的视图. 在Figure 23.1中, 在工作流编辑器里表示的工作流结果显示在了表格左上的格子里. 用户可以直接修改一个工作流参数以及在表格里跨过不同的格子的同步参数.
版本树视图帮助用户在不同工作流版本中导航. 如 Figure 23.2所示, 点击版本树上的一个节点, 用户可以看到一个工作流, 它与结果(视觉向预览)和元数据有关. 一些元数据是自动捕获的, 例如, 创建了特别的工作流用户的和日程创建的ID. 但是用户也可以提供额外的元数据, 包括一个识别工作流的标签以及一个写好的描绘.
[Figure 23.3: VisTrail架构]
23.2 工程历史
VisTrail版本的初始版本使用Java和C++编写的 http://aosabook.org/en/bib1.html#bib:bavoil:vistrails|[BCC+05 ]. C++的版本被分配到一些早期采用者手里,他们的反馈有助于我们对于系统需求的修整.
通过观察到在多个科学社区逐渐增长的基于Python的库和工具趋势, 我们倾向于使用Python来作为VisTrail的基础. Python迅速成为了科学性软件界的一种通用的流行胶水语言. 许多使用不同的语言写,例如Fortran,C,和C++
的库, 都使用Python来作为一种提供教本功能的方式. 自从VisTrail指向于许多不同的工作流中的软件库, 纯Python的实现就让这变得更容易了.特别是Python有同LISP环境相似的动态的代码载入特性, 在拥有巨大的开发者社区以及在2005年之后的一个极其丰富的标准库, 我们便开始了使用Python/PyQT/Qt的当前系统的开发. 这个决定取得了系统的巨大的简化拓展,特别是新模块和包的添加
VisTrail系统的一个测试版是在2007年1月首次发布, 从那时以来, 该系统就被下载超过了2.5万次.
23.3 VisTrail内部
以上描述了关于支持用户接口功能的内部组成是以VisTrail的高等级架构来描写的, 如Figure 23.3所示. 工作流执行是由执行引擎控制的, 它跟踪了操作的调用和他们各自的参数以及捕获工作流执行的起源(Execution Provenance). 作为执行的一部分, VisTrail也允许在内存和磁盘上中间结果的保存. 如同我们在章节23.3讨论的一样, 只有新的模块的组成和参数是可以重复执行的, 并且他们是通过调用底层库里合适的函数来执行的. 与工作流起源连接的结果可以在之后被包含在电子文档里. (章节 23.4)
关于工作流变化的信息是被捕获在版本树里的, 它能坚持使用不同的存储后端, 包括一个XML文件存储来一个当地和一个相关数据库. VisTrail也提供了一个允许用户来探索起源信息的序列引擎.
我们注意到尽管VisTrail是被作为一个交互工具来设计的, 但它也可以作为服务器模式来使用. 一旦工作流被创建, 他们就可以被VisTrail服务器执行. 这个特性在很多情况下都是有用的, 包括创建允许用户来与工作流交互的基于Web的接口和在高性能计算环境下运行工作流的能力.
23.3.1 版本树:基于变化的起源
[Figure 23.4 基于变化的起源模型]
我们介绍过的关于VisTrail的一个新概念就是工作流进化的起源的概念 http://aosabook.org/en/bib1.html#bib:freire:vistrails|[FSC+06 ]. 跟过去的工作流以及基于工作流的视觉性系统相比, 它只为导出的数据产品维持了起源. VisTrail将工作流作为最先类的数据项目并捕获他们的起源. 工作流进化的可获得性支持反思性推理. 用户可以在不丢失任何结果的情况下探索多个推理链, 因为系统存储了中间结果, 用户们可以对这个信息进行推理甚 至做出推论. 它还使得一系列简化搜索进程的操作变为可能. 例如, 用户可以简单的导向因一个给定的任务而被创建的工作流的空间,从视觉上来比较工作流和他们的结果(见 Figure 23.4), 并且探索(大量)
的参数空间. 除此之外, 用户还能排列起源信息并从样例中学习.
工作流进化是通过使用基于变化的源模型捕获的. 如Figure 23.4描绘的一样, VisTrail存储了类似于数据库事务日志的用于工作流的操作或者变化(例如, 模块的添加, 参数的修改等等). 这个信息以树为模型建立, 其中每个节点对应一个工作流版本, 以及一个父和子节点之间表示的用于父母节点获取子节点的变化. 我们使用术语版本树和VisTrail(简称视觉线索)来可交互地查阅这棵树. 要注意的是基于变化的模型一致地捕获参数值的变化和工作流的定义. 这个序列的变化是足够高效率的来决定数据产品的起源并且还能捕获工作流随着时间变化的信息. 这个模型既简单又紧凑, 相比于存储工作流的多个版本, 它本质上使用的空间更少.
使用这个模型有许多的好处. Figure 23.4 显示了VisTrail提供用来对比两种工作流的视觉上的不同功能. 尽管工作流是用图像表示的, 使用基于变化的模型的话, 比较两个工作流就变得非常简单了:它足够可以为版本树导航以及识别一系列需要的动作来将一种工作流转换成别的.
另一个基于变化的起源模型的重要好处是底层的版本树可以作为一种支持协作的机制.因为设计工作流是一个众所周知的困难任务, 它经常是需要多个用户去协作的. 不仅仅只是版本树提供了一个直观的方式来视觉化不同用户的贡献.(例如, 根据用户创建的相应的工作流为节点填色), 但模型的单调性允许简单的算法来同步多个用户之间的改变.
当一个工作流被执行的期间,起源信息可以被相当容易的捕获下来. 一旦执行完成, 维持在数据产品与它的起源间的强连接就变得重要了. 例如, 被用来传递数据产品的工作流,参数和输入文件. 当数据文件或者起源被移动或者修改, 找到与起源关联的数据或者找到数据关联的起源会变得困难. VisTrail提供了一个
持续性的存储机制来管理输入, 中间产物以及输出数据文件, 以此加强了起源和数据之间的链接. 这个机制为再生产提供了更好的支持因为它确保了起源中被引用的数据信息能便利地(并且正确地)就位. 另外一个关于这些管理的重要好处是它允许缓存能与其他用户共享的中间数据.
23.3.2 工作流执行和缓存
VisTrail的执行引擎被设计用来允许整合新的和存在的工具和库. 我们尝试着去容纳不同风格的普遍被用于包裹第三方科学可视化与计算软件. 尤其是VisTrail能被集成于不管是预编译通过shell执行并使用文件作为输入输出的应用库, 还是传递中间对象作为输入/输出的C++/Java/Python 类的库.
VisTrail采用了一种数据流执行模式, 在这种模式里每个模型行使着计算功能并且数据是通过一个通过存在的模块的链接形成的模块流产生的. 模块以一种自底向上的方式执行,每个输入都是通过递归执行的上游模块按需生产的. (当从A到B有一个顺序的连接时,我们说模块A是B的上游). 中间数据是临时性在内存或者磁盘上存储的(由一个包含了访问过数据信息的Python对象包装).
为了允许用户在VisTrail上添加他们自己的功能, 我们建立了一个可扩张的包系统(见 章节23.3[Link]). 包允许用户包入他们自己或者第三方VisTrail工作流模块. 包的开发者必须识别一套计算性模块并且识别每个输入和输入接口以及定义计算. 对存在的库来说, 一个计算方式需要特化 从输入端口到参数的已有函数的转换和从结果值到输出端口的映射.
在探索性任务里, 与工作流类似,它分享了共有的子结构, 经常以紧密的继承关系执行. 为了提高工作流执行的效率, VisTrail缓存了中间结果来最小化重计算. 因为我们重用过去的执行结果, 我们隐式地假设能缓存的模块是有如下功能的:给出相同的输入, 模块会产生相同的输出. 这个要求进行了强制行为限制, 但我们相信这个要求是合理的.
然而,有些情况会有一些可望不可及的行为. 例如,一个模块在往一个远程服务器或者往磁盘上存储一个文件会有一个明显的副作用, 尽管输出相对性没这么重要. 其他模块或许会使用随机化, 并且他们的未决定机制或许是可取的; 这些模块可以被标记成不可缓存的. 然而一些没有那么自然功能的模块是可以被转换的; 将数据写到两个文件的功能或许会被包裹在输出文件内容的输出里.
23.3.3 数据序列化和存储
任何支持起源系统的一个关键组成就是序列化和数据的存储. VisTrail最开始使用简单的通过 ‘’fromXML’’ 和 ‘’toXML’’ 嵌入到它的内部对象的方法来存储XML里的数据.(例如, 版本树的每个模块). 为了支持这些对象模式的演化, 这些功能编码了所有在模式版本间的转换. 同工程进展, 我们的用户基础也成长了, 并且我们决定去支持不同的序列化, 包括关系存储. 除此之外, 随着模式对象的演化, 我们需要为共有数据管理维持更好的基础设施, 例如版本化模式, 版本间的转换, 支持整体关系. 为了做到这些我们添加了一个新的数据库层.
数据库层是由三个核心组件组成的:领域对象, 服务逻辑, 持续性方法. 领域和持续性组件是被标记了版本使得每个模式版本有他自己的一套类. 通过这样的方法, 我们维持了能够读取每个版本模式的代码. 这里也有能定义装换对象到其他一个模式版本的类. 这个服务类提供了与数据和处理检测和模式版本的转换的方法.
因为写如此多的这样的代码过于单调跟重复, 所以我们使用模板和元模式来定义了工程的框架(和记忆指数)和序列化代码. 元模式是用XML编写的, 也是在那种序列化下可以拓展的,而不是去添加默认的VisTrail定义的XML和关系映射. 这与对象-关系映射以及Hibernate和SQLObject框架类似, 但是加入以下特别的路径来自动化像重映射识别器和将一个模式从一个版本向下一个版本转换这样的任务.除此之外我们也能使用相同的元模式来为许多语言生成序列化代码. 在最开始写元Python时, 领域和持续性代码由元模式中获取的变量在运行中的Python代码生成, 我们最近将其迁移到了Mako模板.
自动转换是那些需要迁移他们系统的数据到更新版本的用户的关键. 我们设计添加了钩来让这个转换对开发者来说不这么痛苦. 因为我们维持了每个版本代码的拷贝, 转换代码需要映射到另外一个版本. 在root层次,我们定义了一个能识别版本怎样转换成其他版本的映射. 对比较远的版本来说, 这通常涉及到多个中间版本的一条链. 最初,这是一个唯一的映射,这意味着新的版本不能被翻译为旧版本,但最近的模式映射已经增加了反向映射.
每个对象都有一个 ‘’update_version’’ 方法能管理一个对象的不同版本并且返回当前版本. 默认情况下它会在每个对象由映射旧对象的领域到一个新的版本的情况下做递归的转换. 这个映射默认会用相同的名字来复制每个领域, 但是也能够定义一个函数来重写任何领域的默认行为. 重写是一种能管理老对象返回新版本的一种方式. 因为模式的大多数变化仅仅影响一小部分的领域, 所以默认映射能适用大多数情况, 但重写提供了灵活的定义局部变化的方式.
23.3.4 由包和Python而来的可拓展性
VisTrail的第一个原型有一套固定的模块. 这是发展VisTrail版本树基本思路的理想环境以及多个执行程序的运行, 但它严格局限于长期效益.
我们将VisTrails作为科学计算的基础设施, 这意味着,从字面上看,这个系统应该为其他工具和进程开发以提供支架(scaffolding). 这种情况的一个必要要求就是可扩展性. 实现这一目标的一个典型的方法是定义一个目标语言并编写一个适当的解释器. 这一点是很有吸引力的, 因为紧密的控制提供了超权执行(over execution). 因为我们队缓存的需求, 这一呼吁被加强了. 然而, 然而,实施一个完整的编程语言需要很大的努力,这也不是我们的首要目标. 更重要的是,迫使使用VisTrail的用户去完整地学习一门新的语言也是不可能的.
我们想要对用户来说非常简单就能添加自定义功能的系统.同时,我们需要足够强大的系统来表达相当复杂软件的每一块. 作为一个样例, VisTrail支持VTK可视化库5. VTK包含超过1000个类, 这改变取决于编译,配置和操作系统. 因为为所有的这些案例编写不同代码路径似乎是适得其反且没有希望的,我们觉得有必要来动态地决定由任何被提供的包的VisTrail的全套模块, 于是VTK自然地变成了我们解决复杂包的模型目标.
计算科学是我们最初的目标领域之一, 而且在我们设计这个系统的时候, Python作为“粘合代码”于这些科学家之间变得越来越受欢迎. 通过使用了Python自身特化用户定义的VisTrail行为, 我们都会削除大量的采纳相关的障碍. 事实也证明, Python为动态定义的类和反馈提供了一个很好的基础设施. 几乎所有作为第一个类的表达Python的定义有一个等价的形势. 在我们的包系统中,Python的两种重要的反馈特性如下:
- Python类可以通过函数调用可调用的type 动态地定义. 返回值是类的一个可以以经典定义的Python类一样方式使用的准确展示.
- Python模块可以通过import函数导入, 并以标准的import声明同样的方式来计算出结果值. 从这些模块来的路径在运行时刻也能被指定.
当然,使用Python作为我们的目标有一些缺点. 首先,Python的动态性质以为这我们需要确保一些例如VisTrail包安全的问题,一般这是不可能的. 更重要的是一些VisTrail模块的一些需求, 尤其是那些关于需要参考性透明(之后还有更多的问题)不能强制使用Python. 然而,我们认为通过文化机制来限制Python里允许的结构是值得的, 附加说明,Python对软件的可扩展性来说是一个极具吸引力的语言.
23.3.5 VisTrail包和束
一个VisTrail包包裹了一套模块. 它在磁盘最常见的表示是作为一个Python包的相同表示(不幸的是可能会有命名冲突). 一个Python包由一套定义了例如函数和类的Python值的Python文件组成. 一个VisTrail包是一个遵守特定接口的Python包. 它有定义了特定函数和变量的文件. 在它最简单的形式里, 一个VisTrail包应该是包含两种文件的目录:’’init.py’’ 和 ‘’init.py’’ .
第一个文件init.py 是Python包的必要, 并且需要包含一些是常量的定义.尽管不能保证一直保持这种情况, VisTrail包不能够遵循以上这一点被认为是有bug的. 这个文件里定义的值包含了包的一个全局唯一的标识符, 用于在工作流被序列化时来区分模块, 并且包版本(包版本在处理工作流和包更新的情况变得重要起来, 见 章节23.4). 该文件也包含了函数调用 ‘’package_dependencies’’ 和 ‘’package_requirements’’ . 因为我们允许VisTrail模块从其他VisTrail模块中划分出子类到根模块类下, 所以可以设想对一个VisTrail包去拓展另一个包的行为, 并且一个包需要在另一个之前被初始化. 这些包之间的依赖被 ‘’package_dependencies’’ 规定了. ‘’package_requirements’’ 函数在另外的情况下指定了系统级库的要求***VisTrail在某些情况下能通过它的束抽象尝试自动满足.
束是一个系统级别的包, VisTrail通过系统指定的工具, 例如 RedHat’s RPM or Ubuntu’s APT 来进行管理. 当这些属性满足了, VisTrail能通过直接导入Python模块并且访问合适的变量来定义包属性
第二个文件, ‘’init.py,’’ 包含了所有实际VisTrail模块定义的入口点. 这个文件最重要的特性是定义函数, ‘’initialize’’ 和 ‘’finalize’’. ‘’initialize’’ 函数在一个包可以使用的时候被调用, 毕竟所有的依赖包都会让它们自己可以使用. 它为暴力的所有模块执行安装任务. ‘’finalize’’ 函数, 换句话说经常被用来释放运行时刻资源(例如, 由包创建零食文件是可以被清除的)
每个VisTrail模块是由Python类的表现成一个包的形式. 如果要在VisTrail里注册这个类, 包开发器会为每个VisTrail模块调用 ‘’add_module’’ 函数一次. 这些VisTrail模块可以是随意的Python类, 但是他们必须遵守一些需求. 首先是每一个都必须是一个由VisTrail调用定义的基础Python类的一个子类, 或者简单的 ‘’Module’’ . VisTrail模块一个使用多个继承, 但其中的一个类应该是一个VisTrail模块—费钻石层次也是允许的.多重继承特别在对定义类混合的情况下变得有用:能组合在一起来创造更多复杂行为的简单父类编码行为.
这套可用的端口决定了VisTrail模块的接口, 所以影响到的不仅仅是这些模块的显示还有他们与其他模块的链接. 这些端口, 之后必须精确的根据VisTrail架构描述. 这也能通过在初始化时适当调用 ‘’add_input_port’’ 和 ‘’add_output_port’’ 和来完成 ‘’initialize’’ , 或者通过指定每个类来为每个VisTrail模块列出 ‘’_input_ports’’ and ‘’_output_ports’’ .
每个模块通过重写 ‘’compute’’ 方法来指定将要执行的计算. 数据通过端口在模块间进行传输, 并且通过 ‘’get_input_from_port’’ 和 ‘’set_result’’ 方法来访问. 在传统数据流环境下, 执行指令是通过数据请求来指定的. 我们的情况是, 执行指令是由工作流模块的拓扑排序来指定. 因为缓存算法需要一个非循环图, 我们安排了反向拓扑排序指令的执行,所以这些函数调用不会触发上游模块的执行. 这是我们有意的决定: 它可以更容易地思考每个模块与其他模块间的分离, 这使得我们的缓存策略更加简单更加健壮.
作为一般的原则, VisTrail模块在 ‘’compute’’ 方法的评估的过程中应该避免使用带有副作用的函数. 如 23.3章节讨论的一样, 这个要求使局部工作流可以运行: 如果一个模块遵守该属性, 那么它的行为是上游模块的函数输出. 每个非循环子图只需要计算一次,并且结果可重复使用。
23.3.6 以模块形式传递数据
VisTrail模块的一个奇特的特性以及他们之间的交流在于数据在VisTrail模块间的传递是以他们自己的VisTrail模块的形式. 在VisTrail中, 对模块和数据类有一个单层次结构. 例如一个模块可以将它自己作为一个计算的输出提供出来. (并且实际上每个模块提供了一个默认的“自身”输出端口). 主要的缺点是在数据和计算缺少概念性分离, 有时候在基于数据流的架构里也能看到. 然而这里有两个很好的有点, 首先是它密切模仿了Java和C++的对象类型系统, 并且这个选择不是偶然的, 它在支持大类库, 例如VTK的自动包装, 对我们来说是非常重要的. 这些库允许对象产生其他对象来作为计算的结果, 这使得在计算和数据区分上的包装变得更加复杂.
这一决定带来的第二个好处是定义工作流中的常数值和用户可设置参数变得更加容易, 并且能与系统的其他部分更加均匀的集成在一起. 例如会有一个工作流从一个常量指定的Web指定的位置载入文件这样的情况. 目前这是可以使用能够指定URL作为参数的GUI来指定的(见图23.1 参数编辑区域). 这个工作流的一个自然的修改是去使用它来获取在上游某处被计算出的URL. 我们想要剩下的工作流尽可能的少改变. 通过假设模块能够输出他们自己, 我们能够简单地将一个字符串链接和与参数相符的端口右值链接起来. 因为常量的输出估计了它自己, 如果该值已经实际指定为一个常数, 那么它的行为是完全一样的.
[Figure 23.5 ‘’PythonSource’’ 模块的新功能原型制造]
涉及到设计常数是有其他需要考虑的因素. 每个常数类型有一个为指定值的不同的理想GUI接口. 例如, 在VisTrail里一个文件常数模块提供了一个文件选择对话框. 一个布尔值是有一个复选框指定的. 一个颜色值在每个操作系统中都有一个颜色选择器. 要实现这一共性, 开发社必须为从 ‘’base’’ 基础类里的自定义常量分一个子类并且为定义一个合适的GUI组件和字符串的表示提供重载(使得任意常数可以被序列化到磁盘).
我们注意到对简单的原型设计任务, VisTrail提供了一个内置的Python源模块. 一个 ‘’PythonSource’’ 模块能够被用来直接将脚本插入到一个工作流中. Python源的配置窗口允许由将要执行的Python代码来指定多个输入和输入端口.
23.4 组件和特性
如上所述, VisTrail提供了一组功能和用户接口来简化创建和执行探索计算任务.下面我们介绍其中的一些. 我们也要简单探讨VisTrail是如何被作为一个支持创建起源丰富出版架构的基础的. 关于VisTrail以及它的特性更全面的表述请参阅VisTrail在线文档[6].
[Figure 23.6 可视化电子表格]
23.4.1 可视化电子表格
VisTrail允许用户使用可视化电子表格从多个工作流中浏览和比较结果(参见图 23.6) 电子表格是一个拥有自己的接口,由表单和单元个组成的VisTrail包. 每个表单包含了一套单元格并且有可自定义的布局. 一个单元包含了工作流产生结果可视化表示, 并且可以已定义显示不同的数据类型.
要在表单上显示一个单元格, 一个工作流必须包含从基础 ‘’SpreadsheetCell’’ 模块衍生的模块. 每个 ‘’SpreadsheetCell’’ 模块对应表单里的一个单元, 所以一个工作流可以产生多个单元. 电子表格丹玉模块的计算方法处理了执行引擎和表单间的交流(图23.3). 在执行过程中, 电子表格会根据它的类型按需创建一个单元, 这里利用了Python动态类实例化的优点. 因此自定义可视化表示可以通过创建子类电子表格单元和让它的计算方法发送给电子表格一个自定义单元类型. 例如图23.1中的工作流, ‘’MplFigureCell’’ 是设计来显示由 ‘’matplotlib’’ 创建的图鉴的电子表格单元模块.
由于单子表格使用PyQt作为他的GUI后端, 自定义单元不见必须是来自PyQt’s的 ‘’Qwidget’’ 的子类. 他们还必须定义 ‘’updateContents’’ 方法, 这在心数据到达是会触发电子表格更新组件. 每个单元部件可以通过实现 ‘’toolbar’’ 方法选择定义自定义工具栏; 当单元被选择时,它将被显示在电子表格工具栏区域.
图23.6显示了电子表格在VTK单元被选择的情况下, 工具栏提供了具体的小部件导出PDF图像,保存摄像机位置返回到工作流程,并创建动画。电子表格包定义一个自定义的 ‘’QCellWidget’’ ,它提供了常用的功能,如历史重放(动画)和多点触摸事件转发。为了新单元类型的更快发展, 它可以被用来代替的 ‘’QWidget’’ 。
即使在电子表格只以单元格的形式接受PyQt部件,整合与其他GUI工具包写好的部件是可能的. 为了实现这个,插件必须输出它的元素到本地平台, 并且PyQt能被用来抓取它. 之所以我们对VTKCell部件使用这种方法是因为实际的组件是由C++编写的. VTKCell抓取的窗口ID取决于系统, 如,Win32,X11或Cocoa/Carbon处理,并将其映射到电子表格画布上。
像单元格一样, 表单也可以自定义. 默认情况下,每张纸都处于标签视图,并具有表格布局. 然而,任何工作表可以从电子表格窗口解锁,允许多个工作表在某次变为可见。可以通过继承 ‘’StandardWidgetSheet’’,也可以通过一个PyQt的小工具来创建不同的表布局. ‘’StandardWidgetSheet’’ 管理单元布局以及在编辑模式下的电子表格的相互作用.在编辑模式下,用户可以操作单元布局和在细胞上执行高级操作,而不是与单元格内容进行交互.这些行为包括对比的应用(见章节 23.4) 并且从参数探索中创建新的工作流版本
23.4.2 可视化差异和类比
我们设计VisTrail在于希望能够让除了它的捕获使用源的信息. 首先,我们希望用户看到的版本之间确切的差异, 但我们后来意识到一个更为有用的功能就是能够将这些差异应用到其他工作流. 这两个任务是可能的,因为VisTrails能跟踪工作流的演变。
由于该版本树捕获了所有的变化并且我们可以反转每个动作,我们可以找到一个版本到另一个动作转换的完整序列. 要注意的是某些变化将相互抵消,来使其能够压缩该序列. 例如,有一个添加模块在计算的差的时候不需要被检查, 之后会被删除. 最后,我们在进一步简化序列上有一些启发: 当工作流出现在同一模块中, 但操作是分离的话, 我们可以取消添加和删除。
从集合的变化中我们可以创建一个可视化表示来显示相似和不同的模块、连接和参数. 这在图23.4示出. 每个工作流中出现的工作流模块和连接被涂成了灰色, 而那些出现了一次则是根据他们出现在的工作流中上色. 用不同参数匹配的模块有浅灰色的阴影并且用户可以针对检查出现在表格中, 并在每个工作流中显示了取值的特定模块的参数.
类比操作使用户可以利用这些差异,并将其应用到其他工作流程。如果用户已取得一组更改到现有的工作流程(例如,改变分辨率和输出图像的文件格式), 那么他可以通过类比来做出也适用于其他的工作流程相同的更改. 为了完成这件事,用户需要选择一个源和目标工作流, 这可以让用户限定希望的变化, 以及他们希望应用类比作用于的工作流. VisTrails计算前两个工作流之间的差来作为一个版本, 然后确定如何才能将其应用第三个工作流中重新映射这种差异.因为将差异应用于跟起始工作流相比非准确匹配的工作流是可能的, 所以我们需要一种允许类似模块之间相对应的柔软匹配. 在这种匹配下, 我们可以重新映射的差异来让序列的改变可以应用到选择的工作流中 http://aosabook.org/en/bib1.html#bib:scheidegger:analogy|[SVK+07 ]. 该方法并非万无一失,还可能产生我们非预期的新工作流. 这种情况下用户可能会去试着修复指出的错误,或者返回到以前的版本,并手动应用更改。
要计算在类比中使用的软匹配, 我们要平衡整体工作流结构中的匹配(相同或非常相似的模块). 请注意,由于子图同构的困难性, 即使是相似的匹配也是非常低效的,所以我们需要采用启发式. 总之如果在两个分享类似邻居的工作流时, 我们可以得出结论:两个功能相似的模块也应该被匹配. 更加正式地, 我们构造了一个产品图,该图的每个节点模块在能原有的工作流程上可进行配对和边缘代表共享了的连接. 然后, 我们运行跨过边到领域节点来扩散每个节点分数的步骤. 这是一个类似于谷歌的PageRank的Markov过程, 并最终收敛留下一组包括了全局信息的分数. 从这些分数中,我们可以判断出最佳匹配, 使用阈值留下未匹配极不相似的模块.
23.4.3. 查询起源
通过VisTrails捕获的起源包括了一组工作流, 每个工作流都有它自己的结构,元数据和执行日志. 对用户来说用户可以访问和浏览这些数据是很重要的.VisTrails同时提供了基于文本和视频(WYSIWYG)查询接口。对于像标签,注释和日期这样的信息, 用户可以使用带有可选的标记关键字搜索。例如,寻找与用户希望关键字的所有工作流程:~dakoop。然而,对于一个工作流的特定子图的查询更容易通过视觉, 按样例排序的接口来显示, 用户可以从剪切和复制建立序列并且修改存在的一片管道.
在设计这个查询的示例接口,我们从现有的, 有参数结构一些变化的工作流编辑器中保留了大部分的代码.对于参数来说,它通常是有用的搜索范围或关键字,而不是精确的值。因此,我们添加了对参数值字段的修改器; 当用户添加或编辑参数值时,他们可能会选择其中一个默认为精确匹配的修改符.还有可视化查询结构的查询结果是视觉性的。版本匹配在版本树中突出显示出来, 并且并且任何选定的工作流程都将显示在匹配部分中. 用户可以通过初始化另一个查询或单击“重置”按钮来退出查询结果模式。
23.4.4. 持久性数据
VisTrails保存了如何导出结果和各步骤的详细说明的起源. 然而, 如果由该工作流所需要的数据不再可用,再现这个运行的工作流是很困难的. 此外,对于长期运行的工作流程,在会话中将中间数据储存为永久缓存是很有用的, 它可以避免重复计算.
许多工作流系统将存储的文件系统路径储存在数据中作为起源来使用, 但这种方法是有问题的. 用户可以重命名文件,将工作流程移到另一个系统,而不是复制或改变数据内容. 在所有的这些情况下,存储该路径作为起源是不够的. 散列数据并存储该散列作为出处有助于确定数据是否可能已经改变, 但数据如果存在的话就不会帮助定位. 为了解决这个问题,我们创建了持久性封装包,这个包是使用版本控制结构来存储可能来自起源的数据. 目前我们使用的Git来管理数据,尽管在其他系统中可以很容易地被采用。
我们使用通用唯一标识符(UUID)来识别数据, 并从git向参考版本提交散列.如果数据从一个运行程序到另一个变化了, 新版本将会被嵌入存储库. 尽管(UUID,版本)的元组是一个在任何情况下都能用来检索数据的复合标识符. 除此之外我们存储工作流产生的数据的哈希表还有上游部分的签名(不管它是否为一个输入).这会允许一个连接数据的请求在相同计算运行时可以同复用数据一样被识别.
设计该包时,主要关心的是用户能够选择和检索数据的方式. 我们也希望在同一个库中的保持所有数据, 不管它是否被用作输入,输出,或中间数据(一个工作流程的输出可能被用来作为另一个的输入).一个用户可以使用来标识数据两种主要模式:选择创建一个新的参考或使用现有的. 注意,第一步执行之后, 一个新的参考将会变成在运行期间持续存在的; 用户如果希望的话可以选择在之后创建另一个参考, 虽然这种情况很少见. 由于用户往往希望总是使用最新版本的数据,一个没有具体版本标识的参考会默认为最新版本.
在执行一个模块时,我们会递归的更新其所有的输入。如果上游的计算已经运行持久性数据模块将不能更新其输入。为了确定这一点,我们检查持久库上游子工作流的签名并在签名存在时获取预先计算的数据. 此外,我们记录数据标识符和版本的源,使得一个特定的执行可以被再现。
23.4.5 升级
起源在VisTrail中处于核心地位, 升级旧的工作流程,使他们能与新版本包一起运行是一个关键问题. 因为包可以由第三方来创建,我们需要架构来升级工作流, 同时这也与包的开发者指定他们的更新路径挂钩. 参与工作流升级的核心动作是用新版本更换一个模块。需要注意的是这个动作比较复杂因为我们必须更换所有的连接和参数的从旧模块。此外,升级可能为模块需要重新配置,重新分配,或重命名这些参数或连接. 例如,模块接口更改。
每个包(及其关联的模块一起)通过一个版本进行标记,并且如果该版本的改变了,我们会设该包中的模块可能已经改变。需要注意的是有些甚至大部分,可能都没有改变, 但没有经过我们自己的代码分析,我们就不能检查。然而,我们尝试自动升级接口没有改变的所有模块。要做到这一点,我们尝试用新版本更换模块,并在它不能正常工作并抛出一个异常。当开发着已经改变了模块的接口或重命名一个模块,我们允许他们明确指定这些变化。为了使这更易于管理,我们建立了一个remap_module方法,它允许开发人员定义默认的升级行为需要被修改的地方。例如,开发者可以改名为输入端口’file’为’value’能指定特定的重新映射,所以在新模块被创建时,所有连接到’file’的就模块都会连接到’value’.这里是一个内置VisTrails模块升级路径的例子:
1 | def handle_module_upgrade_request(controller, module_id, pipeline): |
这段代码使用旧 ‘’GetItemsFromDirectory’’(任何高达1.6的版本)而不是 ‘’Directory’’ 模块升级工作流. 它将就模块从 ‘’dir’’ 端口映射到 ‘’value’’, ‘’itemlist’’ 端口映射到 ‘’itemList’’ .
任何升级都会在版本树里创建一个新的版本,以便升级前后的执行可以区分和比较。升级改变工作流的执行是可能的(例如包开发者修复一个BUG), 并且我们需要跟踪它来作为起源信息. 注意在老版本的VisTrail里, 可能有必要升级树中的每个版本。为了减少混乱,我们只升级用户被导航到的版本。另外,我们提供允许用户在工作流修改或执行完毕后任何的延迟升级的偏好;如果用户只是查看该版本,那就没有必要持续升级。
23.4.6 分享和发布起源丰富的结果
尽管科学方法的基石是重复性, 当前描述计算性实验的发布不能提供能让结果重复或者一般化的足够信息。进来在发布可重复性结果这方面出现了一个新的利益.更广泛地采用这种做法的主要障碍在于,创建一个包括所有的组件的束是很难的,它還需要重现以及验证结果。
通过捕捉详细的起源,并通过许多上述特征,VisTrails对于在系统内进行计算实验简化了这一过程。然而,机制是需要链接和分享两个文件和和它的出处信息的。
我们已经开发出使结果显示在纸上并连接到他们起源的VisTrails包,如Deep caption. 使用我们开发的LaTeX,用户可以将链接到VisTrails工作流程的数字包括进来. 下面的代码的LaTeX会生成一个包含工作流结果的图:
1 | \begin{figure}[t] |
当文档使用pdflatex编译时,’’\ vistrail’’ 命令将通过收到的参数调用一个Python脚本,它发送一个XML-RPC消息到VisTrails服务器来执行ID为 ‘’119’’ 的工作流.同样的Python脚本从服务器下载工作流的结果,通过制定好的布局选项 ‘’(width=0.9\linewidth)’’ 生成一个超链接LaTeX ‘’\includegraphics’’ 指令,来将他们包括在生成PDF文档中。
将VisTrails结果包括到网页,维基,Word文档和PowerPoint演示文稿中也是可能的。微软PowerPoint和VisTrails之间的连接是通过组件对象模型(COM),对象链接和嵌入(OLE)接口完成的. 为了让一个对象与PowerPoint相互作用,至少需要 ‘’IOleObject’’,COM的 ‘’IDataObject’’ 的和 ‘’IPersistStorage’’ 这些接口. 由于我们使用实现COM接口的抽象的QAxAggregated类的Qt来构建我们的OLE对象,’’IDataObject’’ 的和 ‘’IPersistStorage’’ 都是由Qt自动处理的。因此,我们只需要实现的 ‘’IOleObject’ ‘接口。在这个接口中最重要的调用是 ‘’DoVerb’’ 。它可以让VisTrails从PowerPoint的某些动作中做出反应,比如对象的激活。在我们的实现中,当VisTrails对象被激活,我们会加载VisTrails应用程序,并允许用户打开,互动和选择一个他们想要插入管道,他们关闭VisTrails后,管道结果将在PowerPoint中显示。管道信息也用OLE对象来存储。
为了使用户能够与相关的起源自由地分享他们的成果,们已经创建了crowdLabs.7 。crowdLabs是一个集成了一套可用的工具和扩展的基础架构,为科学家协同分析和可视化数据的环境的社交网站。crowdLabs与VisTrails紧密集成。如果用户希望共享VisTrails产生的任何结果,她可以直接从VisTrails连接到crowdLabs服务器上传信息。一旦信息被上载时,用户可以交互并通过一个Web浏览器来执行工作流***-这些工作流由VisTrails服务器授权于crowLabs执行。关于VisTrails更多被用于创建可重复的出版物的详细信息,见 ‘’http://www.vistrails.org.''
23.5 学到的东西
幸运的是,早在2004年,当我们开始考虑构建一个支持起源的数据探索和可视化系统时,我们从来没有想象这是如此具有挑战性,或者想到我们做到现在这样会花费多久。如果我们想过的话我们可能根本不会开始这个项目。
更早的时候,我们的运行良好的一种策略被很快地设计出新功能的原型,并将其展示给一组选定的用户。我们从这些用户收到的最初的反馈和鼓励对项目的推进起了很重要的作用。 没有用户的反馈来设计VisTrails是不可能的。我们想强调该项目可能有的一个方面是大多数系统设计的功能时用来直接回应用户的反馈的。然而值得注意的是,用户多次请求的内容不是他需求最好的解决方法,响应给用户并不一定意味着那是他们准确要求的。过了很久,我们不得不设计和重新设计的功能,以确保他们是有用的并且正确集成到系统中。
鉴于我们以用户为中心的方法,有人可能会预期,我们开发的所有功能将被大量使用。不幸的是这没有如此。有时,会这样的原因是,该功能是非常“不寻常”,因为这个功能在其他工具中找不到。例如,类比,甚至大多数用户都熟悉的版本树都没有概念,这需要一段时间让用户逐渐适应他们。另一个重要问题是文档,或缺少相关文件。与许多其他开源项目相比,我们在开发新功能要强于编写存在项目的文档。这种在文档方面的滞后不仅会导致有用的功能利用不足,还会给我们的邮件列表带来许多问题。
使用像VisTrails系统的挑战之一是它非常普遍。尽管我们以最大的努力提高可用性,但VisTrails是一个需要从一些用户逐渐的学习的复杂的工具。我们相信,随着时间的推移,改善的文档,精炼的系统,更多的应用和领域特定的例子,适用性将会变得更好。此外,由于种源的概念越来越广为人知,对用户来说更容易理解我们在开发VisTrails的哲学思考。
23.5.1 致谢
我们要感谢所有的优秀的开发者为VisTrails做出的贡献:Erik Anderson, Louis Bavoil, Clifton Brooks, Jason Callahan, Steve Callahan, Lorena Carlo, Lauro Lins, Tommy Ellkvist, Phillip Mates, Daniel Rees, and Nathan Smith. Special thanks to Antonio Baptista who was instrumental in helping us develop the vision for the project; and Matthias Troyer, whose collaboration has helped us to improve the system, and in particular has provided much of the impetus for the development and release of the provenance-rich publication functionality. The research and development of the VisTrails system has been funded by the National Science Foundation under grants IIS 1050422, IIS-0905385, IIS 0844572, ATM-0835821, IIS-0844546, IIS-0746500, CNS-0751152, IIS-0713637, OCE-0424602, IIS-0534628, CNS-0514485, IIS-0513692, CNS-0524096, CCF-0401498, OISE-0405402, CCF-0528201, CNS-0551724, the Department of Energy SciDAC (VACET and SDM centers), and IBM Faculty Awards.