LoginSignup
7
3

More than 3 years have passed since last update.

PyCall を使って Ruby でハートを描く その 2

Last updated at Posted at 2021-04-25

はじめに

以前 PyCall を使って Ruby でハートを描く という記事を書きました。それから約 4 年後、久しぶりに PyCall を触ってみました。今度は 3D のハートを描画してみようと思います ❤️

PyCall について

PyCall は Ruby から Python のコードを呼び出すことができる、mrkn (Kenta Murata) さんが作成されている Gem です。この mrkn さんは numpy.rbmatplotlib.rb など、Python で非常に有名なライブラリのラッパーライブラリも作成してくれています。今回はそれらも使用します。

バージョン情報

$ ruby -v
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-darwin20]

$ gem list | grep -e "pycall" -e "numpy" -e "matplotlib"
matplotlib (1.1.0)
numpy (0.2.0)
pycall (1.3.1)

$ python --version
Python 3.9.2

$ pip list | grep -e "numpy" -e "matplotlib"
matplotlib      3.4.1
numpy           1.20.2

コード

Stack Overflow の how to draw a heart with pylab という記事に記載されている Python のコードを Ruby に書き換えました。

require 'matplotlib/pyplot'
require 'numpy'

Axes3D = PyCall.import_module('mpl_toolkits.mplot3d').Axes3D

def calculate_3d_heart(x, y, z)
  (x**2 + (9.0 / 4) * y**2 + z**2 - 1)**3 - x**2 * z**3 - (9.0 / 80) * y**2 * z**3
end

def plot_3d_heart
  xmin, xmax, ymin, ymax, zmin, zmax = [-1.5, 1.5] * 3
  fig = Matplotlib::Pyplot.figure
  ax = fig.add_subplot(111, projection: '3d')
  a = Numpy.linspace(xmin, xmax, 100)
  b = Numpy.linspace(xmin, xmax, 40)
  a1, a2 = Numpy.meshgrid(a, a)

  # numpy.ndarray は each や to_a ができないので index で値にアクセスする。
  b.size.times do |i|
    x = a1
    y = a2
    z1 = b[i]
    z2 = calculate_3d_heart(x, y, z1)
    ax.contour(x, y, z1 + z2, [z1], zdir: 'z', colors: ['red'])
  end

  b.size.times do |i|
    x = a1
    z = a2
    y1 = b[i]
    y2 = calculate_3d_heart(x, y1, z)
    ax.contour(x, y1 + y2, z, [y1], zdir: 'y', colors: ['red'])
  end

  b.size.times do |i|
    y = a1
    z = a2
    x1 = b[i]
    x2 = calculate_3d_heart(x1, y, z)
    ax.contour(x1 + x2, y, z, [x1], zdir: 'x', colors: ['red'])
  end

  ax.set_zlim3d(zmin, zmax)
  ax.set_xlim3d(xmin, xmax)
  ax.set_ylim3d(ymin, ymax)

  Matplotlib::Pyplot.show
end

plot_3d_heart

上記の Ruby スクリプトを実行すると Tk のウィンドウが開きます。

Kapture 2021-04-25 at 21.12.27.gif

若干血しぶきが飛び散っているのはご愛嬌 😇

ちょっとした悩み

Python ではスカラー値を x、ベクトル値を X のように変数名の大文字と小文字を使い分けているが、Ruby ではどうすればいいのでしょう 🤔 Ruby だと大文字は定数と判断されるためです。

参考

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3