magattacaのブログ

日付以外誤報

KLIFSで遊んだ話(T11パートAの備忘録)

トークトリアル11イントロに引き続きトークトリアル11パートAも耳慣れない言葉が多く内容のフォローが難しかったです。

と、いうわけで今回も素人による適当解説をしますよ!!

KLIFS

今回はKLIFS(Kinase-Ligand Interaction Fingerprints and Structures)について調べてみます。トークトリアルの説明は文字のみで、データの取得に用いただけだったのですが、実際にWebページ にアクセスしてみるととても素敵な感じでした!

f:id:magattaca:20200510211647p:plain
KLIFSトップページ

KLIFS Webページで遊ぶ

折角なのでT11パートAでコードで実施していた内容をWebページ上でも行なってみます。T11 パートAの内容は以下でした。

  1. Kinaseファミリー 「EGFR」 を検索
  2. PDB ID 3w33 を選択
  3. 描画

まずは検索から。上タブからSearchページに移動します。タンパク質やリガンドだけでなく色々な検索方法が用意されています。興味深いところでは結合ポケットのなかの水分子や、リガンド-キナーゼ相互作用パターンによる検索といったものまであります。目移りしてしまいますが、まずはT11通りにKinaseファミリーで検索します。

Search by classificationにて「FamilyEGFR」「OrganismHuman」として検索しました。

f:id:magattaca:20200510192718p:plain

ヒットした構造(355エントリー)がテーブルとして表示されました。下図に化合物2次元構造がありますが、Orthosteric ligandの列の化合物の名称にマウスオーバーするだけで描画されます。レスポンスも早くてすごい!

f:id:magattaca:20200510192743p:plain

またテーブル左上Plot results on Kinomeをクリックするとキノーム(ゲノム上のプロテインキナーゼ一式)の中で、どの位置に相当するか図示されます。

f:id:magattaca:20200510192821p:plain

検索結果のテーブルはExcelcsv形式でダウンロードすることも可能で、またDownload Structuresで構造をダウンロードすることもできるようです(スクロールしていくとボタンがあります。)

PDB ID: 3W33」の詳細を見るためにDetails列のShowをクリックして見ます。こんな感じ

f:id:magattaca:20200510192907p:plain

エントリーの詳細な情報に加えて3Dの描画やリガンドの活性値情報もあります。ChEMBLから取得されているようで、EGFR以外のキナーゼに対する活性も合わせてみることができるので、選択性やオフターゲットの雰囲気もつかめそうです。

スクロールするともっと面白い項目もあります。

f:id:magattaca:20200510193025p:plain

Kinase-ligand interaction patternは、リガンドがタンパク質のどの残基とどのような相互作用をしているか一目でわかるようになっています。私は結晶構造の描画をみても「格好いい!! で、どこが大事なんですかね???」となってしまうので、こういう見所(?)テーブルがあるのは非常に良いなと思います。また、一番下にひっそりとInteraction pattern searchなるものがあり、類似の相互作用パターンをもつ複合体をKLIFSから探してくれます。エモい・・・

KLIFSの背景

KLIFSのWebページの充実ぶりすごいですね。ちょっと背景を知りたいので論文を参照してみたいと思います。オンラインサービスに関する文献 Nucleic Acids Res. (2016), 44, 6, D365–D371 はオープンアクセスでした。

T11 パートAにも説明がありましたが、KLIFSはPDBからキナーゼの結晶構造を抜き出し、リガンドとの相互作用に関して分析処理を加えたデータベースです。特徴としてキナーゼの触媒ドメインに着目していることが挙げられます。

内部に踏み込む前にまずはキナーゼの構造について一般的な内容から

キナーゼの構造の特徴

こちらの日本語レビュー「 キナーゼを標的とした構造生物学および創薬の現状」が非常に分かりやすかったです。 *1 ざっくりと理解したことを紹介します。

キナーゼは基質をリン酸化するタンパク質ですが、リン酸基のソースはATPです。つまり共通して触媒キナーゼドメインの結合サイトにATPが結合します。
同じものが結合するならポケットも似ているだろ、ということでキナーゼ触媒ドメインはお互いにある程度似た構造をしています。
多くのキナーゼ阻害剤はこのATP結合領域に結合します。なので、異なるキナーゼ間で構造が似ていると、標的以外のキナーゼにも結合して阻害する可能性あります。
OpenTeachCADDで度々出てくる選択性の問題ですね。

