KLIFSで遊んだ話(T11パートAの備忘録)
トークトリアル11イントロに引き続きトークトリアル11パートAも耳慣れない言葉が多く内容のフォローが難しかったです。
と、いうわけで今回も素人による適当解説をしますよ!!
KLIFS
今回はKLIFS(Kinase-Ligand Interaction Fingerprints and Structures)について調べてみます。トークトリアルの説明は文字のみで、データの取得に用いただけだったのですが、実際にWebページ にアクセスしてみるととても素敵な感じでした!
KLIFS Webページで遊ぶ
折角なのでT11パートAでコードで実施していた内容をWebページ上でも行なってみます。T11 パートAの内容は以下でした。
- Kinaseファミリー 「EGFR」 を検索
- PDB ID 3w33 を選択
- 描画
まずは検索から。上タブからSearch
ページに移動します。タンパク質やリガンドだけでなく色々な検索方法が用意されています。興味深いところでは結合ポケットのなかの水分子や、リガンド-キナーゼ相互作用パターンによる検索といったものまであります。目移りしてしまいますが、まずはT11通りにKinaseファミリーで検索します。
Search by classificationにて「Family
:EGFR」「Organism
:Human」として検索しました。
ヒットした構造(355エントリー)がテーブルとして表示されました。下図に化合物2次元構造がありますが、Orthosteric ligandの列の化合物の名称にマウスオーバーするだけで描画されます。レスポンスも早くてすごい!
またテーブル左上Plot results on Kinome
をクリックするとキノーム(ゲノム上のプロテインキナーゼ一式)の中で、どの位置に相当するか図示されます。
検索結果のテーブルはExcel
、csv
形式でダウンロードすることも可能で、またDownload Structures
で構造をダウンロードすることもできるようです(スクロールしていくとボタンがあります。)
「PDB ID: 3W33」の詳細を見るためにDetails列のShow
をクリックして見ます。こんな感じ
エントリーの詳細な情報に加えて3Dの描画やリガンドの活性値情報もあります。ChEMBLから取得されているようで、EGFR以外のキナーゼに対する活性も合わせてみることができるので、選択性やオフターゲットの雰囲気もつかめそうです。
スクロールするともっと面白い項目もあります。
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がどのように複合体のアノテーションを行なっているかを説明した図です。
先に見た単語がちらほら見えますね。この図で面白いのはキナーゼーリガンド相互作用をフィンガープリントして表現している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ページ上で確認、検索することが可能になっています。
以上、非常にざっくりですがKLIFSで行われていることの雰囲気です。分類と解析とが体系化されることで自動化が可能になり、データベースの継続的なアップデートに繋がっているようです。
KLIFSのAPI
KLIFSのWebページについてはだいたいわかったので、T11パートAではAPIを使ってどのように情報が取り出されていたのかを見ていきたいと思います。
取り上げるのは途中で定義された以下の3つの関数です。
_all_kinase_families()
: KLIFSデータベースに含まれているキナーゼファミリーの名前を取得_kinases_from_family(family, species="HUMAN")
: 指定したキナーゼファミリーに含まれるキナーゼの名前を取得_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 をみてみます。
たとえば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種類と同じものがきちんと入っているようです。
関数_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つを返す関数です。、
- キナーゼIDに基づく複合体構造(PDB形式)
- タンパク質のみの構造(mol2形式)
- キナーゼ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)
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)
先に確認したように、「structure_id
: 782」のPDB_IDは3W33で、KLIFSのWebページで見ていた複合体構造と同じでした。確かにここでは同じリガンドが取り出されているようです。
まとめ
以上、今回はT11 パートAで扱われていたデータベースKLIFSで遊んで見ました。素晴らしいWebページ版が提供されているので、まずはこちらで遊んでどのような情報が得られるのか感触をつかんでからの方がプログラムの内容を理解しやすのではないかな?と思いました。一目で結果を理解しやすいGUIベースのページは、プログラムが意図した通りの動きをしているかを検証する目的でも良さそうです。
プログラムの内容についてREST、SWAGGERは相変わらず定義はよく分かりませんが、ぼんやりと何がしたいかはわかったような気がしないでもないような?仕様を定義ってのは、文法みたいなイメージで良いのでしょうか???
素人が適当にしらべたことをだらだら書いているので色々と間違いが多いと思います。ご指摘いただければ幸いです。
*1: キナーゼを標的とした構造生物学および創薬の現状 日本結晶学会誌 59,174-181(2017)