Mgplot.java

/*
 * $Id: Mgplot.java,v 1.34 2008/07/16 15:40:00 koga Exp $
 *
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 *
 */
package org.mklab.tool.graph.mgplot;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import org.mklab.nfc.matrix.BooleanMatrix;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.matrix.IntMatrix;
import org.mklab.nfc.matx.MatxList;
import org.mklab.nfc.scalar.DoubleNumberUtil;
import org.mklab.tool.graph.PlotterException;


/**
 * @author koga
 * @version $Revision: 1.34 $, 2004/04/30
 */
public class Mgplot {

  /** ウィンドウの数の最大値 */
  private static final int MAX_WIN = 100;
  /** フレームの数の最大値 */
  private static final int MAX_FRAME = 100;
  /** パイプが使えるならtrue */
  private static boolean HAVE_PIPE = true;
  /** ロングファイル名が使えるならtrue */
  private static boolean HAVE_LONG_FILENAME = true;
  /** Windows OS で動作中ならtrue */
  private static boolean WINDOWS_OS = false;
  /** 実行中ならtrue */
  private static boolean isRunning = false;
  /** カレントウィンドウ */
  private static int currentWindow = 1;

  /** ウィンドウIDのマップ */
  private static HashMap<Integer, Writer> windowID = new HashMap<>();
  /** データ数 */
  private static IntMatrix dataNumberData = new IntMatrix(MAX_WIN, MAX_FRAME);
  /** マルチプロット */
  private static IntMatrix multiplotData = new IntMatrix(MAX_WIN, 2);
  /** ログスケールモード */
  private static IntMatrix logModeData = new IntMatrix(MAX_WIN, MAX_FRAME);
  /** ホールド */
  private static BooleanMatrix holdOn = new BooleanMatrix(1, MAX_WIN);
  /** グリッドのオン・オフ */
  private static BooleanMatrix gridOn = new BooleanMatrix(1, MAX_WIN);
  /** 線の名前表示のオン・オフ */
  private static BooleanMatrix keyOn = BooleanMatrix.ones(1, MAX_WIN);
  /** 媒介変数表示のオン・オフ */
  private static BooleanMatrix parametricOn = BooleanMatrix.ones(1, MAX_WIN);
  /** 陰面処理のオン・オフ */
  private static BooleanMatrix hidden3dOn = BooleanMatrix.ones(1, MAX_WIN);
  /** プロッターに送る文字列 */
  private static MatxList stringsData = new MatxList(MAX_WIN);
  /** ウィンドウオプション */
  private static MatxList windowOptionsData = new MatxList(MAX_WIN);
  /** プロットコマンドの文字列 */
  private static MatxList plotStringsData = new MatxList(MAX_FRAME);
  /** 大きさ設定コマンドの文字列 */
  private static MatxList sizeStringsData = new MatxList(MAX_FRAME);
  /** タイトル設定コマンドの文字列 */
  private static MatxList titleStringsData = new MatxList(MAX_FRAME);
  /** プロットターム */
  private static String plotTerm;

  /** 改行コード */
  private static final String newLine = System.getProperty("line.separator"); //$NON-NLS-1$

  static {
    if (System.getProperty("file.separator").equals("\\")) { //$NON-NLS-1$ //$NON-NLS-2$
      WINDOWS_OS = true;
    }

    for (int i = 0; i < MAX_FRAME; i++) {
      titleStringsData.set(i + 1, new MatxList(MAX_WIN));
      sizeStringsData.set(i + 1, new MatxList(MAX_WIN));
      plotStringsData.set(i + 1, new MatxList(MAX_WIN));
    }
  }

  /**
   * カレントウィンドウ番号を得る。
   * 
   * @return カレントウィンドウ番号
   */
  public static int getCurrentWindow() {
    return currentWindow;
  }

  /**
   * ウィンドウを初期化します。
   * 
   * @param windowId ウィンドウ番号
   * @throws IOException プロセスの初期化ができないばあい
   */
  private static void init(int windowId) throws IOException {
    init(windowId, ""); //$NON-NLS-1$
  }

  /**
   * ウィンドウを初期化します。
   * 
   * @param windowId ウィンドウ番号
   * @param options オプション
   * @throws IOException プロセスの入出力ができない場合
   */
  private static void init(int windowId, String options) throws IOException {
    if (!isRunning) {
      isRunning = true;
    }

    String allOptions = options;
    if (System.getProperty("MGPLOT_OPTIONS") != null) { //$NON-NLS-1$
      allOptions = System.getProperty("MGPLOT_OPTIONS") + " " + allOptions; //$NON-NLS-1$ //$NON-NLS-2$
    }
    setWindowOption(windowId, allOptions);

    if (plotTerm == null) {
      plotTerm = System.getProperty("MGPLOT_TERM"); //$NON-NLS-1$
      if (plotTerm == null) {
        if (WINDOWS_OS) {
          plotTerm = "windows"; //$NON-NLS-1$
        } else {
          plotTerm = "x11"; //$NON-NLS-1$
        }
      }
    }

    if (HAVE_PIPE) {
      if (windowID.containsKey(Integer.valueOf(windowId))) {
        return;
      }

      String gnuplot;
      if (WINDOWS_OS) {
        gnuplot = "cmd.exe /c pgnuplot.exe -"; //$NON-NLS-1$
      } else if ((gnuplot = System.getProperty("MATX_GNUPLOT")) == null) { //$NON-NLS-1$
        gnuplot = "gnuplot"; //$NON-NLS-1$
      }

      String win_options = getWindowOption(windowId);

      String cmd;
      int pid = 123;
      if (win_options.length() == 0) {
        cmd = gnuplot + " -geometry 380x280 -title mgplot-" + windowId + "-" + pid; //$NON-NLS-1$ //$NON-NLS-2$
      } else {
        cmd = gnuplot + " -geometry 380x280 -title mgplot-" + windowId + "-" + pid + " " + win_options; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      }

      final Process process = Runtime.getRuntime().exec(cmd);
      final Writer writer = new OutputStreamWriter(process.getOutputStream());
      windowID.put(Integer.valueOf(windowId), writer);
      out(windowId, "set term " + plotTerm + ";" + newLine); //$NON-NLS-1$ //$NON-NLS-2$
    } else {
      if (strings(windowId) != "@") { //$NON-NLS-1$
        return;
      }
      strings(windowId, ""); //$NON-NLS-1$
    }

    reset(windowId);
  }

  /**
   * プロットのモードを設定します。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @throws IOException 初期化ができない場合
   */
  private static void plotMode(int windowId, DoubleMatrix X, DoubleMatrix Y) throws IOException {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    init(win);
    currentWindow = win;

    int frame;
    if ((frame = multiplot(win)) != 0) {
      clear(win);
    }

    String log_mode_cmd;
    switch (logMode(win, frame)) {
      case 0:
        log_mode_cmd = "unset logscale xyz"; //$NON-NLS-1$
        break;
      case 1:
        double xmin = (X.getRowVector(1)).min().doubleValue();
        double xmax = (X.getRowVector(1)).max().doubleValue();
        log_mode_cmd = "set xrange [" + xmin + ":" + xmax + "]; " + "set logscale x; unset logscale yz"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
        break;
      case 2:
        double ymin = (Y.getRowVector(1)).min().doubleValue();
        double ymax = (Y.getRowVector(1)).max().doubleValue();
        log_mode_cmd = "set yrange [" + ymin + ":" + ymax + "]; " + "set logscale y; unset logscale xz"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$
        break;
      case 4:
        xmin = (X.getRowVector(1)).min().doubleValue();
        xmax = (X.getRowVector(1)).max().doubleValue();
        ymin = (Y.getRowVector(1)).min().doubleValue();
        ymax = (Y.getRowVector(1)).max().doubleValue();
        log_mode_cmd = "set xrange [" + xmin + ":" + xmax + "]; " + "set yrange [" + ymin + ":" + ymax + "]; " + "set logscale xy; unset logscale z"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
        break;
      default:
        throw new RuntimeException(Messages.getString("Mgplot.0")); //$NON-NLS-1$
    }

    command(win, log_mode_cmd);
  }