よく保存された構造をもつキナーゼの結合ポケットですが、その特徴的な部分には名前がつけられています。例えば・・・

  • Hinge : ATPのアデニンと相互作用する残基部位
  • Gate Keeper : ATP結合ポケットの一番奥の残基部位。ATP結合サイトの立体構造への影響大
  • DFG motif : Asp-Phe-Glyの1文字表記。側鎖の動きが大きくDFG-in構造、DFG-out構造とよばれるコンフォメーションの変化がある

などなど。また、阻害剤にも結合するサイト・阻害様式によってType I ~ IV、共有結合型などの分類があるそうです。

こういうの格好いいですよね!共通の情報が整理されて見通し良くなってく感じが分野の発展の歴史を見ているようで楽しいです。

まとめると「医薬品としてキナーゼ阻害剤は大事だが選択性が課題となる。背景には結合サイトにおける保存されたキナーゼの構造的特徴があり、特徴に従い分類、キナーゼー阻害剤相互作用の細かな差異を分析することで課題解決の有用な情報となる。」・・・ってことですかね?

つまり、そういう情報まとめたKLIFSは素敵なリソース!!

KLIFS文献参照

やっとKLIFSの文献に戻ってFigure 2. を引用します。こちらはKLIFSがどのように複合体のアノテーションを行なっているかを説明した図です。

f:id:magattaca:20200510193619p:plain
Nucleic Acids Res. (2016), 44, 6, D365–D371 Fig.2 Annotation structural kinase-ligand interaction data in KLIFS.より引用

先に見た単語がちらほら見えますね。この図で面白いのはキナーゼーリガンド相互作用をフィンガープリントして表現しているFig.2 A)下部だと思います。各アミノ酸残基について、疎水性相互作用や水素結合といった7種類の相互作用がリガンドとの間にみられるか?というのを、0、1のビットで表記しています(kinase-ligand interaction finger print, IFP)。

KLIFSは触媒ドメインを含む85残基を解析の対象としています。したがって、各複合体のキナーゼーリガンド相互作用の情報は「85残基x相互作用7種=595ビット」のフィンガープリントにエンコーディングされることになります(?あってます?)。これだけ情報が圧縮されてるから「類似の相互作用の複合体は他にあるのか?」といった検索が容易になるんですね。なるほど。

さて、KLIFSでは相互作用のフィンガープリント化と結合ポケットの部位の分類(3 major pockets + 12 subpockets)を行なったことで、各複合体のリガンドの結合ポーズ(binding mode)の分類が可能になったそうです。
また、興味深いことにリガンドに加えて水分子についても解析が行われています。下に引用した図のように、保存された水分子のクラスター位置が見つかっています。こちらもWebページ上で確認、検索することが可能になっています。

f:id:magattaca:20200510193833p:plain
Nucleic Acids Res. (2016), 44, 6, D365–D371 Supplementary Figure S2 A)より改変して引用

以上、非常にざっくりですがKLIFSで行われていることの雰囲気です。分類と解析とが体系化されることで自動化が可能になり、データベースの継続的なアップデートに繋がっているようです。

KLIFSのAPI

KLIFSのWebページについてはだいたいわかったので、T11パートAではAPIを使ってどのように情報が取り出されていたのかを見ていきたいと思います。
取り上げるのは途中で定義された以下の3つの関数です。

  1. _all_kinase_families(): KLIFSデータベースに含まれているキナーゼファミリーの名前を取得
  2. _kinases_from_family(family, species="HUMAN"): 指定したキナーゼファミリーに含まれるキナーゼの名前を取得
  3. _protein_and_ligand_structure(*kinase_ids): 指定したKLIFSのキナーゼIDに紐づいたリガンド-キナーゼ複合体構造 (PDB)、タンパク質のみの構造(MOL2)、リガンド(SMILESリスト)を取得

REST?SWAGGER?

コードの中身を見る前にまずはよくわからない単語たち・・・

  • REST(Representational State Transfer): Web APIの仕様を決める上での基本的な考え方。リソースのURIと、アクセスするメソッド(HTTPのGET、POSTなどの)の組み合わせの設計方針。*2
  • SWAGGER: REST APIを定義、仕様を管理するためのフレームワーク。OpenAPI仕様をもとにした実装

・・・わからない。KLIFSのAPI をみてみます。

f:id:magattaca:20200510194315p:plain

たとえばKinase groupsについて情報が欲しければ、リソースのURI(Uniform Resource Identifier)「~/kinase_groups」に対して、GETメソッドを使えば良いということのようですね。
また、今回のトークトリアルでは、このSwaggerサービスを使うためのクライアントの生成をライブラリBravadoを使っておこなっています。Bravadoのドキュメンテーションこちらです。

