新手问题 没想到在 IRuby 中绘个图这么难…

liggest · 2021年08月22日 · 最后由 liggest 回复于 2021年08月31日 · 1117 次阅读

前情提要

本人小白,没写过太多 Ruby,之前学过一点 Python

最近想试着在 Jupyter Notebook 中写点代码,有个绘制柱状图/直方图的任务,说是建议使用 matplotlib 或 Gnuplot

用过的可能知道,Jupyter Notebook 默认基于 IPython 内核提供了交互式编程环境,用来做一些计算分析和绘图,在一个记事本里展示出来,个人感觉还挺方便的

恰好前段时间发现也有个能用的 IRuby 内核,可以在记事本里面跑 Ruby,听起来还不错

因为 Python 中直接用 matplotlib 就可以轻松在记事本中绘图,故我下意识的以为这应该是个很快就能搞定的任务

前提是在 Ruby 中找到合适的库…

所用环境:

  • Windows 10
  • Ruby 3.0.2
  • Python 3.7.2(用 Anaconda 装的)
  • IRuby 0.7.4
  • Pry 0.14.1(因为用 Pry 做的 IRuby 后台)

太长不看

在尝试过 matplotlib.rbgnuplotrbnumo-gnuplotdaru-view 后,最终发现 daru-view 依赖中的 nyaplot 在 5 年未更新后依然是可用的,折腾了大半天终于画出了柱状图,好耶!

踩坑

matplotlib.rb

因为要绘图,首先想到了 matplotlib,毕竟任务也推荐使用嘛

发现 PyCall 的作者也特地为 matplotlib 做了 Ruby 中的封装 gem,就是 matplotlib.rb,还提供了 IRuby 使用示例,当场就安装了。

起初是在require的时候会提示 Python 那边的ImportError,好像是 numpy 在初始化时无法找到某些 DLL,相应的 matplotlib 也无法成功导入

于是尝试在搜索引擎和 Github Issue 中寻找解决方案,numpy 的 Issue 中似乎提到这是由 Conda 安装的 numpy 才有的问题,应该和 Conda 环境有关

不像用 Python 内核时那样,即便我在启动 Notebook 前先进入 Conda 环境,PyCall 似乎也无法正确导入相应的包

在花了一些时间后,我在 PyCall 仓库一个名为 windows 的 workflow 中发现它好像在执行测试时将环境变量CONDA_DLL_SEARCH_MODIFICATION_ENABLE设为了1

于是我这边在require前也照做了一下,同时用PyCall.init指定了 Python 可执行文件的的位置,确实使得ImportError消失了,但导入仍未成功,取而代之的是从 Ruby 端执行到 C 端后产生的大量报错调试信息,感到自己没法解决这个问题,只能作罢

gnuplotrb

转而去看看能不能用上 Gnuplot,在 SourceForge 上下载并安装了,窗体程序似乎正常运行

Ruby 这边,虽然有 Star 更多的 ruby_gnuplot,但其 README 中似乎没提到任何支持 IRuby 的内容,故选择先试着用与 IRuby 同属一组织的 gnuplotrb

安装完后把它 示例记事本 的首格代码丢到这边的记事本中测试

提示参数个数有问题,应该有 1 个参数,实际给了 2 个,猜测应该是 Ruby3.0 以来关于关键字参数的修改 导致的,斗胆开 VSCode 顺着源码查了一下,把喂给参数的 Hash 按关键字参数的格式传进去了

本以为这样就能画出图了,然后代码一运行当场就卡住了(代码所在的那一格无法停止运行)

调试发现,似乎Plot.new的执行并没有什么问题,但 IRuby 在将其返回的对象显示出来的过程中出现了问题

本以为是 IRuby 的问题,但粗略探索后发现似乎它的display方法主要是调用了对象相应的to_xxx方法(如to_png),而且先前照着 IRuby 示例也成功显示过 svg

转而去看 gnuplotrb 那边,经过数次重启记事本的尝试,发现似乎是同 Gnuplot 通信时,本应用Open3.capture2e获取输出结果,但不知为何其启动的 Gnuplot 无法结束执行,导致程序原地卡住

在 Pry 与 Irb 中都试着运行了同样的语句,均会让程序卡住

更糟的是,即使 Ctrl+C 强行终止,似乎 Gnuplot 依然会在后台运行,甚至记事本重启也不会使其结束,以至于后台运行的 Gnuplot 数量随着记事本重启而不停增加,后面想结束 Jupyter 时似乎才一并把不知多少个 Gnuplot 结束掉,控制台直接未响应了……

这还是试用 Gnuplot 不成,卸载时卸不干净才发现的

尝试把Open3.capture2e换成了能执行命令行指令的 ` `(反引号),似乎解决了上述问题,虽然还搞不清楚它们有什么区别…

但返回去执行示例代码,程序却依然卡住,Github 上似乎也有人提到了这个问题,但却没有解决方案…

