unity > 時系列グラフの描画 > timeGraph > UDPで "時:分,データ" を受信してグラフ化 / y軸の範囲も変更できる / y軸のmin,max表示 / x軸:daily,weekly,monthly,yearly / データexport機能付き

```txt:実装
Unity 5.1.2-f1 on MacOS X 10.8.5
```

http://qiita.com/7of9/items/c346562cefa42bfd981e
にて時系列グラフを描画できるようになったが、時刻については現在時刻を使用しているのでフレキシブルではない。

"12:30,0.3" (12時30分に数値0.3)
という形式のデータを受信してグラフ描画したい。

##code

[v0.3 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.3)

v0.3への変更においては主に以下を変更した。


```udpReceiverScript.cs
...
	string extractCsvRow(string src, int idx)
	{
		string[] splitted = src.Split(new string[] { System.Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
		string res = "";
		foreach(string each in splitted) {
			string [] elements = each.Split(',');
			res = res + elements[idx] + System.Environment.NewLine;
		}
		return res;
	}

	void sendToGraph(string text)
	{
		// udp text should be in the form of "12:30,-0.2"
		// where 
		//   "12:30" is hour and minutes,
		//   and "-0.2" should be in range [-1.0, 1.0]
	
		string first = extractCsvRow (text, /* idx=*/0);
		string second = extractCsvRow (text, /* idx=*/1);

		// TODO: input error check

		System.DateTime dt = System.DateTime.Parse (first);
		float yval = float.Parse (second);
		timeGraphScript.SetXYVal (dt, yval);
	}
```

"12:30,0.3"をextractCsvRow()でパースして、12:30をSystem.DateTime.Parse()で時刻情報に変換している。

##実行環境

- 送信側 > 192.168.10.8 : データをUDPで送信する (OS: CentOS 6.5で確認)
- 受信側 > 192.168.10.3 : 本アプリの実行 (OS: MacOS X 10.8.5で確認)

192.168.10.8 >> UDP(6000) >> 192.168.10.3

192.168.10.8からの送信は以下のスクリプトを使用。
5秒ごとにデータ文字列 ("02:10,-0.9"など）を送信する。
http://qiita.com/7of9/items/1cf64a125784db309100

```bash:udpSend-exec
#!/bin/env bash

for data in \
"00:00,0.2" "02:10,-0.9" "03:40,0.3" \
"05:30,-0.9" "09:30,0.2" "11:30,0.4" \
"13:30,0.1" "16:30,0.5" "18:30,0.9" "22:00,-0.9";do
  sleep 4
  ## echo $data | nc -u 192.168.10.3 6000 &
  echo $data | nc -w 1 -u 192.168.10.3 6000 
done
```

[2015/09/10追記]
<font color=red>上記のコメントアウトした行のようにncに&をつけた方法はncのプロセスが残ってしまうようです。</font>

ncコマンドは`-w 1`で1秒のタイムアウトにできるようなので、上記のように訂正しました。これでncのプロセスが残りません。


##結果

###CentOS側 (送信側 192.168.10.8)

```bash
$ bash udpSend-exec 
00:00,0.2
02:10,-0.9
03:40,0.3
05:30,-0.9
09:30,0.2
11:30,0.4
13:30,0.1
16:30,0.5
18:30,0.9
[tmp]$ 22:00,-0.9
```

###Unityアプリ側 (受信側 192.168.10.3)

![udpTimeGraphMac_と_Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal__と_Assembly-CSharp_-_udpReceiverScript_cs_-_MonoDevelop-Unity.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/dd44bdd7-33cc-ee46-bcf0-ee40b2987914.jpeg)

UDP送信したものをグラフ化できた。

## v0.4 (y rangeの変更コマンド追加)

[v0.4 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.4)

変更点

- UDP通信にsetコマンド対応を追加
- setコマンドの１つとしてyrange対応を追加。グラフのy軸範囲を変更可能

```
set,yrange,-3.0,3.0
```

上記コマンドによりグラフのy軸表示範囲が[-3.0, 3.0]に変更できる。

例として以下は[-1.0,1.0]で描画している。

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/fb2482d0-43d5-9a34-e9ee-d8e30d276d40.jpeg)

`set,yrange,-3.0,3.0`をUDP送信すると以下のようになる。

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/b8b7658c-577b-aee1-d196-1712a75c8fe3.jpeg)


## v0.5 (y軸のmin, maxを表示)

[v0.5 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.5)
[関数の説明 @ mindmup](https://atlas.mindmup.com/2015/09/734cc2803aaf0133b9750a1e3b74be65/timegraphscript_v0_5_150911/index.html)

Panelの近くにTextを表示する方法を学んで、グラフのy軸のmin, maxを表示するように変更した。

- graphScale というTagをタグリストに追加
- drawGraphScale()を実装
  - "graphScale"タグのGameObjectを削除
  - drawTextOnTheLeftOfPanel()にてmin, maxの値を表示

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/b2b2f681-fe7e-9285-4cae-1e925f193341.jpeg)