bravadoによるSwagger用のクライアントの作成

それではbravadoを使って、KLIFS APIのURLからクライアントを作成します。URLからわかるようにjson形式となっているようです。

from bravado.client import SwaggerClient

# URLを定義
KLIFS_API_DEFINITIONS = "http://klifs.vu-compmedchem.nl/swagger/swagger.json"

# SwaggerClient : A client for accessing a Swagger-documented RESTful service
KLIFS_CLIENT = SwaggerClient.from_url(KLIFS_API_DEFINITIONS, config={'validate_responses': False})

作成したSwaggerClientの属性をdir()で確認して見ます。

print(dir(KLIFS_CLIENT))

#  ['Information', 'Interactions', 'Ligands', 'Structures']

これらが利用可能なリソースで、KLIFSのAPIに書かれている4種類と同じものがきちんと入っているようです。

f:id:magattaca:20200510194400p:plain

関数_all_kinase_families()の中身

こちらはKLIFSからKinaseファミリーを取得する関数です。こちらが何をしているか順番に見ていきます。

def _all_kinase_families():
    return KLIFS_CLIENT.Information.get_kinase_families().response().result

まず、リソースとしてinformationを選択し、そのkinase_familyに対してGETで情報を取得します(get_kinase_families())。Bravadoのドキュメンテーションによると、メソッドを実行することで戻り値としてHttPFutureを得るそうです(Futures and responses)。

確認してみます。

print(KLIFS_CLIENT.Information.get_kinase_families())

#  <bravado.http_future.HttpFuture object at 0x117469ef0>

確かに戻り値はHttpFutureオブジェクトとなっています。ここからレスポンスを得るにはHttpFuture.responce()とすればよく、この戻り値としてBravadoResponseインスタンスが得られます。Swaggerの結果を得るためにはこのインスタンスに対してBravadoResponse.resultとすれば良いそうです。

順番にやってみます。

print("レスポンス:", KLIFS_CLIENT.Information.get_kinase_families().response())

#  レスポンス: <bravado.response.BravadoResponse object at 0x117da7048>
print("type:", type(KLIFS_CLIENT.Information.get_kinase_families().response().result))
print("result", KLIFS_CLIENT.Information.get_kinase_families().response().result)

#  type: <class 'list'>
#  result ['A6', 'ABC1', 'AKT', 'ALK', 'AUR', 'Abl', 'Ack', 'Akt', 'Alk', 'Alpha', 'Aur', 'Axl', 'BCR', 'BRD', 'BUB', 'Bud32', 'CAMK-Unique', 'CAMK1', 'CAMK2', 'CAMKK', 'CAMKL', 'CASK', 'CCK4', 'CDC7', 'CDK', 'CDKL', 'CK1', 'CK2', 'CLK', 'Csk', 'DAPK', 'DCAMKL', 'DDR', 'DMPK', 'DYRK', 'EGFR', 'Eph', 'FAK', 'FAST', 'FGFR', 'Fer', 'G11', 'GRK', 'GSK', 'H11', 'Haspin', 'IKK', 'IRAK', 'IRE', 'InsR', 'JakA', 'JakB', 'KIS', 'LISK', 'LRRK', 'Lmr', 'MAPK', 'MAPKAPK', 'MAST', 'MLCK', 'MLK', 'MOS', 'Met', 'Musk', 'NAK', 'NDR', 'NEK', 'NKF1', 'NKF2', 'NKF3', 'NKF4', 'NKF5', 'NRBP', 'Other-Unique', 'PAN3', 'PDGFR', 'PDHK', 'PDK1', 'PEK', 'PHK', 'PIK', 'PIKK', 'PIM', 'PIP', 'PIPK', 'PKA', 'PKC', 'PKD', 'PKG', 'PKN', 'PLK', 'PSK', 'RAD53', 'RAF', 'RCK', 'RGC', 'RIO', 'RIPK', 'RSK', 'RSKL', 'RSKR', 'RSKb', 'Ret', 'Ror', 'Ryk', 'SCY1', 'SGK', 'SRPK', 'STE-Unique', 'STE11', 'STE20', 'STE7', 'STKR', 'Sev', 'SgK071', 'SgK493', 'SgK495', 'SgK496', 'Slob', 'Src', 'Syk', 'TAF1', 'TBCK', 'TIF1', 'TK-Unique', 'TKL-Unique', 'TLK', 'TOPK', 'TSSK', 'TTBK', 'TTK', 'Tec', 'Tie', 'Trbl', 'Trio', 'Trk', 'ULK', 'VEGFR', 'VPS15', 'VRK', 'WEE', 'WNK', 'Wnk', 'YANK']