  /**
   * プロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X データ
   */
  public static void plot(int windowId, DoubleMatrix X) {
    try {
      plotMode(windowId, X, null);
      d1_plot(windowId, X);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    System.out.print("\r                      \r"); //$NON-NLS-1$
  }

  /**
   * プロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void plot(int windowId, DoubleMatrix X, DoubleMatrix Y) {
    try {
      plotMode(windowId, X, Y);
      d2_plot(windowId, X, Y);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    System.out.print("\r                      \r"); //$NON-NLS-1$
  }

  /**
   * プロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void plot(int windowId, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    plot(windowId, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void plot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    try {
      plotMode(win, X, Y);
      d2_plot(win, X, Y, titles);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    System.out.print("\r                      \r"); //$NON-NLS-1$
  }

  /**
   * プロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド
   */
  public static void plot(int windowId, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    try {
      plotMode(windowId, X, Y);
      d2_plot(windowId, X, Y, titles, false, cmds1);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    System.out.print("\r                      \r"); //$NON-NLS-1$
  }

  /**
   * プロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド
   */
  public static void plot(int windowId, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    plot(windowId, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド
   * @param cmds2 コマンド
   */
  public static void plot(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    plot(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド
   * @param cmds2 コマンド
   */
  public static void plot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    try {
      plotMode(win, X, Y);
      d2_plot(win, X, Y, titles, false, cmds1, cmds2);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    System.out.print("\r                      \r"); //$NON-NLS-1$
  }

  /**
   * 再プロットするモードを設定します。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  private static void replotMode(int win, DoubleMatrix X, DoubleMatrix Y) {
    currentWindow = win;

    int frame;
    if ((frame = multiplot(win)) != 0) {
      clear(win);
    }

    String log_mode_cmd = null;
    switch (logMode(win, frame)) {
      case 0:
        log_mode_cmd = "unset logscale xyz"; //$NON-NLS-1$
        break;
      case 1:
        double xmin = X.getRowVector(1).min().doubleValue();
        double xmax = X.getRowVector(1).max().doubleValue();
        log_mode_cmd = "set xrange [" + xmin + ":" + xmax + "]; " + "set logscale x; unset logscale yz"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
        break;
      case 2:
        double ymin = Y.getRowVector(1).min().doubleValue();
        double ymax = Y.getRowVector(1).max().doubleValue();
        log_mode_cmd = "set yrange [" + ymin + ":" + ymax + "]; " + "set logscale y; unset logscale xz"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        break;
      case 4:
        xmin = X.getRowVector(1).min().doubleValue();
        xmax = X.getRowVector(1).max().doubleValue();
        ymin = Y.getRowVector(1).min().doubleValue();
        ymax = Y.getRowVector(1).max().doubleValue();
        log_mode_cmd = "set xrange [" + xmin + ":" + xmax + "]; " + "set yrange [" + ymin + ":" + ymax + "]; " + "set logscale xy; unset logscale z"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
        break;
      default:
        throw new RuntimeException(Messages.getString("Mgplot.20")); //$NON-NLS-1$
    }
    command(win, log_mode_cmd);
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   */
  public static void replot(int win, DoubleMatrix X) {
    replotMode(win, X, null);
    try {
      d1_plot(win, X, new ArrayList<String>(), true);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y) {
    replotMode(win, X, Y);
    try {
      d2_plot(win, X, Y, new ArrayList<String>(), true);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    replotMode(win, X, Y);
    try {
      d2_plot(win, X, Y, titles, true);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    replot(win, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    replotMode(win, X, Y);
    try {
      d2_plot(win, X, Y, titles, true, cmds1);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    replot(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    replot(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * 再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    replotMode(win, X, Y);
    try {
      d2_plot(win, X, Y, titles, true, cmds1, cmds2);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * コマンドを送る。
   * 
   * @param windowId ウィンドウ番号
   * @param cmd コマンド文字列
   */
  public static void command(int windowId, String cmd) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    out(win, cmd + ";" + newLine); //$NON-NLS-1$
    currentWindow = win;
  }

  /**
   * 1次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param Y Y方向のデータ
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d1_plot(int win, DoubleMatrix Y) throws IOException {
    d1_plot(win, Y, new ArrayList<String>(), false, new ArrayList<String>(), new ArrayList<String>());
  }

  // private static void d1_plot(int win, DoubleMatrix Y, List titles) {
  // d1_plot(win, Y, titles, false, new List(), new List());
  // }

  /**
   * 1次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param replotflag 重ねてプロットするならtrue、そうでなければfalse
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d1_plot(int win, DoubleMatrix Y, List<String> titles, boolean replotflag) throws IOException {
    d1_plot(win, Y, titles, replotflag, new ArrayList<String>(), new ArrayList<String>());
  }

  // private static void d1_plot(int win, DoubleMatrix Y, List titles, boolean
  // replotflag, List cmds1) {
  // d1_plot(win, Y, titles, replotflag, cmds1, new List());
  // }

  /**
   * 1次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param replotflag 重ねてプロットするならtrue、そうでなければfalse
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d1_plot(int win, DoubleMatrix Y, List<String> titles, boolean replotflag, List<String> cmds1, List<String> cmds2) throws IOException {
    init(win);

    int frame = multiplot(win);

    int num;
    if (replotflag) {
      num = data_num(win, frame);
    } else {
      num = 0;
    }

    data_num(win, frame, num + 1);

    String datafile;
    if (HAVE_LONG_FILENAME) {
      int pid = 123;
      datafile = "mgplot-" + pid + "-w" + win + "-f" + frame + "-l" + num; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    } else {
      datafile = "w" + win + "f" + frame + "l" + num + ".dat"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    }

    Y.writeMatFormat(new File(datafile));

    for (int i = 1; i <= Y.getRowSize(); i++) {
      String tit;
      if (i <= titles.size()) {
        tit = titles.get(i - 1);
      } else {
        tit = "data-" + (num + 1) + "-" + i; //$NON-NLS-1$ //$NON-NLS-2$
      }

      String cmd1;
      if (i <= cmds1.size()) {
        cmd1 = cmds1.get(i - 1);
      } else {
        cmd1 = ""; //$NON-NLS-1$
      }

      String cmd2;
      if (i <= cmds2.size()) {
        cmd2 = cmds2.get(i - 1);
      } else {
        cmd2 = ""; //$NON-NLS-1$
      }

      String str = "'" + datafile + "' u 0:" + i + " " + cmd1 + " t '" + tit + "' " + cmd2; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$

      if (i == 1 && num == 0) {
        plot_strings(win, frame, str);
      } else {
        plot_strings(win, frame, plot_strings(win, frame) + ", " + str); //$NON-NLS-1$
      }
    }

    while (!new File(datafile).exists()) {
      //
    }

    out(win, "plot " + plot_strings(win, frame) + newLine); //$NON-NLS-1$

    if (HAVE_PIPE && !hold(win)) {
      out(win, "plot"); //$NON-NLS-1$
    }
  }

  /**
   * 2次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d2_plot(int win, DoubleMatrix X, DoubleMatrix Y) throws IOException {
    d2_plot(win, X, Y, new ArrayList<String>(), false, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * 2次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d2_plot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) throws IOException {
    d2_plot(win, X, Y, titles, false, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * 2次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param replotflag 重ねてプロットするならtrue、そうでなければfalse
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d2_plot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, boolean replotflag) throws IOException {
    d2_plot(win, X, Y, titles, replotflag, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * 2次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param replotflag 重ねてプロットするならtrue、そうでなければfalse
   * @param cmds1 コマンド1
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d2_plot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, boolean replotflag, List<String> cmds1) throws IOException {
    d2_plot(win, X, Y, titles, replotflag, cmds1, new ArrayList<String>());
  }

  /**
   * 2次元グラフをプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param replotflag 重ねてプロットするならtrue、そうでなければfalse
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   * @throws IOException ファイルへ出力できない場合
   */
  private static void d2_plot(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, boolean replotflag, List<String> cmds1, List<String> cmds2) throws IOException {
    int m = X.getRowSize();
    int n = Y.getRowSize();

    if (m != 1 && n != 1 && m != n) {
      throw new RuntimeException(Messages.getString("Mgplot.41")); //$NON-NLS-1$
    }

    init(win);

    int frame = multiplot(win);

    int num;
    if (replotflag) {
      num = data_num(win, frame);
    } else {
      num = 0;
    }

    data_num(win, frame, num + 1);

    String datafile;
    if (HAVE_LONG_FILENAME) {
      int pid = 123;
      datafile = "mgplot-" + pid + "-w" + win + "-f" + frame + "-l" + num; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
    } else {
      datafile = "w" + win + "f" + frame + "l" + num + ".dat"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    }

    X.appendDown(Y).writeMatFormat(new File(datafile));

    for (int i = 1; i <= Math.max(m, n); i++) {
      String tit;
      if (i <= titles.size()) {
        tit = titles.get(i - 1);
      } else {
        tit = "data-" + (num + 1) + "-" + i; //$NON-NLS-1$//$NON-NLS-2$
      }
      String cmd1;
      if (i <= cmds1.size()) {
        cmd1 = cmds1.get(i - 1);
      } else {
        cmd1 = ""; //$NON-NLS-1$
      }
      String cmd2;
      if (i <= cmds2.size()) {
        cmd2 = cmds2.get(i - 1);
      } else {
        cmd2 = ""; //$NON-NLS-1$
      }

      String str = null;
      if (m == 1) {
        str = "'" + datafile + "' u 1:" + (i + 1) + " " + cmd1 + " t '" + tit + "' " + cmd2; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ //$NON-NLS-5$
      } else if (n == 1) {
        str = "'" + datafile + "' u " + i + ":" + (m + 1) + " " + cmd1 + " t '" + tit + "' " + cmd2; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
      } else if (m == n) {
        str = "'" + datafile + "' u " + i + ":" + (m + i) + " " + cmd1 + " t '" + tit + "' " + cmd2; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
      }

      if (i == 1 && num == 0) {
        plot_strings(win, frame, str);
      } else {
        plot_strings(win, frame, plot_strings(win, frame) + ", " + str); //$NON-NLS-1$
      }
    }

    File f = new File(datafile);
    while (!f.exists()) {
      //
    }

    String str = plot_strings(win, frame);
    out(win, "plot " + str + newLine); //$NON-NLS-1$

    if (!HAVE_PIPE && !hold(win)) {
      out(win, "plot"); //$NON-NLS-1$
    }
  }

  /**
   * コマンドを保持することを指示します。
   * 
   * @param win ウィンドウ番号
   * @return コマンドを保持するするならtrue、そうでなければfalse
   */
  public static boolean hold(int win) {
    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
    return false;
  }

  /**
   * コマンドを保持することを指示します。
   * 
   * @param win ウィンドウ番号
   * @param on コマンドを保持するするならtrue、そうでなければfalse
   * @return コマンドを保持するするならtrue、そうでなければfalse
   */
  public static boolean hold(int win, boolean on) {
    hold(win);

    // if (holdOn.getElement(win) && !on && !HAVE_PIPE) {
    // out(win, "plot"); //$NON-NLS-1$
    // }
    holdOn.setElement(win, on);

    return holdOn.getElement(win);
  }

  /**
   * プロッターに文字列を送る。
   * 
   * @param windowId ウィンドウ番号
   * @param string 文字列
   */
  public static void out(int windowId, String string) {
    // System.err.println("" + win + ":" + str);

    if (HAVE_PIPE) {
      if (!isOpened(windowId)) {
        throw new RuntimeException("Window-" + windowId + Messages.getString("Mgplot.43")); //$NON-NLS-1$ //$NON-NLS-2$
      }
      try {
        windowID.get(Integer.valueOf(windowId)).write(string);
        windowID.get(Integer.valueOf(windowId)).flush();
      } catch (IOException e) {
        throw new PlotterException(e);
      }
    } else {
      if (string.equals("plot") || string.equals("replot")) { //$NON-NLS-1$ //$NON-NLS-2$
        final String fileName = "mgplot_" + windowId + ".plt"; //$NON-NLS-1$//$NON-NLS-2$
        final File file = new File(fileName);
        if (file.exists()) {
          file.delete();
        }

        try (Writer writer = new FileWriter(fileName)) {
          writer.write(strings(windowId));

          if (multiplot(windowId) != 0) {
            writer.write("unset multiplot;" + newLine); //$NON-NLS-1$
          }

          writer.write("pause -1 \"Hit return to continue\";" + newLine); //$NON-NLS-1$
          writer.write("quit;" + newLine); //$NON-NLS-1$
        } catch (IOException e) {
          throw new PlotterException(e);
        }
        
        String gnuplot = System.getProperty("MATXGNUPLOT"); //$NON-NLS-1$
        if (gnuplot.length() == 0) {
          gnuplot = "gnuplot"; //$NON-NLS-1$
        }

        try {
          final Process process = Runtime.getRuntime().exec(gnuplot + " " + fileName); //$NON-NLS-1$
          process.waitFor();
        } catch (IOException e1) {
          throw new PlotterException(e1);
        } catch (InterruptedException e) {
          throw new PlotterException(e);
        }

      } else {
        strings(windowId, strings(windowId) + string);
      }
    }
  }

  /**
   * プロッターの送った文字列を得る。
   * 
   * @param win ウィンドウ番号
   * @return プロッターに送った文字列
   */
  private static String strings(int win) {
    if (stringsData.getObject(win) instanceof Integer) {
      return "@"; //$NON-NLS-1$
    }
    return stringsData.getString(win);
  }

  /**
   * プロッターに送る文字列を保存します。
   * 
   * @param win ウィンドウ番号
   * @param str 文字列
   */
  private static void strings(int win, String str) {
    stringsData.set(win, str);
  }

  /**
   * プロッターに送る文字列を保存する場所を初期化します。
   * 
   * @param win ウィンドウ番号
   */
  private static void plot_strings(int win) {
    plotStringsData.set(win, new MatxList(MAX_FRAME));
  }

  /**
   * 指定されたウィンドウ、フレームに関してプロッターに送った文字列を得る。
   * 
   * @param windowId ウィンドウ番号
   * @param frameId フレーム番号
   * @return プロッターに送った文字列
   */
  private static String plot_strings(int windowId, int frameId) {
    int frame = frameId;
    if (frame == 0) {
      frame = 1;
    }
    if (plotStringsData.getList(windowId).getObject(frame) instanceof Integer) {
      return ""; //$NON-NLS-1$
    }
    return plotStringsData.getList(windowId).getString(frame);
  }

  /**
   * 指定されたウィンドウ、フレームに関してプロッターに送る文字列を設定します。
   * 
   * @param windowId ウィンドウ番号
   * @param frameId フレーム番号
   * @param str プロッターに送る文字列
   */
  private static void plot_strings(int windowId, int frameId, String str) {
    int frame = frameId;
    if (frame == 0) {
      frame = 1;
    }
    MatxList ll = plotStringsData.getList(windowId);
    ll.set(frame, str);
    plotStringsData.set(windowId, ll);
  }

  /**
   * データ数を得る。
   * 
   * @param dataId データのID
   * @return データ数
   */
  private static int data_num(int dataId) {
    if (dataId < 0 || MAX_WIN < dataId) {
      throw new RuntimeException(Messages.getString("Mgplot.44") + dataId); //$NON-NLS-1$
    }

    // Only one frame
    return ((dataNumberData.getRowVector(dataId))).intSum();
  }

  /**
   * データ数を得る。
   * 
   * @param dataId データのID
   * @param frame フレーム番号
   * @return データの数
   */
  private static int data_num(int dataId, int frame) {
    if (dataId < 0 || MAX_WIN < dataId) {
      throw new RuntimeException(Messages.getString("Mgplot.45") + dataId); //$NON-NLS-1$
    }

    if (MAX_FRAME < frame) {
      throw new RuntimeException(Messages.getString("Mgplot.46") + frame); //$NON-NLS-1$
    }

    if (frame < 0) { // Reset
      dataNumberData.setRowVector(dataId, new IntMatrix(1, MAX_FRAME));
      return 0;
    } else if (frame == 0) { // Only one frame
      return dataNumberData.getIntElement(dataId, 1);
    } else {
      return dataNumberData.getIntElement(dataId, frame);
    }
  }

  /**
   * データ数を設定します。
   * 
   * @param dataId データのID
   * @param frame フレーム番号
   * @param num データの数
   */
  private static void data_num(int dataId, int frame, int num) {
    if (dataId < 0 || MAX_WIN < dataId) {
      throw new RuntimeException(Messages.getString("Mgplot.47") + dataId); //$NON-NLS-1$
    }

    if (MAX_FRAME < frame) {
      throw new RuntimeException(Messages.getString("Mgplot.48") + frame); //$NON-NLS-1$
    }

    if (frame == 0) { // Only one frame
      dataNumberData.setElement(dataId, 1, num);
    } else {
      dataNumberData.setElement(dataId, frame, num);
    }
  }

  /**
   * ウィンドウが開いているか調べる。
   * 
   * @param windowId ウィンドウ番号
   * @return ウィンドウが開いていればtrue、そうでなければfale
   */
  private static boolean isOpened(int windowId) {
    if (HAVE_PIPE) {
      return windowID.containsKey(Integer.valueOf(windowId));
    }
    return !strings(windowId).equals("@"); //$NON-NLS-1$
  }

  /**
   * ウィンドウをクリアします。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void clear(int windowId) {
    if (!isOpened(windowId)) {
      return;
    }
    command(windowId, "clear"); //$NON-NLS-1$
  }

  /**
   * マルチプロットのウィンドウIDを得る。 ウィンドウに複数のフレームを表示することを宣言します。
   * 
   * @param windowId ウィンドウ番号
   * @return ウィンドウID
   */
  private static int multiplot(int windowId) {
    return multiplotData.getIntElement(windowId, 1);
  }

  /**
   * マルチプロットのウィンドウIDを得る。
   * 
   * @param windowId ウィンドウ番号
   * @param frame フレーム番号
   * @return ウィンドウID
   */
  private static int multiplot(int windowId, int frame) {
    if (multiplotData.getIntElement(windowId, 1) != 0 && frame == 0) {
      removeDatafile(windowId);
      if (HAVE_PIPE) {
        out(windowId, "unset multiplot;" + newLine); //$NON-NLS-1$
        out(windowId, "set size 0.98,1.0;" + newLine); //$NON-NLS-1$
        out(windowId, "set origin 0,0;" + newLine); //$NON-NLS-1$
      }
    } else if (multiplotData.getIntElement(windowId, 1) == 0 && 0 < frame) {
      removeDatafile(windowId);
      out(windowId, "set multiplot;" + newLine); //$NON-NLS-1$
    } else if (frame < 0) {
      return multiplotData.getIntElement(windowId, 2); // max frame number */
    }
    if (multiplotData.getIntElement(windowId, 2) < frame || frame == 0) {
      multiplotData.setElement(windowId, 2, frame);
    }
    multiplotData.setElement(windowId, 1, frame);
    return multiplotData.getIntElement(windowId, 1);

  }

  /**
   * ウィンドウに関連して作成されたデータファイルを削除します。
   * 
   * @param windowId ウィンドウ番号
   */
  private static void removeDatafile(int windowId) {
    int frame = multiplot(windowId, -1);

    int i0;
    if (frame == 0) {
      i0 = 0;
    } else {
      i0 = 1;
    }

    for (int i = i0; i <= frame; i++) {
      int num = data_num(windowId, i) - 1;
      for (int j = 0; j <= num; j++) {
        if (HAVE_PIPE) {
          if (windowID.containsKey(Integer.valueOf(windowId))) {
            String datafile;
            if (HAVE_LONG_FILENAME) {
              int pid = 123;
              datafile = "mgplot-" + pid + "-w" + windowId + "-f" + i + "-l" + j; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
            } else {
              datafile = "w" + windowId + "f" + i + "l" + j + ".dat"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
            }
            new File(datafile).delete();
          }
        } else {
          if (!strings(windowId).equals("@")) { //$NON-NLS-1$
            String datafile;
            if (HAVE_LONG_FILENAME) {
              datafile = "mgplot-w" + windowId + "-f" + i + "-l" + j; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            } else {
              datafile = "w" + windowId + "f" + i + "l" + j + ".dat"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
            }
            new File(datafile).delete();
          }
        }
      }
    }
  }

  /**
   * ログスケールのモードを返します。 mode == 0 : nologscale mode == 1 : logscale x mode == 2 : logscale y mode == 3 : logscale z mode == 4 : logscale xy mode == 5 : logscale xz mode == 6 : logscale yz mode == 7 :
   * logscale xyz
   * 
   * @param windowId ウィンドウ番号
   * @param frameId フレーム番号
   * @return モード
   */
  private static int logMode(int windowId, int frameId) {
    int frame = frameId;
    if (frame == 0) {
      frame = 1;
    }

    return logModeData.getIntElement(windowId, frame);
  }

  /**
   * ログスケールのモードを設定します。 mode == 0 : nologscale mode == 1 : logscale x mode == 2 : logscale y mode == 3 : logscale z mode == 4 : logscale xy mode == 5 : logscale xz mode == 6 : logscale yz mode == 7 :
   * logscale xyz
   * 
   * @param windowId ウィンドウ番号
   * @param frameId フレーム番号
   * @param mode モード
   * @return モード
   */
  private static int logMode(int windowId, int frameId, int mode) {
    int frame = frameId;
    if (frame == 0) {
      frame = 1;
    }

    logModeData.setElement(windowId, frame, mode);

    return logModeData.getIntElement(windowId, frame);
  }

  /**
   * オプション文字列を得る。
   * 
   * @param windowId ウィンドウ番号
   * @return オプション文字列
   */
  private static String getWindowOption(int windowId) {
    if (windowOptionsData.getObject(windowId) instanceof Integer) {
      return ""; //$NON-NLS-1$
    }
    return windowOptionsData.getString(windowId);
  }

  /**
   * オプション文字列を設定します。
   * 
   * @param windowId ウィンドウ番号
   * @param option オプション文字列
   * @return オプション文字列
   */
  private static String setWindowOption(int windowId, String option) {
    windowOptionsData.set(windowId, option);
    return option;
  }

  /**
   * ウィンドウをリセットします。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void reset(int windowId) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    if (!isOpened(win)) {
      return;
    }

    removeDatafile(win);

    if (!HAVE_PIPE) {
      File f = new File("mgplot_" + win + ".plt"); //$NON-NLS-1$//$NON-NLS-2$
      if (f.exists()) {
        f.delete();
      }
      strings(win, ""); //$NON-NLS-1$
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (windowID.containsKey((Integer.valueOf(win)))) {
      data_num(win, -1);
    }
    multiplot(win, 0);
    grid(win, false);
    hold(win, false);
    key(win, true);

    resetCode(win);
  }

  /**
   * ウィンドウをリセットする文字列をプロッターに送る。
   * 
   * @param windowId ウィンドウ番号
   */
  private static void resetCode(int windowId) {
    out(windowId, "unset logscale xyz;" + newLine); //$NON-NLS-1$
    out(windowId, "set autoscale;" + newLine); //$NON-NLS-1$
    out(windowId, "unset label;" + newLine); //$NON-NLS-1$
    out(windowId, "set xlabel;" + newLine); //$NON-NLS-1$
    out(windowId, "set ylabel;" + newLine); //$NON-NLS-1$
    out(windowId, "set zlabel;" + newLine); //$NON-NLS-1$
    out(windowId, "set title;" + newLine); //$NON-NLS-1$
    out(windowId, "set zero 1e-20;" + newLine); //$NON-NLS-1$
    out(windowId, "set style data lines;" + newLine); //$NON-NLS-1$
  }

  /**
   * グリッドを表示します。
   * 
   * @param win ウィンドウ番号
   */
  public static void grid(int win) {
    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (gridOn.getElement(win)) {
      command(win, "unset grid"); //$NON-NLS-1$
      gridOn.setElement(win, false);
    } else {
      command(win, "set grid"); //$NON-NLS-1$
      gridOn.setElement(win, true);
    }

  }

  /**
   * グリッドを表示する設定します。
   * 
   * @param windowId ウィンドウ番号
   * @param on グリッドを表示するならtrue、そうでなければfalse
   */
  public static void grid(int windowId, boolean on) {
    try {
      init(windowId);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (on) {
      command(windowId, "set grid"); //$NON-NLS-1$
    } else {
      command(windowId, "unset grid"); //$NON-NLS-1$
    }
    gridOn.setElement(windowId, on);

    if (HAVE_PIPE) {
      update(windowId);
    }
  }

  /**
   * グラフに関する名前を表示する設定をします。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void key(int windowId) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (keyOn.getElement(win)) {
      command(win, "unset key"); //$NON-NLS-1$
      keyOn.setElement(win, false);
    } else {
      command(win, "set key"); //$NON-NLS-1$
      keyOn.setElement(win, true);
    }

  }

  /**
   * グラフに関する名前を表示する設定をします。
   * 
   * @param windowId ウィンドウ番号
   * @param on グラフに関する名前を表示するならtrue、そうでなければfalse
   */
  public static void key(int windowId, boolean on) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (on) {
      command(win, "set key"); //$NON-NLS-1$
    } else {
      command(win, "unset key"); //$NON-NLS-1$
    }
    keyOn.setElement(win, on);

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * ウィンドウを更新(再描画)します。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void update(int windowId) {
    if (!isOpened(windowId)) {
      return;
    }

    if (data_num(windowId) != 0 && multiplot(windowId) == 0) {
      command(windowId, "replot"); //$NON-NLS-1$
      System.out.print("\r                      \r"); //$NON-NLS-1$

      if (!HAVE_PIPE) {
        out(windowId, "replot"); //$NON-NLS-1$
      }
    }
  }

  /**
   * プロッターに送る大きさに関する文字列を保存する場所を初期化します。
   * 
   * @param win ウィンドウ番号
   */
  private static void size_strings(int win) {
    sizeStringsData.set(win, new MatxList(MAX_FRAME));
  }

  /**
   * 大きさに関する文字列を得る。
   * 
   * @param windowId ウィンドウ番号
   * @param frame フレーム番号
   * @return 大きさに関する文字列
   */
  private static String size_strings(int windowId, int frame) {
    if (sizeStringsData.getList(windowId).getObject(frame) instanceof Integer) {
      return ""; //$NON-NLS-1$
    }
    return sizeStringsData.getList(windowId).getString(frame);
  }

  /**
   * 大きさに関する文字列を設定します。
   * 
   * @param win ウィンドウ番号
   * @param frame フレーム番号
   * @param str 大きさに関する文字列
   */
  private static void size_strings(int win, int frame, String str) {
    MatxList ll = sizeStringsData.getList(win);
    ll.set(frame, str);
    sizeStringsData.set(win, ll);
  }

  /**
   * タイトルを保存する場所を初期化します。
   * 
   * @param windowId ウィンドウ番号
   */
  private static void title_strings(int windowId) {
    titleStringsData.set(windowId, new MatxList(MAX_FRAME));
  }

  /**
   * タイトルに関する文字列を得る。
   * 
   * @param windowId ウィンドウ番号
   * @param frame フレーム番号
   * @return タイトルに関する文字列
   */
  private static String title_strings(int windowId, int frame) {
    if (titleStringsData.getList(windowId).getObject(frame) instanceof Integer) {
      return ""; //$NON-NLS-1$
    }
    return titleStringsData.getList(windowId).getString(frame);
  }

  /**
   * タイトルに関する文字列を設定します。
   * 
   * @param windowId ウィンドウ番号
   * @param frame フレーム番号
   * @param string タイトルに関する文字列
   */
  private static void title_strings(int windowId, int frame, String string) {
    MatxList ll = titleStringsData.getList(windowId);
    ll.set(frame, string);
    titleStringsData.set(windowId, ll);
  }

  /**
   * 新しく開くウィンドウの番号を得る。
   * 
   * @return 新しく開くウィンドウの番号
   */
  public static int newWindow() {
    for (int i = 1; i <= MAX_WIN; i++) {
      if (!windowID.containsKey(Integer.valueOf(i))) {
        return i;
      }
    }

    return 0;
  }

  /**
   * 全てのウィンドウを削除します。
   * 
   * @throws IOException ファイルへ出力できない場合
   */
  private static void destroyAll() throws IOException {
    for (int id = 1; id <= MAX_WIN; id++) {
      if (HAVE_PIPE) {
        if (windowID.containsKey(Integer.valueOf(id))) {
          destroy(id);
        }
      } else {
        if (strings(id) != "@") { //$NON-NLS-1$
          destroy(id);
        }
      }
    }
    currentWindow = 1;
  }

  /**
   * ウィンドウを削除します。
   * 
   * @param windowId ウィンドウ番号
   * @throws IOException パイルを閉じれない場合
   */
  private static void destroy(int windowId) throws IOException {
    removeDatafile(windowId);
    int oldWindow = currentWindow;

    if (HAVE_PIPE) {
      if (windowID.containsKey(Integer.valueOf(windowId))) {
        command(windowId, "quit"); //$NON-NLS-1$
        
        try (Writer wt = windowID.get(Integer.valueOf(windowId))) {
          wt.close();
        }

      }
      data_num(windowId, -1);
      windowID.remove(Integer.valueOf(windowId));
    } else {
      File f = new File("mgplot_" + windowId + ".plt"); //$NON-NLS-1$ //$NON-NLS-2$
      if (f.exists()) {
        f.delete();
      }
      strings(windowId, "@"); //$NON-NLS-1$
    }

    if (oldWindow == windowId) {
      currentWindow = 1;
    } else {
      currentWindow = oldWindow;
    }
  }

  /**
   * グラフの媒介変数描画に関する設定を得る。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void parametric(int windowId) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (parametricOn.getElement(win)) {
      command(win, "unset parametric"); //$NON-NLS-1$
      parametricOn.setElement(win, false);
    } else {
      command(win, "set parametric"); //$NON-NLS-1$
      parametricOn.setElement(win, true);
    }
  }

  /**
   * グラフの媒介変数描画に関する設定をします。
   * 
   * @param windowId ウィンドウ番号
   * @param on グラフを媒介変数描画するならtrue、そうでなければfalse
   */
  public static void parametric(int windowId, boolean on) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (on) {
      command(win, "set parametric"); //$NON-NLS-1$
    } else {
      command(win, "unset parametric"); //$NON-NLS-1$
    }
    parametricOn.setElement(win, on);

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 陰面処理に関する初期化をします。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void hidden3d(int windowId) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (hidden3dOn.getElement(win)) {
      command(win, "unset hidden3d"); //$NON-NLS-1$
      hidden3dOn.setElement(win, false);
    } else {
      command(win, "set hidden3d"); //$NON-NLS-1$
      hidden3dOn.setElement(win, true);
    }
  }

  /**
   * 陰面処理に関する設定をします。
   * 
   * @param windowId ウィンドウ番号
   * @param on 陰面処理するならtrue、そうでなければfalse
   */
  public static void hidden3d(int windowId, boolean on) {
    int win = windowId;
    if (win <= 0) {
      win = 1;
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (on) {
      command(win, "set hidden3d"); //$NON-NLS-1$
    } else {
      command(win, "unset hidden3d"); //$NON-NLS-1$
    }
    hidden3dOn.setElement(win, on);

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void loglog(int windowId, DoubleMatrix X, DoubleMatrix Y) {
    loglog(windowId, X, Y, new ArrayList<String>(), new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void loglog(int windowId, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    loglog(windowId, X, Y, titles, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void loglog(int windowId, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    loglog(windowId, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void loglog(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    loglog(win, X, Y, titles, cmds1, new ArrayList<String>());
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void loglog(int windowId, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    loglog(windowId, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param windowId ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void loglog(int windowId, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    loglog(windowId, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * ログ・ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void loglog(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    IntMatrix idxx = X.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idxx.length() != 0) {
      X.setSubMatrix(idxx, 1, DoubleMatrix.ones(idxx.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    IntMatrix idxy = Y.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idxy.length() != 0) {
      Y.setSubMatrix(idxy, 1, DoubleMatrix.ones(idxy.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    grid(win, true);
    logMode(win, multiplot(win), 4);
    plot(win, X, Y, titles, cmds1, cmds2);
    logMode(win, multiplot(win), 0);
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y) {
    replot_loglog(win, X, Y, new ArrayList<String>(), new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    replot_loglog(win, X, Y, titles, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    replot_loglog(win, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    replot_loglog(win, X, Y, titles, cmds1, new ArrayList<String>());
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    replot_loglog(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    IntMatrix idxx = X.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idxx.length() != 0) {
      X.setSubMatrix(idxx, 1, DoubleMatrix.ones(idxx.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    IntMatrix idxy = Y.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idxy.length() != 0) {
      Y.setSubMatrix(idxy, 1, DoubleMatrix.ones(idxy.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    grid(win, true);
    logMode(win, multiplot(win), 4);
    replot(win, X, Y, titles, cmds1, cmds2);
    logMode(win, multiplot(win), 0);
  }

  /**
   * ログ・ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot_loglog(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    replot_loglog(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * エキスポートするモードを設定します。
   * 
   * @param win ウィンドウ番号
   * @param mode モード
   */
  private static void export_mode(int win, String mode) {
    if (mode.equals("ps")) { //$NON-NLS-1$
      command(win, "set terminal postscript monochrome 'Times-Roman' 16"); //$NON-NLS-1$
    } else if (mode.equals("psplus")) { //$NON-NLS-1$
      command(win, "set terminal postscript plus monochrome 'Times-Roman-Mincho' 16"); //$NON-NLS-1$
    } else if (mode.equals("eps")) { //$NON-NLS-1$
      command(win, "set terminal postscript eps monochrome 'Times-Roman' 22"); //$NON-NLS-1$
    } else if (mode.equals("epsplus")) { //$NON-NLS-1$
      command(win, "set terminal postscript eps plus monochrome 'Times-Roman-Mincho' 22"); //$NON-NLS-1$
    } else if (mode.equals("fig")) { //$NON-NLS-1$
      command(win, "set terminal fig monochrome portrait fontsize 16 size 5 3"); //$NON-NLS-1$
    } else {
      throw new RuntimeException(Messages.getString("Mgplot.111")); //$NON-NLS-1$
    }
  }

  /**
   * ファイルにエキスポートします。
   * 
   * @param win ウィンドウ番号
   * @param filename ファイル名
   * @param mode モード {"ps", "eps", "psplus", "epsplus", "fig"}
   */
  public static void export(int win, String filename, String mode) {
    export(win, filename, mode, ""); //$NON-NLS-1$
  }

  /**
   * ファイルにエキスポートします。
   * 
   * @param win ウィンドウ番号
   * @param filename ファイル名
   * @param mode モード {"ps", "eps", "psplus", "epsplus", "fig"}
   * @param cmd コマンド文字列
   */
  public static void export(int win, String filename, String mode, String cmd) {
    if (multiplot(win) != 0) {
      command(win, "unset multiplot"); //$NON-NLS-1$
    }

    export_mode(win, mode);

    command(win, "set output '" + filename + "'"); //$NON-NLS-1$ //$NON-NLS-2$

    if (cmd.length() != 0) {
      command(win, cmd);
    }

    if (multiplot(win) != 0) {
      command(win, "set size 1.0,1.0"); //$NON-NLS-1$
      command(win, "set origin 0,0"); //$NON-NLS-1$
      command(win, "set multiplot"); //$NON-NLS-1$
      for (int i = 1; i <= MAX_FRAME; i++) {
        String str = size_strings(win, i);
        if (str.length() > 0) {
          out(win, str);
        }
        str = title_strings(win, i);
        if (str.length() > 0) {
          out(win, str);
        }
        str = plot_strings(win, i);
        if (str.length() > 0) {
          out(win, "plot " + str + newLine); //$NON-NLS-1$
          // mgplot_out(win, str + "\n");
        }
      }
      command(win, "unset multiplot"); //$NON-NLS-1$
    } else {
      update(win);
    }

    // reset the window as before
    command(win, "set terminal x11"); //$NON-NLS-1$
    command(win, "set output"); //$NON-NLS-1$

    if (multiplot(win) != 0) {
      command(win, "set size 0.98,1.0"); //$NON-NLS-1$
      command(win, "set origin 0,0"); //$NON-NLS-1$
      command(win, "set multiplot"); //$NON-NLS-1$
      for (int i = 1; i <= MAX_FRAME; i++) {
        String str = size_strings(win, i);
        if (str.length() > 0) {
          out(win, str);
        }
        str = title_strings(win, i);
        if (str.length() > 0) {
          out(win, str);
        }
        str = plot_strings(win, i);
        if (str.length() > 0) {
          out(win, "plot " + str + newLine); //$NON-NLS-1$
          // mgplot_out(win, str + "\n");
        }
      }
    } else {
      update(win);
    }
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y) {
    semilogx(win, X, Y, new ArrayList<String>(), new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    semilogx(win, X, Y, titles, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    semilogx(win, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    semilogx(win, X, Y, titles, cmds1, new ArrayList<String>());
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    semilogx(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    IntMatrix idx = X.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idx.length() != 0) {
      X.setSubMatrix(idx, 1, DoubleMatrix.ones(idx.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    grid(win, true);
    logMode(win, multiplot(win), 1);
    plot(win, X, Y, titles, cmds1, cmds2);
    logMode(win, multiplot(win), 0);
  }

  /**
   * X方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void semilogx(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    semilogx(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y) {
    replot_semilogx(win, X, Y, new ArrayList<String>(), new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    replot_semilogx(win, X, Y, titles, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    replot_semilogx(win, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    replot_semilogx(win, X, Y, titles, cmds1, new ArrayList<String>());
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    replot_semilogx(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    IntMatrix idx = X.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idx.length() != 0) {
      X.setSubMatrix(idx, 1, DoubleMatrix.ones(idx.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    grid(win, true);
    logMode(win, multiplot(win), 1);
    replot(win, X, Y, titles, cmds1, cmds2);
    logMode(win, multiplot(win), 0);
  }

  /**
   * X方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot_semilogx(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    replot_semilogx(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y) {
    semilogy(win, X, Y, new ArrayList<String>(), new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    semilogy(win, X, Y, titles, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    semilogy(win, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    semilogy(win, X, Y, titles, cmds1, new ArrayList<String>());
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    semilogy(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    IntMatrix idx = Y.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idx.length() != 0) {
      Y.setSubMatrix(idx, 1, DoubleMatrix.ones(idx.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    grid(win, true);
    logMode(win, multiplot(win), 2);
    plot(win, X, Y, titles, cmds1, cmds2);
    logMode(win, multiplot(win), 0);
  }

  /**
   * Y方向ログスケールでプロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void semilogy(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    semilogy(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y) {
    replot_semilogy(win, X, Y, new ArrayList<String>(), new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles) {
    replot_semilogy(win, X, Y, titles, new ArrayList<String>(), new ArrayList<String>());
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles) {
    replot_semilogy(win, X, Y, new ArrayList<>(Arrays.asList(titles)));
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1) {
    replot_semilogy(win, X, Y, titles, cmds1, new ArrayList<String>());
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1) {
    replot_semilogy(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)));
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y, List<String> titles, List<String> cmds1, List<String> cmds2) {
    IntMatrix idx = Y.getColumnVector(1).compareElementWise(".==", 0).find(); //$NON-NLS-1$
    if (idx.length() != 0) {
      Y.setSubMatrix(idx, 1, DoubleMatrix.ones(idx.length(), 1).multiply(DoubleNumberUtil.EPS));
    }

    grid(win, true);
    logMode(win, multiplot(win), 2);
    replot(win, X, Y, titles, cmds1, cmds2);
    logMode(win, multiplot(win), 0);
  }

  /**
   * Y方向ログスケールで再プロットします。
   * 
   * @param win ウィンドウ番号
   * @param X X方向のデータ
   * @param Y Y方向のデータ
   * @param titles タイトル
   * @param cmds1 コマンド1
   * @param cmds2 コマンド2
   */
  public static void replot_semilogy(int win, DoubleMatrix X, DoubleMatrix Y, String[] titles, String[] cmds1, String[] cmds2) {
    replot_semilogy(win, X, Y, new ArrayList<>(Arrays.asList(titles)), new ArrayList<>(Arrays.asList(cmds1)), new ArrayList<>(Arrays.asList(cmds2)));
  }

  /**
   * 文字列を描画します。
   * 
   * @param win ウィンドウ番号
   * @param text テキスト文字列
   * @param x X座標
   * @param y Y座標
   */
  public static void text(int win, String text, double x, double y) {
    text(win, text, x, y, ""); //$NON-NLS-1$
  }

  /**
   * 文字列を描画します。
   * 
   * @param win ウィンドウ番号
   * @param text テキスト文字列
   * @param x X座標
   * @param y Y座標
   * @param cmds コマンド
   */
  public static void text(int win, String text, double x, double y, String cmds) {
    String str;
    if (text.length() == 0) {
      str = "unset label"; //$NON-NLS-1$
    } else {
      if (cmds.length() == 0) {
        str = "set label '" + text + "' at " + x + "," + y; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      } else {
        str = "set label '" + text + "' at " + x + "," + y + ", " + cmds; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
      }
    }

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * タイトルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text タイトル文字列
   */
  public static void title(int win, String text) {
    String str = "set title '" + text + "'"; //$NON-NLS-1$ //$NON-NLS-2$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      title_strings(win, frame, str + newLine);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text X軸ラベル文字列
   */
  public static void xlabel(int win, String text) {
    String str = "set xlabel '" + text + "'"; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text X軸ラベル文字列
   * @param xoff X座標のオフセット
   */
  public static void xlabel(int win, String text, int xoff) {
    String str = "set xlabel '" + text + "' " + xoff; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text X軸ラベル文字列
   * @param xoff X座標のオフセット
   * @param yoff Y座標のオフセット
   */
  public static void xlabel(int win, String text, int xoff, int yoff) {
    String str = "set xlabel '" + text + "' " + xoff + "," + yoff; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 第二X軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text 第二X軸ラベル文字列
   */
  public static void x2label(int win, String text) {
    String str = "set x2label '" + text + "'"; //$NON-NLS-1$ //$NON-NLS-2$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 第二X軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text 第二X軸ラベル文字列
   * @param xoff X座標のオフセット
   */
  public static void x2label(int win, String text, int xoff) {
    String str = "set x2label '" + text + "' " + xoff; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 第二X軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text 第二X軸ラベル文字列
   * @param xoff X座標のオフセット
   * @param yoff Y座標のオフセット
   */
  public static void x2label(int win, String text, int xoff, int yoff) {
    String str = "set x2label '" + text + "' " + xoff + "," + yoff; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Y軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text Y軸ラベル文字列
   */
  public static void ylabel(int win, String text) {
    String str = "set ylabel '" + text + "'"; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Y軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text Y軸ラベル文字列
   * @param xoff X座標オフセット
   */
  public static void ylabel(int win, String text, int xoff) {
    String str = "set ylabel '" + text + "' " + xoff; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Y軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text Y軸ラベル文字列
   * @param xoff X座標オフセット
   * @param yoff Y座標オフセット
   */
  public static void ylabel(int win, String text, int xoff, int yoff) {
    String str = "set ylabel '" + text + "' " + xoff + "," + yoff; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 第二Y軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text 第二Y軸ラベル文字列
   */
  public static void y2label(int win, String text) {
    String str = "set y2label '" + text + "'"; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 第二Y軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text 第二Y軸ラベル文字列
   * @param xoff X軸オフセット
   */
  public static void y2label(int win, String text, int xoff) {
    String str = "set y2label '" + text + "' " + xoff; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 第二Y軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text 第二Y軸ラベル文字列
   * @param xoff X軸オフセット
   * @param yoff Y軸オフセット
   */
  public static void y2label(int win, String text, int xoff, int yoff) {
    String str = "set y2label '" + text + "' " + xoff + "," + yoff; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Z軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text Z軸ラベル文字列
   */
  public static void zlabel(int win, String text) {
    String str = "set zlabel '" + text + "'"; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Z軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text Z軸ラベル文字列
   * @param xoff X軸オフセット
   */
  public static void zlabel(int win, String text, int xoff) {
    String str = "set zlabel '" + text + "' " + xoff; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Z軸ラベルを描画します。
   * 
   * @param win ウィンドウ番号
   * @param text Z軸ラベル文字列
   * @param xoff X軸オフセット
   * @param yoff Y軸オフセット
   */
  public static void zlabel(int win, String text, int xoff, int yoff) {
    String str = "set zlabel '" + text + "' " + xoff + "," + yoff; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 視点をX軸周りに回転します。
   * 
   * @param win ウィンドウ番号
   * @param rotate_x X軸周りの回転角度
   */
  public static void view(int win, double rotate_x) {
    String str = "set view " + rotate_x; //$NON-NLS-1$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X方向の範囲を設定します。
   * 
   * @param win ウィンドウ番号
   * @param xmin X方向の最小値
   * @param xmax X方向の最大値
   */
  public static void range(int win, double xmin, double xmax) {
    String str = "set xrange [" + xmin + ":" + xmax + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X方向の範囲を設定します。
   * 
   * @param win ウィンドウ番号
   * @param xmin X方向の最小値
   * @param xmax X方向の最大値
   * @param ymin Y方向の最小値
   * @param ymax Y方向の最大値
   */
  public static void range(int win, double xmin, double xmax, double ymin, double ymax) {
    String str = "set xrange [" + xmin + ":" + xmax + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    str = str + newLine + "set yrange [" + ymin + ":" + ymax + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X方向の範囲を設定します。
   * 
   * @param win ウィンドウ番号
   * @param xmin X方向の最小値
   * @param xmax X方向の最大値
   * @param ymin Y方向の最小値
   * @param ymax Y方向の最大値
   * @param zmin Z方向の最小値
   * @param zmax Z方向の最大値
   */
  public static void range(int win, double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) {
    String str = "set xrange [" + xmin + ":" + xmax + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    str = str + newLine + "set yrange [" + ymin + ":" + ymax + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    str = str + newLine + "set zrange [" + zmin + ":" + zmax + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * X方向の範囲を設定します。
   * 
   * @param win ウィンドウ番号
   * @param min 最小値
   * @param max 最大値
   */
  public static void xrange(int win, double min, double max) {
    String str = "set xrange [" + min + ":" + max + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Y方向の範囲を設定します。
   * 
   * @param win ウィンドウ番号
   * @param min 最小値
   * @param max 最大値
   */
  public static void yrange(int win, double min, double max) {
    String str = "set yrange [" + min + ":" + max + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * Z方向の範囲を設定します。
   * 
   * @param win ウィンドウ番号
   * @param min 最小値
   * @param max 最大値
   */
  public static void zrange(int win, double min, double max) {
    String str = "set zrange [" + min + ":" + max + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 視点をX軸周り、Z軸周りに回転します。
   * 
   * @param win ウィンドウ番号
   * @param rotate_x X軸周りの回転角度
   * @param rotate_z Z軸周りの回転角度
   */
  public static void view(int win, double rotate_x, double rotate_z) {
    String str = "set view " + rotate_x + "," + rotate_z; //$NON-NLS-1$ //$NON-NLS-2$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 視点をX軸周り、Z軸周りに回転し、スケール倍します。
   * 
   * @param win ウィンドウ番号
   * @param rotate_x X軸周りの回転角度
   * @param rotate_z Z軸周りの回転角度
   * @param scale 倍率
   */
  public static void view(int win, double rotate_x, double rotate_z, double scale) {
    String str = "set view " + rotate_x + "," + rotate_z + "," + scale; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 視点をX軸周り、Z軸周りに回転し、スケール倍します。
   * 
   * @param win ウィンドウ番号
   * @param rotate_x X軸周りの回転角度
   * @param rotate_z Z軸周りの回転角度
   * @param scale 倍率
   * @param scale_z Z方向への倍率
   */
  public static void view(int win, double rotate_x, double rotate_z, double scale, double scale_z) {
    String str = "set view " + rotate_x + "," + rotate_z + "," + scale + "," + scale_z; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

    command(win, str);

    int frame = multiplot(win);
    if (frame != 0) {
      str = size_strings(win, frame) + str + newLine;
      size_strings(win, frame, str);
    }

    if (HAVE_PIPE) {
      update(win);
    }
  }

  /**
   * 全てのウィンドウを終了します。
   */
  public static void quit() {
    if (!isRunning) {
      return;
    }
    try {
      destroyAll();
    } catch (IOException e) {
      throw new PlotterException(e);
    } finally {
      isRunning = false;
    }
  }

  /**
   * ウィンドウを終了します。
   * 
   * @param windowId ウィンドウ番号
   */
  public static void quit(int windowId) {
    if (!isRunning) {
      return;
    }
    try {
      destroy(windowId);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 2個のウィンドウを終了します。
   * 
   * @param windowId1 ウィンドウ1
   * @param windowId2 ウィンドウ2
   */
  public static void quit(int windowId1, int windowId2) {
    if (!isRunning) {
      return;
    }
    try {
      destroy(windowId1);
      destroy(windowId2);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 3個のウィンドウを終了します。
   * 
   * @param windowId1 ウィンドウ1
   * @param windowId2 ウィンドウ2
   * @param windowId3 ウィンドウ3
   */
  public static void quit(int windowId1, int windowId2, int windowId3) {
    if (!isRunning) {
      return;
    }
    try {
      destroy(windowId1);
      destroy(windowId2);
      destroy(windowId3);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 4個のウィンドウを終了します。
   * 
   * @param win1 ウィンドウ1
   * @param win2 ウィンドウ2
   * @param win3 ウィンドウ3
   * @param win4 ウィンドウ4
   */
  public static void quit(int win1, int win2, int win3, int win4) {
    if (!isRunning) {
      return;
    }
    try {
      destroy(win1);
      destroy(win2);
      destroy(win3);
      destroy(win4);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * 5個のウィンドウを終了します。
   * 
   * @param win1 ウィンドウ1
   * @param win2 ウィンドウ2
   * @param win3 ウィンドウ3
   * @param win4 ウィンドウ4
   * @param win5 ウィンドウ5
   */
  public static void quit(int win1, int win2, int win3, int win4, int win5) {
    try {
      destroy(win1);
      destroy(win2);
      destroy(win3);
      destroy(win4);
      destroy(win5);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * オプションを保存します。
   * 
   * @param windowId ウィンドウ番号
   * @param options オプション文字列
   */
  public static void options(int windowId, String options) {
    try {
      init(windowId, options);
    } catch (IOException e) {
      throw new PlotterException(e);
    }
  }

  /**
   * サブプロットの設定をします。
   * 
   * @param windowId ウィンドウ番号
   * @param rows 行方向のフレームの数
   * @param cols 列方向のフレームの数
   */
  public static void subplot(int windowId, int rows, int cols) {
    subplot(windowId, rows, cols, 1);
  }

  /**
   * サブプロットの設定をします。
   * 
   * @param win ウィンドウ番号
   * @param rows 行方向の番号
   * @param cols 列方向の番号
   * @param frame フレーム番号
   */
  public static void subplot(int win, int rows, int cols, int frame) {
    if (cols < 0) {
      throw new RuntimeException(Messages.getString("Mgplot.208")); //$NON-NLS-1$
    }
    if (rows < 0) {
      throw new RuntimeException(Messages.getString("Mgplot.209")); //$NON-NLS-1$
    }
    if (frame < 0 || cols * rows < frame) {
      String mess = Messages.getString("Mgplot.210") + rows * cols; //$NON-NLS-1$
      throw new RuntimeException("subplot(): " + mess); //$NON-NLS-1$
    }

    try {
      init(win);
    } catch (IOException e) {
      throw new PlotterException(e);
    }

    if (rows == 1 && cols == 1) {
      if (multiplot(win) != 0) {
        if (HAVE_PIPE) {
          multiplot(win, 0);
          command(win, "set size 0.98,1.0"); //$NON-NLS-1$
          command(win, "set origin 0,0"); //$NON-NLS-1$
        } else {
          strings(win, ""); //$NON-NLS-1$
          resetCode(win);
        }
        plot_strings(win);
        size_strings(win);
        title_strings(win);
      }
      return;
    }

    if (!HAVE_PIPE && multiplot(win) == 0) {
      strings(win, ""); //$NON-NLS-1$
      resetCode(win);
    }
    if (multiplot(win) == 0) {
      plot_strings(win);
    }

    final double xsize = 1.0 / cols;
    final double ysize = 1.0 / rows;

    final int y = (frame - 1) / cols;
    final int x = frame - 1 - y * cols;
    final double xorg = xsize * x;
    final double yorg = ysize * (rows - 1 - y);

    if (multiplot(win) != frame) {
      multiplot(win, frame);
    }
    command(win, "set size " + (0.98 * xsize) + "," + ysize); //$NON-NLS-1$//$NON-NLS-2$
    command(win, "set origin " + xorg + "," + yorg); //$NON-NLS-1$//$NON-NLS-2$

    size_strings(win, frame, "set size " + (0.98 * xsize) + "," + ysize + newLine + "set origin " + xorg + "," + yorg); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
  }

}