日本語プログラミング言語「プロデル」でグラフを描く

## はじめに

折れ線グラフを描きます。グラフ理論のグラフではありません。

## 実装

縦軸は任意で，横軸はデータの個数である折れ線グラフを描けるようにしたいと思います。
データ構造としては，1つの系列を1行とする行列を与えることにします。

### 色

複数の系列が入ったときに分かりやすいよう，色分けをします。色相を系列の数で等分してやればそれなりに良い感じになるのではないでしょうか。

$360 \div $系列数

HSV色空間をRGB色空間に直す方法は，[Wikipedia](https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93#HSV%E3%81%8B%E3%82%89RGB%E3%81%B8%E3%81%AE%E5%A4%89%E6%8F%9B)にありましたので，そのまま使います。円柱です。

```プロデル:色.rdr
【HSV：配列】をRGBに変換する手順
	【H】は，HSV（1）。
	【S】は，HSV（2）。
	【V】は，HSV（3）。
	Hは，H÷60.0。
	Xは，（1－（Hを2で割った剰り－1）の絶対値）×S。
	【RGB：配列】は，｛V－S，V－S，V－S｝。
	もしHが0以上かつHが1未満なら
		RGB（1）は，S。
		RGB（2）は，X。
		RGB（3）は，0。
	他でもしHが1以上かつHが2未満なら
		RGB（1）は，X。
		RGB（2）は，S。
		RGB（3）は，0。
	他でもしHが2以上かつHが3未満なら
		RGB（1）は，0。
		RGB（2）は，S。
		RGB（3）は，X。
	他でもしHが3以上かつHが4未満なら
		RGB（1）は，0。
		RGB（2）は，X。
		RGB（3）は，S。
	他でもしHが4以上かつHが5未満なら
		RGB（1）は，X。
		RGB（2）は，0。
		RGB（3）は，S。
	そうでなければ
		RGB（1）は，S。
		RGB（2）は，0。
		RGB（3）は，X。
	もし終わり
	RGB（1）は，RGB（1）×255.0。
	RGB（2）は，RGB（2）×255.0。
	RGB（3）は，RGB（3）×255.0。
	RGBを返す。
終わり
```

プロデルでは，色の指定はキーワードを除けばRGBのみで，かつ0～255の整数値を取ります。

これで，Hに適当な角度を入力すればRGBを返してもらえるようになりました。

### ウィンドウを作る

画像ファイルに出力しても良いのですが，データ処理などをする際にはその場で見たいことが多いと思うので，ウィンドウに描画することにします。

プロデルでは，ウィンドウは種類として提供されています。また，描画するためのキャンバス種類があり，これを用います。

```プロデル:グラフ描画.rdr
グラフとは
	－メイン画面
	【大きさ：配列】は，｛0，0｝。
	【オフセット：配列】は，｛50，50，50，50｝。
	はじめ（幅，高さ）の手順
		メイン画面は，ウィンドウを作ったもの。
		メイン画面の初期位置は，中央。
		メイン画面の実質大きさは，｛幅＋オフセット（3）＋オフセット（4），高さ＋オフセット（1）＋オフセット（2）｝。
		メイン画面のタイトルは，「グラフ」。
		メイン画面へ描画領域というキャンバスを作る。
		描画領域のドッキング方向を全体に変える。
		大きさは，｛幅，高さ｝。
		描画領域へ四角形を描く。
			その位置と大きさは，｛オフセット（3），オフセット（1），幅，高さ｝。
			その線色を黒色に変える。
	終わり
	自分を表示する手順
		メイン画面を表示。
	終わり
終わり
```

軸やラベルを描くためにグラフの描画領域とは別に上下左右に50ピクセルずつ用意しました。コンストラクタで，ウィンドウとキャンバスを作っています。大きさは引数で指定します。

### 折れ線グラフを描く

今回は横軸は描画領域の幅を均等に割ってやることになるので，描画領域の幅をデータの個数で割ったものをかけてやります。また，縦軸については，データの最大値と最小値の差分を取って，さらに座標がプロデル上では上から下に値が増えていくので，引き算をして良い感じにします。

この前作った行列ライブラリの最大値最小値を求める手順が，欠陥で，行列が0で初期化されてしまうので，0より小さい最大値と0より大きい最小値が出てこないという仕様になっています。今回の場合，0をまたがないデータでも0から始まります。

```プロデル:グラフ描画.rdr
自分に【データ：行列】で折れ線グラフを描く手順
	【横軸最大値：浮動小数】は，データの大きさ（2）。
	【縦軸最大値：浮動小数】は，0。
	【縦軸最小値：浮動小数】は，0。
	【各系列最大値】は，データが最大値を計算したもの。
	【各系列最小値】は，データが最小値を計算したもの。		
	データの大きさ（1）回【カウンタ】にカウントして繰り返す
		もし縦軸最大値＜各系列最大値の中身（カウンタ）（1）なら
			縦軸最大値は，各系列最大値の中身（カウンタ）（1）。
		もし終わり
		もし縦軸最小値＞各系列最小値の中身（カウンタ）（1）なら
			縦軸最小値は，各系列最小値の中身（カウンタ）（1）。
		もし終わり
	繰り返し終わり
	【横軸単位】は，大きさ（1）÷（横軸最大値－1）
	【縦軸単位】は，大きさ（2）÷（縦軸最大値－縦軸最小値）。
	データは，［データへ縦軸最小値を全部足したもの］に縦軸単位を全部かけたもの。
終わり
```

これで，座標に変換できました。

次に色ですが，

```
【色相：配列】は，｛｝。
データの大きさ（1）回【あ】にカウントして繰り返す
	【RGB：配列】は，｛360÷データの大きさ（1）×（あ－1），1.0，0.5｝をRGBに変換したもの。
	色相（あ）は，色情報を作ったもの。
	色相（あ）の要素は，｛0，RGB（1），RGB（2），RGB（3）｝。
繰り返し終わり
```

このようにして，色相に入れておきます。プロデルには色情報という種類がありますが，これがアルファチャネルを要求するので，5行目で1番目の要素に0（透明度0＝不透明）を入れています。

ではここから描画をしていきます。

```
データの大きさ（1）回【系列】にカウントして繰り返す
	【系列データ】は，データの中身（系列）。
	系列データの個数－1回【カウンタ】にカウントして繰り返す
		描画領域へ線を描く
			その線色を「［色相（系列）］」に変える。
			その始点は，｛オフセット（3）＋（カウンタ－1）×横軸単位，オフセット（1）＋大きさ（2）－系列データ（カウンタ）｝。
			その終点は，｛オフセット（3）＋カウンタ×横軸単位，オフセット（1）＋大きさ（2）－系列データ（カウンタ＋1）｝。
	繰り返し終わり
繰り返し終わり
```

最後に，縦軸のラベルを描きます。原点と最大値だけ描きます。

```
描画領域へ縦軸最小値という文字を書く。
	その文字サイズを10に変える。
	その位置は，｛オフセット（3），オフセット（1）＋大きさ（2）－文字サイズ÷2｝。
	その文字色を黒色に変える。
	その文字配置を右に変える。
描画領域へ縦軸最大値という文字を書く。
	その文字サイズを10に変える。
	その位置は，｛オフセット（3），オフセット（1）－文字サイズ÷2｝。
	その文字色を黒色に変える。
	その文字配置を右に変える。
```

一通り終わったら，

```
描画領域を更新する
```

で反映します。


## 使う

では，実際にグラフを描いてみたいと思います。特に思いつかないので，三角関数を描きます。

$y=\sin x,\cos x, -\sin x$

を描きます。

```プロデル
「行列.rdr」を参照する。
「色.rdr」を参照する。
「Produire.PGraphics.dll」を利用する。
「Produire.WinControl.dll」を利用する。

あは，グラフ（600，300）を作ったもの。
いは，行列（3，600）を作ったもの。
600回【う】にカウントして繰り返す
	いの中身（1）（う）は，（（う－1）×（円周率÷100））のラジアンサイン
	いの中身（2）（う）は，（（う－1）×（円周率÷100））のラジアンコサイン
	いの中身（3）（う）は，－（（う－1）×（円周率÷100））のラジアンサイン
繰り返し終わり
あにいで折れ線グラフを描く。
あを表示。
待機する。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150160/65d965a7-355d-161f-5b75-8a8716cb972c.png)

描けました。色相は0°＝赤色から始まっています。

「待機する」というのは，ウィンドウを閉じたら終了し，閉じるまでは終了しないという手順です。DLLの参照は，コンパイルしない場合は書かなくても動きます。