Ruby/Tkで少しだけインタラクティブなグラフを表示する
はじめに
以前書いたように、Ruby/TkとPlotchartでグラフを表示できるのですが、それだけではつまらないので、ちょっとだけマウスと連動させてみます。
コード
#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'csv' require 'tk' require 'tkextlib/tcllib/plotchart' # plotchart.rb を修正するモンキーパッチ module Tk::Tcllib::Plotchart class XYPlot def pixel_to_coords(x, y) list(tk_call_without_enc('::Plotchart::pixelToCoords', @path, x, y)) end end end # データを読み込み en, cn = CSV.parse(DATA).map { |r| [r[0].to_f, r[1].to_i] }.transpose # データをプロット pl = Tk::Tcllib::Plotchart::XLogYPlot .new([0, en.size, 10**Math.log10(en.size).floor], [1, 10**Math.log10(cn.max).ceil], width: 600, height: 400) do title 'Spectrum' xtext 'Channel' ytext 'Counts/Channel' dataconfig('series1', color: :red) cn.each_with_index { |c, i| plot('series1', i, c) } pack(fill: :both) end # マウスカーソルの位置の値を表示 label = TkLabel.new.pack pl.bind(:Motion, '%x %y') do |x, y| ch = pl.pixel_to_coords(x, y)[0].to_i if 0 <= ch && ch < en.size label.text(sprintf('%10d ch, %10.1f keV, %10d counts', ch, en[ch], cn[ch])) end end # イベントループ Tk.mainloop __END__ 32.78,1074 62.72,12131 92.70,13944 122.72,13110 152.79,11859 182.90,13204 213.05,11647 243.24,8780 273.47,7412 303.75,6632 334.07,6460 364.43,6369 394.83,6503 425.28,6566 455.76,5250 486.29,2766 516.86,1574 547.48,1062 578.13,914 608.83,3532 639.57,15018 670.35,18992 701.18,6495 732.04,660 762.95,177 793.90,157 824.89,134 855.93,154 887.00,131 918.12,124 949.28,129 980.48,113 1011.73,96 1043.01,103 1074.34,112 1105.72,92 1137.13,95 1168.58,86 1200.08,85 1231.62,66 1263.20,50 1294.83,29 1326.49,40 1358.20,33 1389.95,47 1421.74,93 1453.57,111 1485.45,67 1517.37,41 1549.33,19 1581.33,17 1613.38,11 1645.46,13 1677.59,18 1709.76,15 1741.98,10 1774.23,6 1806.53,13 1838.87,15 1871.25,11 1903.67,6 1936.14,8 1968.64,6 2001.20,8
実行結果
OSX Yosemiteで実行した結果です。下記のように、マウスカーソルの位置の値がグラフの下に表示されます。
Ruby 2.2.0同梱のplotchart.rbのバグ
グラフ内におけるマウスカーソルの座標を取得するためにTk::Tcllib::Plotchart::XLogYPlot#pixel_to_coords
を使ったのですが、Ruby 2.2.0 同梱のplotchart.rb
にはバグがあるので、下記のようにモンキーパッチを当てています。
module Tk::Tcllib::Plotchart class XYPlot def pixel_to_coords(x, y) list(tk_call_without_enc('::Plotchart::pixelToCoords', @path, x, y)) end end end
既に修正が本家に取り込まれたようなので、そのうち必要なくなると思います。
最後に
Ruby/TkとPlotchartさえ入っていればWindowsでも動きます。しかし、WindowsはPlotchartを使えるようにするまでがちょっと面倒でした(こちらに書きました)。