ブログ新設のお知らせ

Livedoor Blogでブログ新しく開設してみました。
僕はただ僕らしく


とは言っても、このブログを辞めるつもりではなく、技術と関係ない戯言を書く場所が欲しいと思っただけです。
あとはJavaScript実行できるブログ欲しいなと思ったのもありますね。


技術系のこと(グリモン作ったりとか)に関しては、今後もこっちでも書く予定です。
そして、コラムやらなんやら属人性の高いものはあっちで書くようにしようと思ってます。
興味のある方は見に来てやってください。そして、こちらも今後ともよろしくお願いします。

Twitterのフォロワー一覧のページでプロフィール情報を表示するブックマークレット書いたよ。

お久しぶりです。
更新をだいぶ怠っていたんですけど、ちょっと書いてみたブックマークレットの紹介をしときます。

内容

フォローしてる人(following)とかされてる人(followers)の一覧ページで
それぞれの最新のポストが一個だけ表示されてますけど、
個人的にはそれよりもその人のプロフィールが見たいと思って以下のようなブックマークレット書いてみました。
とっくに誰か作ってそうな気がしますが、習作ってことで。

使い方

Twitterのフォロワー一覧ページ(例:http:twitter.com/ombran/followers)で
ブラウザのアドレスバーに貼り付けて実行してみてください。

Firefox3.5.5とOpera10.01で動作確認してます。他のブラウザでもたぶん動くはず。

[注意点]表示されてるユーザ(20名)分の通信が行われるので、処理が重くなる可能性があります。

プロフィール情報追加版ブックマークレット

ユーザそれぞれの最新ポストの上にプロフィール情報が追加されます。

javascript:(function(){var addresses = $("#follow_grid address"); addresses.each(function(){ var user = $(this).find(".screenname:first > a").text(); var user_url = "http://twitter.com/" + user; var self = this; $.get(user_url, {}, function(response){ bio = $(response).find("#bio > .bio").text(); $(self).append("<br /><span>" + bio + "</span>"); }); }); })();

プロフィール情報書換版ブックマークレット

ユーザそれぞれの最新ポストをプロフィール情報に書き換えます。

javascript:(function(){ var addresses = $("#follow_grid address"); addresses.each(function(){ var user = $(this).find(".screenname:first > a").text(); var user_url = "http://twitter.com/" + user; var self = this; $.get(user_url, {}, function(response){ bio = $(response).find("#bio > .bio").text(); $(self.parentNode).find(".user-body:first .currently").replaceWith("<span>" + bio + "</span>"); }); }); })();

ソース

本当はグリモンにする予定だったんですが、jQueryの関係でうまく動作しなかったんで、
とりあえずブックマークレットで公開しました。
それぞれは以下のソースを二つに分けたものです。

(function(){
    // プロフィール情報の追記か書換かのフラグ
    // true: 書換,  false: 追記
    var replace = false;

    var addresses = $("#follow_grid address");
    addresses.each(function(){
        // ユーザ名取得
        var user = $(this).find(".screenname:first > a").text();
        var user_url = "http://twitter.com/" + user;

        // プロフィール追加
        var self = this;
        $.get(user_url, {}, function(response){
            // ユーザページからプロフィール情報取得
            bio = $(response).find("#bio > .bio").text();

            if(replace){
                // 表示内容をプロフィール情報に書換
                $(self.parentNode).find(".user-body:first .currently").replaceWith("<span>" + bio + "</span>");
            } else {
                // 表示内容にプロフィール情報を追加
                $(self).append("<br /><span>" + bio + "</span>");
            }
        });
    });
})();

以上

リストとか作成するときに、プロフィール情報見れたほうが便利だろうなー、と思って作りました。
TwitterjQuery使ってるみたいなので、かなり楽してますw
使ってみたい方はご自由にお使いください。

Twitterのページ内でインクリメンタルサーチするグリモン書いたよ