此时我已经有点疲惫了,决定先去看看其他绘图库

numo-gnuplot

借助搜索引擎我找到了 ruby_gnuplot、gnuplotrb 之外的另一个 Gnuplot 库—— numo-gnuplot,本体 Numo 似乎是一个数值计算库(类似 Numpy?),也写明了支持 IRuby

虽然安装本体 Numo 没能成功,但似乎 numo-gnuplot 可以单独安装使用

然后执行了 README 中的示例代码,不出意外地又卡住了

果然在 Windows 下用 Ruby 调用 Gnuplot 会有问题吧…?这样想着,也不再太多兴趣去试着解决卡住的问题,干脆把上述几个用不了的库全都卸掉了 (╯‵□′)╯︵┻━┻

解决

再次求助谷歌(百度搜不到什么相关内容啦…),又看到一个名为 daru-view 的,本体是 Daru(看起来像类似 pandas 的东西?)

daru-view 似乎作为 Daru 的插件使用,万幸两者都安装成功

它看起来还挺高级的,内部集成了:googlecharts:highcharts:nyaplot三套绘图工具,安装时一下子装了十四、五个 gem,好家伙,我只是想画个柱状图而已

其中安装 nyaplot 时命令行出现了诸如欢迎使用 nyaplot 和推荐使用 IRuby 的输出,让我想起 IRuby 的示例中确实也有使用 nyaplot 绘图的内容,想必两者关系还挺密切的

但 nyaplot 仓库默认分支的最后更新日期是 2016 年,已经约莫 5 年没更新过了,看起来就是一种年久失修的状态

抱着既然都装上了就先试试看的心态,用记事本运行了一些示例代码

结果图啪地一下就出来了,我也啪地从椅子上弹了起来——折腾了大半天,终于看到了柱状图!

不知道说什么好,默默地看了一眼那个让我找到其它几个绘图库的帖子的标题——Nyaplot 在 Jupyterhub 上的 IRuby 中无输出

总而言之,没有再继续测试 daru-view 的各种用法,暂且先用 nyaplot 完成了几个简单的绘图任务

虽然绘图功能看起来不及 matplotlib 那样复杂且强大,但用起来感觉还挺相似的,而且在 IRuby 上显示出来的图还能有轻度交互(缩放、查看数值之类的),感觉还算有点小惊喜的

碎碎念

感觉接触 Ruby 后,像这样想用一些工具,经常会出现不好使的情况…

除了 Ruby 对 Windows 的支持确实不算很优秀之外,感觉对于一些特定任务,可能也缺少那种大家集中开发、使用,处于领导地位的库

相应地在 Python 中,绘图大概会用 matplotlib,数值计算常常需要 Numpy,数据分析有 pandas 等等…似乎大家会聚焦于几个特定的库,而这些库也因此能愈发发展,变得更加强大,因而也越能吸引更多人,比如我这样的小白去入门使用

因此看到有类似的 NumoDaru 等出现在 Ruby 中,第一反应还挺开心的(虽然 Numo 装都没装上)

IRuby 用起来感觉还有一些小问题,比如代码提示有时候不起效,会把代码结构搞乱等,可能是我还对相关工具不太熟练吧,体验不算完美,但也没有很差,能让 Ruby 搭上 Jupyter Notebook 交互式编程这一得力工具,感觉也挺不错的了

这些库目前感觉关注的人很少,从 Github 的 Star 数也能看出来,但就像 Python 那一系列库和 Jupyter Notebook 一起被用到各种学术研究领域,感觉 Ruby 在这方面还是能有一定前景才是…

至于绘图相关的库… numo-gnuplot 的 README 中提及的参考便有 ruby_gnuplotruby-plotPlotrobber(404)gnuplotrgnuplotterscbi_plotgnuplotrbnumplot,此外还能找到 rubyplotcharty 等…

再补上文中提到的,不禁让人感叹,要是只有“matplotlib”该多好…可能更多开发者能合力维护一个项目,不至于像 nyaplot 那样看起来年久失修吧…

最后需要说明的是以上内容包含大量个人见解和闲扯,萌新一枚不太懂什么规矩,如有问题还请随意指正…如果大致读完了,那真的很感谢能看我啰嗦这么多!

IRuby 内核对 Jupyter 消息协议的实现不太完整....可能 IPython 更易用😂

exfx 回复

确实,感觉很多地方都挺简陋的…比如代码格中执行命令行脚本的 "!" 好像就没在 IRuby 中看到过

不过毕竟 py 那边是原装的,ruby 有总比没有强,能跑起来就感觉还不错了 233

liggest 回复

再怎么说 IPython 可是(号称)能当系统 Shell 的东西,有着!开头的系统 Shell 透传和%开头的各种 Magic,甚至还用了 https://www.python.org/dev/peps/pep-0215/ 的字符串嵌入展开,还有着基于变量的强类型管道。

