RubyでPubMedの論文を検索して、国別グラフをつくる

![Nature_communications.png](https://qiita-image-store.s3.amazonaws.com/0/144608/a6a3f7ea-b7b4-c4b2-2e0a-a485ff99bda3.png)


事前準備：

 - [BioRuby](https://github.com/bioruby/bioruby) のインストール。
 - グラフを描出したい場合は、[gnuplot](http://www.gnuplot.info) にパスを通して、[numo-gnuplot](https://github.com/ruby-numo/numo-gnuplot) をインストール

```terminal
gem install bio
gem install numo-gnuplot # グラフ描出
```

# Ruby で PubMed を検索する
この BioRuby を用いて [PubMed](https://www.ncbi.nlm.nih.gov/pubmed/) を検索します。国別グラフはおまけです。
BioRuby で PubMed を検索する方法はいくつかあるようですが、

```ruby

require 'bio'
ids = Bio::PubMed.esearch('検索したい文字列')
# Array を返す
```

とすると最大100件まで結果を返してくれます。

pubmed id から文献情報を取得する場合は、

```ruby
string = Bio::PubMed.efetch(pubmed_id)
# 引数は配列でも大丈夫
string_array = Bio::PubMed.efetch([id1,id2,id3])
```
などとします。

# 文献情報を扱うMEDLINEクラス
このままでは文字列の情報なので、MEDLINEクラスに入れます。
もっともこのようなクラスを用いず WebAPI から取得する方法の方が現代的なのかもしれませんが、今回は BioRuby を使用しているので、古典的な方法にのっとってやることにします。

```ruby
# PubMed ID の検索 (ここではBioRubyに関する論文を検索）

ids = Bio::PubMed.esearch('BioRuby')
# 新着順で100件まで結果が返ってくる
# => ["25431153", "23749959", "22994508", "22399473",
#     "20739307", "20015970", "14693808"]

# ID から書誌情報の取得
bibinfo = Bio::PubMed.efetch(ids)
bibinfo.class # string

# 文字列をMEDLINEクラスのオブジェクトにパース
medlines = bibinfo.map { |str| Bio::MEDLINE.new(str) }

# 情報が取り出しやすい
medlines[4].title
# => BioRuby: bioinformatics software for the Ruby programming languag
medlines[4].au
# Goto N Prins P Nakao M Bonnal R Aerts J Katayama T
puts medlines[4].ad
# Department of Genome Informatics, Genome Information Research Center, Research Institute for Microbial Diseases, Osaka University, Japan.
```

# おまけ：国別ランキングを作ってみる
　せっかくなので、NatureMedicine とPLoS one の直近100報について、作者の国を集計して棒グラフ化してみます。国名は、表記のブレや、データの例外のようなものがどうしても混入するので、きちんと情報を洗って集計するのは大変だと思いますが、適当に傾向を見るだけなら下のようないい加減なスクリプトでもできると思います（ある程度は）。

![Nature_Medicine.png](https://qiita-image-store.s3.amazonaws.com/0/144608/9c442413-703b-75c1-2644-add1c961ce11.png)
　Incとか、Ltdが国名に混ざってしました。USA や UK などは多様な表記のブレがあるので更に増える可能性があります。ちなみに Incはほとんどアメリカです。日本からは DeNA Life Science, Inc が入っています。otherはNature編集部の記事のようです。


![PloS_one.png](https://qiita-image-store.s3.amazonaws.com/0/144608/55aa2728-188d-feb4-a2fc-8caa0a28a0a8.png)
　PloS Oneです。こちらのほうが、より正確に人材の力を反映しているような気もしますね。実際には USA は表記のばらつきがあったり、UK は United Kingdam など表記も数件存在するのでさらに増えて Germanyに近くなります。よくみるとオランダが２つあります。Koreaがありませんが、korea(9)とRepublic of Korea(9) の書き方があって、足し合わせると(18)となってNorway と同じ位置にきます。

　いずれにしろ、国別グラフはおまけでして、直近100報なのでかなり偶然に左右されていると思います。

### スクリプト
irb や pry だとgnuplotがうまくいかない場合があるので、ファイルに保存してから実行。

```ruby
require 'bio'
require 'numo/gnuplot'


journals = [
  "Nature Medicine",
  "PloS one"
]

journals.each do |journal_name|

  pubmed_ids = Bio::PubMed.esearch('"' + journal_name + '"[journal]')
  data = Bio::PubMed.efetch(pubmed_ids).map do |str|
    Bio::MEDLINE.new(str)
  end

  count = Hash.new(0)
  
  data.each do |item|
    item.ad.each do |ad|
      country = ad[/(?<=,\s)[^,\.]*(?=\.)/].strip
      if country == ""
        country = "other"
      elsif country == "Inc"
        puts ad
      end
      count[country] += 1
    end
  end

  country, number = count.sort_by{ |_, c| -c }.transpose

  Numo.gnuplot do
    set title: journal_name
    set terminal: 'png'
    set output: journal_name.gsub(" ", "_") + ".png"
    set boxwidth:0.5
    set 'grid'
    set yrange:[0..(number.max + 50)]
    set xtics: 'rotate by 315'
    set style:[fill: 'solid']
    plot country[0...20], number[0...20], using:[2, 'xtic(1)'], w:'boxes', t:'ad', lc:'rgb "web-green"'
  end

end
```

# おわりに

Ruby で PubMed を検索する方法を示しました。 
PubMedは巨大なデータベースであり、維持には大変な資金と労力がかかっているという噂を聞きます。中の人は大変なのかもしれませんが今後とも無償で利用できるように頑張ってもらいたいものです。一方で [bioRxiv](https://www.biorxiv.org) などプレプリントの論文や、[中国語の論文](https://xueshu.baidu.com/usercenter/data/journal)なども大切な時代に入ってきているのかもしれません。そういった方面も簡単に検索できる方法があったら便利だと思いました。