takashiskiのブログ

覚書の殴り書き

d3.jsの拡縮できるグラフの時間軸を任意の書式で表示できるようにする

d3.jsはzoomによるグラフの拡大縮小ができます。このとき軸を数値ではなく時間軸として設定していると、自動で軸の表記粒度を変更してくれます。具体的には以下のサンプルグラフを弄ってみてください。マウススクロールで拡縮、ドラッグで移動できると思います。

Zoomable Area

気付くと思いますが、時間軸の表記が日本では一般的でない表記です(US表記らしい)。私はこれでもわかるのでよいと思うのですが、これでは困るという人がいます。

今回は、この部分を書き換える方法を検討します。実際の描画サンプルまでは提示しません。

 

使うもの

  • d3.time.format.mutil()
  • d3.locale()

d3.locale()

d3.locale()で月名や曜日名を再定義します。デフォルトだと完全に英語で扱いづらいです。

var definition = {
"decimal": ".", "thousands": ",", "grouping": [3], "currency": ["$", ""], "dateTime": "%a %b %e %X %Y", "date": "%m/%d/%Y", "time": "%H:%M:%S", "periods": ["AM", "PM"], "days": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], "shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], "months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], "shortMonths": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] }

 

%Xな表記はTimeFormattingのページを参照しながら書き換えてください。

あとは通常のtimeFormatと同じ流れで

var format = d3.locale(definition).format("%b %m");

console.log(format(new Date(2016,2,25));

みたいな感じでやれば扱えます。

d3.time.format.multi()

デフォルトだとこんな感じ

var format = d3.time.format.multi([
  [".%L", function(d) { return d.getMilliseconds(); }],
  [":%S", function(d) { return d.getSeconds(); }],
  ["%I:%M", function(d) { return d.getMinutes(); }],
  ["%I %p", function(d) { return d.getHours(); }],
  ["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
  ["%b %d", function(d) { return d.getDate() != 1; }],
  ["%B", function(d) { return d.getMonth(); }],
  ["%Y", function() { return true; }]
]);

これが、基本が曜日+日付で日曜日だけ月名+日付な謎表記の原因です。

おそらく

  • 一日は月名のみ
  • 日曜日は月名+日付
  • それ以外は曜日名+日付
  • 時間は12時間表記+AM/PM or :分

といった感じになってます。一番粒度が大きい下から順に評価されていく、と考えればよさそうです。

  ["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
  ["%b %d", function(d) { return d.getDate() != 1; }],

この二行がよくわからないのでjs詳しい人いたら教えていただきたいです。

  • ミリ秒
  • 時間
  • 日付
  • 日付(一日?)
  • 月名

を"表記方法"+"使う値"で記述すればよさそうです。表記方法はやっぱりtimeFormatting参照で。

使い方は

var format = d3.time.format.multi(略);

var scale = d3.time.scale();

scale.tickFormat(format);

な感じで使えます。

複合

time.locale()とd3.time.format.multi()を複合して使います。ドキュメントの関数一覧に見つからないんですが、よく見るとd3.time.format.multi()の最後にちょこっと書いてあります。

The multi method is available on any d3.time.format constructor. For example,d3.time.format.utc.multi returns a multi-resolution UTC time format, and locale.timeFormat.multi returns a multi-resolution time format for the specified locale.

てことで、使い方は以下。

var custom_locale = d3.locale(略);

var format = custom_locale.timeFormat.multi(略);

var scale = d3.time.scale();

scale.tickFormat(format);

感想

そもそもd3自体が難解であることもありますが、こいつにたどり着くのは大変でした。ぐぐっても見つからないしサンプルにもない...表記的にLocalizationにたどり着けば読めばわかるじゃんってことなんでしょうね。

あと手軽にそこそこきれいなグラフが書けると評判なnvd3は、日付をUNIX秒に直して渡すことになっているので、localizationはできますが、multiはできないようです。死ね。やれた人がいたら教えてください。切望しています。

 

参考文献

beniyama.hatenablog.jp

↓TimeFormatting

github.com

↓Localization

github.com

 

JavaScriptによるデータビジュアライゼーション入門

JavaScriptによるデータビジュアライゼーション入門