这些概念 Jupyter 是不关心的,虽然我有理由怀疑 Jupyter 的块是为了 IPython 的块魔法开的绿灯。而 IRuby 在我印象里应该就只是把 IRB 或者可选的 Pry 用 ZeroMQ 连接到 Jupyter 而已,没有这些特性也是理所应当的吧。

至于绘图那更是 Python 老家那边更加擅长,把 matplotlib 的 ipympl 后端列为 JupyterLab 的依赖里就是说句话的事情。所以折腾 ML 和统计还是直接用 Python 得了。

459650075 回复

还有这种,涨知识了 233,这样看 IPython 好厉害啊

单纯执行命令行指令的话 Ruby 本身有反引号,感觉还算可用,剩下的就只能羡慕 IPython 的魔法了

IRuby 好像确实只是把 IRB 或 Pry 接到了记事本上面

结果我这边用 Pry 后台对双引号字符串就没有代码补全;若不在代码块尾部触发补全,还可能把后面的代码吞掉,总之感觉是有点别扭的…

这次主要是想试着写点 Ruby,然后看看 IRuby 能做到什么地步,就经历来说确实有点折腾了 233

目前是感觉 Ruby 在一些简单的迭代逻辑上更清晰一些,可以将对可迭代对象的一系列处理串起来(如 .map.zip 这样)

而且似乎 Ruby3 的 IRuby 在我这里执行速度还挺快的(不知道是不是错觉)

遇到一些复杂的任务(统计、机器学习啥的),缺少第三方库的支持,确实还是得回去依靠 Python 了

马太效应,强者越强。有这个需求的一开始就会选最成熟的平台,缺少人扩展 Ruby 的这一领域。

liggest 回复

IPython 在执行命令这方面还是猛的,一方面是把很多东西都 Alias 进来了,不用加感叹号也能执行,另一方面是命令的返回不仅仅是其他语言的 REPL 里捕获标准输出作为一个字符串或者 Buffer,还按照 Unix 的习惯分节符给切成了数组(有时候不准,就是一行一个元素),所以有人说 IPython 尝试做 PowerShell 的有类型管道(虽然没多少人 care)。

Ruby3 我印象里是提升了粘贴 IRB 多行代码的效率,以前的话要等好久。至于速度和以前有什么区别还真不太确定。我倒是觉得没有必要强行往 Jupyter 上面凑,那上面虽然列出来 Kernel 的很多,能用的也就是 Python 和 R 的了。至于逻辑的组合,隔壁 Elixir 的作者在搞一个叫 Nx 的东西,借助 Elixir 能够操纵 AST 的宏机制,把 Elixir 代码编译到 Google 的 XLA,这样写个核函数或者激活函数啥的,就能以比较高效的方式在 CPU 或者 GPU 上运行。我觉得这才是比较合理的思路,Ruby 的话因为宏基本上还是基于字符串的,虽然其本身控制流在通用领域比 Python 强不少,但在计算这方面往往还是需要手动请原生外援然后做绑定,像 Elixir 这样直接编译过去应该比较难做吧。

另外 Elixir 就不打算去做适应 Jupyter 的尝试,而是自己用 Phoenix LiveView 写了一个 Livebook,可能也是因为这么做更加符合 BEAM 虚拟机的架构(一个 Notebook 一个 BEAM Process 或 Node),另外用了 LiveView 也好做多人协作。这样的话绘图之类的也是自己从头做起,用的是 Vega Lite,还做了动画的适配。

与其这样,不如直接用 python 了。

liggest 回复

之前写过一个在 IRuby 中安装 gem 的小工具,欢迎试用

459650075 回复

果然自己对 IPython 等的了解还是太少了…之前只在记事本中用过一点相关的

至于 Elixir,虽然只是听到过名字的程度,但这边好像时不时就会有相关的帖子,感觉好像还挺受推崇的样子?

接触一点 Ruby 之后感觉总能看到各种看起来挺有意思的东西,包括 Ruby 本身的工具链,以及 Rust、Elixir 什么的…奈何自己学习力跟不上,太多信息涌进来就有点不知从何入手了😶

Rei 回复

确实是这样…我这种只会装、卸包的人缺了工具就只能干着急了😶

感觉要发展起来,有技术的主力开发者和热闹的社区都是挺必要的…

gingerhot 回复

看了一下,感谢分享~

直接用 python 吧

在 Windows 上折腾 ruby,想想就头大。。

pynix 回复

目前感觉是还算能用的程度😶

  • RubyInstaller 装上的本体和 gem 等看起来都没太大问题,不同版本也可以暂时通过环境变量、命名等区分
  • IRuby 之类一些做过支持的库也能正常安装
  • 装了插件的 VSCode 和记事本写起来虽然都有别扭的地方,但感觉也还算能用(不知道 RubyMine 会不会好用一些)
  • 第三方 gem,尤其是非纯 Ruby 的那种,就有点不妙了…

至于 Rails 相关的目前还没接触太多,就不太清楚体验如何了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号