Tag Archive for 'visualization'

DokuWikiのタグクラウドをバックリンクにするパッチ

1行パッチなんですけど。

DokuWikiのtag pluginと、cloud pluginをあわせると、タグクラウドができます。 なんだけど、デフォルトではタグクラウドのリンク先が /tag/tagname へのPermaLinkとなってしまいます。そのタグを用いているページのリストが表示されてほしい、というのがよくあるケースなのではないでしょうか。

ということで、パッチを書きました。 tagcloud-backlinkpatch.zip

内容は、これだけのもの:

--- syntax.php.orig     2007-10-01 00:01:07.000000000 +0900
+++ syntax.php  2007-10-01 00:01:03.000000000 +0900
@@ -78,7 +78,7 @@
         if ($type == 'tag'){
           $id = $word;
           resolve_pageID($tag->namespace, $id, $exists);
-          $link = wl($id);
+          $link = wl($id, 'do=backlink');
           $title = $id;
           $class .= ($exists ? '_tag1' : '_tag2');
         } else {

$DOKUWIKI/lib/plugins/cloud にて、patch -p0 < tagcloud-backlink.patch みたいにしてあててください。

ApacheLogPatchを公開してみて

被ブックマーク数が2ケタを越えて自己最高記録を樹立するなど、思ったよりも反応をいただけたApacheLogPatchですが、公開してみて感じたことをメモしておきます。

リリースたいへん

アイデアを思いついて、がりがりとつくってきたものが、できたー! という時は最高に楽しいものです。

しかし、これをいざ公開するという段になると、

  • スクリーンショットとらなきゃ
  • スクリーンキャストもとらなきゃ
  • ライセンスってどうしたらよいんだろう
  • コードの汚い部分をマシに
  • 動作検証しなきゃ
  • リリースビルドにしなきゃ
  • パッケージにしなきゃ

なんていう複雑で雑多なタスクがあり、ちょっとめげます。これは仕事でもそう。 慣れてないことをするから敷居が高いのかも。

リリース段階になると、開発のときとは違う人格になるのがよさそうです。

Mac mini (PPC) きつい

うちのサーバは Mac mini (PPC) なのですが、今回みたいなアクセス数がきただけできついことになりました。スラッシングしてしまうのです。なんて貧弱。512MBもメモリを持っているというのに。170MBもfree領域があるというのに。 スラッシングしてしまうと、コンソールから入ることもできなくなってしまって困ります。

反応うれしい

とはいえ、redditとかはてブとかで参照されてるととてもうれしくなります。反応ドリブン開発。

プログラムと絵

ハッカーと画家 でも言われていた気がしますが、プログラムをつくっていくことと絵を描いていくことの共通点は、対象に手を入れることを止めたときが完成のときだ、というところです。この前みに行ったモネの大回顧展NHKの特集でも言われていたような。

とくにQuartzComposerの作品をつくるのは楽しくて、あ、ここはちょっとJavascriptで対数を使えばきれいにフェードできるんじゃない? とか、細かいところを調整しているとキリがありません。 もうここらでいいや! という見切りをどこでつけるかというところにその人のセンスが表われそうです。

インタラクション

僕を駆りたてるのは、インタラクションなのです。 打てばすぐ響いてほしい。

なぜ最近QuartzComposerにはまっているかというと、フィードバックがものすごい迅速だからです。パラメータをちょっと変えただけで敏感に反応してくれる。 Rubyのirbもそうで、なにかちょっと実験してみるとすぐ答えが得られる。 思いつく→やってみる→確かめる のループをどれだけ速く回せるか、が生産性にかかってくると思うわけです。

それに対して、Objective-Cでカスタムパッチを書いているときの生産性はものすごい低い。 デバッガを使えないのでpritnfデバッグをするしかない。打ってもすぐに響かず、やまびこのように聞こえる。

とか言ってたら組み込みの開発なんてできないんですけどね。


などと、まとまりなくつらつらと書き連ねてみました。 次はなにつくろう。

2007.07/11 22:53 追記

Google Analyticsを眺めていたら、自己最多アクセス数 (約400セッション、ユーザ) になっていたので記念にとっておきました。 2007.06/19頃にもひと山あるのですが、これはSocketReaderPatchのとき。どちらもオレンジニュース効果です。OrangeNewsed !

20070710-ganalytics.png

ApacheLogPatch

Apache の ログ を、リアルタイムに QuartzComposer で表示するものをつくりました。 tail -f /var/log/httpd/access.log の代わりにつかう、みたいな。

Download

httpd2qc package (Universal Binary, tested on Tiger)

Screencast

プライバシーをまもるために、リモートホストのIPアドレスは “xxx.xxx.xxx.xxx” にしています。実際にはばっちり表示されます。

Quick Start

  • ApacheLogPatch.plugin を、/Library/Graphics/Patches にコピー
  • Apacheの設定ファイル (httpd.conf とか) に、filter.rb へ カスタムログ を パイプするような設定を加える
    例:
      LogFormat "%h \"%{Referer}i\" %U" httpd2qc
      CustomLog "|/opt/local/httpd2qc/filter.rb" httpd2qc
  • ApacheLogDisplay.qtz を 開く
  • Apache を restart
  • 眺める

Detail

overview.png

  1. ApacheのカスタムログをパイプでRubyスクリプトに流しこむ
  2. Rubyスクリプト (filter.rb) は、文字列のURI デコードなどをして、QuartzComposerのカスタムパッチ用にデータをつくる (ここでもうちょっと賢いことができそう)
  3. QuartzComposerのカスタムパッチ (ApacheLogPatch) は、流れてきたデータをQCStructureのスロット (とりあえず3つ) に詰め込む

ApacheLogPatch は、QCStructureのオブジェクトを出力します。実際には、[リクエストパス、リモートホストのアドレス、リファラー、検索キーワード] の要素をもつQCStructure の配列になっています。

より詳しくはソースを。

ToDo

  • 背景に世界地図を描いておいて、ログが来たときにIPアドレスから地理情報を取得して、それらしき場所を点滅させる (IP2Location とかをつかえばよさそう)
  • もうちょっとカスタマイザブルに
  • もうちょっとかっこよく

きっかけ

Google本社では、検索キーワードがリアルタイムに画面を流れているのが見れるとか聞きました。僕が行ったときには、そんなディスプレイは見当たらなかったのだけれど。

せっかく自宅サーバをMacで動かしているのだし、なにか面白いことはできないもんかなー、と風呂でぼんやり考えていて、最近遊んでいる QuartzComposer の CustomPatch と組み合わせてみたら? と。

taskMap 0.1.0

cartesianTaskを公開してみます。 ほんとまだまだの出来なんですけれど、公開することに意味があると思うので。

既知のバグがたくさんあるので、多少のことには目をつぶれる寛容な方のみお試しください。

cartesiantask専用ページ → こちら

(x,y)の属性 → Note

どうやって(x,y)の値を保持するか? と考えた結果、各TaskのNoteを用いることにしました。

  • すべてのTaskに(taskMapX, taskMapY)という2つのタイトルのNoteを追加します。
  • taskMapを試して、もういいやと思ったら menu にある reset を押してください。

注意事項

  • 初回起動時がもの凄く遅い (すべてのTaskにNoteを加えるため)
  • resetがものもの凄く遅い (すべてのTaskからNoteをはぎとるため) 。タイムアウトしてしまうと、いくつかのTaskにNoteが残ったままになってしまう場合がある

懸念事項

すべてのTaskのNoteにアクセスを行うため、RTMから怒られるかもしれません。 RTM APIの注意事項には、平均して1秒間に1回のAPIアクセスにせよとあるので。

このへんは、0.2.0リリースあたりでうまく解決する予定です。

関連エントリ

追記

  • 公開してから6時間で22アクセス、少しでも試して頂いた人は2人。
  • 1日たち、69アクセス、試して頂いた人は12人。

cartesianTask

cartesianTask は、Remember the MilkのTaskを二次元座標にドラッグアンドドロップで配置することにより、重要度や緊急度をひとめで分かるようにするものです。

旧名称 : taskMap

紹介ビデオ

YouTube::cartesianTask introduction

更新情報

0.1.0 を公開しました。

免責

自分ではたくさんテストを行っていますが、いかんせん1人で行っているので漏れがあると思います。

TaskやListを消したりはしませんが、Noteのadd/deleteは行っています。 cartesianTaskの管理外のNoteは触れていませんが、万が一NoteやTask、Listが消失しても勘弁してください。

2007.05/26 追記

taskMapという名称は、商標登録されているとのことなので、名前を変更しました。 taskMap → cartesianTask

rtmProgress 復活

ここ数日、rtmProgressがダウンしていましたが、復活させました。

ダウンしていた理由は、rtmProgressがbackendで用いているrtmilkというライブラリのバージョンを0.3.0に上げたからです。rtmilk 0.3.0 では、それまでのバージョンとの互換性をぶったぎってしまったので、rtmProgressが動かなくなってしまっていたという不恰好な顛末でした。

rtmProgress : RTMの進捗状況を棒グラフで見える化

RTM Hackシリーズです。

今回は、RTMのUIではなかなか分かりづらいタスクの進捗状況を、棒グラフで見える化してみました。 いまのところ、期間は (今週/今月/今年) で切り替えることができます。

実装

  • サーバサイドのRubyスクリプトで全てのTaskをRTMから取得し、JSONフォーマットでブラウザに送信
  • ブラウザでタスクの範囲を絞りこんで、棒グラフを描画
  • 期間の切り替えはAjaxでさくっと

というシンプルなつくりです。

ToDo

  • 任意の範囲の進捗の表示
  • 認証の仕組みを実装して、リリース

自分がいまどこにいるのかが分かると、やる気が出ます。 「今週はこれだけやった!」みたいなものをぱっと見ることができればいいかな、と思ってつくってみました。

taskMap (2)

taskMap – Taskを2次元で可視化 の続き。

TaskMap 3

List一覧と、個々のListに応じた色付けをTaskに割り当てるようにしました。 これで、

  • 何のTaskが
  • どんな状態に

あるのかが分かるようになります。 ある色のTaskが多いと、なにかの種類に行動が偏っているとかいうのが一目瞭然。 自分でちょこちょこ試してみているのですが、なかなか便利です。

だいぶ公開できるレベルになってきているので、もうすぐソースごと公開しようと思います。

flow

  1. RTMからList一覧を取得
  2. Listの各要素に対して、Taskのリストを取得
  3. Taskのリストを並べる

内部のつくり

Model

  • RTMのAPI を用いて、List/Taskのデータを取得
  • 独自のパラメータ (x, y) をローカルでSQLiteを用いて管理
  • RTMと独自のパラメータとは、RTMのidを通して同期

View

  • Yahoo UI をつかったDragDrop

Controller

  • Railsなんて使わない生CGI
  • DragDropのendDragイベントのタイミングで、(x, y) の値をサーバに送信 -> サーバでDBにstore

ToDo

  • デモのScreenCast を撮る (どうやったらいいんだろう)
  • 公開

メモ

これからのWeb2.0時代では、データが重要なんだってよく言われるけれど、 そのデータを活かすのがViewだと思います。 たしかに、Modelはすごい勢いで充実してきているし、それを公開するAPIもじゃんかじゃんか出てきていますが、Viewが著しく貧弱だと思うのです。 ブラウザのDivなんかによる矩形表示やリスト表示だけなんてナンセンスだと。 もっといろんなViewの可能性を求めて、ひとに優しいUIをつくりたいなとか。


しかし眠いのです。

taskMap – Taskを2次元で可視化

Remember the Milk のTaskデータを、2次元座標にプロットするアプリを書いています。

taskMap

↑こんなかんじ。

以前つくった、rtmilk というRubyライブラリを用いてRTMからTaskデータをひっぱってきて、Ajax風にブラウザに表示しています。Drag&Dropすることで、Taskの属性を変えることもできます。

DragDrop、Ajax、LoggerなんかはYahooUI libraryを使っています。フレームワークはとっつきにくいけれど、一度慣れてしまうとrawで書くよりも便利。

なぜ二次元で表示しているかというと、単純なリストでは全体を把握しづらいから。 現在は、横軸に”"価値”"、縦軸に”"タイムリミット”"を割り振っています。これは、定時に帰る仕事術 や他のいろんな本でも用いられている形式。 右下のところにいつまでもいるTaskは、爆弾になる可能性があるので注意、ってやつです。

まだプロトタイプができたところなのでデモもありませんが、これからもちょこちょことつくり続けていこうと思っています。早くリリースできるといいな。

Hikiでタグクラウド

Rubyで書かれているWikiエンジンであるHikiで、タグクラウドを実現するプラグインを書きました。

ダウンロード

CodeRepos

背景

やっぱりカテゴリよりもタグの方が手軽です。 HIkiにはもともとキーワードというタグのような機能があったので、これを利用できないかと思い、keywordプラグインを使ってみたところ、ほぼ期待通りのことができて小躍りしていました。

んじゃせっかくだし、タグクラウド (tag cloud) みたいな表示もできないかな、とkeywordプラグインを改造してみました。フォントサイズのアルゴリズムなんかは、blosxomでのタグクラウド実装の1つであるBLOGGING IS FUTILE : Blosxom plugin tagging を参考にしました。

ライセンスは、Hiki及びBlosxom plugin taggingに従って、GPL v2以降です。

ソースは続きにて。

ソース

# show keywords like tag-cloud
# Licensing: GPL v2 or newer, http://www.gnu.org/licenses/gpl.txt
 
#
# Original:
# $Id: keyword.rb,v 1.5 2005/09/30 11:45:49 fdiary Exp $
# Copyright (C) 2003 TAKEUCHI Hitoshi &lt;hitoshi@namaraii.com&gt;
 
THRESHOLD = 1
MAX = 156
MIN = 32
 
def keyword_cloud(*key)
  # sort by category
  list = keywords(*key).to_a.sort {|a,b| a[0].downcase &lt;=&gt; b[0].downcase}
 
  max = 1
  min = 0
  list.each do |j|
    sz = j[1].size
    next if sz &lt; THRESHOLD
 
    max = sz if sz &gt; max
    min = sz if sz &lt; min
  end
 
  diff = max - min
 
  s = ''
  list.each do |j|
    sz = j[1].size
    next if sz &lt; THRESHOLD
 
    category = j[0]
    p = j[1]
 
    fts = MIN + (((MAX-MIN)/diff.to_f) * (sz-min+1))
 
    ## for debug
    # s &lt;&lt; "&lt;h4&gt;"
    # s &lt;&lt; [sz, max, min, MIN, (MAX-MIN), diff, (MAX-MIN)/diff.to_f, (sz-min+1), fts].join(', ')
    # s &lt;&lt; "&lt;/h4&gt;"
 
    s &lt;&lt; "&lt;span id='tag' style='font-size:#{fts}%'&gt;#{view_title(category)}&lt;/span&gt; "
  end
 
  s
end
 
def keywords(*keyword)
  keyword.collect! {|a| a.unescapeHTML}
 
  key = Hash::new
  @db.page_info.each do |info|
    next unless info.values[0][:keyword]
    info.values[0][:keyword].each do |k|
      if keyword.size == 0 || keyword.index(k)
        key[k] = [] unless key[k]
        key[k] &lt;&lt; info
      end
    end
  end
  key
end
 
def keyword_entries_n(pages)
    p = j[1]
 
end
 
export_plugin_methods(:keyword_cloud)