[2009年2月23日追記]
Twitterのページ内をインクリメンタルサーチするグリモン作りました。
メモ用にふぁぼってたやつとかを探しやすくする用途とかに使えるかな。
名前は適当に「twincre」・・・センスがありませんねw
名前は「Twitter Incremental Search Helper」に変えました。長いですけどわかりやすくということで。
ページ内にデータが多ければ多いほど便利さが上がるんで、AutoPagerizeと併用を推奨します。
というより、1ページに表示される量なら普通に見たほうが早いですねw


実際にインストールすると上のようなインクリメンタルサーチ用のテキスト入力ボックスが表示されるので、
そこに検索データの入力を行えば、対応するデータのみ表示されるようになります。

あと、document.getElementsByClassNameという関数をつかってるので、Firefox2では動きません。
というわけで、Firefox3専用となります。Operaだと9.50以上なら動くかも。

githubに置いているので、使いたいかたはご自由にどうぞ。

twitter_incremental_search_helper.user.js · GitHub

Userscripts.orgにも置くようにしました。
http://userscripts.org/scripts/show/42933

HTMLレンダリングエンジンとJavaScriptエンジンの対応について調べてみた

ちょっとHTMLレンダリングエンジンとJavaScriptエンジンの対応について調べたりしたんで、そのメモ。
名前調べただけなんで、詳しいことはググってください。

HTMLレンダリングエンジン JavaScriptエンジン 主なWebブラウザ
Gecko SpiderMonkey Firefox 3.0まで
TraceMonkey Firefox 3.1以降に実装予定
WebKit JavaScriptCore Safari
V8 Google Chrome
Presto linear_b Opera 7から9.27まで
futhark Opera 9.50以降
Trident JScript Internet Explorer

[修正]SquirrelFish ExtremeはJavaScriptCoreの一部(VMの名称)

以上

こんな感じですかね。間違いあったら教えてください。

gihyo.jpの「具体例で学ぶ!情報可視化のテクニック」のプログラムを勝手にRubyで書き換えてみた。その4

勝手にRubyで書き換えてみたプログラムも今回でラストになります。
プログラムのダウンロードは以下のリンク先のdownloadからご自由にどうぞ。
GitHub - ombran/gihyojp-visualization-ruby: The Ruby version of the information visualization introduced by gihyo.jp.(unofficial)
今回はvisualization6フォルダのプログラムについての説明になります。

visualization6の説明

元記事だと第6回にあたる内容になります。
このプログラムは、はてなブックマーク人気エントリーをツリーマップとして可視化するプログラムになります。
詳しいことは元記事を見てもらったほうがわかりやすいと思います。

visualization6フォルダの内容

visualization6のフォルダ内容は以下のようになっています。

$ tree visualization6
visualization6
-- Demo.rb
-- Visualization
-- BinaryTreeMapRenderer.rb
-- Bookmark.rb
-- BookmarkDetail.rb
-- BookmarkItem.rb
-- Cluster.rb
-- ClusterBuilder.rb
-- DistanceEvaluator.rb
-- HatenaBookmarkAPI.rb
-- Item.rb
-- MultiVector.rb
-- Node.rb
-- TreeMapRenderer.rb
`-- WardDistanceEvaluator.rb
-- Visualization.rb
`-- hatena_bookmark.png

Visualization.rbを読み込むことだけで、Visualizationフォルダ以下のファイルを全て読み込めるようにしてあります。
Demo.rbがデモ用のプログラムとなります。

RMagickとJSONライブラリのインストール

画像処理にRMagick、JSONデータのパースにJSONライブラリを使用するので、あらかじめインストールしておいてください。
まずRMagickはgemだと

# gem install rmagick

ちなみに、Ubuntuだとaptでインストールできます。

# apt-get install librmagick-ruby

次にJSONライブラリはgemでインストールできます。

# gem install json

プログラムの説明

基本的にプログラムのクラスそれぞれは元記事のプログラムと対応させてあるので、見比べられるようにしてあります。
ただ、ブックマークのタグを整数インデックスに変換するIndexMapperクラスというのが元記事のプログラムにはありますが、こちらのプログラムではMultiVectorクラスのデータがハッシュで作成しているので、IndexMapperクラスがいらなくなります。
以下のBookmarkItemクラスから元記事でのマッピングをしていないことがわかると思います。

