Ruby + Numo::Gnuplot（numo-gnuplot gem）で散布図を描く


@obelisk68 さんに教えてもらったサンプル（[ruby_gnuplot の記事のコメント](https://qiita.com/sonota88/items/50609275668fcd7511e4#comment-0890d29e9583e74eba70), [ブログ](https://obelisk.hatenablog.com/entry/2022/05/29/181912)）で十分という気もしたのですが、一応自分でも触ってみました。

https://rubygems.org/gems/numo-gnuplot

https://github.com/ruby-numo/numo-gnuplot



# 準備

- gnuplot コマンドをインストール
  - Ubuntu 18.04 の場合は `sudo apt install gnuplot`
- Numo::Gnuplot をインストール
  - `gem install numo-gnuplot`

これだけ。

[Numo::NArray](https://github.com/ruby-numo/numo-narray) は必須ではありません（インストールも不要）。以下は Numo::NArray なしで試しています。




# 最低限の例

PNG ファイルに出力する最低限の例です。

```ruby
# sample.rb

require "numo/gnuplot"

xs = [1, 2, 3, 4, 5]
ys = [11, 22, 33, 44, 55]

Numo.gnuplot do
  set terminal: "png"
  set output: "output.png"
  plot xs, ys
end
```

```sh
  # 実行 ... output.png が生成される
ruby sample.rb
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/ee12ff3d-91d0-f2e1-1fb8-fc5bcf1be8e9.png)


簡単ですね。
ちょっと見えにくいですが、 両端の点は枠線に重なっています。

<!--
PNG 以外にも、 SVG や PDF として出力することもできます。
-->


# 環境

```sh
Ubuntu Linux 18.04
gnuplot -V #=> gnuplot 5.2 patchlevel 2
ruby -v    #=> ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
gem:
  numo-gnuplot 0.2.4
```



# メモ

- [ruby_gnuplot](https://github.com/rdp/ruby_gnuplot) と同様、インストールが楽なのが良い。gnuplot コマンドのインストールさえ済んでしまえば、他にインストール絡みでトラブルが起きる余地がなさそう。気分的に楽 :ok_hand:
- `numo/gnuplot.rb` ( https://github.com/ruby-numo/numo-gnuplot/blob/master/lib/numo/gnuplot.rb ) はコメントを除くと1,000行ちょいなので、サッと読める。ruby_gnuplot よりは大きめですが。
  - `Numo::Gnuplot#initialize` で `IO.popen` したプロセスにコマンドを送る方式

<!--
`Numo::NArray` が使いたい場合はよさそう。あとなるべく Ruby っぽく書きたいという気持ちがある場合。
そうでない場合は、個人的には ruby_gnuplot を使うのもシンプルでいいんじゃないかなあ、みたいな感想です。
-->

---

ruby_gnuplot との機能比較でいえば、以下のあたりが違うようです:

- Numo::NArray に対応している
- [IRuby](https://github.com/SciRuby/iruby) に対応している
- irb で対話的に操作できる
  - gnuplot の対話型インターフェイスの代わりに使えるっぽい




# 自分が使いそうな機能についてメモ

- グラフのタイトル指定
- 複数の系列の描画
- 数式のプロット

などは [README](https://github.com/ruby-numo/numo-gnuplot) や [Introduction.ja · ruby-numo/numo-gnuplot Wiki](https://github.com/ruby-numo/numo-gnuplot/wiki/Introduction.ja) にサンプルがあるので、そっちを見てください。

## 軸タイトル

```ruby
Numo.gnuplot do
  set xlabel: "x軸のラベル"
  set ylabel: "y軸のラベル"
  # ...
```
## x軸, y軸の範囲指定

```ruby
Numo.gnuplot do
  set xrange: 0..6
  set yrange: 0..60
  # ...
```

## 凡例の系列名

```ruby
Numo.gnuplot do
  plot xs, ys, title: "series name"
  # ...
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/abaae699-e8d5-f12c-b479-33a713f9abb5.png)



## 日本語フォント

無指定だと日本語が豆腐になりました。

```ruby
Numo.gnuplot do
  set terminal: "png font 'VL Gothic,20'"
  # ...
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/550b4167-cb35-0b05-f8f3-badfdb95292b.png)




## 点の代わりにラベルを表示する

```ruby
xs = [1, 2, 3, 4, 5]
ys = [11, 22, 33, 44, 55]
labels = ["A", "B", "C", "D", "E"]

Numo.gnuplot do
  # ...
  plot xs, ys, labels, with: "labels"
end

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/794c85dc-e325-124e-cb8b-6a1c204d4a5e.png)




## デバッグ出力

`debug_on` を使うと、 gnuplot に送信しているコマンドを標準出力に出力することができます。

```ruby
xs = [1, 2, 3, 4, 5]
ys = [11, 22, 33, 44, 55]

Numo.gnuplot do
  debug_on
  set terminal: "png"
  set output: "output.png"
  plot xs, ys
end
```

```sh
$ ruby sample_debug.rb
<set terminal png
<set output "output.png"
<plot '-' 
<1 11
<2 22
<3 33
<4 44
<5 55
<e
```

行頭の `<` を取り除いてやれば、そのまま gnuplot に渡せるようです。

```sh
$ ruby sample_debug.rb | sed -e 's/^<//g' > sample.gs

$ cat sample.gs
set terminal png
set output "output.png"
plot '-' 
1 11
2 22
3 33
4 44
5 55
e

  # スクリプトを gnuplot コマンドに渡して実行
$ gnuplot sample.gs
```




# まとめたもの

せっかくなのでいろいろ含めたものも貼ってみます。
@obelisk68 さんが書いてくださったのとほぼ同じ。

```ruby
require "numo/gnuplot"

xs = [1.0, 1.8, 3.1]
ys1 = [11, 25, 32]
ys2 = [21, 35, 42]
ys3 = [31, 45, 52]
  
Numo.gnuplot do
  set terminal: "png font 'Noto Sans CJK JP,12'"
  set output: "output.png"
  set title: "グラフのタイトル"
  set xrange: 0..6
  set yrange: 0..60
  set xlabel: "x軸のラベル"
  set ylabel: "y軸のラベル"

  plot xs, ys1, { title: "系列1（点のみ）" },
       xs, ys2, { title: "系列2（線のみ）", with: :lines },
       xs, ys3, { title: "系列3（点と線）", with: :linespoints },
       "x * 10", { title: "y = x * 10" }
end
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/a1f7a457-1bad-3749-58d8-89419cb7f7a7.png)




`with: :lines` のように指定するか、または数式を使えば任意の直線が描画できるので、回帰直線もこれでいけますね（フィッティングの話については割愛）。

# 参考

<!--
ruby-numo/numo-gnuplot-demo: Ruby/Numo::Gnuplot Demo
-->
https://github.com/ruby-numo/numo-gnuplot-demo

めちゃくちゃいっぱいある gnuplot 本家のサンプルを Numo::Gnuplot に書き直した版。README から辿れる情報ですが一応。





# この記事を読んだ人は（ひょっとしたら）こちらも読んでいます

<!--
Ruby + ruby_gnuplot（gnuplot gem）で散布図を描く - Qiita
-->

https://qiita.com/sonota88/items/50609275668fcd7511e4

ruby_gnuplot もシンプルで良いと思いますよ。

<!-- SVG::Graph（svg-graph gem）で散布図を描く - Qiita -->
https://qiita.com/sonota88/items/86afece3b2595648a656

<!--
Galaaz を触ってみた（TruffleRuby + ggplot2 で散布図を描いてみた） - Qiita
-->
https://qiita.com/sonota88/items/b586e96f7805a5695a34