D3.jsでリソースモニターみたいなグラフの作成 version 4.0
比較的最近*1に 4.0 のメジャーバージョンアップされたみたいですね。
また、D3.js 3.0 と 4.0 は互換性がありません。
変更点は公式を参考にして、前回紹介した 3.0 グラフを書き直しました。
d3/CHANGES.md at master · d3/d3 · GitHub
変更点
正直なところ 3.0 を理解していないので変更したソースも小さいため
あまり参考にならないかもしれませんが、記載させていただきます。
ざっくり大きな点といえば D3 のオブジェクト名が短くなりました。
ほとんどのオブジェクトが d3. と始まるようになったようです。
var xScale = d3.scale.linear() // v3 var xScale = d3.scaleLinear() // v4
軸も変わりました。orientの指定せず、上下左右の軸
d3.axisTop, d3.axisRight, d3.axisBottom, d3.axisLeft が用意されています。
var yAxis = d3.svg.axis() // v3 .scale(yScale) .orient("left"); var yAxis = d3.axisLeft(yScale); // v4
d3.lineオブジェクトにて、interpolateが使用できなくなり、
かわりにcurveが使えます。curveに用意されているオブジェクトを渡すことで使用できます。
用意されている種類もたくさんありますので色々試すと面白いかもしれません。
GitHub - d3/d3-shape: Graphical primitives for visualization, such as lines and areas.
var line = d3.svg.line() .x(function(d,i) { return xScale(i); }) .y(function(d,i) { return yScale(d); }) .interpolate("linear"); // v3 var line = d3.line() .x(function(d,i) { return xScale(i); }) .y(function(d,i) { return yScale(d); }) .curve(d3.curveLinear); // v4 これは直線
curveのパラメータを渡すときは下記のように。
var line = d3.line() .x(function(d,i) { return xScale(i); }) .y(function(d,i) { return yScale(d); }) .curve(d3.curveCatmullRom.alpha(0.5)); // v4
そのほか、アニメーションの個所も変更になったようです。
大幅に変更されているようですが、メソッドチェインの考え方は同じかと感じました。
*1:2016/6月末ごろに4.0にアップデートされたようです。
CodePenでD3.jsのグラフを記載してみた
CodePen
はてなブログ上でJavaScriptをゴリゴリ動かすと、
意図しない動きをする場合があるかもしれないのでCodePenを利用してみました。
CodePen - Front End Developer Playground & Code Editor in the Browser
いままでローカルでAtomとChromeで試していたのですが、
CodePen上の編集も使いやすかったです。すぐ結果も出ますし、そのまま公開できますし。
よく考えたら、記事に埋め込む用のソースコードを作成していたのもナンセンスかもしれません。
CodePenの使い方はこちらを参考にしました。
【はてなブログ】CodePenをはてなに貼る方法 - のんびり猫プログラマの日常
作成したグラフ
前回のグラフと同じです。
See the Pen D3_LineChart by book_stone (@book_stone) on CodePen.
実行結果も見やすくなった気がします。
HTML、CSSおよびJavaScriptが分離されているのがいいですね。
ただペタッとコピペして使えないかもしれませんが。
次回は適当にグラフに数値を入れたりして遊んでみようと思います。
D3.jsでリソースモニターみたいなグラフの作成
前回、はてなブログで、D3.jsの動作が確認できたので、
表題のようなリソースモニターみたいなグラフができないかと作成してみました。
作成するグラフ
さっそく目標とするグラフを紹介したいと思います。
データが古いものから左にずれていきますので、リソースモニターっぽく表現しようと思います。
ソースコード
基本的には、D3.jsのサンプルなどを参考にして作成しました。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <style> /* 軸のスタイル */ .axis path, .axis line { fill: none; stroke: #000; shape-rendering: auto; /*アンチエイリアス処理*/ } /* Pathのスタイル */ .line { fill: none; stroke: steelblue; stroke-width: 1.5px; } </style> <body> <div id="result"> <script src="http://d3js.org/d3.v3.min.js"></script> <script> // マージンの設定(領域) var margin = {top: 30, right: 20, bottom: 30, left: 50}, width = 400 - margin.left - margin.right, height = 300 - margin.top - margin.bottom; // 描画データ var array = [ 2 , 0 , 3 , 4 , -1 , -2 , 5 , -3 , 1 , -5] ; // スケールの設定 x要素としてインデックス var xScale = d3.scale.linear() .domain(d3.extent(array, function(d,i) { return i; })) .range([0, width]); // スケールの設定 y要素として配列の値 var yScale = d3.scale.linear() .domain(d3.extent(array, function(d,i) { return d; })) .range([height, 0]); // X軸 var xAxis = d3.svg.axis() .scale(xScale) .orient("bottom") .tickFormat(""); // 軸ラベルはなしにした // Y軸 var yAxis = d3.svg.axis() .scale(yScale) .orient("left"); // 線グラフのラインオブジェクト var linestyle = "linear"; var line = d3.svg.line() .x(function(d,i) { return xScale(i); }) .y(function(d,i) { return yScale(d); }) .interpolate(linestyle); // SVGの追加 var svg = d3.select("#result").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // グループ要素にX軸を追加 svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height / 2 + ")") // 真ん中にした .call(xAxis); // グループ要素にY軸を追加 svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("x", 10) .attr("y", -10) .style("text-anchor", "end") .text("Value"); // 実際のラインを追加 var paths = svg.append("path") .datum(array) // 配列をマッピング .attr("class", "line") .attr("d", line); // データ追加し、再描画がするメソッド function pushData(){ // 先頭を削除 array.shift(); // +5から-5までの乱数発生 var rand = Math.floor( Math.random() * 11 ) - 5 ; // 配列に追加 array.push(rand); // path要素を削除 // paths.remove(); // あらたにPath追加 line.interpolate(linestyle); // 追加して削除だったが、Data-Drivenっぽくない // paths = svg.append("path") // .datum(array) // .attr("class", "line") // .attr("d", line); // データだけ入れ替る。動きは一緒。 paths.attr("d", line); } // スタイルを変える(コンボのイベント) function changeStyle(obj){ linestyle = obj.value; } </script> </div> </body> <input type="button" value="Add" onclick="pushData()"/> <select name="interpolate" onChange="changeStyle(this)" > <option value="linear">linear</option> <option value="cardinal">cardinal</option> <option value="step-before">step-before</option> <option value="step-after">step-after</option> </select> </html>
タイマーなどをうまく使うことで、リアルタイムにグラフが更新できるようになりそうです。
これを使ってそれっぽいグラフを次、作成したいと思います。
心電図っぽくして遊ぶのも面白いかもしれませんね。
補足
どうやら、はてなブログ上でうまく動いていなかったようなので、画像に修正しました。
変数名が衝突していたのかな。。
はてなブログ上で、JavaScriptをゴリゴリ動かすより、CodePen利用したほうがいいかもしれませんね。
CodePen - Front End Developer Playground & Code Editor in the Browser
補足2
ソースコードが Data-Drivenっぽくなかったので修正しました。
こちらの記事で動作確認できます。
stone-book.hatenablog.com
はてなブログでD3.jsの動作実験
はてなブログで、D3.jsの動作ができるか試してみました。
可視化の際に使用できればと考えております。
こちらのサイトを参考にしてみました。
はてなブログの記事内でJavascriptを書く方法 - Three.jsを使って、作ってみた
JavaScriptは以下のタグでくくっておけば使えるそうです。
<script type="text/javascript">...</script>
手順
さっそく「はてな記法」で以下を記載しました。
<div id="test" style="width:100;height:100"></div> <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script type="text/javascript"> var width = 100; var height =100; var svg = d3.select("#test").append("svg") .attr("width", width) .attr("height", height); svg.append("circle") .attr("cx",50) .attr("cy",50) .attr("r",20) .attr("fill","blue") .attr("stroke-width",3) .attr("stroke","black"); </script>
以下のDIVにSVG出力を試しております。
<div id="test" style="width:100;height:100"></div>
出力結果
円が表示されているようなので、使えそうです。
PythonとMeCabによるツイートの単純分析(その2)
Twitterの分析で興味を持った文献がありました。
CiNii Articles - E-003 Extraction of Associative Relations Based on Connective Expression on Tweets
こちらの文献では「のくせに」という接続表現を検索し
「○○のくせに××」という関係から「○○」と「××」が対立する連想関係を抽出しているようです。
すこし興味を持ったので、やってみました。
環境、MeCabのインストール、Twitterのデータ収集は前回の記事と同様です。
PythonとMeCabによるツイートの単純抽出 - とあるSEの手順書
スクリプト
取り急ぎ、ダウンロードしたcsvを読込、MeCabを実行して、分かち書きにして、「のくせに」の前後を
抽出する一連のスクリプトを書いてみました。
import subprocess import pandas as pd import codecs import re datas = pd.read_csv("1500ttr.csv" , header=None) # 「のくせに」を含むもののみ抽出 (検索でなぜか「のくせに」以外が混じってた。) datas = datas[datas[5].str.contains("のくせに")] # CSV読込 for key, row in datas.iterrows(): # Mecab用に出力 fout =codecs.open("in_mecab.txt", "w" , "utf-8") # 5列目にツイート本文 tw = str(row[5]) # 英数字を消し、日本語のみに tw = re.sub("[^ぁ-んァ-ンー一-龠]", "", tw); # Mecabに食わせるファイルを出力 fout.writelines(tw) fout.close() # Mecab実行 -E でEOFを出力しない、 >> で追記 -Owakatiで分かち書き cmd = "\"C:\\Program Files (x86)\\MeCab\\bin\\mecab.exe\" < in_mecab.txt >> out_mecab.txt -E \"\" -Owakati" #cmd = "mecab < in_mecab.txt > out_mecab.txt" subprocess.call(cmd , shell=True) # 出力結果を読み込む f = codecs.open("out_mecab.txt" , "r" , "utf-8") lines = f.readlines() # 「○○のくせに××」の○○をsrcに××をdstに格納する kuseni_list = pd.DataFrame(columns=["src" , "dst"]) # 1行づつ処理 for line in lines : # 「のくせに」まで形態素が分割されているのでとりあえず一つに line = line.replace("の くせ に", "のくせに") # 分かち書きを分割 words = line.split(" ") #「そのくせに」とかもあるので、「のくせに」だけで抽出 if("のくせに" in words) : # 「のくせに」のインデックスを求め、その前後をみる i = words.index("のくせに") # インデックスを超えていないか、「のくせに改行コード」の場合スルー(jupyterの場合エスケープらいない??) if((i-1 >= 0) & (len(words) > i+1)) & (words[i+1] != "\r\n") : df = pd.DataFrame([[words[i-1], words[i+1]]], columns=["src" , "dst"]) kuseni_list = kuseni_list.append(df , ignore_index=True) # カウントする pd.DataFrame(kuseni_list["src"].value_counts()) pd.DataFrame(kuseni_list["dst"].value_counts())
結果
「○○のくせに××」の「○○」の個所に含まれる単語TOP10
順位 | 単語 | 個数 |
---|---|---|
1 | だけ | 122 |
2 | に | 24 |
3 | 男 | 19 |
4 | ヒットアンドアウェー | 15 |
5 | ブス | 13 |
6 | デブ | 12 |
7 | くらい | 11 |
8 | ドラマ | 9 |
9 | 者 | 8 |
10 | 中 | 8 |
「○○のくせに××」の「××」の個所に含まれる単語TOP10
順位 | 単語 | 個数 |
---|---|---|
1 | 年 | 119 |
2 | あんな | 20 |
3 | 生意気 | 19 |
4 | 何 | 17 |
5 | ヒットアンドアウェー | 15 |
6 | なんで | 14 |
7 | 犯罪 | 11 |
8 | な | 9 |
9 | 半分 | 8 |
10 | 私 | 7 |
うーん、広告や報道などのバイアスが結構強く出てそうです。
また、リツイートによる同文が複数入っている影響もありますね。
リツイートを排除し、ユニーク文のデータ数を多くすれば、このあたりの誤差が隠れて面白い結果が
出るかもしれません。(前回の分析も・・ですね。)
参考にした論文では、CaboCha(南瓜)による構文解析も行っているみたいですね。
この辺りも、折を見て触れたいと思います。
ひとまずでした。
PythonとMeCabによるツイートの単純分析
今回は、Pythonと形態素解析エンジンのMeCabをつかってTwitterに投稿されているツイートから
特定の単語と同時に登場する名詞を抽出し、頻出度を調べてみようと思います。
MeCabのインストール
公式サイトからダウンロードしてインストールで完了です。
辞書は、UTF-8が無難とのこと。
ただコマンドプロンプトの表面では文字化けするようです。
公式サイト
MeCab: Yet Another Part-of-Speech and Morphological Analyzer
インストールの参考にしたサイト
64bit Windows + python 2.7 + MeCab 0.996 な環境をつくる - Qiita
Windows+Python環境でMeCabを動かす際に、Visual Studioで再ビルドしたり
MeCabのライブラリをセットアップが必要です。
はやく動くものが見たい*1がために、
Pythonスクリプト内で、SubprocessコールでMeCabを実行しファイルを食わせて吐き出すことにしました。
Twitterのデータ収集
TwitterのAPIで取得することができますし、収集アプリもあります。
私は下記のサイトからcsvでダウンロードしました。
UTF-8でダウンロードできるのが親切です。
1500ったー
http://membonia.com/1500ttr/
スクリプト
取り急ぎ、ダウンロードしたcsvを読込、MeCabを実行して、形態素を取得、名詞だけを抽出するまでの
一連のスクリプトを書いてみました。
pandasはCSVを読み込んだり、フィルタをかけたりとデータ操作に便利なライブラリです。
import subprocess import pandas as pd import codecs import re # CSVファイル読込 datas = pd.read_csv("1500ttr.csv" , header=None) for key, row in datas.iterrows(): # Mecab用に出力 fout =codecs.open("in_mecab.txt", "w" , "utf-8") # 5列目にツイート本文 tw = str(row[5]) # 英数字を消し、日本語のみに tw = re.sub("[^ぁ-んァ-ンー一-龠]", "", tw); # Mecabに食わせるファイルを出力 fout.writelines(tw) fout.close() # Mecab実行 -E でEOFを出力しない、 >> で追記 cmd = "\"C:\\Program Files (x86)\\MeCab\\bin\\mecab.exe\" < in_mecab.txt >> out_mecab.txt -E \"\" " subprocess.call(cmd , shell=True) # 出力結果を読込 wordlist = pd.read_csv("out_mecab.txt" , header=None , delimiter="\t") # 一般名詞だけ抽出 MeCabの形態素解析結果に品詞が記載されている nounlist = wordlist[wordlist[1].str.contains("名詞,一般")] # 名詞のカウントをする pd.DataFrame(nounlist[0].value_counts(), columns=["COUNT"])
少し補足すると、MeCab実行の際につけている
-E \"\" "
このオプションは、通常、MeCabの出力結果にはEOS(end of string)が末尾に出力されます。
今回は「>>」で指定のファイルに追記し、一つの一覧にしたいため、つけました。
結果
順位 | 名詞 | 個数 |
---|---|---|
1 | 私 | 299 |
2 | 魔法 | 244 |
3 | 少女 | 214 |
4 | むら | 211 |
5 | あたし | 116 |
6 | 何 | 110 |
7 | それ | 100 |
8 | マギカ | 99 |
9 | 杏子 | 81 |
10 | ゾンビ | 80 |
1位、5位の「私」「あたし」は「あたしって、ほんとバカ」のセリフの影響でしょうか。
2位、3位の「魔法」「少女」は、そのままですね。
4位の「むら」は最初わからなかったですが「暁美ほむら*3」の「むら」が形態素になっているようです。*4
10位の「ゾンビ」もキャラのセリフですね。
「鹿目まどか*5」でもしてみましたが、「少女」「魔法」「マギカ」「フィギュア」「マギ」などで
特徴的な単語が上位にはありませんでした。
単純なので、このあたりの改善もすれば、もっと面白い抽出ができるかもしれませんね。
ひとまずでした。
*1:処理速度的には、きちんとライブラリのセットアップしたほうが良いと思います。
*2:魔法少女まどか☆マギカのキャラクター、魔法少女の一人。
*3:魔法少女まどか☆マギカのキャラクター、魔法少女の一人。
*4:こういう場合でもMeCabでチューニングできるようです。
*5:魔法少女まどか☆マギカのキャラクター、名の通り魔法少女で主人公。「まどか」で変換したら「まどか☆マギカ」が出てきて驚き。