## v0.6 (v0.5のリファクタ版)

[v0.6 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.6)

timeGraphScriptの処理の可読性を上げるため、timeGraphScript.csで実装していたPanel関連のものを MyPanelUtil.cs に移した。
DrawLineはまだ移動していない。


## v0.7 (Dictionary<System.DateTime,float>を保持)

[v0.7 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.7)

今後、横軸をhour:minutes以外の表示に変更するための前段階として、以下の変更をした。

[変更前]
SetXYVal()されるたびに(System.DateTime, float)のデータを(float, float)に変換した上でListに保持

[変更後]
SetXYVal()されるたびに(System.DateTime, float)をDictionaryに追加。
グラフ描画前に `refreshGraphPoints()`にて全データについてSystem.DateTimeの値から横軸を計算。

```csharp:v0.6まで
void Update() {
		accTime += Time.deltaTime;
		if (accTime < 0.3f) { // for every 300 msec
			return;
		}
		accTime = 0.0f;
		
		clearGraph (timeGraphPanel);
		
		if (isSet) {
			isSet = false;
			timeGraph_xy (timeData, timeGraphPanel, xval, yval);
		}
		
		drawGraph (timeData, timeGraphPanel);
	}
```

```csharp:v0.7から
    static public void SetXYVal(System.DateTime time, float yval_)
	{
		dateTime_val_dic.Add (time, yval_);
	}
	void Update() {
		accTime += Time.deltaTime;
		if (accTime < 0.3f) { // for every 300 msec
			return;
		}
		accTime = 0.0f;

		clearGraph (timeGraphPanel);
		refreshGraphPoints (dateTime_val_dic, timeGraphPanel); 
		drawGraph (graphPoints, timeGraphPanel);
	}
```

##v0.8 (x軸のスケール[dailyのみだった]にweekly追加)

[v0.8 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.8)

以下を追加した

- set,xtype,[種類]コマンドを追加
  - set,xtype,daily 
  - set,xtype,weekly
  - set,xtype,monthly (計算の実装は途中)
  - set,xtype,yearly (計算の実装は途中)
- 上記のdailyとweeklyについて、x軸の位置計算を実装


送信側(CentOS)のスクリプト

```bash
#!/bin/env bash

toadr="192.168.10.3"
sleep 5

echo "set,xtype,weekly" | nc -w 1 -u $toadr 6000

for data in \
"2015/9/10 00:00,0.1" \
"2015/9/10 02:10,0.45" \
"2015/9/11 03:40,-0.45" \
"2015/9/11 05:30,-0.45" \
"2015/9/12 09:30,0.2"  \
"2015/9/12 11:30,0.4" \
"13:30,0.1" "16:30,0.5" "18:30,0.9" "22:00,-0.9";do
#  sleep 1
  echo $data | nc -w 1 -u $toadr 6000 
done

sleep 3
echo "set,yrange,-3.0,3.0" | nc -w 1 -u $toadr 6000
sleep 3
echo "set,yrange,-1.0,1.0" | nc -w 1 -u $toadr 6000
```

###結果

daily表示 (set,xtype,daily コマンド発行後)

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/da087014-6ebf-3eba-7c58-3110baddfe7c.jpeg)


weekly表示 (set,xtype,weekly コマンド発行後)

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/55738dba-619a-4be4-2402-848bff40fb12.jpeg)

bug: "12:30,0.3", "2015/09/10,0.5"のように、日付なしとありのデータが混ざっているとX軸の計算が失敗している。


##v0.10 (montly, yearlyグラフ対応)

[v0.10 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.10)

v0.8以降の変更は以下の通り。

- テスト用GameObjectを追加
  - TestRelated/Test_xscaletype : グラフにサンプル用時系列データを追加
  - TestRelated/Test_xcalechange : Activeにすることで時系列の表示タイプを変更できる
- バグ修正
  - dailyグラフ表示 : 他の日のデータも表示されていた
  - weeklyグラフ表示 : 他の週のデータも表示されていた
- 機能追加
  - MyTimeUtil.cs追加 : 時系列関連の計算用
  - monthlyグラフ表示追加
  - yearlyグラフ表示追加  


##使用例

プレイモードにて実行

Test_xscaletypeをActiveにすることで、グラフにサンプルデータが追加される。最初はdailyグラフが表示される。

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/63a1204f-b590-7529-ca0b-76a427d71b83.jpeg)

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/5268c80c-14b9-ff85-8c75-80244c9cb9a2.jpeg)

Test_xcalechangeをActiveにして、XTypeの値を変更する。
0:Daily, 1:Weekly, 2:Monthly, 3:Yearly. 
下の例ではWeeklyにしている。

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/1d46227a-cafd-620d-8190-5feaa315eb01.jpeg)

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/bc097299-c417-568f-0d65-d94f6e1fd6bf.jpeg)

