Skip to content

Instantly share code, notes, and snippets.

@TetsuyaKimotsuki
Last active July 27, 2017 08:40
Show Gist options
  • Save TetsuyaKimotsuki/4bd3730fb4fa0968b67938cc8c2546d0 to your computer and use it in GitHub Desktop.
Save TetsuyaKimotsuki/4bd3730fb4fa0968b67938cc8c2546d0 to your computer and use it in GitHub Desktop.
DS3 V4 Grouped Bar Chart
license: mit

D3.v4入門としてやってみた。

総務省の情報通信白書(平成28年版)より、SNS等のサービス利用度を可視化。

若者のFacebook離れというのはデマですね。。

カーソルキーを叩くとデータセットが切り替わります。

参考にさせて頂いたサイト

<!DOCTYPE html>
<meta charset="utf-8">
<style></style>
<svg width="960" height="500">
<g id="chart">
<g id="legend" font-family="sans-serif" text-anchor="end"></g>
<text id="cluster" font-size="64" text-anchor="middle"></text>
</g>
</svg>
<script src="https://d3js.org/d3.v4.js"></script>
<script>
// 変化しない描画要素の初期化
var svg = d3.select("svg"),
margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var chart = svg.select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var legend = chart.select("g");
var cluster = chart.select("text")
.attr("x", width / 2)
.attr("y", height / 2)
.attr("fill", "black");
// 軸の変化しない部分を設定
var x0 = d3.scaleBand().rangeRound([0, width]);
var x1 = d3.scaleBand() // .rangeRoundはx0.domainをやってみた後のグループ毎の幅を後でセットする
.padding(0.1); // グループ内の各bar間の空白調整(単位は割合?)
var y = d3.scaleLinear().rangeRound([height, 0]).domain([0, 100]); // 比較のためY軸のdomainは固定
// 描画単位が国かサービスかで、使うデータセットやスケール類を束ねておきます
var bycountry = {};
var byservice = {};
var target = [bycountry, byservice];
// 色チャート
bycountry.colors = d3.scaleOrdinal().range([
// Facebook, Google+, Twitter, LinkedIn, YouTube, USTREAM, Instagram, Tumblr, Pinterest,
"#305097", "#db4a39", "#00aced", "#0077B5", "#cd201f", "#3388ff", "#bc2a8d", "#35465c", "#bd081c",
// LINE, WhatsApp, 微博(Weibo), 微信(WeChat), 人人網(Renren), KakaoTalk, Other
"#5ae628", "#075e54", "#df2029", "#7bb32e", "#2266b0", "#fcd411", "#6a737b"
]);
byservice.colors = d3.scaleOrdinal().range([
// Japan, USA, China, UK, Germany, India, Korea, Australia
"Red", "blue", "yellow", "blue", "gold", "Saffron", "orange", "Green"
]);
// 年代のリスト
var ages = {}; // total, 20-29,,,,
// グループ内の項目名のリスト
bycountry.group = []; // Facebook, Google+,,,
byservice.group = {}; // Japan, USA,,,
d3.csv("social.csv")
// 各行の加工
.row(function (raw, i, columns) {
ages[raw['Age']] = raw['Age'];
byservice.group[raw['Country']] = raw['Country'];
for (var j = 2, n = columns.length; j < n; ++j)
raw[columns[j]] = +raw[columns[j]]; // 文字列値を可能なら数値に変換している
raw['Group'] = raw['Country'];
return raw;
})
// 加工後のデータが揃ったら描画
.get(function (error, rows) {
if (error) throw error;
ages = Object.keys(ages); // 扱い易く素直なリストにしておく
bycountry.group = rows.columns.slice(2); // Country,Age, までを捨てる
byservice.group = Object.keys(byservice.group); // ages同様
// CSVの列構造ママ
bycountry.data = rows;
// Group, Age, Japan, USA,,,,,
// Facebook, total, 35.3, 77.7,,,,, となる筈
byservice.data = Array.prototype.concat.apply([], bycountry.group.map((s) => {
return ages.map((a) => {
var temp = { "Group": s, "Age": a };
rows.filter((row, i) => row.Age == a).map((row) => temp[row.Country] = row[s]);
return temp;
});
}));
// 今描画している単位(国orサービス)を保持するためのリスト
bycountry.list = byservice.group.concat(); // Japan, USA,,,
byservice.list = bycountry.group.concat(); // Facebook, Google+,,,
// とりあえず描画
drawFrame();
drawLegend();
draw();
});
function draw() {
var dataset = target[0];
var dset = dataset.data.filter((row, i) => row['Group'] == dataset.list[0]);
// mapでAgeの凡例リストを作って、横軸の項目として設定して描画
x0.domain(dset.map((d) => d.Age));
chart.selectAll("#axisx").call(d3.axisBottom(x0));
// x0.bandwidth()で棒グラフのグループ毎の幅を取れる
// その幅をさらにグループ内の項目数で均等割しているのではないか説
x1.domain(dataset.group).rangeRound([0, x0.bandwidth()]);
// 棒グラフのグループにデータセットを束縛
var grps = chart.selectAll("#group")
.data(dset, function (d) { return d.Age });
grps.enter()
.append("g").attr("id", "group");
grps.exit().remove();
// グループの横位置を移動
chart.selectAll("#group")
.attr("transform", function (d) { return "translate(" + x0(d.Age) + ",0)"; });
// グループ内の各barにデータを束縛
var bars = chart.selectAll("#group").selectAll("#bar")
// 各グループ毎に棒を書くため[{key:"Facebook", value:2704659},{},,]というデータを作る
.data(function (d) { return dataset.group.map(function (key) { return { key: key, value: d[key] }; }); }, function (d) { return d.key });
bars.enter()
.append("rect").attr("id", "bar")
// 以下は要素が追加された場合の初期値となる
.attr("width", x1.bandwidth())
.attr("height", 0)
.attr("x", function (d) { return x1(d.key); })
.attr("y", +svg.attr("height") - margin.top - margin.bottom);
bars.exit().remove();
// 束縛したデータでbarを再描画
chart.selectAll("#bar")
.transition().duration(1000)
.attr("fill", function (d) { return dataset.colors(d.key); })
.attr("x", function (d) { return x1(d.key); })
.attr("y", function (d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function (d) { return height - y(d.value); });
// 説明テキストも再描画
cluster
.transition().duration(500)
.attr("opacity", 0.0)
.transition().duration(500)
.text(dataset.list[0])
.attr("opacity", 0.3);
}
function drawLegend() {
var dataset = target[0];
legend.selectAll("g").remove();
var ls = legend.selectAll("g")
.data(dataset.group.slice())
.enter()
.append("g")
.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
ls.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", dataset.colors);
ls.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function (d) { return d; });
}
function drawFrame() {
chart.append("g").attr("id", "axisx")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")");
chart.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, "s"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Utilization(%)");
}
// カーソルキーを拾って描画対象を切り替え
document.onkeydown = function (event) {
if (event.keyCode == 39) { // right key
target[0].list.push(target[0].list.shift());
draw();
}
else if (event.keyCode == 37) { // left key
target[0].list.unshift(target[0].list.pop());
draw();
}
else if (event.keyCode == 38 || event.keyCode == 40) { // up or down key
target.unshift(target.pop());
drawLegend();
draw();
}
}
</script>
Country Age Facebook Google+ Twitter LinkedIn YouTube USTREAM Instagram Tumblr Pinterest LINE WhatsApp 微博(Weibo) 微信(WeChat) 人人網(Renren) KakaoTalk Other
Japan total 35.3 9.4 28.7 2.1 39.5 4.0 10.2 1.2 1.5 44.9 1.0 0.5 0.5 0.2 1.4 0.2
Japan 20-29 51.0 15.0 53.5 4.0 61.5 9.5 24.5 3.5 4.5 73.0 3.0 1.5 2.0 1.5 4.0 0.0
Japan 30-39 42.0 11.0 35.5 4.0 50.5 5.5 16.0 1.5 2.5 58.5 2.0 0.5 0.0 0.0 2.0 0.0
Japan 40-49 34.0 10.0 29.0 0.5 41.0 3.0 8.0 1.5 0.5 43.0 0.5 0.0 0.5 0.0 1.5 0.5
Japan 50-59 27.5 7.0 21.0 1.0 26.5 2.5 4.5 0.0 1.0 39.0 0.0 0.0 0.5 0.0 0.0 0.5
Japan 60-69 26.0 5.5 11.0 1.5 23.5 1.0 2.0 0.0 0.0 19.5 0.0 0.5 0.0 0.0 0.0 0.0
USA total 77.7 29.1 39.1 26.3 53.7 3.3 34.3 10.4 24.4 8.7 22.7 1.5 5.8 0.9 2.4 1.2
USA 20-29 91.0 43.5 62.5 28.5 80.5 5.0 68.5 24.0 36.5 18.0 39.0 2.5 9.5 1.5 4.0 0.5
USA 30-39 85.5 51.0 60.5 30.0 73.0 9.0 59.5 14.5 29.0 20.5 53.0 4.5 14.5 2.0 6.5 0.5
USA 40-49 77.5 23.0 31.5 26.5 52.5 2.0 23.0 7.0 23.5 3.5 14.5 0.5 4.0 1.0 1.0 1.0
USA 50-59 70.0 16.5 22.0 27.5 34.5 0.0 9.5 2.5 16.5 0.0 2.5 0.0 0.0 0.0 0.0 3.0
USA 60-69 61.5 8.0 14.5 17.5 22.0 0.0 5.5 2.0 14.5 0.0 1.0 0.0 0.0 0.0 0.0 1.0
China total 16.1 14.7 9.4 6.9 12.2 2.7 4.1 2.6 2.6 4.0 2.0 54.9 88.2 24.3 1.1 2.5
China 20-29 24.5 17.5 14.0 9.5 17.5 3.5 8.5 2.0 2.5 5.0 1.5 56.5 83.5 25.0 1.0 2.5
China 30-39 23.0 22.0 13.5 10.5 18.0 6.0 7.5 5.5 5.5 7.0 4.0 64.0 84.0 32.0 2.0 3.0
China 40-49 13.5 14.5 9.0 6.0 10.0 2.5 1.5 2.0 1.5 3.0 1.0 56.0 94.0 25.5 0.5 1.0
China 50-59 9.4 9.9 5.2 4.2 5.6 0.5 0.5 1.9 2.3 2.3 1.9 42.3 92.0 19.2 1.4 2.8
China 60-69 4.8 5.3 1.1 2.1 7.0 0.0 0.5 1.1 1.1 2.1 1.6 53.5 86.6 16.0 0.5 4.3
UK total 69.8 19.8 33.6 17.0 48.5 1.9 19.4 5.8 13.8 2.4 30.1 1.0 2.7 0.6 0.9 1.3
UK 20-29 84.0 33.0 50.5 24.0 74.5 3.0 45.5 16.5 22.0 6.5 52.0 2.0 4.0 1.0 2.0 2.0
UK 30-39 81.0 28.5 41.0 24.0 65.5 4.5 26.0 7.0 20.5 4.0 39.5 3.0 6.5 2.0 2.0 0.5
UK 40-49 75.5 17.0 34.5 14.0 46.0 1.5 14.5 2.5 11.0 1.0 27.0 0.0 1.5 0.0 0.5 1.0
UK 50-59 56.5 11.5 23.0 12.5 32.5 0.0 5.5 1.0 8.5 0.0 15.5 0.0 0.5 0.0 0.0 1.0
UK 60-69 48.0 7.0 15.5 9.5 19.0 0.0 2.5 1.5 6.0 0.0 13.5 0.0 0.5 0.0 0.0 2.0
Germany total 64.4 18.6 12.5 5.1 47.9 0.6 10.4 2.3 5.6 1.1 56.0 0.5 1.1 0.5 0.9 2.4
Germany 20-29 81.0 20.5 16.0 4.5 73.0 0.5 26.0 7.0 13.5 1.0 78.5 1.0 1.5 0.5 3.5 1.5
Germany 30-39 70.0 24.0 16.5 4.5 54.0 1.5 15.5 3.5 4.5 2.5 65.0 0.0 1.5 1.0 0.0 2.5
Germany 40-49 66.0 20.0 15.0 6.5 42.0 0.5 8.0 0.5 4.5 0.5 57.0 1.0 1.5 0.5 0.5 4.0
Germany 50-59 55.5 16.5 10.0 5.5 42.0 0.0 4.0 1.0 4.5 1.0 48.0 0.5 1.0 0.0 0.5 2.0
Germany 60-69 52.0 12.0 5.0 4.0 31.5 0.5 1.0 0.0 1.5 0.5 33.5 0.0 0.0 0.5 0.0 2.0
India total 92.9 62.3 50.5 46.5 78.3 2.1 25.9 7.2 17.2 11.4 81.2 1.7 22.4 1.0 1.7 2.5
India 20-29 90.5 61.0 49.5 43.0 79.5 5.0 38.0 8.5 20.0 20.5 82.0 4.0 30.5 3.0 3.0 3.0
India 30-39 95.0 66.0 52.0 48.0 80.0 0.5 24.0 10.5 18.5 11.5 84.5 1.5 27.5 0.0 2.0 2.0
India 40-49 95.5 61.0 54.0 49.0 80.0 2.0 25.0 6.0 17.0 7.0 83.0 0.5 19.0 0.5 1.0 2.0
India 50-59 91.8 62.5 49.6 41.8 74.1 0.4 16.4 3.0 12.5 5.2 77.6 0.0 11.6 0.0 0.4 3.4
India 60-69 91.7 58.9 43.5 55.4 72.6 0.0 8.9 3.0 13.1 1.2 71.4 0.0 7.1 0.0 0.0 1.8
Korea total 69.3 27.6 33.0 5.6 58.8 1.3 29.1 3.9 2.9 20.2 2.6 1.9 1.5 0.4 75.6 0.5
Korea 20-29 79.0 26.0 29.0 3.0 63.0 2.0 47.5 6.5 2.0 24.0 3.0 2.5 1.0 0.0 77.0 0.0
Korea 30-39 70.0 30.0 34.5 7.5 60.0 3.0 39.0 7.0 7.5 28.0 3.0 4.5 2.0 1.5 77.5 0.5
Korea 40-49 64.5 26.0 35.0 7.0 58.0 0.5 21.0 3.0 2.5 21.0 3.0 1.0 1.0 0.5 76.5 1.0
Korea 50-59 71.0 29.5 36.5 5.5 60.5 0.0 21.5 1.0 1.0 13.5 2.0 0.0 2.5 0.0 76.5 0.5
Korea 60-69 60.5 26.0 27.0 4.0 50.0 1.0 14.5 1.5 1.0 12.0 2.0 1.5 0.5 0.0 67.5 0.0
Australia total 75.3 25.0 20.4 18.9 50.6 1.4 22.4 5.7 16.2 3.3 18.2 1.1 4.0 0.2 1.3 2.7
Australia 20-29 83.5 30.5 32.5 21.0 71.0 2.0 44.5 12.0 17.5 7.5 26.0 2.0 5.0 0.0 2.0 2.0
Australia 30-39 83.0 28.0 25.0 24.0 63.0 3.0 31.0 8.5 22.0 5.0 34.0 1.5 7.5 0.5 3.5 4.0
Australia 40-49 76.0 29.0 20.0 20.5 49.0 1.0 15.0 4.0 15.0 1.0 15.5 1.0 4.0 0.5 0.5 3.0
Australia 50-59 70.0 20.0 12.0 13.5 37.0 0.5 11.0 1.5 16.5 2.0 7.0 0.5 2.0 0.0 0.0 1.5
Australia 60-69 59.0 14.0 8.0 14.0 24.0 0.0 4.0 0.5 8.0 0.0 3.5 0.0 0.5 0.0 0.0 3.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment