研究開発

グラフを描く(5)

第5章 ワークシートからデータを読んでみる

さて、ここまで色々なタイプのグラフを描いてきましたが、「何度実行しても同じグラフが出るじゃないか!」とか、「数値を変えるたびにソースを開くのってどうよ?」と、お嘆きの方々にとっておきの技をお教えします。

なんと、VectorScriptにも某表計算ソフトのようにワークシートからグラフを描くことができるんです。
Vectorworksではワークシートを使って図形の集計などかできるなど、本体のみでワークシートが簡単に扱えるようになっています。このワークシートを入力インタフェースとしてグラフを描いてみましょう。
ちなみに、テキストファイルを読み込む等のいかにも普通のプログラムスタイルなやり方もできます。

ワークシートの作り方の説明はしませんが、重要なのはワークシートの名前です。データを探しに行くにあたり、ハンドルというオブジェクトの住所にあたるものが必要になりますが、そのハンドルを名前から探す関数がありますのでワークシートの名前を間違えないでください。

ワークシートからデータを読んでくるには、

手続きGetWSCellValue(worksheet : HANDLE; row, column : INTEGER; VAR cellValue : REAL);

を使います。

ワークシートは縦方向が、 row、横方向が columnで表します。一行目のデータを読んでくるには、
ワークシート名からハンドルを取得し、ハンドルとセル番号(1,1)を使って読んできたデータをメッセージウインドウに表示してみましょう。

PROCEDURE WS2Graph;
CONST
	kWSName = '名称未設定-1';
VAR
	worksheet : HANDLE;
	cellValue : REAL;
BEGIN
	worksheet := GetObject( kWSName );
	GetWSCellValue( worksheet, 1, 1, cellValue );
	Message( cellValue );
END;
Run( WS2Graph );

さらに、(1,2)(1,3)(1,4)(1,5)とすれば一行目のセルデータを読めますね。
さて、データが用意されたのであれば、これまでやってきたグラフの描画と組み合わせれば、任意のグラフが完成するわけです。

PROCEDURE WS2Graph;
CONST
	kWSName = '名称未設定-1';
VAR
	worksheet : HANDLE;
	cellValue : REAL;
BEGIN
	worksheet := GetObject( kWSName );

	PenSize( 39 );
	FillPat( 0 );
	PenFore( 65535, 0, 0 );

	BeginPoly;

	GetWSCellValue( worksheet, 1, 1, cellValue );
	AddPoint( 0, cellValue );

	GetWSCellValue( worksheet, 1, 2, cellValue );
	AddPoint( 10, cellValue );

	GetWSCellValue( worksheet, 1, 3, cellValue );
	AddPoint( 20, cellValue );

	GetWSCellValue( worksheet, 1, 4, cellValue );
	AddPoint( 30, cellValue );

	GetWSCellValue( worksheet, 1, 5, cellValue );
	AddPoint( 40, cellValue );

	EndPoly;

END;
Run( WS2Graph );

2行目のデータを使ってもう一本描くにはどうしたらよいでしょう?
そうです。(2,2)(2,3)(2,4)(2,5)とすれば二行目のセルデータを読めます。

PROCEDURE WS2Graph;
CONST
	kWSName = '名称未設定-1';
VAR
	worksheet : HANDLE;
	cellValue : REAL;
BEGIN
	worksheet := GetObject( kWSName );

	PenSize( 39 );
	FillPat( 0 );
	PenFore( 65535, 0, 0 );

	BeginPoly;

	GetWSCellValue( worksheet, 1, 1, cellValue );
	AddPoint( 0, cellValue );

	GetWSCellValue( worksheet, 1, 2, cellValue );
	AddPoint( 10, cellValue );

	GetWSCellValue( worksheet, 1, 3, cellValue );
	AddPoint( 20, cellValue );

	GetWSCellValue( worksheet, 1, 4, cellValue );
	AddPoint( 30, cellValue );

	GetWSCellValue( worksheet, 1, 5, cellValue );
	AddPoint( 40, cellValue );

	EndPoly;

	PenFore( 0, 65535, 0 );

	BeginPoly;

	GetWSCellValue( worksheet, 2, 1, cellValue );
	AddPoint( 0, cellValue );

	GetWSCellValue( worksheet, 2, 2, cellValue );
	AddPoint( 10, cellValue );

	GetWSCellValue( worksheet, 2, 3, cellValue );
	AddPoint( 20, cellValue );

	GetWSCellValue( worksheet, 2, 4, cellValue );
	AddPoint( 30, cellValue );

	GetWSCellValue( worksheet, 2, 5, cellValue );
	AddPoint( 40, cellValue );

	EndPoly;

