Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

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

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

chart6.png

プログラム全文

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>
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に空行があってもグラフでは除去します。
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番ポートで立ててみます。

terminal(pythonの例)
python3 -m http.server -port 9000
terminal(nodejsの例)
npm install -g http-server
http-server -p 9000
terminal(rubyの例)
ruby -run -e httpd . -p 9000
terminal(phpの例)
php -S localhost:9000

http://localhost:9000

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

できたグラフ

chart4.png

最後に

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

参考

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

rgbaStr関数 in bpostlethwaite/colormap@github
グラデーション生成 in color list-items from a range of colors@stackoverflow

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away