最強のコマンドライン グラフ プロット ツール

いちいち Gnuplot を起動してグラフを描画するのが面倒なので,コマンドラインから使える Gnuplot のラッパスクリプトを書いた.変化するデータファイルをリアルタイムにプロットするスクリプトも組み込んだ.とても使いやすいので紹介する.

スクリプト qplot は最後に掲載.

使い方

qplot [オプション] 描画ライン

「描画ライン」はそのまま gnuplot の plot コマンド (or splot) に渡される.つまり,gnuplot

> plot "hoge.dat" u 1:3 w l, "hoge.dat" u 1:5 w l

に相当するコマンドライン

qplot "hoge.dat" u 1:3 w l, "hoge.dat" u 1:5 w l

となる.ただし,

  • ファイル名の前のコンマは省略できる(自動的に挿入される)
  • ファイル名のクォートは省略できる(同上)

ので,

qplot hoge.dat u 1:3 w l hoge.dat u 1:5 w l

と書いてもよい.

オプション

  • -s XXX : コマンド XXX を plot コマンドの前に実行する(主に set コマンドを使う).注意: XXX は '' でクォートする必要がある.
  • -3d : 3D-plot (splot) コマンドを使う.
  • -o FILE : グラフをファイルに書き出す.画面には表示されない.ファイルタイプは拡張子から自動判別される.現在使用可能なのは,png, jpg, svg, eps.
  • - : 標準入力から入力されたデータを表す.`qplot - u 1:3 - u 1:5' のように何度でも使える.
  • -it : イタレーティブ・モード.変化するファイルを定期的に replot で更新する.Ctrl+C で終了する.
  • -i T : イタレーティブ・モードの更新間隔を変更する(秒.デフォルトは1秒).
  • -cs YYY : 共通のプロットスタイル (w l など).各ファイル名の直後に自動挿入される.
  • -ac : 自動コンマモード.コンマがファイル名の直前に自動的に挿入される.
  • -nc : 自動コンマモードをオフにする.
  • -help : ヘルプを表示.

オプションの位置は,どこでも構わない.ただし,-cs YYY はその位置以降のファイルにしか適用されない.

基本:

qplot hoge.dat using 3:4

表示範囲を変更する:

qplot -s 'set xrange [-1.5:1.5];set yrange [-1.5:1.5]' hoge.dat

プロット結果を hoge.svg に保存する:

qplot out.dat u 1 w l out.dat u 2 w l -o hoge.svg

サインカーブ(データファイルを使わない):

qplot -s 'set xrange [0:10]' 'sin(x)' w p

trajectory.dat の最後の100行をイタレーティブ・モードでプロットする.0.2秒ごとに更新する:

qplot -i 0.2 '"< tail -100 trajectory.dat"' u 1:3 w lp

ほかのコマンドで処理した結果のデータをプロット.1:3行目を使ったプロット,及び1:5行目を使ったプロットを描画する:

(some command) | qplot - u 1:3 w l - u 1:5 w l

すべての test*.dat をプロットする.共通のスタイル w l を使う:

qplot -cs 'w l' test*.dat

スクリプト qplot

#!/usr/bin/python
import os,time,sys
import subprocess
import tempfile

usage='''graph plotter using gnuplot
  usage: qplot [OPTION] PLOTLINE
    OPTION:
      -s XXX     setting line
      -3d        3D-plot (splot)
      -o FILE    save graph into FILE; file type is determined by the extension (png,jpg,svg,eps are available)
      -          use std-in as a data file
      -it        iterative plot mode (quit by Ctrl+C)
      -i T       iteration interval (second; default=1.0)
      -cs YYY    common graph style (put after each filename)
      -ac        auto-comma mode (default=True): comma is automatically inserted before each filename
      -nc        disable auto-comma mode
      -help      show help
  example:
    qplot hoge.dat using 3:4
    qplot -s 'set xrange [-1.5:1.5];set yrange [-1.5:1.5]' hoge.dat
    qplot -i 0.2 '"< tail -100 trajectory.dat"' u 1:3 w lp
    (some command) | qplot - u 1:3 w l - u 1:5 w l
    qplot -ac -cs 'w l' test*.dat'''

# default setting:
setting='set key right bottom'
setting=setting+'; min(x,y)=x<=y?x:y; max(x,y)=x>=y?x:y'
iterative=False
tsleep=1.0
pline=''
plotter='plot'
commonstyle=''
autocomma=' ,'

stdindata=''

def ask_yes_no():
  if stdindata!='':
    sys.stdout.write('  (y|n) > n\n')
    return False
  while True:
    sys.stdout.write('  (y|n) > ')
    ans= sys.stdin.readline().strip()
    if ans=='y' or ans=='Y':  return True
    elif ans=='n' or ans=='N':  return False

def add_to_pline(elem,comma):
  global pline,autocomma
  if comma and pline!="": pline=pline+autocomma
  pline=pline+' '+elem

it= iter(sys.argv)
it.next() # skip exec name
while True:
  try:
    a= it.next()
    if a=='-help' or a=='--help': print usage; sys.exit(0)
    elif a=='-3d': plotter='splot'
    elif a=='-s': setting=setting+'; '+it.next()
    elif a=='-o':
      filename=it.next()
      if os.path.exists(filename):
        print filename+' : already exists. will you overwrite?'
        if not ask_yes_no():  sys.exit(0)
      dummy,ext= os.path.splitext(filename)
      ext= ext.lower()
      if ext=='.png':
        setting=setting+'; set terminal png size 800, 640 transparent'
      elif ext=='.jpg' or ext=='.jpeg':
        setting=setting+'; set terminal jpeg size 800, 640'
      elif ext=='.svg':
        setting=setting+'; set terminal svg size 1200 780 fname "Trebuchet MS" fsize 24'
      elif ext=='.eps':
        setting=setting+'; set terminal postscript eps color "Trebuchet MS" 11'
      else:
        print 'WARNING: undefined extension. save graph as png...'
        setting=setting+'; set terminal png size 800, 640 transparent'
      setting=setting+'; set output "'+filename+'"'
    elif a=='-it': iterative=True
    elif a=='-i': tsleep=float(it.next()); iterative=True
    elif a=='-cs': commonstyle=' '+it.next()
    elif a=='-ac': autocomma=' ,'
    elif a=='-nc': autocomma=''
    elif a=='-':
      if stdindata=='':
        dummy,stdindata=tempfile.mkstemp('.dat')
        pout=open(stdindata,'w+')
        while(1):
          line=sys.stdin.readline()
          if(not line):  break
          pout.write(line)
        pout.close()
      add_to_pline('"'+stdindata+'"'+commonstyle,True)
    elif os.path.exists(a): add_to_pline('"'+a+'"'+commonstyle,True)
    else: add_to_pline(a,False)
  except StopIteration:
    break

if pline=='':
  print usage; sys.exit(0)

print plotter+' '+pline

if not iterative: g= subprocess.Popen('gnuplot -persist',shell=True,stdin=subprocess.PIPE)
else:             g= subprocess.Popen('gnuplot -noraise',shell=True,stdin=subprocess.PIPE)
g.stdin.write(setting+'\n')
g.stdin.write(plotter+' '+pline+'\n')
g.stdin.flush()

if iterative:
  try:
    while True:
      g.stdin.write("replot\n")
      g.stdin.flush()
      time.sleep(tsleep)
  except KeyboardInterrupt:
    #g.terminate()  # available for python's version >= 2.6
    sys.exit(0)