END;
Run( WS2Graph );

では最後に、列方向は5つどころかいくつやってくるかわからないし、行方向もグラフが何本になるかわからない場合、この勢いでプログラムが長くなっちゃうんですか?って思っているアナタのためにプログラムをリファクタリングしてみましょう。

まず、ワークシートがどれくらいの大きさなのかを知り、それに合わせて列方向、行方向に任意の数に対応できるように変数化します。

ワークシートの大きさを求めるのは

手続きGetWSRowColumnCount(worksheet : HANDLE; VAR numRows, numColumns : INTEGER);

を使います。

列と行の大きさわかれば、2重の繰り返し文を作って、内側の繰り返しで、列方向にデータを拾っていき、端まで行き着いたら次の行をまた読み始めるそして行がなくなるまで繰り返せばいいわけです。

色についてはカラーインデックス番号からRGB値を取得する

手続きColorIndexToRGB(color : INTEGER; VAR red, green, blue : LONGINT);

を使って、外側の繰り返し別に色を変えています。

PROCEDURE WS2Graph;
CONST
	kWSName = '名称未設定-1';
VAR
	worksheet : HANDLE;
	numRows, numColumns : INTEGER;
	cellValue : REAL;
	red, green, blue : LONGINT;
	ii, jj : INTEGER;
BEGIN
	worksheet := GetObject( kWSName );

	GetWSRowColumnCount( worksheet, numRows, numColumns );

	PenSize( 39 );
	FillPat( 0 );

	FOR ii := 1 TO numRows DO
	BEGIN
		ColorIndexToRGB( ii+1, red, green, blue );
		PenFore( red, green, blue );

		BeginPoly;

		FOR jj := 1 TO numColumns DO
		BEGIN
			GetWSCellValue( worksheet, ii, jj, cellValue );
			AddPoint( jj*10, cellValue );
		END;

		EndPoly;

	END;
END;
Run( WS2Graph );

ちなみに、円グラフの場合、全体の母数を求めてセルごとの数値を割ることで、100分の何%であるかを計算しなくてはなりません。その場合はどうすればよいでしょうか?
単純に2回読めばいいんです(笑)、一回目に全体のトータルを計算して、二回目に描画計算をすればバッチリです。

PROCEDURE WS2Graph;
CONST
	kWSName = '名称未設定-1';
VAR
	worksheet : HANDLE;
	numRows, numColumns : INTEGER;
	cellValue, totalValue : REAL;
	startAngle, sweepAngle : REAL;
	red, green, blue : LONGINT;
	ii : INTEGER;
BEGIN
	worksheet := GetObject( kWSName );

	GetWSRowColumnCount( worksheet, numRows, numColumns );

	totalValue := 0.0;
	FOR ii := 1 TO numColumns DO
	BEGIN
		GetWSCellValue( worksheet, 1, ii, cellValue );
		totalValue := totalValue + cellValue;
	END;

	startAngle := 90;

	FOR ii := 1 TO numColumns DO
	BEGIN
		ColorIndexToRGB( ii+1, red, green, blue );
		FillBack( red, green, blue );
		PenFore( red, green, blue );

		GetWSCellValue( worksheet, 1, ii, cellValue );
		sweepAngle := cellValue*360/totalValue;
		ArcByCenter( 0, 0, 50, startAngle, -sweepAngle );
		startAngle := startAngle - sweepAngle;

	END;
END;
Run( WS2Graph );