無駄に複雑になったコード（CSVデータをchart.js化する、その２）

前回の投稿
[CSVデータをchart.jsでグラフ化する！](http://qiita.com/tabetomo/items/f1fa423bf826a1d2efb8)
で、ソフトウェアの全文を載せるよ、と書いたので、載せておきます。改行コードをとったり、カラーマップを自作したり、リストを使ったり、リロードボタンをつけたりして無駄に長くなっているので、「chart.jsの使い方だけ見たい人」は前の投稿を参考にしてください。

2016-9-27 0:35追記：
データポイント数が多い場合やグラフの横幅が狭い場合、X軸のラベルが間引かれることがありますが、ticksオプションの**autoSkipをfalse**にすれば全部のラベルを表示できるようです。また、X軸のラベルの方向（xaxis orientation）を変える方法をウェブでサーチしても見つからなかった（＆ドキュメントを見てもはっきりしなかった）のですが、結論をいうと**maxRotation: 90**と **minRotation: 90**を設定すればできるようです。ということでコードを修正してみました。以下、例も載せています。

```javascript:
  var myChart = new Chart(ctx, {
    type: 'bar',
    data: chartData,
    options: {
      scales: {
        xAxes: [{
          ticks: {
            autoSkip: false,
            maxRotation: 90,
            minRotation: 90
          }
        }],
      }
    }
  });
```

![chart6.png](https://qiita-image-store.s3.amazonaws.com/0/93734/4892e868-9c80-8a2e-a7b5-788c3675ab56.png)



# プログラム全文

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--jqueryを利用しない場合、jquery.min.jsは不要です。-->
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script>
    <script src="mychart.js"></script>

    <title>chart</title>
</head>
<body>
<!--ここにグラフが挿入されます-->
<div style="width: 100%; height: 100%;">
    <canvas id="myChart" style="width: 100%; height: auto;"></canvas>
</div>
<!--ボタンを押すとリロードします。-->
<input type="button" value="relaod" onclick="main()"/>
<!--ここにCSVデータが挿入されます-->
<div id="rawdata"></div>
</body>
</html>
```

```javascript:mychart.js

// https://gist.github.com/tigawa/8858345
// http://uxmilk.jp/11586
function csv2Array(str) {
  var csvData = [];
  str = str.replace(/\r\n/g, '\n'); // CRを削除
  str = str.replace(/\n+/g, '\n'); // 空行を削除
  str = str.replace(/\s+,|,\s+/g, ','); // 不要な空白を削除
  var lines = str.split('\n');
  for (var i = 0; i < lines.length; i++) {
    var cells = lines[i].split(",");
    csvData.push(cells);
  }
  return csvData;
}

// リクエストにjqueryを利用する場合
function main_jquery() {
  var csvData = $.ajax({
    url: 'data.csv',
    dataType: 'text',
    cache: false
  }).then(function (resText) {
    var data = csv2Array(resText);

    // print raw data
    var target = document.getElementById("rawdata");
    target.innerText = resText;
    // plot chart
    drawBarChart(data)
  })
}

// リクエストにjqueryを利用しない場合
function main_nojquery() {
  var req = new XMLHttpRequest();
  var filePath = 'data.csv';
  req.open("GET", filePath, true); //true:非同期,false:同期
  req.onload = function () {
    var resText = req.responseText;
    data = csv2Array(resText);

    // print raw data
    var target = document.getElementById("rawdata");
    target.innerText = resText;
    // plot chart
    drawBarChart(data);
  }
  req.send(null);
}

// colormapもどき
function mycolmap(l) {
  // https://github.com/bpostlethwaite/colormap/blob/master/index.js
  function rgbaStr(rgba) {
    return 'rgba(' + rgba.join(',') + ')';
  }
  // http://stackoverflow.com/questions/20306650/color-list-items-from-a-range-of-colors
  var cStr = [];
  var color_from = [54, 162, 235, 0.3];
  var color_to = [255, 99, 132, 0.3];
  var l1 = l - 1;
  for (var i = 0; i < l; i++) {
    var c = [];
    var j = 0;
    for (; j < 3; ++j) {
      c[j] = Math.floor(color_from[j] * (l1 - i) / l1 + color_to[j] * (i) / l1);
    }
    // alpha doesn't need floor
    c[j] = color_from[j] * (l1 - i) / l1 + color_to[j] * (i) / l1;
    cStr[i] = rgbaStr(c)
  }
  return cStr;
}

// common part
// http://stackoverflow.com/questions/32977262/loading-an-external-json-into-chartjs
// http://microbuilder.io/blog/2016/01/10/plotting-json-data-with-chart-js.html
// https://www.webtoolnavi.com/chart-js/
function drawBarChart(data) {
  // set chart labels and data
  var tmpLabels = [];
  var dataList = [];
  var nameList = ["Tokyo", "Osaka", "Cafe"];
  var numData = data[0].length-1;  // とりあえず先頭行の列数からデータ数を導出する
//  var bgcolList = ["rgba(54,162,235,0.2)","rgba(255,99,132,0.2)"];
  var bgcolList = mycolmap(numData);

  for (var i = 0; i < numData; i++) {
    dataList[i] = [];
  }
  for (var row in data) {
    tmpLabels.push(data[row][0])
    for (var i = 0; i < numData; i++) {
      dataList[i].push(data[row][i+1]);
    }
  };

  var datasetList = [];
  for (var i = 0; i < numData; i++) {
    datasetList.push({
      label: nameList[i],
      backgroundColor: bgcolList[i],
      data: dataList[i]
    });
  }

  var chartData = {
    labels: tmpLabels,
    datasets: datasetList
  };

  var ctx = document.getElementById("myChart").getContext("2d");
  ctx.canvas.width = 1000;
  ctx.canvas.height = 800;
  // for chart.js 2.0
  // <script src="http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script>
  var myChart = new Chart(ctx, {
    type: 'bar',
    data: chartData,
    options: {
      scales: {
        xAxes: [{
          ticks: {
            autoSkip: false,
            maxRotation: 90,
            minRotation: 90
          }
        }],
        yAxes: [{
          scaleLabel: {
            display: true,
            labelString: 'temprature',
            fontSize: 14
          }
        }]
      },
      legend: {
        display: true,
        position: 'right'
      }
    }
  });
}

// ここがメイン
function main() {
  main_jquery();
  //main_nojquery();
}

main();
```

- csvに空行があってもグラフでは除去します。

```csv:data.csv
January, -10.4, -5.5, 3.3

Feburary, -30.3, 1, 1.3
March, 3.8, 12.3, 4.3
April, 5.9, 13.5, 5.3
May, 9.6, 16.4, 6.3
June, 12.0, 19.4, 8.9
July, 16.1, 28.2, 10.9
August, 20.6, 30.3, 15.9
September, 17.2, 26.2, 17.9
October, 15.0, 20.8, 10.9
November, 5.9, 10.1, 8.9
December, 0.0, 3.3, 1.9
```

# 実行例

フォルダ構成としては、以下になっているものとします。

├── index.html
├── mychart.js
└── data.csv

HTTPサーバを立てます。ここでは9000番ポートで立ててみます。

```bash:terminal(pythonの例)
python3 -m http.server -port 9000
```

```bash:terminal(nodejsの例)
npm install -g http-server
http-server -p 9000
```

```bash:terminal(rubyの例)
ruby -run -e httpd . -p 9000
```

```bash:terminal(phpの例)
php -S localhost:9000
```


http://localhost:9000

にアクセスすればチャートが見えるはず！

# できたグラフ

![chart4.png](https://qiita-image-store.s3.amazonaws.com/0/93734/f52a313f-6fdc-ea1c-d8de-2174fb2d272a.png)

# 最後に

- （まともな？）javascriptは今日初めてだったので、普通はこんな書き方はしない、ということもあると思います。コメントをいただければ幸いです。`for (var i = 0; i < numData; i++)`のところがもろにCで鈍臭い。。
- 正直、JSは、あまり出来のよくない言語、、、という(昔の)印象がありましたが、配列や正規表現も思ったように動くし触ってみたら悪くありませんでした。むしろいい。スクリプト言語の中では最速ですし、しばらくは伸びるような。
- デバッグも最初、printfデバッグもできん！、と思いました(concole.logしても何も表示されない!!)が、途中からchromeやsafariのデバッガが動くことに気づき助けられました。
 
# 参考

前回に加え、以下のページのコードにお世話になりました。ありがとうございます。

> [rgbaStr関数 in bpostlethwaite/colormap@github](https://github.com/bpostlethwaite/colormap/blob/master/index.js)
> [グラデーション生成 in color list-items from a range of colors@stackoverflow](http://stackoverflow.com/questions/20306650/color-list-items-from-a-range-of-colors)