2017年06月16日(金)

DIYスクリプティング

投稿者: 山下征輔

東大富田研の山下です。最近、結晶化実験に対してRを用いたラボハックを試み、ささやかな達成感を得られたので紹介させていただきます。

私たちの研究室の主要な実験手法のひとつはX線結晶構造解析です。なにはなくとも生体高分子(タンパクなど)の結晶が必要で、結晶ができるかどうかが主要課題です。結晶は精製したサンプルを沈殿剤と混ぜて溶解度を下げ、析出させることで作成します。タンパクは別にきれいだから結晶になるわけではなく、不定形に沈殿するよりも周期的に並んだ状態(=結晶)のほうが自由エネルギー的に有利になりやすい、という現実的な理屈がそこにはあります。とはいえ分子のフレキシビリティや安定性などとの兼ね合いもあるので単純に成否を判断することはできません。むしろ結晶化予測に関してはいまだに人知はおろか計算機でも及ばず、数多くの沈殿剤条件(pH, 沈殿剤や添加する塩の種類や濃度)を試して良いものを探るというスクリーニング実験が必須となっています。

スクリーニング実験を効率よく簡便に行うために、あらかじめ沈殿剤やbuffer、塩がmixされた溶液のセット(キット)がいくつかの会社から販売されています。私たちのラボではこれらのキットを使い、数百通りの沈殿剤についてタンパク質溶液と混ぜ合わせて結晶化を試みています。幸運にも結晶が得られたらその写真と沈殿剤条件を対応付けて整理し、よりよい結晶の調製を目指します。ここで結果をまとめる際に、今まではメモをとりながら結晶写真を集めたあと、机に戻ってパワポに画像を張り付けつつ結晶化条件を手入力(or コピペ)していました。これでも悪くはないのですが、ヒューマンエラーで写し間違えたり、数が多いと手間がかかったりします。しかし自分でプログラミングして省力化するという発想は無く、これまで手作業を続けてきました。そんな状況ではあったのですが、Rを試しているときにふと、”なんだこれならできるな。”と思いたち、スクリプトを実装してみることにしました。

R以外の私のプログラミング経験としては、学部時代に生物情報科学学部教育特別プログラムでJavaを学んだり、その後少しだけ(2日くらい)pythonを触ったりしたことはあるものの、実用としてはごく簡単なシェルスクリプトを作成するくらいでした。そう思うと10年と少し前にJavaを教えていただいた先生方に申し訳ない気もしてきます。かなり勉強になったので改めて御礼申し上げます。

さて、まず、コマンドラインで完結するスクリプトの作成に取り組みました。
“Rで結晶写真の画像ファイルを読み込ませ、結晶化条件と対応づけて出力する。”
ことを目指します。ほぼ全てにおいて、できるであろうことはわかるが具体的なやり方はわからない、というスタートではありましたが、多くの方々のネット上の知恵を切り貼りして形を整えていきました。

画像ファイルはjpegパッケージを導入して、readJPEGで読み込みます。複数の画像を一つのフォルダにまとめてlist.filesでリストアップし、for文の中で順番に処理をするようにしました。