無事BravadoResponseオブジェクトの生成と、結果として全キナーゼファミリーを要素としてもつリストを得ることができました。

Bravadoの動作の流れをまとめると・・・

  • SwaggerClient作成 > リソース選択 > get_URIで情報取得 > HttpFuture > response()でレスポンス取得 > BravadoResponse > resultで結果取得

・・・長い。

以上が定義した_all_kinase_families()関数になります。

関数_kinases_from_family(family, species="HUMAN")の中身

こちらは指定したGETメソッドの引数にキナーゼファミリーの名前と種(デフォルトの引数はHUMANに設定)を与えてキナーゼの名前を取得する関数です。
操作自体は先の例と同様です。

def _kinases_from_family(family, species="HUMAN"):
    return KLIFS_CLIENT.Information.get_kinase_names(kinase_family=family, species=species).response().result

関数_protein_and_ligand_structure()の中身

こちらはキナーゼのIDを引数として与え、以下の3つを返す関数です。、

  1. キナーゼIDに基づく複合体構造(PDB形式)
  2. タンパク質のみの構造(mol2形式)
  3. キナーゼIDに基づく共結晶構造中のリガンドのリスト(SMILESのみを抜き出して出力)

1、2はStructuresリソースから、3はLigandsリソースから得ています。

def _protein_and_ligand_structure(*kinase_ids):
    structures = KLIFS_CLIENT.Structures.get_structures_list(kinase_ID=kinase_ids).response().result
    molcomplex = KLIFS_CLIENT.Structures.get_structure_get_pdb_complex(structure_ID=structures[0].structure_ID).response().result
    protein = KLIFS_CLIENT.Structures.get_structure_get_protein(structure_ID=structures[0].structure_ID).response().result
    ligands = KLIFS_CLIENT.Ligands.get_ligands_list(kinase_ID=kinase_ids).response().result
    print(f"Chosen KLIFS entry with PDB ID {structures[0].pdb} with chain {structures[0].chain} and alternate model {structures[0].alt}")
    return molcomplex, protein, [ligand.SMILES for ligand in ligands]

EGFRを例として順番に見ていきます。準備としてまず例とするEGFRのkinase_IDを取得します。

EGFR_id_result = KLIFS_CLIENT.Information.get_kinase_ID(kinase_name="EGFR").response().result
print(EGFR_id_result)
print("number of result:", len(EGFR_id_result))

#  [KinaseInformation(HGNC='EGFR', family='EGFR', full_name='epidermal growth factor receptor', group='TK', iuphar=1797, kinase_ID=406, kinase_class='', name='EGFR', pocket='KVLGSGAFGTVYKVAIKELEILDEAYVMASVDPHVCRLLGIQLITQLMPFGCLLDYVREYLEDRRLVHRDLAARNVLVITDFGLA', species='Human', uniprot='P00533'), KinaseInformation(HGNC='Egfr', family='EGFR', full_name='epidermal growth factor receptor', group='TK', iuphar=0, kinase_ID=663, kinase_class='', name='EGFR', pocket='KVLGSGAFGTVYKVAIKELEILDEAYVMASVDPHVCRLLGIQLITQLMPYGCLLDYVREYLEDRRLVHRDLAARNVLVITDFGLA', species='Mouse', uniprot='Q01279')]
# number of result: 2

2つ結果が得られました。今回はhumanの情報をとりたいので一つ目のIDを取り出します。

EGFR_ID = EGFR_id_result[0].kinase_ID
print(EGFR_ID)

#  406

では_protein_and_ligand_structure()関数の1行目、複合体の構造のリストの取得です。ここではkinase_IDをリストで与えてやる必要があるので[406]として渡します。

EGFR_structures = KLIFS_CLIENT.Structures.get_structures_list(kinase_ID=[406]).response().result
print(len(EGFR_structures))    

#  324

全部で324個の構造情報が得られました。次の工程で複合体のPDBファイルを得るには、構造情報のうちstructure_idが必要となります。一つ目の構造情報で確認します。

EGFR_structure_id = EGFR_structures[0].structure_ID
print(EGFR_structure_id)

#  782

このstructure_idで複合体を取得します。今回は引数はintのままで大丈夫です。

EGFR_molcomplex = KLIFS_CLIENT.Structures.get_structure_get_pdb_complex(structure_ID=782).response().result
print(type(EGFR_molcomplex))
#  str