# BookmarkItem.rb
module Visualization
  # はてなブックマークエントリに対応する末端ノード
  class BookmarkItem < Visualization::Item
    # @param bookmark:Visualization::Bookmarkオブジェクト
    # @param detail:Visualization::BookmarkDetailオブジェクト
    def initialize(bookmark, detail)
      # ブックマーク数をそのまま平均化すると比率が極端になるので
      # 平方根をとって調整する
      super(bookmark.title, tagsToVector(detail), Math.sqrt(detail.bookmarkCount))
      @bookmark = bookmark
      @detail = detail
    end
    
    def tagsToVector(detail)
      vector = Visualization::MultiVector.new
      detail.tags.each do |tag|
        vector.set(tag => (vector.get(tag).to_i + 1))
      end
      vector.normalize
      return vector
    end
    
    def getBookmark
      return @bookmark
    end
    
    def getDetail
      return @detail
    end
  end
end

あとは、画像描画をしているBinaryTreeMapRendererクラスですね。
基本的に元記事と同じですが、画像に文字を書き込んでいるdrawStringWithinメソッドは特殊なんで説明しときます。
まずプログラムは以下のようになります。

# BinaryTreeMapRenderer.rb(一部分)
module Visualization
  class BinaryTreeMapRenderer
...

    # ブックマークされたエントリのタイトル
    def drawStringWithin(draw, title, rect)
      d = draw
      # フォントサイズ
      pointsize = [(Math.sqrt(rect.width * rect.height) / 10).to_i, 10].max
      # 日本語表示のためにフォント指定(環境によって変更してください)
      d.font = "/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"
      # 文字色
      d.fill("white")
      d.stroke_width(0)
      d.pointsize(pointsize)
      
      # 文字を改行しながら出力
      words = [rect.width.to_f/pointsize.to_f, 1].max.to_i
      t_ary  = title.split("")
      t_size = t_ary.size
      rows = (t_size.to_f/words.to_f).ceil
      rows.times do |i|
        start  = i * words
        finish = ((i + 1) * words) - 1
        text = t_ary[start..finish].join
        y = rect.y + pointsize * (i + 1)
        d.text(rect.x + 5, y + 5, text)
      end
    end
  end
end

d.fontでフォントの指定をしないと日本語を表示できないので気をつけてください。またこれは環境によって違うので、それぞれの環境で日本語を表示できるフォントの絶対パスを指定してください。
あとはpointsizeで文字の大きさを設定していたり、表示領域ごとに文字列を改行しながら表示しています。
ちなみにブックマーク数が多さで文字の大きさを変更してあります。

デモプログラムの実行

プログラムのデモを行うDemoクラスは以下のようになります。

# Demo.rb
$KCODE = 'u'

require 'rubygems'
require 'RMagick'
require File.dirname(__FILE__) + '/Visualization'

class Demo
  include Visualization
  
  # 出力ファイル名
  OUTPUT_FILE_NAME = 'hatena_bookmark.png'
  
  def run
    api = HatenaBookmarkAPI.new
    bookmarks = api.getHotEntries
    puts bookmarks.size.to_s + " entries."
    
    # 階層的クラスタリングの入力データを作成
    input = []
    bookmarks.each do |bookmark|
      puts bookmark.title
      puts "  [url] " + bookmark.url
      # サーバの負荷を抑えるため呼び出し間隔を空ける
      sleep(1)
      detail = api.getDetail(bookmark.url)
      input << BookmarkItem.new(bookmark, detail)
      if (detail !=  nil)
        puts "  [bookmarkCount] " + detail.bookmarkCount.to_s
        puts "  [tags] [" + detail.tags.join(", ") + "]"
      end
    end
    
    # Ward法に基づく階層的クラスタリングを準備
    evaluator = Visualization::WardDistanceEvaluator.new
    builder = Visualization::ClusterBuilder.new(evaluator)
    
    # クラスタリングを実行
    puts "クラスタリング開始(結構時間かかります)"
    result = builder.build(input)
    puts "クラスタリング終了"
    
    # クラスタリング結果を表示
    puts "画像生成開始"
    output(result)
    puts "出力ファイル:" + OUTPUT_FILE_NAME
  end
  
  def output(node)
    # 出力画像を作成
    g = Magick::Image.new(1024, 768)
    
    # グラフィックオブジェクトを作成
    d = Magick::Draw.new
    
    # 背景を白で塗りつぶす
    d.fill("white")
    d.rectangle(0, 0, g.columns, g.rows)
    d.draw(g)

    # ツリーマップの描画を実行
    renderer = Visualization::BinaryTreeMapRenderer.new
    bounds = Magick::Rectangle.new(g.columns - 40, g.rows - 40, 20, 20)
    renderer.render(g, node, bounds)
    
    # 画像をPNGファイルに保存
    g.write(OUTPUT_FILE_NAME)
  end