出力に関してはR2PPTというパッケージでRからパワポを操作し、.pptx形式で保存するようにしました(参考: http://datasciesotist.hatenablog.jp/entry/2016/07/01/005536)。資料に適するようにパワポのテンプレートファイルも別途作成しておきます。

沈殿剤条件との対応については、画像ファイルの名前を利用するようにしました。すなわち、ファイル名の1-3文字目を沈殿剤キットの名前、5-6文字目を96wellに対応した番号とし、サンプル名はその後に記述するというmyルールにしました。

沈殿剤条件を参照できるように、各メーカーからダウンロードしてきた組成のファイルをエクセルで調整して、1列目にキット(プレート)の名前、2列目に01から96までの番号、3列目に組成を羅列したcsvファイルを作成しました。

ここまである程度個別に挙動の確認を済ませて、事前準備として画像ファイル、csvファイルのフォルダ、pptテンプレートファイルのフォルダを一つのフォルダにまとめておきました。この状態で動作するようにスクリプトを並べたものが以下です。

#script_for_pptfiles.R
install.packages("jpeg")
install.packages("png")
install.packages("R2PPT")
install.packages("RDCOMClient")
library(jpeg)
library(png)
library(R2PPT)
library(RDCOMClient)

setwd("~/R/xxxx") #いろいろまとめたフォルダの場所

csvfilelist <- list.files("./csvfiles", pattern = ".csv", full.names = T)
table <- data.frame()
for(i in 1:length(csvfilelist)){
add <- read.csv(csvfilelist[i], header = F, colClasses ="character")
table <- rbind(table,add)
}

jpgfilelist <- list.files(".", pattern = ".jpg")

myPPT<-PPT.Init(visible=T,method="RDCOMClient")
myPPT<-PPT.ApplyTemplate(myPPT, file= "./ppt_template/ppt_template_for_R.potx")

for (i in 1:length(jpgfilelist)){
 dftmp <- table[table$V1 == substr(jpgfilelist[i],1,3) & table$V2 == substr(jpgfilelist[i],5,6),]
 kakuchoshinashi <- gsub("¥¥..+$", "", as.character(jpgfilelist[i]))
 myPPT<-PPT.AddTextSlide(myPPT,title=kakuchoshinashi,text=dftmp[1,3],text.font="Arial", title.fontsize = 16, text.fontsize = 12)
 image <- readJPEG(jpgfilelist[i])
 tate <- dim(image)[1]
 yoko <- dim(image)[2]
 myPPT<-PPT.AddGraphicstoSlide(myPPT,file=jpgfilelist[i], size=c(10,160,200,tate*200/yoko))
 }

myPPT<-PPT.SaveAs(myPPT, file = "output_ppt.pptx")

実行すると、図のようなパワポファイルが出力されます。1スライドにつき結晶写真1枚としてあるので、適当にカット&ペーストで並べ替えて整えます。それなりに人の手を入れる必要はありますが、スタート地点としては悪くないでしょう。


これでひとまずの目的は達成できたのですが、せっかくなので周りにも使ってもらいたいと欲が出てきます。資料作成係になるのは避けたいです。そこでGUIも実装することにしました。ざっと調べてみたところshinyというパッケージが今風のデザインで、使い方もネットに充実していたのでこれにします。詳細は省きますがapp.Rとして以下のファイルを作成しました。事前にjpeg, png, R2PPT, RDCOMClient, shinyをそれぞれinstall.packages()でインストールしておき、RStudioのRun Appボタン(緑の三角)から起動します。

#app.R
library(jpeg)
library(png)
library(R2PPT)
library(RDCOMClient)
library(shiny)

server <- function(input, output) {

 csvfilelist <- list.files("./csvfiles", pattern = ".csv", full.names = T)
 table <- data.frame()
 for(i in 1:length(csvfilelist)){
  add <- read.csv(csvfilelist[i], header = F, colClasses ="character")
  table <- rbind(table,add)
 }

observeEvent(input$button01, {
 jpgfilelist <- input$file1
 pngfilelist <- input$file2

 if(is.null(jpgfilelist) && is.null(pngfilelist)){
 } else {
  myPPT<-PPT.Init(visible=T,method="RDCOMClient")
  myPPT<-PPT.ApplyTemplate(myPPT, file= "./ppt_template/ppt_template_for_R.potx")
 }

 if(is.null(jpgfilelist)) {
 } else {
  for (i in 1:length(jpgfilelist[,1])){
   dftmp <- table[table$V1 == substr(jpgfilelist[i,1],1,3) & table$V2 == substr(jpgfilelist[i,1],5,6),]
   kakuchoshinashi <- gsub("¥¥..+$", "", as.character(jpgfilelist[i,1]))
   myPPT<-PPT.AddTextSlide(myPPT,title=kakuchoshinashi,text=dftmp[1,3],text.font="Arial", title.fontsize = 16, text.fontsize = 12)
   image <- readJPEG(jpgfilelist[i,4])
   tate <- dim(image)[1]
   yoko <- dim(image)[2]
   myPPT<-PPT.AddGraphicstoSlide(myPPT,file=jpgfilelist[i,4], size=c(10,160,200,tate*200/yoko))
  }

  if(is.null(pngfilelist)) {
  } else {
   for (i in 1:length(pngfilelist[,1])){
   dftmp <- table[table$V1 == substr(pngfilelist[i,1],1,3) & table$V2 == substr(pngfilelist[i,1],5,6),]
   kakuchoshinashi <- gsub("¥¥..+$", "", as.character(pngfilelist[i,1]))
   myPPT<-PPT.AddTextSlide(myPPT,title=kakuchoshinashi,text=dftmp[1,3],text.font="Arial", title.fontsize = 16, text.fontsize = 12)
   image <- readPNG(pngfilelist[i,4])
   tate <- dim(image)[1]
   yoko <- dim(image)[2]
   myPPT<-PPT.AddGraphicstoSlide(myPPT,file=pngfilelist[i,4], size=c(10,160,200,tate*200/yoko))
  }
 }
 myPPT<-PPT.SaveAs(myPPT, file = input$text1)
 }})
}

ui <- fluidPage(
 headerPanel('.ppt from photos'),
 hr(),
 hr(),
 fileInput('file1', 'Choose jpg Files',
  accept = c('image/jpeg'), multiple = T ),
 hr(),
 fileInput('file2', 'Choose png Files',
  accept=c('.png'), multiple = T ),
 textInput("text1", label = h4("file name")),
 textOutput("textOut01"),
 hr(),
 actionButton("button01", label="submit!")
)

shinyApp(ui = ui, server = server)

起動に成功すると、
Listening on http://127.0.0.1:xxxxなど
と表示された後、ブラウザで図2のようなGUIが立ち上がります。
(http://127.0.0.1:xxxxは自分自身を指すアドレスなので、公開されるわけではありません。)

jpgあるいはpngのファイルをアップロードして、出力のファイル名を入力した後にsubmit!ボタンを押すと、先ほどと同様にpptファイルが保存されます。これなら画像ファイルの保存先や出力ファイルの名前などに融通が利きますし、先ほどよりも使用にあたっての敷居を低くできたと思います(管理するための敷居が上がってしまったのは痛し痒しです)。

このあともう一段上の利便性を目指して、shinyのスクリプトをひとつのアプリケーションとして実行できるRInno(https://ficonsulting.github.io/RInno)というソフトを試してみたのですが、残念ながらうまくいきませんでした。トラブルはPCによって起動できたりできなかったりするというもので、RInno開発者のHPでも同様の例がいくつか報告されていました。なのでいったん一区切りにすることにして、fixされたらまた取り組んでみたいと思っています。

今回のスクリプトはささやかなものですが、自分でこれをしたい、と思ったことを実現できた点はなかなか満足です。率直な感想として、NGSに比べれば今回のようなことのほうがよほど直感的でやりやすいですし、ラボハックなら数日で結果を得られてお手頃です。日々の実験のなかでなにか省力化できそうな作業に心当たりがある方は、ぜひぜひトライしてみてください。

ブログアーカイブ

ログイン

サイト内検索