Javaからgnuplotへデータを送る
Javaで生成したデータを与えgnuplotにチャートを描かせてJava側でそれを表示する。
gnuplotによって正弦の計算をさせるのではなく、
Java側で正弦の値を一周期21点分π/5ラジアンごとに計算してgnuplotに与える。
基本的には以前に示したコードそのままである。
随分前なのでいちおう全文示しておく。
変更点は、クラス名と環境で変わるであろうgnuplotの位置以外は、
Javaからplotコマンドを出力するところから、
gnuplotの出力をフラッシュするところまでと、
その間にデータを出力するための静的メソッドwriteData
を加えただけである。
GnuplotUser2.java
import java.awt.BorderLayout; import java.io.*; import javax.imageio.ImageIO; import javax.swing.*; public class GnuplotUser2 implements Runnable { private static final String GNUPLOT = "/usr/bin/gnuplot"; /** plot a sine curve for one period */ private static void writeData(PrintWriter out) { for (int i = 0; i <= 20; i++) { double x = 2 * Math.PI * i / 20; double y = Math.sin(x); out.println(x + " " + y); } } public static void main(String[] args) throws IOException { Process p = new ProcessBuilder(GNUPLOT, "-").start(); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(p.getOutputStream()))); BufferedInputStream in = new BufferedInputStream(p.getInputStream()); BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream())); StringWriter log = new StringWriter(); out.println("set terminal png"); // output png to stdout out.println("plot '-' with linespoints"); // plot data following with lines and points writeData(out); // output data out.println("e"); // mark end-of-data out.println("set output"); // flush gnuplot output out.close(); // flush and close stdout ImageIcon icon = new ImageIcon(ImageIO.read(in)); // create icon from stdin in.close(); // close stdin while (true) { // create log from stderr int c = err.read(); if (c == -1) break; log.append((char)c); } err.close(); try { p.waitFor(); } catch (InterruptedException e) { } SwingUtilities.invokeLater(new GnuplotUser2(icon, log.toString())); } private ImageIcon icon; private String message; private GnuplotUser2(ImageIcon icon, String message) { this.icon = icon; this.message = message; } public void run() { JFrame f = new JFrame("sin(x)"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new JLabel(icon), BorderLayout.CENTER); f.add(new JScrollPane(new JTextArea(message, 4, 40)), BorderLayout.SOUTH); f.pack(); f.setVisible(true); } }
この変更はJavaでどうこうというよりも、
gnuplotでの操作を変えただけのことである。
gnuplotのplotコマンドにおいて、
データファイルの指定を'-'
にしてやると、
その直後に直接データを入力していくモードになる。
モードの終了はe
を与えてやればよい。
たとえば、以下で放物線的なプロットができる。
gnuplot> plot '-' with linespoints input data ('e' ends) > 0 0 input data ('e' ends) > 1 1 input data ('e' ends) > 2 4 input data ('e' ends) > 3 9 input data ('e' ends) > 4 16 input data ('e' ends) > 5 25 input data ('e' ends) > e gnuplot>
gnuplotの対話モードなので実際に入力するのは>
より右である。
上のJavaコードは、人間が標準入出力を通してgnuplotと対話するかわりに、
Javaが標準入出力を通して対話しているだけである。
したがって、gnuplotにおいて自分が行っている操作を、
Java内で文字列として構築してgnuplotに送ってやればいい。
上は正弦波形だったが、任意のプロットは与えるx座標とy座標の対を変えれば済む。
つまり、上のコードでいえばメソッドwriteData
の中身を変えるだけである。
あまりにデータ点数が多いようなら一時ファイルを作成して、
それをplotコマンドに与えた方がいいかもしれない。