冗長なので省略しますがprintするとPDB形式になっていることが確認できます。ちなみに中身を見るとPDB_ID: 3w33でKLIFSのWebページで眺めていたものと同じでした。

同様にして同じstructure_idでタンパク質単体も取り出します。

EGFR_protein = KLIFS_CLIENT.Structures.get_structure_get_protein(structure_ID=782).response().result
print(type(EGFR_protein))
# str

こちらも省略しますがprintするとmol2形式になっていることが確認できます。

最後にリガンドのリストを取得します。EGFRのkinase_IDを使いますが、ここでもリスト[406]にして渡します。

EGFR_ligands = KLIFS_CLIENT.Ligands.get_ligands_list(kinase_ID=[406]).response().result
print(len(EGFR_ligands))

#  94

94個のリガンド情報を取得できました。ここからSMILESを取り出しますが、参考までにどのような情報があるか見てみます。

print(type(EGFR_ligands[0]))
print(dir(EGFR_ligands[0]))

# <class 'abc.ligandDetails'>
#  ['InChIKey', 'Name', 'PDB-code', 'SMILES', 'ligand_ID']

SMILES以外にもInChIKeyやNameなどの情報があるようです。

EGFR_SMILES = []
for lig in EGFR_ligands:
    smi = lig.SMILES
    EGFR_SMILES.append(smi)

print("number of ligands: ", len(EGFR_SMILES))
print("Example SMILES: ", EGFR_SMILES[0])

# number of ligands:  94
# Example SMILES:  P(=O)(OP(=O)(O)O)(OC[C@H]1O[C@@H](N2c3ncnc(N)c3N=C2)[C@H](O)[C@@H]1O)O

94個全ての構造のSMILESを取り出すことができました!これで_protein_and_ligand_structure()関数の全行程の確認ができました。

T11パートAのKLIFSに関する部分は、ここまで見てきたコードを踏まえて見返すとなんとなくやりたいことがわかりました。

最後に取り出したリガンドの構造を描画して見ましょう。

from rdkit import Chem
from rdkit.Chem import Draw

m = Chem.MolFromSmiles(EGFR_SMILES[0])
Draw.MolToImage(m)

f:id:magattaca:20200510194746p:plain

ADPでした。

T11パートAの結果を振り返って

以上、KLIFSのWebページ版とAPIとを比較してきました。T11パートAの結果と見比べることで、取り出されたリガンド構造に関して気づいた点があります。

T11パートAの最後、ケーススタディー: EGFRでEGFRのリガンドを取り出した時、同時に取り出したPDB共結晶構造中のリガンドが選ばれたと思っていました。実行時に得られたPDB_ID3w33とリガンドADPでした。ですが、上で見たようにKLIFSのWebページで同じPDB_ID3w33を確認するとorthosteric ligndはADPではない化合物でした。

この差が不思議だったのですが、APIを順番に見ていくことでT11 パートAの最後はkinase_IDで指定したリガンドを全て取り出し、その最初の一つを表示させているだけ、ということがわかりました。

もし同時にPDBのリガンドを指定して取得したいのなら、同じstructure_IDを使って以下のようにすれば良さそうです。

# mol2形式でリガンドを取得

ligand_782 = KLIFS_CLIENT.Structures.get_structure_get_ligand(structure_ID=782).response().result

# Mol2の中身は3次元で見づらいのでSMILES経由で2次元に戻してから描画

m782 = Chem.MolFromMol2Block(ligand_782)
smi782 = Chem.MolToSmiles(m782)
m782_2d = Chem.MolFromSmiles(smi782)
Draw.MolToImage(m782_2d)

f:id:magattaca:20200510194808p:plain

先に確認したように、「structure_id: 782」のPDB_IDは3W33で、KLIFSのWebページで見ていた複合体構造と同じでした。確かにここでは同じリガンドが取り出されているようです。

まとめ

以上、今回はT11 パートAで扱われていたデータベースKLIFSで遊んで見ました。素晴らしいWebページ版が提供されているので、まずはこちらで遊んでどのような情報が得られるのか感触をつかんでからの方がプログラムの内容を理解しやすのではないかな?と思いました。一目で結果を理解しやすいGUIベースのページは、プログラムが意図した通りの動きをしているかを検証する目的でも良さそうです。

プログラムの内容についてREST、SWAGGERは相変わらず定義はよく分かりませんが、ぼんやりと何がしたいかはわかったような気がしないでもないような?仕様を定義ってのは、文法みたいなイメージで良いのでしょうか???

素人が適当にしらべたことをだらだら書いているので色々と間違いが多いと思います。ご指摘いただければ幸いです。