end

demo = Demo.new
demo.run

デモプログラムを実行すると、以下のような出力が得られます。

$ ruby Demo.rb 
30 entries.
おいしいスープのレシピ集:アルファルファモザイク
  [url] http://alfalfa.livedoor.biz/archives/51402336.html
  [bookmarkCount] 249
  [tags] [あとで読む, レシピ, お役立ち, ...
...
クラスタリング開始(結構時間かかります)
30
29
28
27
26
...
6
5
4
3
2
クラスタリング終了
画像生成開始
出力ファイル:hatena_bookmark.png

これで、hatena_bookmark.pngという以下のような画像ファイルが出力されます。
ツリーマップによってクラスタリングの結果が視覚的にわかりやすく表現されていることがわかると思います。
ただし、入力データは、はてなブックマークホッテントリに依存するので、出力される画像はその時によって変化します。

以上

今回で、はてなブックマークホッテントリのツリーマップ化ができるようになったので、これで勝手にRubyで書き換えたプログラムは終了です。
情報可視化に関してすごく勉強になりました。あと、書き換えをする中でRubyのプログラミングについてもいい勉強になりました。
こういう記事を書いてくれたgihyo.jpに感謝です。

gihyo.jpの「具体例で学ぶ!情報可視化のテクニック」のプログラムを勝手にRubyで書き換えてみた。その3

前回前々回に引き続いて今回も勝手にRubyで書き換えたプログラムの簡単な説明をします。
プログラムのダウンロードは以下のリンク先のdownloadからご自由にどうぞ。
GitHub - ombran/gihyojp-visualization-ruby: The Ruby version of the information visualization introduced by gihyo.jp.(unofficial)
今回はvisualization5フォルダのプログラムについての説明になります。

visualization5の説明

元記事だと第5回にあたる内容になります。
このプログラムは、はてなブックマークが提供するWeb APIにアクセスし,人気エントリーの情報を取得するプログラムになります。
詳しいことは元記事を見てもらったほうがわかりやすいと思います。

visualization5フォルダの内容

visualization5のフォルダ内容は以下のようになっています。

visualization5
-- Demo.rb
-- Visualization
-- Bookmark.rb
-- BookmarkDetail.rb
`-- HatenaBookmarkAPI.rb
`-- Visualization.rb

元記事のプログラムと拡張子の違いはありますが、ファイル名と内容を対応させてあります。
Visualization.rbを読み込むことだけで、Visualizationフォルダ以下のファイルを全て読み込めるようにしてあります。
Demo.rbがデモ用のプログラムとなります。

JSONライブラリのインストール

今回はJSON形式のデータを扱うので、JSONライブラリをインストールしておきます。
gemを用いて以下のようにインストールできます。

# gem install json

プログラムの説明

まずデータ格納用のクラスですが、Bookmarkクラスはエントリ情報を格納するクラスで、BookmarkDetailクラスはブックマーク数やタグの一覧などエントリの詳細を格納するクラスとなっています。

次に、今回のメインとなるHatenaBookmarkAPIクラスについて説明します。
プログラムは以下のようになります。

# HatenaBookmarkAPI.rb
require 'rss'
require 'open-uri'
require 'uri'

require 'rubygems'
require 'json'

module Visualization
  # はてなブックマークのAPIにアクセスするクラス
  class HatenaBookmarkAPI
    # 人気エントリーの情報を取得
    # @return:ブックマーク情報のリスト
    def getHotEntries
      bookmarks = []
      content = nil
      # 人気RSSフィードを読み込む
      open("http://b.hatena.ne.jp/hotentry.rss"){|u|
        content = u.read
      }
      rss = nil
      # RSSをParseする
      begin
        rss = RSS::Parser::parse(content)
      rescue RSS::InvalidRSSError
        rss = RSS::Parser::parse(content, false)
      end
      # 各エントリの情報を取得
      rss.items.each do |item|
        bookmark = Visualization::Bookmark.new
        bookmark.url   = item.link
        bookmark.title = item.title
        bookmarks << bookmark
      end
      return bookmarks
    end
    
    # ブックマークの詳細情報を取得
    # @param url:ブックマーク対象のURL
    # @return:詳細情報
    def getDetail(url)
      encodeUrl = URI.encode(url)
      # エントリ情報取得APIのURL
      apiUrl = "http://b.hatena.ne.jp/entry/json/?url=" + encodeUrl
      json = nil
      # URLを開き、データを読み込む
      open(apiUrl) do |f|
        # JSONをパース
        if f.read =~ /^\((.*)\)$/
          json = JSON.parse($1)
        end
      end

      # 詳細情報を作成
      detail = Visualization::BookmarkDetail.new
      detail.bookmarkCount = json["count"].to_i
      detail.tags = []
      
      # bookmarks配列を読み込む
      bookmarks = json["bookmarks"]
      bookmarks.each do |item|
        # tags配列を読み込む
        tags = item["tags"]
        tags.each do |tag|
          detail.tags << tag
        end
      end
      
      return detail
    end
  end
end

getHotEntriesメソッドは、はてなブックマークの人気エントリの一覧をVisualization::Bookmarkオブジェクトの配列として返すメソッドです。
RSSフィードを取得するためにopen-uriライブラリを、RSSフィードをパースするためにRSSライブラリを使用しています。

getDetailメソッドは、特定のURLからブックマークエントリの詳細情報を取得するメソッドです。
JSONデータのパースのためにJSONライブラリを使用しています。
ちなみに、JSONのパースの際に

# JSONをパース
if f.read =~ /^\((.*)\)$/
  json = JSON.parse($1)
end

として、取得したはてなブックマークJSONデータの最初と最後にある括弧を取り除いてあげないとパースの際にエラーになってしまうので気を付けてください。

デモプログラムの実行

プログラムのデモを行うDemoクラスは以下のようになります。

# Demo.rb
require File.dirname(__FILE__) + '/Visualization'

class Demo
  include Visualization

  def run
    api = HatenaBookmarkAPI.new
    bookmarks = api.getHotEntries
    puts bookmarks.size.to_s + " entries."
    
    bookmarks.each do |bookmark|
      puts bookmark.title
      puts "  [url] " + bookmark.url
      # サーバの負荷を抑えるため呼び出し間隔を空ける
      sleep(1)
      detail = api.getDetail(bookmark.url)
      if (detail != nil)
        puts "  [bookmarkCount] " + detail.bookmarkCount.to_s
        puts "  [tags] [" + detail.tags.join(", ") + "]"
      end
    end
  end
end

demo = Demo.new
demo.run

Demoクラスを実行すると,実行時点での最新の人気エントリーの情報が,例えば次のように出力されます。

$ ruby Demo.rb 
30 entries.
ベア速  日本SUGEEEEEEEEEEEEEEEE!ってなるコピペくれ
  [url] http://vipvipblogblog.blog119.fc2.com/blog-entry-248.html
  [bookmarkCount] 373
  [tags] [2ch, neta, ネタ, 2ch, あとで読む, ...
SEOやSMMのためにブログを作ったらまずやることリスト - ソーシャルメディアマーケティング(SMM).jp
  [url] http://www.socialmediamarketing.jp/2008/12/seosmm.html
  [bookmarkCount] 265
  [tags] [SEO, Webサービス, seo, web制作, まとめ, ...
Color of Book - 雑誌の色からhtml,cssで利用できるカラーチャートの紹介
  [url] http://colorchart.jp/
  [bookmarkCount] 362
  [tags] [color, webデザイン, webサービス, css, ...
...

エントリのurlやブックマーク数、タグの一覧が表示されてるのがわかると思います。

以上

今回はここまです。
細かい部分はプログラムや元記事を見てください。
あと、間違ってる部分などありましたら教えてください。
次回の可視化で最後になります。

gihyo.jpの「具体例で学ぶ!情報可視化のテクニック」のプログラムを勝手にRubyで書き換えてみた。その2

前回に引き続き、今回も勝手にRubyで書き換えたプログラムの簡単な説明をします。
プログラムのダウンロードは以下のリンク先のdownloadからご自由にどうぞ。
GitHub - ombran/gihyojp-visualization-ruby: The Ruby version of the information visualization introduced by gihyo.jp.(unofficial)

今回はvisualization4のフォルダにあるプログラムの説明します。

visualization4の説明

元記事だと第3回第4回にあたる内容になります。
このプログラムは階層的クラスタリングの実行結果をツリーマップで表現するものです。
詳しいことは元記事を見てもらったほうがわかりやすいと思います。

visualization4フォルダの内容

visualization4のフォルダ内容は以下のようになっています。

$ tree visualization4/
visualization4/
-- Demo.rb
-- Visualization
-- BinaryTreeMapRenderer.rb
-- Cluster.rb
-- ClusterBuilder.rb
-- ColorItem.rb
-- DistanceEvaluator.rb
-- Item.rb
-- MultiVector.rb
-- Node.rb
-- TreeMapRenderer.rb
`-- WardDistanceEvaluator.rb
-- Visualization.rb
`-- treemap.png

今回も前回同様、元記事のプログラムと拡張子の違いはありますが、ファイル名と内容を対応させてあります。
Visualization.rbを読み込むことだけで、Visualizationフォルダ以下のファイルを全て読み込めるようにしてあります。
Demo.rbがデモ用のプログラムで、treemap.pngは出力結果となります。

RMagickのインストール

プログラムの説明の前に、RMagickのインストール方法について説明します。
今回のプログラムでは画像を扱うので、画像処理用のライブラリとしてRMagickを用いるためです。
gemだと以下のようになります。

# gem install rmagick

RMagickのインストールにはライブラリが色々必要になりますけど、
それはいろんなところで書かれてると思うので頑張ってください。
ちなみに、Ubuntuとかなら、aptで簡単にインストールできます。

# apt-get install librmagick-ruby

プログラムの説明

今回のプログラムで元記事のプログラムと大きな違いは、画像描画部分になります。
そもそも使ってるライブラリ違うんで、当然といえば当然ですね。
その画像描画のプログラムはBinaryTreeMapRenderer.rbで、以下のようになります。

# BinaryTreeMapRenderer.rb
require 'rubygems'
require 'RMagick'

module Visualization
  #
  # 領域の2分割を再帰的に繰り返し、ツリーマップの描画を行う
  #
  class BinaryTreeMapRenderer
    include Visualization::TreeMapRenderer
    
    def render(graphic, node, bounds)
      doRender(graphic, node, bounds, 0)
    end
    
    def doRender(graphic, node, bounds, depth)
      d = Magick::Draw.new
      if (node.kind_of? Visualization::ColorItem)
        # ノードが色項目の場合は、その色で長方形を塗りつぶす
        d.fill("rgb(#{node.getVector.data[:red]}, #{node.getVector.data[:green]}, #{node.getVector.data[:blue]}, #{depth})")
        d.rectangle(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height)
      elsif (node.kind_of? Visualization::Cluster)
        cluster = node
        
        # 子ノードchild1とchild2を取得
        child1 = cluster.getLeft
        child2 = cluster.getRight
        # child1の面積の方が大きくなるようにする
        if (child1.getArea < child2.getArea)
          temp = child1
          child1 = child2
          child2 = temp
        end
        
        # 子ノードの面積比を計算
        area1 = child1.getArea
        area2 = child2.getArea
        ratio1 = area1 / (area1 + area2)
        ratio2 = area2 / (area1 + area2)
        
        x = bounds.x
        y = bounds.y
        w = bounds.width
        h = bounds.height

        rect1 = nil
        rect2 = nil
        # 領域分割を実行
        if (w > h)
          # boundsが横長の場合、左右に分割
          rect1 = Magick::Rectangle.new(ratio1 * w, h, x, y)
          rect2 = Magick::Rectangle.new(ratio2 * w, h, x + ratio1 * w, y)
        else
          # boundsが縦長の場合、上下に分割
          rect1 = Magick::Rectangle.new(w, ratio1 * h, x, y)
          rect2 = Magick::Rectangle.new(w, ratio2 * h, x, y + ratio1 * h)
        end
        # 子ノードを再帰的に処理する
        doRender(graphic, child1, rect1, depth + 1)
        doRender(graphic, child2, rect2, depth + 1)
      end
    
      # 輪郭を階層の深さに応じた太さで描画
      d.fill("transparent")
      borderWidth = [8 - depth, 1].max
      d.stroke_width(borderWidth)
      d.stroke("black")
      d.rectangle(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height)
      d.draw(graphic)
    end
  end
end

doRenderメソッドのgraphicはMagick::Imageオブジェクト、boundsはMagick::Rectangleオブジェクトになります。
d.fillで塗りつぶしの色を設定し、d.rectangleで四角の描画を行います。
あとd.stroke_widthで線の幅指定やd.strokeとかで線の色を指定したりしています。
そして最後にd.drawとすることで図形の元のMagick::Imageオブジェクトに図形の描画を行っています。
RMagickのメソッドの詳しい説明はこちらにあるので、細かいことはそちらをご覧ください。
ちなみに、元記事とライブラリなどは違いますが、プログラムの形式はほぼ同じになっているので、
元記事と比較しながら見れると思います。

デモプログラムの実行

プログラムのデモを行うDemoクラスは以下のようになります。

# Demo.rb
require 'rubygems'
require 'RMagick'
require File.dirname(__FILE__) + '/Visualization'

class Demo
  include Visualization
  
  OUTPUT_FILE_NAME = 'treemap.png'
  
  def run
    color = Struct.new(:red, :green, :blue)
    # ランダムな色データを100個作成
    input = []
    100.times do |i|
      c = color.new(rand(256), rand(256), rand(256))
      area  = 0.2 + 0.8 * rand
      input << ColorItem.new(c, area)
    end
    
    # Ward法に基づく階層的クラスタリングを準備
    evaluator = WardDistanceEvaluator.new
    builder = ClusterBuilder.new(evaluator)
    
    # クラスタリングを実行
    puts "クラスタリング開始(結構時間かかります)"
    result = builder.build(input)
    puts "クラスタリング終了"
    
    # クラスタリング結果を表示
    puts "画像生成開始"
    output(result)
    puts "出力ファイル:" + OUTPUT_FILE_NAME
  end
  
  def output(node)
    # 400x400ピクセルの画像を作成
    g = Magick::Image.new(400, 400)
    
    # グラフィックオブジェクトを作成
    d = Magick::Draw.new
    
    # 背景を白で塗りつぶす
    d.fill("white")
    d.rectangle(0, 0, g.columns, g.rows)
    d.draw(g)

    # ツリーマップの描画を実行
    renderer = BinaryTreeMapRenderer.new
    bounds = Magick::Rectangle.new(360, 360, 20, 20)
    renderer.render(g, node, bounds)
    
    # 画像をPNGファイルに保存
    g.write(OUTPUT_FILE_NAME)
  end
end

demo = Demo.new
demo.run

デモプログラムを実行すると、以下のような出力が得られます。

$ ruby Demo.rb 
クラスタリング開始(結構時間かかります)
100
99
98
97
96
95
...
5
4
3
2
クラスタリング終了
画像生成開始
出力ファイル:treemap.png

これで、treemap.pngという以下のような画像が出力されます。
ツリーマップによってクラスタリングの結果が視覚的にわかりやすく表現されていることがわかると思います。
ただし、入力データはランダムに作成しているので、出力される画像は毎回違うものとなります。

以上

今回はここまでです。
細かい部分はプログラムにコメントを書いてるんでそちらを読んでください。
あと、間違ってる部分などありましたら教えていただけるとありがたいです。
残りのプログラムについては次回以降説明します。