D3.js で Word Clouds
Wordle ライクに Word Clouds を描きたいなーと思い、D3 の Word Cloud Layout を試してみました。
データの準備
とりあえず CSV からデータを読み込むことを想定してサンプルを作ります。単語と頻度を記述してあれば何でもいいのですが、折角なので公開されているデータを利用してみます。
今回使ったのはこちら ↓
FDA Adverse Event Reporting System (FAERS)
米食品医薬品局 (FDA) が公開している医薬品の有害事象報告データです。簡単に言うと、「この薬を使ったらこんな副作用っぽい反応があった」的な情報の集積です。
今回は 2012q4 のデータから医薬品と報告数を抽出してサンプルとします。下記の処理は Fedora 19 のシェルで行っていますが、他の Linux や Mac の場合でも似たような感じです。
1 - データのダウンロード
FAERS から FAERS_ASCII_2012q4.zip をダウンロード・展開します。
$ mkdir faers && cd faers $ wget http://www.fda.gov/downloads/Drugs/GuidanceComplianceRegulatoryInformation/Surveillance/AdverseDrugEffects/UCM364757.zip $ unzip UCM364757.zip && rm UCM364757.zip
以下は展開したファイルの中身。
$ tree . ├── FAQs.doc ├── README.doc └── ascii ├── ASC_NTS.doc ├── demo12q4.pdf ├── demo12q4.txt ├── drug12q4.pdf ├── drug12q4.txt ├── indi12q4.pdf ├── indi12q4.txt ├── outc12q4.pdf ├── outc12q4.txt ├── reac12q4.pdf ├── reac12q4.txt ├── rpsr12q4.pdf ├── rpsr12q4.txt ├── ther12q4.pdf └── ther12q4.txt
今回使うのは drug12q4.txt のみです。
$ head ascii/drug12q4.txt primaryid$caseid$drug_seq$role_cod$drugname$val_vbm$route$dose_vbm$cum_dose_chr$cum_dose_unit$dechal$rechal$lot_nbr$exp_dt$nda_num$dose_amt$dose_unit$dose_form$dose_freq 34483284$3448328$1$PS$SUSTIVA$1$TRANSPLACENTAL$UNK UNK$$$$U$$$020972$$$$ 34483284$3448328$2$SS$NEVIRAPINE$1$TRANSPLACENTAL$$$$$U$$$$$$$ 34483284$3448328$3$SS$VIRACEPT$1$TRANSPLACENTAL$UNK UNK$$$$U$$$$$$$ 34483284$3448328$4$SS$COMBIVIR$1$TRANSPLACENTAL$UNK UNK$$$$U$$$$$$$ 34483284$3448328$5$SS$RETROVIR$1$TRANSPLACENTAL$UNK UNK$$$$U$$$$$$$ 35676563$3567656$1$PS$EXELON$1$ORAL$1.5 MG, BID$59.714$MG$$U$$$020823$1.5$MG$$BID 36059074$3605907$1$PS$EXELON$1$ORAL$1.5 MG, BID$$$$U$$$020823$1.5$MG$Capsule$BID 36177452$3617745$1$PS$EXELON$1$ORAL$1.5 MG, BID$$$$U$$$020823$1.5$MG$Capsule$BID 36177452$3617745$2$SS$EXELON$1$ORAL$1.5 MG, ONCE/DIALY$$$$U$$$020823$1.5$MG$Capsule$X1
1行目はヘッダー、2行目以降がレコード、 $ はフィールドの区切りです。
drugname 毎の primaryid を集計して報告数とします。
2 - 医薬品と報告数の CSV 出力
ヘッダーを作成。
$ echo 'count,word' > example.csv
drugname と primaryid のユニークなペアを抽出 → 集計 → 上位100剤を出力。
$ awk -F \$ '{ print $5 "$" $1 }' ascii/drug12q4.txt | \ sort | uniq | awk -F \$ '{ print $1 }' | sort | uniq -c | \ sort -r | sed -e 's/^ \+\([0-9]\+\) /\1,/g' | \ head -100 >> example.csv
example.csv がサンプルの CSV となります。
集計処理は Gawk でちゃんと書けばここまでパイプ使わない気もしますが、楽だから気にしない!
Word Clouds 描画
HTML で D3.js と d3.layout.cloud.js を読み込ませ、 SVG を描画する JavaScript を書いていきます。
<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>D3 Word Clouds</title> <meta name="author" content="d4i"/> </head> <body> <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script src="https://rawgithub.com/jasondavies/d3-cloud/master/d3.layout.cloud.js"></script> <script> var filename = 'example.csv'; d3.csv(filename, function(data){ data = data.splice(0, 100); var width = 1200, height = 600, fill = d3.scale.category20(), maxcount = d3.max(data, function(d){ return d.count; } ), wordcount = data.map(function(d) { return {text: d.word, size: d.count / maxcount * 10}; }); d3.layout.cloud().size([width, height]) .words(wordcount) .padding(5) .rotate(function() { return ~~(Math.random() * 2) * 90; }) .font("Impact") .fontSize(function(d) { return d.size; }) .on("end", draw) .start(); function draw(words) { d3.select("body").append("svg") .attr({ "width": width, "height": height }) .append("g") .attr("transform", "translate(" + [ width >> 1, height >> 1 ] + ")") .selectAll("text") .data(words) .enter() .append("text") .style({ "font-size": function(d) { return d.size + "px"; }, "font-family": "Impact", "fill": function(d, i) { return fill(i); } }) .attr({ "text-anchor": "middle", "transform": function(d) { return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; } }) .text(function(d) { return d.text; }); } }); </script> </body> </html>
作成した example.csv を同じディレクトリに置いてブラウザから描画される図を見ます。コードで細かく調整できます。
Web から見るとこんな感じ。
(位置はランダムなのでリロードで形が変わります。)
感想
描画の自由度が高くて良いですね。逆に調整が複雑になる印象はありますが。
D3 は JavaScript や CSS で小回りが効くので、可視化を美しくするポテンシャルがあるなーと思います。
- 作者: Mike Dewar
- 出版社/メーカー: Oreilly & Associates Inc
- 発売日: 2012/07/10
- メディア: ペーパーバック
- この商品を含むブログを見る