いまGNU OctaveCUIソフトウェアと呼ぶのは不正確ですが、コマンド入力だけでもグラフを描けるという意味で大目に見て下さい。今回はFLTKによるグラフ描画機能を試し、若干問題あるもののpsqlからシームレスに使う基礎ができました。
Contents



実行環境

 • Windows7 x64 + Cygwin 2.5.1 + ConEmu 150813g
 • Cygwinpsql(パッケージpostgresql-client 9.5.3でインストール)
 • WindowsOctave 4.0.3
 • Windowsの管理者権限ユーザ

psqlが接続したPostgreSQLWindows版の9.5.3(直接関係ないけど。何らかDBサーバに接続しないとpsqlを使えないので)。Octave
公式サイトのFTPから。ここにあるのは32bit版のみで、octave-4.0.3.zipをダウンロード&適当な場所に解凍しました。これでポータブルに使えます。


準備その1 : Octave動作確認

まず、前回のWingnuplotと同様Cygwinシェルから起動&グラフ表示できるかの確認。今回用いたzipには起動用batvbsが複数含まれ、本来はそれを使う(または同等の環境設定をする)べきですが、とりあえずCUIプログラムを直接実行したら ↓ 普通に対話型シェルが起動し、グラフもFLTKがデフォルトで描画されました。
$ d:/works/octave/current/bin/octave-cli
GNU Octave, version 4.0.0
Copyright (C) 2015 John W. Eaton and others.
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  For details, type 'warranty'.

Octave was configured for "i686-w64-mingw32".

Additional information about Octave is available at http://www.octave.org. 

Please contribute if you find this software useful.
For more information, visit http://www.octave.org/get-involved.html

Read http://www.octave.org/bugs.html to learn how to submit bug reports.
For information about changes from previous versions, type 'news'.

octave:1> plot(1:10)

グラフをよく見ると目盛ラベルの数値が変です。これが冒頭に書いた「若干問題ある」点。Octaveの起動方法を端折りすぎたせい? でも一応グラフは出たので良しとし、今後の課題にします。(814日追記)ロケールのLC_CTYPEja_JP.UTF-8のシェルでWindowsOctaveを起動したのが原因で、LC_CTYPECにして起動したら解消しました。詳細は最終回のこちら。

他の環境でも問題が再現するか、職場のWin7 x64(標準ユーザ)のコマンドプロンプトで同様に起動させたら、plotコマンドでOctave自体が異常終了。↓ グラフィックウィンドウが出た後、何か問題が起きてるっぽい。。。

職場のPCは自分が管理してなく、いろいろ制約が多いので一般化できませんがOctaveでのFLTK自体まだ発展途上かも。という仮定で、とりあえず先に進みます。


準備その2 : CygwinpsqlからOctave対話シェルの動作確認

psqlから、外部コマンド実行(\!)でOctaveを動かすテスト。前項ではOctaveのフルパスを入力しましたが、ここから簡単のため環境変数に入れます(\setenv)。ついでに起動時の長いメッセージを非表示にするオプション -q を追加。
# \setenv octave 'd:/works/octave/current/bin/octave-cli -q' 
# \! $octave
octave:1> plot(1:11)
octave:2> exit

# (returned to psql)

前項と同様、対話型シェルに普通に入ることができ、グラフ出力は目盛ラベルだけ変という結果。今回はこれでテストを終え、次に本来の目的「PostgreSQLのクエリ結果をOctaveへ渡してグラフ表示」に移ります。


クエリ結果をOctaveに渡し、対話型シェルでグラフ描画

Octave起動時に標準入力で何か渡すと、コマンドとして実行し即終了します(psqlが標準入力をSQLとして実行するのと同じ)。だからgnuplotでやった標準入力利用はできず、一時ファイル経由が唯一の選択肢。

psqlOctaveを起動する際、--persistを付ければ対話シェルに留まります。また --evalに続けてOctaveのコードを書けるので、クエリ結果(一時ファイルの中身)を変数として読み込む処理を入れておくと便利。それに続いてグラフ用の変数を整えてプロットしたのが ↓ です。冒頭の画像もこれ。
-- set output format
# \t on \\\pset format unaligned \\\f ' '

# select x, y, sin(r) / r
  from generate_series(-8, 8, 0.4) as x,
      generate_series(-8, 8, 0.4) as y,
      cast(sqrt(x^2 + y^2) + 1e-9 as float) as r
  \g tmp3 \\\! $octave --persist --eval "d=load('tmp3');" 
octave:1> x = sort(unique(d(:,1)));
octave:2> y = sort(unique(d(:,2)));
octave:3> z = reshape(d(:,3), length(x), length(y));
octave:4> mesh(x, y, z)
octave:5> exit

# (returned to psql)

プロットしたのは
ドキュメントにあるソンブレロ。3次元座標をPostgreSQLのクエリで作り、Octaveシェル内でmesh関数に渡す形にしてます。SQLは全点のx, y, zを出力し(でないと表形式にならない)mesh関数のxyは区画を1回だけ受け取るので、結果として非効率。PostgreSQLの配列型などを使い改善できないか、今後考えます。


Octave起動と同時にグラフを出す場合

例えば ↓ こんな感じ。クエリは前項のソンブレロ用3次元座標をそのまま使い、\gの後だけ変えました。データ全体を変数(ここではd)に入れても、Octaveのグラフ描画で列ごとの変数に分ける必要があって--eval以下が長くなりがち。書式も1列目なら(:,1)と、[]を使わないのが馴じみにくい…。
-- set output format
# \t on \\\pset format unaligned \\\f ' '

# \g tmp3 \\\! $octave --persist --eval "d=load('tmp3'); plot3(d(:,1), d(:,2), d(:,3))" 
octave:1> ...


上のようにグラフを描画した後、そのままOctaveの対話シェルで作業できます。psqlに戻るには対話シェルの終了が必要(exitコマンド)。


グラフを閉じたら即psqlに戻る場合

前項の方法で、psqlから1コマンドでグラフを出せます。次に、グラフを一見して「あ~クエリ間違えた、psqlでやり直す」時を想定すると、いちいちOctaveシェルにフォーカスを移してexit入力はちょっと面倒。グラフウィンドウを閉じたら即psqlに戻れる方法として ↓ こんな手があります。
-- set output format
# \t on \\\pset format unaligned \\\f ' '

# \g tmp3 \\\! $octave --eval "d=load('tmp3'); plot(d(:,1), d(:,3)); waitfor(gcf); exit" 

グラフ描画後に続いてコマンドwaitfor(gcf)を入れると、グラフィックウィンドウを閉じるまで待機状態になるらしい。でその後にexitを入れておけば「グラフを閉じたら即終了」になってpsqlに戻るという仕組みです。シェルに留まる必要はないのでOctave起動時のオプション --persist不要。

この状態ではシェルが反応しなくなりますが、Ctrl-COctaveを強制終了してpsqlに戻ることは可能でした。

さらにもう一歩進め、「グラフをクリック」するだけでも自動的に閉じてpsqlに戻るなら ↓ こちら。waitforbuttonpressというコマンドがあり、ボタンに限らずグラフィックウィンドウのクリックでも待機状態を抜けます。
-- set output format
# \t on \\\pset format unaligned \\\f ' '

# \g tmp3 \\\! $octave --eval "d=load('tmp3'); bar(d(:,3)); waitforbuttonpress; exit" 


以上、gnuplotより手軽さは低いけど、意外にいろんな形でpsqlOctaveでグラフ⇒psqlのパターンが作れました。課題は、
グラフの目盛ラベル(または文字全般?)を直すことと、表形式のクエリ結果をOctaveの変数にする効率的な方法。進展があったらここに追記します。⇒ 文字の件はここで解決