チャート座標と画像座標の変換方法[EspressChart]


チャートをデザインする際に、点や線、テキストを描画することは多いかと思います。これが静的なものや平均や最大、最小、標準偏差などであれば下記のようにGUIから事前に設定を行えます。しかし、任意のものを動的に描画する際にはプログラムで読み込んだチャートに対して描画を行う必要があります。

この時、単純に画像上の座標や相対位置であれば描画も容易に行えますが、グラフのY軸値とX軸値を基とする場合には変換を必要になります。今回はこの方法をご紹介します。

今回ご紹介する方法はX軸はカテゴリであり、Y軸に値があるケースです。

まず、なぜ変換を行わなければならないのかというとチャート内にAPIで描画を行うときに使用する座標はチャートの原点からの座標ですが、 APIでチャートを読み込んだ後に各要素の位置情報として取得できる座標がキャンバスの原点からの座標となっているためです。

したがってキャンバス座標からの変換には下記の計算を行う必要が有ります。

チャートの長さ=チャート最大座標-チャート原点の座標
対象ポイントの長さ= 対象ポイントの座標-チャート原点の座標
比率=チャート精度 / チャートの長さ
チャート上の座標=対象ポイントの長さ×比率

実際にAPIに落とし込むと以下のようになります。

//X軸のティッカー(目盛り)情報を取得
Point3D[] tickerPs = chart.getChart().a_x.ticker.getPoints();
//チャートのX軸最大座標(X軸の最終点)からチャートのX軸原点座標を減算
int xLength = chart.getChart().getAxis(Axis.X).endp.x - chart.getChart().getAxis(Axis.X).xorigin;
//チャート精度をチャートのX軸の長さで除算
double xRatio = (double)chart.getChart().PRECISION/xLength;
//対象ポイントのX軸の座標からチャートのX軸原点座標を減算
//X軸はカテゴリであるためティッカーのインデックスの位置を取得
xP = tickerPs[xIndex].x - chart.getChart().getAxis(Axis.X).xorigin;
//対象ポイントのX軸上での長さに比率を乗算
xP = (int) (xP * xRatio);

//チャートのY軸最大座標(Y軸の最終点)からチャートのY軸原点座標を減算
int yLength = chart.getChart().a_y.endp.y - chart.getChart().a_y.yorigin;
//チャート精度をチャートのY軸の長さで除算
double yRatio = (double)chart.getChart().PRECISION/yLength;
//対象ポイントのY軸の座標からチャートのY軸原点座標を減算
//対象ポイントの座標はY軸の間隔をから補間し取得
yP = chart.getChart().a_y.stepsize.interpolatePixel2(yV) - chart.getChart().a_y.yorigin;
//対象ポイントのY軸上での長さに比率を乗算
yP = (int) ((yP)*yRatio) ;

このように求めた値を用いて下記のようにポイントをプロットできます。

Vector<Vertex> line = new Vector<Vertex>();
line.add(new Vertex(test.xP,test.yP,0));
line.add(new Vertex(test.xP,test.yP,0));
PolyLine pl = new PolyLine();
pl.setThickness(5);
pl.set(line.elements(), Color.RED);

ただ、これではX軸のカテゴリ名で指定を行えませんので、カテゴリ名から特定を行いたい場合にはティッカーのラベルを取得し、下記のようにインデックスを特定します。

CString[] labels =  chart.getChart().a_x.ticker.label;
String labelstrs[]= new String[labels.length];
for(int i=0;i<labels.length;i++) {labelstrs[i]=labels[i].str;}
List<String> list = Arrays.asList(labelstrs);
int xIndex = list.indexOf(xV);

コードとしてまとめると下記のようになります。

import java.util.Arrays;
import java.util.List;
import quadbase.ChartAPI.QbChart;
import quadbase.chart.Axis;
import quadbase.chart.CString;
import quadbase.chart.Point3D;

public class ConvertCoordinate {
	public int xP;
	public int yP;
	public ConvertCoordinate(QbChart chart, String xV, Double yV) {

	int yLength = chart.getChart().a_y.endp.y - chart.getChart().a_y.yorigin;
        double yRatio = (double)chart.getChart().PRECISION/yLength;
        yP = chart.getChart().a_y.stepsize.interpolatePixel2(yV) - chart.getChart().a_y.yorigin;
        yP = (int) ((yP)*yRatio) ;

        CString[] labels =  chart.getChart().a_x.ticker.label;
        String labelstrs[]= new String[labels.length];
        for(int i=0;i<labels.length;i++) {labelstrs[i]=labels[i].str;}
        List<String> list = Arrays.asList(labelstrs);
        int xIndex = list.indexOf(xV);

        Point3D[] tickerPs = chart.getChart().a_x.ticker.getPoints();
        int xLength = chart.getChart().getAxis(Axis.X).endp.x - chart.getChart().getAxis(Axis.X).xorigin;
        double xRatio = (double)chart.getChart().PRECISION/xLength;
        xP = tickerPs[xIndex].x - chart.getChart().getAxis(Axis.X).xorigin;
        xP = (int) (xP * xRatio);
   }
}
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Vector;

import quadbase.ChartAPI.QbChart;
import quadbase.chart.chart3d.lib3d.Vertex;
import quadbase.util.PolyLine;

public class viewandexport extends Applet {
	public static void main(String[] args) throws IOException {
		viewandexport chart = new viewandexport();
		Frame frame = new Frame();
		frame.setLayout(new BorderLayout());
		frame.add("Center", chart.doDataFromArguments(null));
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
				}
			}
		);

		frame.setSize(800, 600);
		frame.setVisible(true);
	}

	public void init() {
		setLayout(new BorderLayout());
			try {
				add("Center", doDataFromArguments(this));
				} catch (IOException e) {
				e.printStackTrace();
				}
	}

	Component doDataFromArguments(Applet applet) throws IOException  {
	    QbChart.setEspressManagerUsed(false);
	    QbChart chart = new QbChart(applet, "../chart/ForConvertCoordinate.PAC");

	    ConvertCoordinate test = new ConvertCoordinate(chart,"Thu",200.0);

	    Vector<Vertex> line = new Vector<Vertex>();
        line.add(new Vertex(test.xP,test.yP,0));
        line.add(new Vertex(test.xP,test.yP,0));
        PolyLine pl = new PolyLine();
        pl.setThickness(5);
        pl.set(line.elements(), Color.RED);
        chart.getChart().addLine(pl);

        chart.export(QbChart.PNG, "ConvertCoordinate.PNG");

	    return chart;
	}

}

上記コードではThu , 200の位置に赤い点を描画しており、エクスポートした画像では下記のようになります。

関連するトピックス:

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください