#はじめに
シリース第6回です。
PDB形式のタンパク質立体構造データをもとに、タンパク質の立体構造モデルをSketchUpで作成するのがテーマのシリーズです。前回までに一応タンパク質の構造が作れるようになったということで、今回はDNAを描画する番外編です。
今回のデータは、MMDB ID:71816
のデータです。NCBIのサイトから入手しました。データは逆転写酵素と二本鎖DNAの複合体です。従ってファイルにはDNAのデータとタンパク質のデータが両方含まれています。
タンパク質の立体構造をSketchUpでモデル化 その1
タンパク質の立体構造をSketchUpでモデル化 その2【アミノ酸の側鎖を描画】
タンパク質の立体構造をSketchUpでモデル化 その3【アミノ酸の側鎖も含めて描画】
タンパク質の立体構造をSketchUpでモデル化 その4【主鎖を立体に】
タンパク質の立体構造をSketchUpでモデル化 その5【玉の描画】
タンパク質の立体構造をSketchUpでモデル化 その6【ついでにDNAをモデル化】
タンパク質の立体構造をSketchUpでモデル化 その7【最終回】
#DNAの部分のデータ
例えば塩基がTである2つ目のヌクレオチドの構造は以下のように書かれています。
だいたいタンパク質の時と同じですね。
3番目のカラムは、元素記号 + 原子番号
4番目のカラムは、塩基(A、C、G、T)の別
5番目のカラムは、ストランド名
6番目のカラムは、何番目のヌクレオチドか
のようです。
ATOM 18 P T E 2 9.972 44.770 14.327 1.00100.00 P
ATOM 19 O1P T E 2 9.051 43.878 13.567 1.00100.00 O
ATOM 20 O2P T E 2 9.454 46.055 14.876 1.00100.00 O
ATOM 21 O5* T E 2 10.567 43.941 15.554 1.00100.00 O
ATOM 22 C5* T E 2 11.045 42.603 15.396 1.00 99.64 C
ATOM 23 C4* T E 2 10.346 41.683 16.372 1.00100.00 C
ATOM 24 O4* T E 2 10.332 42.346 17.664 1.00100.00 O
ATOM 25 C3* T E 2 8.882 41.384 16.042 1.00100.00 C
ATOM 26 O3* T E 2 8.562 39.978 16.160 1.00100.00 O
ATOM 27 C2* T E 2 8.076 42.336 16.911 1.00100.00 C
ATOM 28 C1* T E 2 9.002 42.679 18.075 1.00100.00 C
ATOM 29 N1 T E 2 8.991 44.121 18.467 1.00 99.19 N
ATOM 30 C2 T E 2 7.775 44.797 18.591 1.00 95.98 C
ATOM 31 O2 T E 2 6.681 44.274 18.411 1.00 90.58 O
ATOM 32 N3 T E 2 7.896 46.128 18.937 1.00 93.91 N
ATOM 33 C4 T E 2 9.068 46.835 19.169 1.00 95.09 C
ATOM 34 O4 T E 2 9.019 48.031 19.460 1.00 92.11 O
ATOM 35 C5 T E 2 10.290 46.067 19.037 1.00 96.38 C
ATOM 36 C5M T E 2 11.601 46.745 19.283 1.00 95.47 C
ATOM 37 C6 T E 2 10.191 44.771 18.697 1.00 97.99 C
O1P、O2Pはリン酸基についた酸素原子、O5は5'の炭素原子の隣の酸素原子、O4はC4(そしてC1の)隣の炭素原子、ですね。 N1からC6までは塩基チミンの元素のはずです。各元素の番号はwikipediaを参照したらわかりました。
#DNAの結合情報の整理
シリーズ第3回と同じように、データを整理します。以下のようになりました。index 2と5のデータが、バックボーンです。
nucleotidesAndBonds = {
"A" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N9","C8","N7","C5","C6","N1","C2","N3","C4","N9"],["C4","C5"],["C6","N6"]],#A
"G" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N9","C8","N7","C5","C6","N1","C2","N3","C4","N9"],["C4","C5"],["C6","O6"],["C2","N2"]],#G
"C" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N1","C2","N3","C4","C5","C6","N1"],["C2","O2"],["C4","N4"]],#C
"T" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N1","C2","N3","C4","C5","C6","N1"],["C2","O2"],["C4","O4"],["C5","C5M"]],#T
}
アミノ酸の時は、主鎖と側鎖に分けて作成しました。これは主鎖だけを、色を塗るなどして表示できるようにしたかったからですが、これはDNAについても同じです。
##バックボーンデータを集める
#DNAのバックボーンデータを整理
strands = []
strandIdentity = ""
for line in lines
dataInLine = line.split
if dataInLine[0] == "ATOM"
if strandIdentity != dataInLine[4]
points = []
strands.push(points)
strandIdentity = dataInLine[4]
end
if ["P","O5*","C5*","C4*","C3*","O3*","P"].include?(dataInLine[2])
points.push(Geom::Point3d.new(dataInLine[6].to_f, dataInLine[7].to_f, dataInLine[8].to_f))
end
end
end
各モノマーのデータの整理
#A C G T関連の側鎖データをキープ
# hashを使用。ヌクレオチド_strand_ DNA番号をkey、配列をvalueにする。配列は行全体を要素とする。
nucleotidesAndLines = Hash.new{ |hash, key| hash[key] = [] }
for line in lines
dataInLine = line.split
if dataInLine[0] == "ATOM" and ["A","C","G","T"].include?(dataInLine[3]) then
key = dataInLine[3..5].join("_")
nucleotidesAndLines[key].push(line)
end
end
コード全体
# DNA用
#モデルを取得
model = Sketchup.active_model
entities = model.active_entities
#ファイルを読み込む
lines = IO.readlines("/Users/yoho/Downloads/mmdb_1D0E.pdb")
# 立体的なストランドを追加するメソッド。ストランドの半径と色を指定
def addStrand(strand,r,color)
model = Sketchup.active_model
entities = model.active_entities
strandEdge = entities.add_edges(strand)
#circleを追加する。
vector = strand[0] - strand[1]
circleEdges = entities.add_circle(strand[0], vector , r)
#円をfaceに変換。
face = entities.add_face(circleEdges)
#faceにフォローミーツールを適用
face.followme(strandEdge)
#ストランドに色を付ける。entitiesの中から、フォローミーに使ったFaceの中心座標を含むFaceを探す。
for x in entities #監修 @scivola 先生
next unless x.typename == "Face"
result = x.classify_point(strand[0])
next unless result == Sketchup::Face::PointInside
connected_entities = x.all_connected
for y in connected_entities
y.material= color if y.typename == "Face"
end
end
end
#使用する色のリスト
colors = ["SpringGreen","SlateBlue","MediumVioletRed","MediumBlue","Lime","LightSeaGreen","Indigo",
"Green","Gold","DodgerBlue","DarkOrchid","Crimson","Coral","RoyalBlue"]
#DNAのバックボーンデータを整理
strands = []
strandIdentity = ""
for line in lines
dataInLine = line.split
if dataInLine[0] == "ATOM"
if strandIdentity != dataInLine[4]
points = []
strands.push(points)
strandIdentity = dataInLine[4]
end
if ["P","O5*","C5*","C4*","C3*","O3*","P"].include?(dataInLine[2])
points.push(Geom::Point3d.new(dataInLine[6].to_f, dataInLine[7].to_f, dataInLine[8].to_f))
end
end
end
#主鎖を描画edgeとして、追加
colorIndex = 0
for strand in strands
next unless strand.size >=2
addStrand(strand,0.1,colors[colorIndex%14])#立体的にしないなら entities.add_edges(strand)
colorIndex += 1
end
#A C G T関連の側鎖データをキープ
# hashを使用。ヌクレオチド_strand_ DNA番号をkey、配列をvalueにする。配列は行全体を要素とする。
nucleotidesAndLines = Hash.new{ |hash, key| hash[key] = [] }
for line in lines
dataInLine = line.split
if dataInLine[0] == "ATOM" and ["A","C","G","T"].include?(dataInLine[3]) then
key = dataInLine[3..5].join("_")
nucleotidesAndLines[key].push(line)
end
end
nucleotidesAndBonds = {
"A" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N9","C8","N7","C5","C6","N1","C2","N3","C4","N9"],["C4","C5"],["C6","N6"]],#A
"G" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N9","C8","N7","C5","C6","N1","C2","N3","C4","N9"],["C4","C5"],["C6","O6"],["C2","N2"]],#G
"C" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N1","C2","N3","C4","C5","C6","N1"],["C2","O2"],["C4","N4"]],#C
"T" => [["P","O1P"],["P","O2P"],["P","O5*","C5*","C4*","C3*"],["C3*","C2*","C1*"],["C4*","O4*","C1*"],["C3*","O3*"],["C1*","N1","C2","N3","C4","C5","C6","N1"],["C2","O2"],["C4","O4"],["C5","C5M"]],#T
}
# DNAを描画
nucleotidesAndLines.each{|key,value|
#最初の行を分割したアレイのindex 3からヌクレオチド名を取得
symbol = value[0].split[3]
#それぞれの行にあるATOMの名前と、座標をHashにしまう。
atomsAndCoordinates = Hash.new
for x in value
data = x.split
atomsAndCoordinates[data[2]] = Geom::Point3d.new(data[6].to_f, data[7].to_f, data[8].to_f)
end
#ヌクレオチドごとに、描画すべき結合を、edgeとして追加する。
#原子情報が欠けている場合があるので、bondsから2つずつ取り出して、対応する座標データが両方得られる場合に限って、edgeを追加する。
list = nucleotidesAndBonds[symbol]
for bonds in list
for index in 0..bonds.size - 2 do
atomA = atomsAndCoordinates[bonds[index]]
atomB = atomsAndCoordinates[bonds[index+1]]
if atomA != nil and atomB != nil then
entities.add_edges([atomA,atomB])
else
puts "結合情報がありません" + key +" "+ symbol + " "+ bonds[index] + "-" + bonds[index + 1]
end
end
end
}
#描画結果
描画した結果です。
#終わりに
DNAをモデル化できるようになったのは嬉しいですが、あんまりやらない方が良いことをしてしまいました。コードの一部だけをちょっとだけ変えて、他の機能にするというやつです。これでは、保守の手間が2倍になってしまいます。
もう少しRNAについてデータ形式を調べたら、タンパク質、DNA、RNAいずれのデータも描画できるように、機能をマージしたいと思います。おそらく、各ストランド(ポリマー)が何のストランドなのかを判別するようにして、判別結果に応じて集めるべき主鎖/バックボーン原子情報を指定することになると思います。
また、なるべくメインルーチンで書くのではなくて、機能単位でメソッド化するようにしたいと思います。