d4i.log

作ったものなど

CSS と jQuery によるアコーディオンメニュー

 小ネタです。

 CSSjQuery でシンプルなアコーディオンメニューを作ってみました。

デモ

 上と同じもの

jQueryクックブック

jQueryクックブック

Ruby on Rails で Oauth を使う

 Ruby on Rails 4 で Oauth 認証するときにやったことの自分用メモ。

 主に RailsCasts を参考に OmniAuth による Twitter 認証を実装してみました。

f:id:d4i:20130909212839p:plain

手順


アプリの登録

 プロバイダ (今回は Twitter) に自分のアプリを登録しておきます。
 例えば、ローカルのマシンで開発してる場合は下記のように適当に。

Website: http://127.0.0.1:3000/
Callback URL: http://127.0.0.1:3000/auth/twitter/callback

 加え、 Consumer key と Consumer secret の値を控えておきます。

Rails アプリ作成
$ rails new demo
$ cd demo
$ rails g controller sessions
$ touch app/views/sessions/index.html.erb
$ rails g model user provider uid name
$ rake db:migrate
/Gemfile

 OmniAuth は Oauth 認証に、 Figaro は後述のキーの管理に使用します。

gem 'omniauth-twitter'
gem 'figaro'
bundler
$ bundle install
キーの管理

 Consumer key と Consumer secret は Git の外の YAML で管理します。

$ rails g figaro:install
/config/application.yml

 控えた Consumer key と Consumer secret を記述 (下記例は架空のもの) 。

TWITTER_KEY: 7381a978f7dd7f9a1117
TWITTER_SECRET: abdc3b896a0ffb85d373
/config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
/config/routes.rb
root 'sessions#index'

get '/auth/:provider/callback' => 'sessions#create'
delete '/signout' => 'sessions#destroy', as: :signout
/app/controllers/sessions_controller.rb
def create
  auth = request.env["omniauth.auth"]
  user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
  session[:user_id] = user.id
  redirect_to root_url, :notice => "Signed in!"
end

def destroy
  session[:user_id] = nil
  redirect_to root_url, :notice => "Signed out!"
end
/app/controllers/application_controller.rb
helper_method :current_user

private

def current_user
  @current_user ||= User.find(session[:user_id]) if session[:user_id]
end
/app/models/user.rb
def self.create_with_omniauth(auth)
  create! do |user|
    user.provider = auth["provider"]
    user.uid = auth["uid"]
    user.name = auth["info"]["name"]
  end
end
/app/view/layouts/application.html.erb
<% if current_user %>
  Welcome <%= current_user.name %>!
  <%= link_to "Sign Out", signout_path %>
<% else %>
  <%= link_to "Sign in with Twitter", "/auth/twitter" %>
<% end %>

 これで完了です。

テスト


WEBrick 起動
$ rails s
ブラウザからアクセス

認証前

f:id:d4i:20130909214205p:plain

Twitter 認証

認証後

f:id:d4i:20130909214233p:plain

できた! (はず)

WEB+DB PRESS Vol.73

WEB+DB PRESS Vol.73

  • 作者: 設樂洋爾,白土慧,はまちや2,大和田純,松田明,後藤大輔,ひろせまさあき,小林篤,近藤宇智朗,まかまか般若波羅蜜,Mr. O,川添貴生,重国和宏,柳澤建太郎,奥野幹也,佐藤鉄平,後藤秀宣,mala,中島聡,堤智代,森田創,A-Listers,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/02/23
  • メディア: 大型本
  • 購入: 12人 クリック: 131回
  • この商品を含むブログ (4件) を見る

D3.js で Word Clouds

 Wordle ライクに Word Clouds を描きたいなーと思い、D3Word Cloud Layout を試してみました。

f:id:d4i:20130831013322p:plain

データの準備


 とりあえず 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.jsd3.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 は JavaScriptCSS で小回りが効くので、可視化を美しくするポテンシャルがあるなーと思います。

Getting Started With D3

Getting Started With D3

静的 Web サイトを GitHub に

 GitHub Pages で。

f:id:d4i:20130909220839j:plain

手順


  1. GitHub のアカウントを用意します。

  2. (username).github.io という名前でリポジトリを作ります。

  3. 作ったリポジトリに index.html を加えます。

 以上です。簡単!

応用例


 筆者の作ったサイトはこちら

 背景は Flat Surface Shader で、フォントは Google Fonts で作ってます。最初は Octopress で出力するブログを deploy してたんですけど、更新が面倒くさそうだったので今のような1枚絵にしました。

 リポジトリごと管理できるのが便利で良いですね~。

WEB+DB PRESS Vol.69

WEB+DB PRESS Vol.69

  • 作者: 大塚弘記,渡辺修司,堤智代,森田創,中島聡,A-Listers,はまちや2,川添貴生,井上誠一郎,近藤宇智朗,ヒノケン,後藤秀宣,佐藤鉄平,mala,奥野幹也,伊藤智章,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2012/06/23
  • メディア: 大型本
  • 購入: 13人 クリック: 143回
  • この商品を含むブログ (18件) を見る