以下はMonthlyやYearlyにした例。

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/566a78a6-e07a-f9cc-07ea-570acceafa19.jpeg)

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/60372a8f-f665-553c-edd4-e648709c5237.jpeg)


サンプルデータ生成部分

以下の日時データ(縦軸は乱数)が上のグラフではきちんと表示されているようだ。

```Test_xscaletype.cs
...

	void Test_addData() {
		string [] dts = new string[]{ 
			"2015/01/10 05:30",
			"2015/02/05 12:30",
			"2015/03/01 08:30",
			"2015/04/07 23:50",
			"2015/07/11 09:30",
			"2015/08/12 12:30",
			// for today (as of Sep.13, 2015)
			"2015/09/13 8:30",
			"2015/09/13 10:00",
			"2015/09/13 11:30",
			"2015/09/13 16:30",
			"2015/09/13 20:10",
			"2015/09/13 23:40",
			//
			"2015/09/14 09:30", 
			"2015/09/15 11:30", 
			"2015/09/16 13:30",
			"2015/09/17 13:30",
		};

		System.DateTime curDt;
		float yval;
		int idx = 0;

		foreach(var dt in dts) {
			curDt = System.DateTime.Parse(dt);
			yval = Random.Range(-1.0f, 1.0f);
			timeGraphScript.SetXYVal(curDt, yval);
			idx++;
		}
...
```

サンプルデータ表示後は TestRelated/Test_xcalechange をDeactivateにして、UDP通信でグラフの縦軸、横軸の変更が可能。


##v0.11 (データexport機能追加)

グラフに表示したものを後で取り出して使いたい、ということはありそうなので、data export機能を追加した。

UDPコマンドは以下で取り出せる。

```
set,export
```

[v0.11 @ github](https://github.com/yasokada/unity-150908-udpTimeGraph/releases/tag/v0.11)

<font color=red>(追記 2015/09/13) 時刻表記が12時間表記だったのを24時間表記に修正。同じv0.11としてタグづけした。</font>


###主な変更箇所

timeGraphScript.csにおいて、データ辞書であるdateTime_val_dicをstatic public定義に変更 (udpReceiverScriptでアクセスするため)。

```
static public Dictionary<System.DateTime, float> dateTime_val_dic;
```

udpReceiverScript.csにおいてexportData()を追加し、"set,export"を受信したら実行するようにした。

```udpReceiverScript.cs
...
	private void exportData(ref UdpClient client, ref IPEndPoint anyIP) 
	{
		byte[] data;
		string text;

		text = "SOT"; // start of table
		text = text + System.Environment.NewLine;
		data = System.Text.Encoding.ASCII.GetBytes(text);
		client.Send(data, data.Length, anyIP);

		foreach (var ptr in timeGraphScript.dateTime_val_dic) {
			text = ptr.Key.ToString("yyyy/MM/dd HH:mm:ss");
			text = text + ",";
			text = text + ptr.Value.ToString();
			text = text + System.Environment.NewLine;

			data = System.Text.Encoding.ASCII.GetBytes(text);
			client.Send(data, data.Length, anyIP);
		}

		text = "EOT"; // end of table
		text = text + System.Environment.NewLine;
		data = System.Text.Encoding.ASCII.GetBytes(text);
		client.Send(data, data.Length, anyIP);
	}
```

###実行例

プレイモードで実行後、サンプルデータを足すため Test_xscaletypeゲームオブジェクトをActiveにする (通常使用時はUDP通信[データコマンド]でデータを送信し続けてデータを蓄積しておく)。

![Main_unity_-_150908-udpTimeGraph_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/7f80ca49-e8b3-fed3-a797-c11302447ef0.jpeg)

データを受けたい側(例: 192.168.10.6 CentOS)で`set,export`コマンドを発行して、受信し続ける(データはプロトコル通信ではなく、一気に送られる)。

```txt:CentOS6.5側実行例
$echo "set,export" | nc -u 192.168.10.3 6000
SOT
2015/01/10 05:30:00,-0.1320719
2015/02/05 12:30:00,0.2371362
2015/03/01 08:30:00,-0.6964777
2015/04/07 11:50:00,-0.1670557
2015/07/11 09:30:00,0.07135642
2015/08/12 12:30:00,-0.2585875
2015/09/13 08:30:00,-0.4348444
2015/09/13 10:00:00,-0.4057344
2015/09/13 11:30:00,-0.9436774
2015/09/13 04:30:00,0.2064427
2015/09/13 08:10:00,0.678241
2015/09/13 11:40:00,-0.9753504
2015/09/14 09:30:00,-0.5227482
2015/09/15 11:30:00,-0.4138082
2015/09/16 01:30:00,-0.4343764
2015/09/17 01:30:00,0.1775364
EOT
^C
```

上記のSOT(Start of Table)からEOT(End of Table)の間のデータが日時と値のセット。

一気に送られるので、受信側はEOTを受けるまで受信し続けないといけない。




## 今後

[今後の予定](https://github.com/yasokada/unity-150908-udpTimeGraph/issues)