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

liggest · August 22, 2021 · Last by liggest replied at August 31, 2021 · 1123 hits

前情提要

本人小白,没写过太多 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 更易用😂

Reply to exfx

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

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

Reply to 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 得了。

Reply to 459650075

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

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

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

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

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

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

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

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

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

Reply to 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 了。

Reply to liggest

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

Reply to 459650075

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

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

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

Reply to Rei

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

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

Reply to gingerhot

看了一下,感谢分享~

直接用 python 吧

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

Reply to pynix

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

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

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

You need to Sign in before reply, if you don't have an account, please Sign up first.