物理量的单位对于科学家和工程师来说至关重要。它们传递信息非常有效,但遗憾的是,也可能导致代价高昂的错误。我们开发了一款插件,旨在帮助用户在 JMP 中管理单位,从而减少此类错误。该插件利用 JMP 18 新增的 Python 集成功能,轻松实现 JMP 17 中难以实现的功能。本次演示将展示该插件的功能,以及它的开发过程,包括 Python 的使用、源代码控制、测试、文档编写和构建系统。
大家好,我叫埃文·麦考克尔 (Evan McCorkle),是 JMP 的一名开发人员。今天我想和大家聊聊我使用 JMP 18 新增的 Python 集成功能开发的一个插件。这个插件用于物理单位换算。接下来,我将介绍我开发这个插件的原因、开发过程、使用的技术,以及其中用到的 JMP 18 Python 集成的一些细节。
我的训练和早期职业生涯都是工程师专业。在训练和早期职业生涯中,我不得不接触很多不同的单位制和各种单位,主要是美制单位和公制单位。我相信你们很多人也遇到过类似的情况,而且我相信你们很多人都知道,由于单位换算问题,曾经发生过许多代价高昂的重大事故。因此,我总是会使用一些工具来帮助我检查单位换算。
我经常使用名为 Pint 的 Python 库来实现这个功能。我最近在研究 JMP 18 的新 Python 集成,想知道能否将它与 JMP 现有的列单位标注功能结合起来?比如,用户可以在某一列上添加单位,然后我们能否利用这个功能进行单位转换、单位验证等等?
这就是开发此插件的初衷。该插件的功能在于,当您导入表格时,它可以检测列中的括号单位,自动分配单位属性并验证这些单位。它可以让您一目了然地查看整个表格及其单位,批量更改单位,确保系统能够理解所使用的单位和缩写,并自动确定简单公式列的单位。
该插件的主要功能是转换列的单位。例如,将英寸转换为毫米。您可以直接转换现有列,也可以创建新列。转换数据时,它还会同时转换列属性,例如参考线、访问设置、规格限制等等。
除了这些功能之外,还有一个可浏览的数据库,其中包含所有支持的单位及其组合方式,以及一个 JSL API。如果您对此感兴趣,可以扫描屏幕上的二维码,或者访问社区查找单位转换插件。
关于插件的功能介绍就到这里。接下来,我将介绍插件的开发过程。插件的源代码控制我使用了 Git 和一个内部的 GitLab 实例。构建和部署插件时,我使用了自定义的解决方案,包括一个构建插件 JSL 文件和一个清单 JSL 文件,稍后我会详细介绍。测试方面,我使用了 JSL Hamcrest 框架,你可以在 GitHub 上找到它。我是该框架的共同开发者之一。我们在 JMP 内部使用该框架来测试 JMP 本身,我也用它来测试这个插件。
文档主要使用 Markdown 文件,然后通过 Pandoc 转换为 HTML,再导入到插件中,最后使用 JMP 内置的 Web 浏览器在插件中显示。所有功能均使用 JSL 和 Python 实现,并使用了 Python 中的 pint 库。此外,还使用了其他工具,包括 JMP、VS Code、Git、Pandoc 和 Google Material Icons。
插件的顶层结构如下:构建文件夹、文档文件夹、源代码文件夹、测试文件夹,以及自述文件(markdown格式)。测试文件是独立存在的。构建文件夹包含构建插件、清单文件和工件子文件夹,工件子文件夹用于存放HTML文件以及构建完成后JMP插件本身。文档文件夹主要包含屏幕截图等内容。源代码文件夹包含多个子文件夹、图标文件夹和菜单文件夹。菜单文件夹包含一些非常简单的JSL操作文件,它们只是作为JMPcust文件的入口点,源代码文件夹(包含大部分代码)也使用了这些文件。此外,还有定义JMPcust文件和添加加载JSL文件。
清单文件本质上是左侧结构中所有文件的列表,这些文件最终都会被打包到 JMP 插件的归档文件中,然后进行安装。构建插件的 JSL 脚本会执行 Pandoc 步骤,将 Markdown 转换为 HTML,读取清单文件,并使用 JSL Zip 归档 API 收集所有文件,然后将它们放入构建工件目录中的 JMP 插件文件中。
每当我想添加新功能时,我都会在源图标中添加一个图标。然后我会在源菜单中添加一小段占位代码,大部分代码也会添加到源文件中。我会将这三个文件添加到清单文件中,并编辑 JMP 插件的 Cust 文件,使其引用源菜单中的那段占位代码。之后,我就可以构建插件,开始开发该功能,并在测试文件中添加测试用例。
源菜单中的子程序只会进行一些基本的验证,例如查找当前数据表之类的操作。然后它会包含主源文件,并调用 GUI。这样做的目的是为了方便我们在测试中包含主源文件,从而在不调用 GUI 的情况下测试该功能。这很好地划分了源菜单(点击菜单时交互式调用的部分)和测试文件,它们都通过源文件运行。
最后,由于这个插件很大一部分都用到了新的 JMP 18 Python 集成,我想详细讲解一下它的工作原理。它主要包含三个部分。首先是插件加载文件。每次加载插件时,我们都会尝试安装 Python 包。pint 就是其中之一。安装它,并确保它已安装成功。然后,我还有一个随插件一起安装的 com_jmp_unitconversion.py 文件。接下来,我将使用这个完全限定名称导入它。
基本上,这个 Python 文件里的所有内容都是函数定义,它们都使用了 pint 库。但实际上并没有太多工作要做,只是函数定义而已。然后在核心 JSL 代码中,我使用完全限定名和 Python 集成将这些 Python 调用封装在一个 JSL 函数中。这样,在插件的其他部分,我就可以直接使用右侧的 JSL 函数了。单位可以转换吗?英尺到公里?可以。英尺到毫升?不行。它只是使用了普通的 JSL 函数,但在内部,这些函数是通过 Python 集成传递给 Python 代码的。所有东西都在插件加载时设置好,我的所有 Python 代码都整齐地包含在这个包里,所以不会污染整个 Python 命名空间。
我就是这样利用 JMP 18 中新增的 Python 集成功能开发了这个物理单位转换插件。谢谢。