gihyo.jpの「具体例で学ぶ!情報可視化のテクニック」のプログラムを勝手にRubyで書き換えてみた。
gihyo.jpで情報可視化の特集をやってて、すごく勉強になってよかったんですけど、
プログラムがJavaで書かれてて、個人的にRubyでやりたかったんで、
勉強ついでにプログラムをRubyで書き換えてみました。
そのRubyのプログラムはGithubにおいてあるので、ご自由にお使いください。
以下のリンクのdownloadからzip、またはtarで固めたものがダウンロードできます。
GitHub - ombran/gihyojp-visualization-ruby: The Ruby version of the information visualization introduced by gihyo.jp.(unofficial)
とまあ、さすがにこれで終わるのはひどいので、プログラムの簡単な説明をします。
今回はvisualization2のフォルダにあるプログラムの説明をします。
ただしここでRubyはインストール済みであるものとします。
Rubyのインストールとかの記事はいろんなところにあるんでそっちを参考にしてください。
Linuxとかなら元々インストール済みだったりしますし。
visualization2の説明
元記事だと第2回にあたる内容になります。
このプログラムは簡単に言えば、色集合を最短距離法に基づいて階層的クラスタリングを行うものです。
詳しいことは元記事を見てもらったほうがわかりやすいと思います。
visualization2フォルダ内容
visualization2のフォルダ内容は以下のようになっています。
$ tree visualization2 visualization2
-- Demo.rb | |
-- Visualization | |
-- Cluster.rb | |
-- ClusterBuilder.rb | |
-- DistanceEvaluator.rb | |
-- Item.rb | |
-- MultiVector.rb | |
-- NearestDistanceEvaluator.rb | |
`-- Node.rb |
拡張子の違いはありますが、元記事のプログラムのファイル名と内容を対応させてあります。
Visualization.rbを読み込むことだけで、Visualizationフォルダ以下のファイルを全て読み込めるようにしてあります。
元記事のプログラムとの違い
プログラムの内容自体はさほど違いはないんですけど、
元プログラムと大きく違うところとしてMultiVectorクラスの引数がハッシュになっています。
# MultiVector.rb module Visualization class MultiVector # ベクトル生成(引数はハッシュ) def initialize(hash={}) @data = {} hash.each do |key, value| @data[key] = value end end ... end
これはベクトルの次元数が違うもの同士でもクラスタリングできるようにするためです。
ちなみに今回はベクトルの次元数が全て同じなのでこの利点が実感できませんが、
visualization6ではこれによって元記事のプログラムで用いられているクラスを一つ削減できるようになっています。
まあとりあえずハッシュのほうが便利だよ、とでも思っておいてください。
その他のクラスでは言語の違いはありますが内容にほとんど変化はありません。
ただし、全てのクラスはVisualizationモジュール内に含まれるようにしてあります。
Javaでのパッケージの代わりだと考えてください。
デモプログラムの実行
それではプログラムのデモを行うDemoクラスは以下のようになります。
# Demo.rb require File.dirname(__FILE__) + '/Visualization' class Demo include Visualization def run # 入力データ作成 input = [] color = Struct.new(:red, :green, :blue) input << Item.new("BLUE", colorToVector(color.new(0, 0, 255))) input << Item.new("CYAN", colorToVector(color.new(0, 255, 255))) input << Item.new("MAGENTA", colorToVector(color.new(255, 0, 255))) input << Item.new("ORANGE", colorToVector(color.new(255, 200, 0))) input << Item.new("PINK", colorToVector(color.new(255, 175, 175))) input << Item.new("RED", colorToVector(color.new(255, 0, 0))) # 最短距離法に基づく階層的クラスタリングを準備 evaluator = NearestDistanceEvaluator.new builder = ClusterBuilder.new(evaluator) # クラスタリングを実行 result = builder.build(input) # クラスタリング結果を表示 output(result, 0) end def colorToVector(c) # 色成分を3次元のベクトルに変換 MultiVector.new({:red => c.red, :green => c.green, :blue => c.blue}) end def output(node, depth) # インデントを表示 depth.times do print " " end if (node.kind_of? Item) # 末端ノードなら項目名を表示 puts node.getName elsif (node.kind_of? Cluster) # クラスタなら"+"を表示し、子ノードを再帰的に表示 puts "+" cluster = node output(cluster.getLeft, depth + 1) output(cluster.getRight, depth + 1) end end end demo = Demo.new demo.run
入力データの色情報はRGBの値をそのまま入力してあります。
Demoクラスを実行すると,以下の出力が得られます。
$ ruby Demo.rb + + RED + MAGENTA + ORANGE PINK + BLUE CYAN
結果は元記事と同じになってるんで、プログラムは合ってると思うんですが、
もし何か間違い等ありましたら教えていただけるとありがたいです。
以上
今回はここまでです。
ほんとに簡単な説明で申し訳ないですけど、
元記事のプログラムと対応させて見てもらえるとわかりやすいかなと思います。
他のプログラムに関しては次回以降に説明します。
いろんなソーシャルブックマークサービスのブックマーク件数を数値で取得するRubyのクラス書いた
SBMはいっぱいありますけど、ブックマーク件数を取得するには、
XMLRPCやらJSONやらRESTやらでいろいろ違うんで、
簡単に取得できるクラスが欲しいと思って作りました。
Perlで書かれてるこちらをかなり参考にさせてもらってます。
というかこれのRuby版という感じになります。
ちなみに、SBMは、はてなブックマーク、livedoorクリップ、Yahoo!ブックマーク、
del.icio.us、Buzzurl、FC2ブックマーク、POOKMARK Airlinesの7つ利用できるようにしています。
ブックマーク件数取得プログラム
ブックマーク件数取得用ライブラリのプログラムは以下のようになります。
require 'open-uri' require 'xmlrpc/client' require 'rexml/document' require 'digest/md5' require 'rubygems' require 'json' class SBM # 初期設定 @@sbms = { :hatena => { :name => 'はてなブックマーク', :proxy => 'http://b.hatena.ne.jp/xmlrpc', :entry => 'http://b.hatena.ne.jp/entry/', :method => 'bookmark.getCount', }, :livedoor => { :name => 'livedoorクリップ', :proxy => 'http://rpc.clip.livedoor.com/count', :entry => 'http://clip.livedoor.com/page/', :method => 'clip.getCount', }, :yahoo => { :name => 'Yahoo!ブックマーク', :proxy => 'http://num.bookmarks.yahoo.co.jp/yjnostb.php?urls=', :xpath => '//SAVE_COUNT/@ct', :entry => 'http://bookmarks.yahoo.co.jp/url?url=', }, :delicious => { :name => 'del.icio.us', :proxy => 'http://badges.del.icio.us/feeds/json/url/data?url=', :entry => 'http://del.icio.us/url/', :key => 'total_posts', }, :buzzurl => { :name => 'Buzzurl', :proxy => 'http://api.buzzurl.jp/api/counter/v1/json?url=', :entry => 'http://buzzurl.jp/entry/', :key => 'users', }, :fc2 => { :name => 'FC2ブックマーク', :proxy => 'http://bookmark.fc2.com/image/users/', :regexp => /(\d+)\.png$/, :entry => 'http://bookmark.fc2.com/search/detail?url=', }, :pookmark => { :name => 'POOKMARK Airlines', :proxy => 'http://pookmark.jp/count/', :regexp => /(\d+)$/, :entry => 'http://pookmark.jp/url/', } } attr_accessor :url def initialize(url) @url = url end # 一覧の出力 def result self.get_all.each do |sbm, val| puts @@sbms[sbm][:name] puts "\t count:" + val[:count].to_s + "\t Entry:" + val[:entry] end end # すべてのSBMからブックマーク件数とSBMのURL取得 def get_all sbm_counts = {} i = 0 thread = [] @@sbms.each do |sbm, etc| thread[i] = Thread.start do sbm_counts[sbm] = self.get(sbm) end i += 1 end thread.each{|t| t.join} return sbm_counts end # 指定したSBMからブックマーク件数 def get(sbm) case sbm when :hatena self.hatena when :livedoor self.livedoor when :yahoo self.yahoo when :delicious self.delicious when :buzzurl self.buzzurl when :fc2 self.fc2 when :pookmark self.pookmark else puts "Sorry, #{sbm} is not support." end end # SBMそれぞれ出力 def hatena { :count => get_sbm_xmlrpc(:hatena), :entry => get_sbm_entry(:hatena) } end def livedoor { :count => get_sbm_xmlrpc(:livedoor), :entry => get_sbm_entry(:livedoor) } end def yahoo { :count => get_sbm_rest(:yahoo), :entry => get_sbm_entry(:yahoo) } end def delicious { :count => get_sbm_json(:delicious), :entry => get_sbm_entry(:delicious) } end def buzzurl { :count => get_sbm_json(:buzzurl), :entry => get_sbm_entry(:buzzurl )} end def fc2 { :count => get_sbm_imageicon(:fc2), :entry => get_sbm_entry(:fc2) } end def pookmark { :count => get_sbm_imageicon(:pookmark), :entry => get_sbm_entry(:pookmark) } end private # XMLRPCによるブックマーク件数取得(hatena,livedoor) def get_sbm_xmlrpc(sbm) count = 0 client = XMLRPC::Client.new2(@@sbms[sbm][:proxy]) res = client.call2(@@sbms[sbm][:method], @url) res[1].each{|url, value| count = value } if res[0] return count end # REST(XML)によるブックマーク件数取得(Yahoo) def get_sbm_rest(sbm) count = 0 open(@@sbms[sbm][:proxy] + @url) do |xml| doc = REXML::Document.new(xml.read) count = REXML::XPath.first(doc, @@sbms[sbm][:xpath]).value.to_i end return count end # JSONによるブックマーク件数取得(delicious, buzzurl) def get_sbm_json(sbm) count = 0 open(@@sbms[sbm][:proxy] + @url) do |json| data = JSON.parse(json.read) if data[0] != nil count = data[0][@@sbms[sbm][:key]].to_i end end return count end # 画像のURLからブックマーク件数取得(fc2, pookmark) def get_sbm_imageicon(sbm) count = 0 open(@@sbms[sbm][:proxy] + @url) do |image| path = image.base_uri.path if path =~ @@sbms[sbm][:regexp] count = $1.to_i end end return count end # 入力されたURLに対応したSBMのURL表示 def get_sbm_entry(sbm) url = @url url = Digest::MD5.hexdigest(@url) if sbm == :delicious return @@sbms[sbm][:entry] + url end end
使い方
上で示したプログラムを「sbm.rb」というファイルで保存したとして、irbで試したものを以下に示します。
対象のURLは適当にGoogleで試してます。
irb(main):001:0> require 'sbm.rb' irb(main):002:0> sbm = SBM.new('http://www.google.co.jp/') irb(main):003:0> pp sbm.get_all {:fc2=> {:count=>405, :entry=> "http://bookmark.fc2.com/search/detail?url=http://www.google.co.jp/"}, :livedoor=> {:count=>293, :entry=>"http://clip.livedoor.com/page/http://www.google.co.jp/"}, :pookmark=> {:count=>202, :entry=>"http://pookmark.jp/url/http://www.google.co.jp/"}, :yahoo=> {:count=>62646, :entry=>"http://bookmarks.yahoo.co.jp/url?url=http://www.google.co.jp/"}, :hatena=> {:count=>2133, :entry=>"http://b.hatena.ne.jp/entry/http://www.google.co.jp/"}, :delicious=> {:count=>947, :entry=>"http://del.icio.us/url/9d0f4061beb6ae41f64eb124665e0768"}, :buzzurl=> {:count=>62, :entry=>"http://buzzurl.jp/entry/http://www.google.co.jp/"}}
という感じでget_allでそれぞれのブックマーク数とSBMのURLのハッシュを取得できます。
そして、
irb(main):004:0> pp sbm.hatena {:count=>2133, :entry=>"http://b.hatena.ne.jp/entry/http://www.google.co.jp/"} irb(main):005:0> pp sbm.delicious {:count=>947, :entry=>"http://del.icio.us/url/9d0f4061beb6ae41f64eb124665e0768"}
という感じで、はてブやdeliciouなどにも個別にアクセスできます。
あと、ちなみに、resultメソッドを実行すると
irb(main):006:0> pp sbm.result FC2ブックマーク count:405 Entry:http://bookmark.fc2.com/search/detail?url=http://www.google.co.jp/ livedoorクリップ count:293 Entry:http://clip.livedoor.com/page/http://www.google.co.jp/ POOKMARK Airlines count:202 Entry:http://pookmark.jp/url/http://www.google.co.jp/ Yahoo!ブックマーク count:62646 Entry:http://bookmarks.yahoo.co.jp/url?url=http://www.google.co.jp/ はてなブックマーク count:2133 Entry:http://b.hatena.ne.jp/entry/http://www.google.co.jp/ del.icio.us count:947 Entry:http://del.icio.us/url/9d0f4061beb6ae41f64eb124665e0768 Buzzurl count:62 Entry:http://buzzurl.jp/entry/http://www.google.co.jp/
という感じで一覧を出力するようにしています。
UbuntuでのEmeraldのインストール方法
Ubuntuをデフォルトのままじゃいまいち格好良くないので、見た目をよくしたい。
でも、できるだけ楽にテーマをかえたいってことでEmeraldを使うことにして、そのインストール方法。
インストール
$ sudo aptitude install emerald compizconfig-settings-manager fusion-icon
起動
インストールできたら、
「システムツール」->「Compiz Fusion Icon」
で、Fusion Iconを起動する。
タスクトレイにあるアイコンを右クリックして
「Select Window Decorator」->「Emerald」
でEmeraldを選択すれば、Emeraldが利用できるようになります。
テーマ設定
そして、もう一度タスクトレイにあるアイコンを右クリックして
「Emerald Theme Manager」
をクリックすれば、Emeraldのテーマを設定するウィンドウが表示されるのでここでテーマを設定します。
テーマはこの辺からダウンロードしてきてください -> /s/Compiz
ダウンロードするのめんどくさいという方は、ここのリポジトリを設定して、
emerald-themesというパッケージをインストールしてください。
ただし、非公式なので自己責任でお願いします。
具体的にはUbuntu8.10の場合は以下のようになります。
まず、以下のリポジトリを設定して、
deb http://ppa.launchpad.net/portis25/ubuntu intrepid main deb-src http://ppa.launchpad.net/portis25/ubuntu intrepid main
emerald-themesというをaptでインストール
$ sudo aptitude install emerald-themes
これだけで、Emeraldのテーマがいくつか利用可能になります。
ただし、それほど多いわけではない感じなので、ここから好みのテーマをダウンロードしてインストールしたほうがいいような気もします。
以上
結構簡単にテーマをかえたりできるので便利ですね。
githubでforkしてAutoPagerizeのオンオフをキーボードショートカットでするパッチを当ててみた
githubでAutoPagerizeが公開されているので、gitの勉強ついでにforkして、この間書いたパッチを当ててみた。
タイトルの日本語おかしい気がするけど気にしないw
流れとしては、forkした後にgit cloneして、修正加えたら、git commitしてgit pushという流れです。
んで、パッチ当てたやつがこれ↓
autopagerize/autopagerize.user.js at master · ombran/autopagerize · GitHub
「shift+t」でAutoPagerizeをオンオフできるようにしたものなので、
興味のある人はご自由にどうぞ
一応差分は以下のような感じ。
@@ -28,6 +28,7 @@ var CACHE_EXPIRE = 24 * 60 * 60 * 1000 var BASE_REMAIN_HEIGHT = 400 var FORCE_TARGET_WINDOW = true var USE_COUNTER = true +var TOGGLE_KEY = 'shift+t'; var SITEINFO_IMPORT_URLS = [ 'http://wedata.net/databases/AutoPagerize/items.json', ] @@ -109,6 +110,8 @@ var AutoPager = function(info) { (Math.round(scrollHeight * 0.8)) this.remainHeight = scrollHeight - bottom + BASE_REMAIN_HEIGHT this.onScroll() + + window.addEventListener("keydown", function(e){ self.keydown(e) }, false); } AutoPager.prototype.getPageElementsBottom = function() { @@ -119,6 +122,40 @@ AutoPager.prototype.getPageElementsBottom = function() { catch(e) {} } +AutoPager.prototype.keydown = function(event){ + var keys = TOGGLE_KEY.toLowerCase().split('+'); + + var special_keys = { + 27: 'esc', 9: 'tab', 32: 'space', 13: 'return', 8: 'backspace', + 145: 'scroll', 20: 'capslock', 144: 'numlock', 19: 'pause', + 45: 'insert', 36: 'home', 46: 'del',35: 'end', 33: 'pageup', + 34: 'pagedown', 37: 'left', 38: 'up', 39: 'right',40: 'down', + 112: 'f1',113: 'f2', 114: 'f3', 115: 'f4', 116: 'f5', 117: 'f6', + 118: 'f7', 119: 'f8', 120: 'f9', 121: 'f10', 122: 'f11', 123: 'f12' + }; + + var code = event.which, + character = String.fromCharCode(code).toLowerCase(), + special = special_keys[code], + shift = event.shiftKey, + ctrl = event.ctrlKey, + alt = event.altKey; + + var modif = { "shift": false, "ctrl": false, "alt": false }; + + for(var i=0; i<keys.length; i++){ + if(keys[i]=="shift" || keys[i]=="ctrl" || keys[i]=="alt"){ + modif[keys[i]] = true; + keys.splice(i, 1); + } + } + if(shift == modif.shift && ctrl == modif.ctrl && alt == modif.alt){ + if(special == keys[0] || character == keys[0]){ + this.toggle(); + } + } +} + AutoPager.prototype.initHelp = function() { var helpDiv = document.createElement('div') helpDiv.setAttribute('id', 'autopagerize_help')
DragScrollをgithubに移動しました
以前作っていたグリモンを、何かと便利だと思ったのでgithubで管理するようにしました。
正確にはDiscover gists · GitHubで、コピペしただけですけど。
そのページがこちらです。
drag and page scroll · GitHub
内容は特別変更はないです。
以上
コピペだけでできたので、すごい簡単でした。
ちなみに、githubでの自分のページはこちらです。
ombran (Nobuhiro Nakashima) · GitHub
Google Chromeのabout:ページリスト
こことかこことかにGoogle Chromeのabout:ページのリストが載ってたんでメモ
- about:version
- about:plugins
- about:cache
- about:memory
- about:stats
- about:histograms
- about:dns
- about:network
- about:crash
- about:hang
- about:internets
以上
about:internetsは所謂Easter Eggってやつですね。あとabout:hangは実行するとそのタブがハングアップしますので注意してください。まあこれでタブそれぞれが別プロセスで動いてるっていう確認にもなりますね。
詳しくは以下を見てください。
Google Chrome's about: Pages
http://lifehacker.com/5045164/google-chromes-full-list-of-special-about-pages
TwitterとRemember The Milk連携時の文字化けの対処法
Twitterと連携できて、スマートリストとかが便利そうなRemember The Milkを使うことにしたんですけど、
Twitterとの連携でいきなり文字化けして困ったんで、その対処法のメモ。
対処法といっても
Twitterの言語設定を「英語 - English」に変更する
これだけです。
理由はよくわかりませんが、日本語版TwitterでRTMにタスク追加しても文字化けしてしまいます。
ですが、英語版に切り替えることでこの問題は解決します。
以上
文字化けして困ってた方は、言語設定を英語にすればたぶん直りますよ。
ただし、これはWebからポストした場合で、クライアントからのポストでは文字化けしてしまいます。
誰か、クライアントからでも文字化けしない方法教えて><