創薬・ターゲット探索データベース

Open Targets入門 #3:Python + GraphQL APIでデータを取得する

Open Targets入門 #2:Platform UIで疾患から創薬ターゲットを探すでは、アルツハイマー病から創薬ターゲット候補を画面上で探索しました。APP、APOE、PSEN1などのターゲットをAssociated Targets・Target Prioritisation・Evidenceページで深掘りする流れを見ました。

今回は同じ発想を、Python + GraphQL APIで再現します。UIで見ていたAssociated Targetsの一覧をプログラムから取得し、pandasのDataFrameに整形してCSVとして保存します。

本記事はOpen Targetsシリーズの第3回です。

タイトル主なゴール
第1回Open Targets入門 #1:概要と仕組みを理解するPlatformの位置づけ、データソース、association scoreの考え方を理解する
第2回Open Targets入門 #2:Platform UIで疾患から創薬ターゲットを探すアルツハイマー病を例に、UIでAssociated TargetsとEvidenceを読む
第3回(本記事)Python + GraphQL APIでデータを取得するGraphQL APIから疾患関連ターゲットを取得し、解析しやすい表に変換する
GOAL
  • GraphQL APIのendpoint・query・variablesの関係を理解できる
  • Pythonでページネーションしながら全件取得できる
  • overall scoreとdatatype別スコアをDataFrameで読んで解釈できる
  • 大量取得にはAPIではなくParquetを使うべき理由がわかる

例として使用する疾患は、前回と同じアルツハイマー病(Alzheimer disease)です。APIクエリでは MONDO_0004975 を指定します。

注意

Open Targets v26.03では疾患IDにMONDO Ontologyを使用しています。旧来のEFO IDは使用できません。


分析環境を準備する

必要なものはPython本体と、HTTPリクエスト・表形式データ処理用の最小限のライブラリです。

項目推奨
Python3.8以上
HTTPクライアントrequests
表形式データpandas
出力形式CSV(必要に応じてParquetへ変更)

インストールは以下で十分です。

python -m pip install requests pandas

仮想環境を使う場合は、先に以下のように作成してからインストールします。

python -m venv .venv
source .venv/bin/activate
python -m pip install requests pandas

GraphQL APIでデータを取得する仕組み

Open Targets PlatformのGraphQL API endpointは以下です。

https://api.platform.opentargets.org/api/v4/graphql

GraphQLでは、REST APIのようにURLパスを細かく切り替えるのではなく、1つのendpointに対して「どのフィールドが欲しいか」をqueryとして送ります。

要素役割本記事での例
endpointリクエスト送信先https://api.platform.opentargets.org/api/v4/graphql
query取得したいデータ構造disease { associatedTargets { rows { ... } } }
variablesqueryに渡す引数efoId, index, size
pageページネーション指定{ index: 0, size: 20 }

本記事で使うqueryは以下です。ページネーションは page: { index, size } 形式で指定します。

query AssociatedTargets($efoId: String!, $index: Int!, $size: Int!) {
  disease(efoId: $efoId) {
    associatedTargets(page: { index: $index, size: $size }) {
      count
      rows {
        target { id approvedSymbol approvedName }
        score
        datatypeScores { id score }
      }
    }
  }
}

変数は以下のように渡します。

{
  "efoId": "MONDO_0004975",
  "index": 0,
  "size": 20
}

curlで最小動作確認をする

Pythonを書く前に、curl で最小限のPOSTリクエストを確認できます。

curl -sS -X POST https://api.platform.opentargets.org/api/v4/graphql \
  -H 'Content-Type: application/json' \
  --data-binary @- <<'JSON'
{
  "query": "query AssociatedTargets($efoId: String!, $index: Int!, $size: Int!) { disease(efoId: $efoId) { associatedTargets(page: { index: $index, size: $size }) { count rows { target { id approvedSymbol approvedName } score datatypeScores { id score } } } } }",
  "variables": {
    "efoId": "MONDO_0004975",
    "index": 0,
    "size": 20
  }
}
JSON
注意

GraphQLではHTTPステータスコードが200でもレスポンス内に errors が含まれることがあります。Python側ではステータスコードだけでなく、JSON内の errors キーも必ず確認してください。


Pythonで全件取得するコード

以下は、アルツハイマー病に関連するターゲット一覧を取得し、datatype別スコアを列に展開してCSV保存する完全なコードです。

import requests
import pandas as pd


ENDPOINT = "https://api.platform.opentargets.org/api/v4/graphql"

QUERY = """
query AssociatedTargets($efoId: String!, $index: Int!, $size: Int!) {
  disease(efoId: $efoId) {
    associatedTargets(page: { index: $index, size: $size }) {
      count
      rows {
        target { id approvedSymbol approvedName }
        score
        datatypeScores { id score }
      }
    }
  }
}
"""


def fetch_associated_targets(efo_id, page_size=500):
    rows = []
    index = 0
    total_count = None

    while True:
        variables = {
            "efoId": efo_id,
            "index": index,
            "size": page_size,
        }
        response = requests.post(
            ENDPOINT,
            json={"query": QUERY, "variables": variables},
            timeout=60,
        )
        response.raise_for_status()
        payload = response.json()

        if "errors" in payload:
            raise RuntimeError(payload["errors"])

        associated_targets = payload["data"]["disease"]["associatedTargets"]
        if total_count is None:
            total_count = associated_targets["count"]

        page_rows = associated_targets["rows"]
        rows.extend(page_rows)

        if not page_rows or len(rows) >= total_count:
            break

        index += 1

    return rows


def rows_to_dataframe(rows):
    records = []

    for row in rows:
        target = row["target"]
        record = {
            "target_id": target["id"],
            "approved_symbol": target["approvedSymbol"],
            "approved_name": target["approvedName"],
            "overall_score": row["score"],
        }

        for datatype_score in row.get("datatypeScores", []):
            column_name = f"score_{datatype_score['id']}"
            record[column_name] = datatype_score["score"]

        records.append(record)

    df = pd.DataFrame(records)
    df = df.sort_values("overall_score", ascending=False).reset_index(drop=True)
    return df


def main():
    EFO_ID = "MONDO_0004975"

    rows = fetch_associated_targets(EFO_ID)
    df = rows_to_dataframe(rows)

    output_path = f"open_targets_associated_targets_{EFO_ID}.csv"
    df.to_csv(output_path, index=False)

    print(f"Saved: {output_path}")
    print(df.head(20))


if __name__ == "__main__":
    main()

APIから返る associatedTargets.count を見ながら index を1ずつ増やしてページを取得します。1ページ目だけを取る場合は page_size=20 でも十分ですが、後で疾患ごとの全候補を比較したい場合に備えて、関数側のデフォルトは page_size=500 にしています。

実行するとどうなるか

python main.py を実行すると、まずAPIへのリクエストが走り(アルツハイマー病では全件取得に数秒かかります)、以下のような出力が得られます。

Saved: open_targets_associated_targets_MONDO_0004975.csv
        target_id approved_symbol  ...  overall_score
0  ENSG00000142192             APP  ...          0.870
1  ENSG00000080815           PSEN1  ...          0.866
2  ENSG00000164458           PSEN2  ...          0.817
3  ENSG00000130203            APOE  ...          0.775
4  ENSG00000176884           GRIN1  ...          0.700
...

保存されるCSVの列構成は以下のとおりです。datatypeのエビデンスがないターゲットでは、対応する score_* 列が NaN になります。

target_id, approved_symbol, approved_name, overall_score,
score_genetic_association, score_genetic_literature, score_clinical,
score_affected_pathway, score_literature, score_animal_model,
score_rna_expression, score_somatic_mutation

結果のDataFrameを読む

rows_to_dataframe() の出力では、ネストしたGraphQLレスポンスを解析しやすい横持ちの表に変換します。

内容読み方
target_idEnsembl gene IDターゲットを一意に識別するID
approved_symbolHGNC approved symbol一般的に使う遺伝子シンボル
approved_nameHGNC approved name遺伝子・タンパク質の正式名称
overall_score総合association score疾患とターゲットの関連性を0〜1で表す総合スコア
score_genetic_association遺伝的関連スコアGWAS、ClinVar、gene burdenなどの寄与
score_known_drug既知薬・臨床エビデンスChEMBL等に基づくclinical precedence
score_literature文献エビデンスEurope PMCなどのテキストマイニング

Open Targets入門 #1:概要と仕組みを理解するで説明したように、association scoreは単純な件数カウントではありません。各データソース内のエビデンスを**harmonic sum(調和和)**で統合し、datatypeや全体のassociation scoreへ集約します。

ポイント

overall_score が高いターゲットは「強い証拠がある」「複数の独立した証拠がある」可能性がありますが、「創薬ターゲットとして必ず正しい」という意味ではありません。datatype別スコアを見ることで、根拠の種類と強さを判断できます。

datatypeScoresに出てくる主な id は以下です(v26.03実測値)。

datatypeScoresのid日本語での意味主なデータソース・解釈
genetic_association遺伝的関連(統計的)GWAS associations、ClinVar、Gene Burdenなど。GWAS credible setをL2Gスコアでターゲットへ変換したエビデンス
genetic_literature遺伝的関連(文献キュレーション)Gene2Phenotype、PanelApp、ClinGenなど。メンデル遺伝病・希少疾患の遺伝子-疾患キュレーション
clinical臨床・薬剤エビデンスChEMBL、ClinicalTrials.gov等に基づく臨床先行性(旧バージョンでは known_drug と表記されることもある)
affected_pathwayパスウェイ・機能Reactome、CRISPR Screens、Project Scoreなど
literature文献テキストマイニングEurope PMCのテキストマイニング
animal_model動物モデルIMPCなどのモデル生物表現型
rna_expressionRNA発現変動Expression Atlasなどの疾患組織・対照組織比較
somatic_mutation体細胞変異Cancer Gene Census、IntOGenなど。主にがん関連疾患で寄与

前回のUI探索では、APP、APOE、PSEN1をEvidenceページで深掘りしました。APIから得たDataFrameでも、同じターゲットが上位に現れ、どのdatatypeがスコアを支えているかを列として確認できます。

API出力の上位10ターゲット例(v26.03)

以下は MONDO_0004975(Alzheimer disease)を page: { index: 0, size: 10 } で取得した実測結果です。スコアは小数第3位に丸めています。

ranksymboloverallgenetic_assocgenetic_litclinicalpathwayliteratureanimal_modelrna_exp
1APP0.8700.9240.6080.9730.6080.9950.391
2PSEN10.8660.9540.8860.6220.9710.5710.050
3PSEN20.8170.9090.7720.6220.693
4APOE0.7750.8960.6080.2670.9990.2690.017
5GRIN10.7000.9870.5820.845
6SORL10.6890.7610.3040.9720.6330.048
7ADAM100.6820.7820.6080.9180.020
8CDK50.6800.8770.9310.090
9GRIN3B0.6690.4390.9870.179
10ACE0.6340.8630.6080.1220.941

(—はそのdatatypeのエビデンスがゼロまたは返却なし。列見出しは列名の略記)

APPやPSEN1/PSEN2は clinical(臨床先行性)・genetic_associationliterature など複数のdatatypeから強く支えられています。APOEは genetic_associationliterature が特に高く、GWAS由来の遺伝的支持と文献蓄積が順位を押し上げています。

各列の解釈の基準は以下のとおりです。

見る場所何を判断するか注意点
overall_score疾患との関連の総合順位研究量の多い疾患・遺伝子では高くなりやすい
score_genetic_associationヒト遺伝学的な支持(GWAS・Gene Burden)GWAS locusでは因果遺伝子推定の不確実性が残る
score_genetic_literature遺伝的関連(文献キュレーション)メンデル遺伝病は高くなりやすい
score_clinical臨床・薬剤開発の先行性既存薬があることは有望材料にも競合材料にもなる
score_literature文献での言及量文献バイアスを受けやすい
score_animal_modelモデル生物での表現型ヒト疾患との対応関係を別途確認する
score_rna_expression発現変動原因か結果かはこの列だけでは判断できない

大量取得にはParquet/BigQueryを使う

GraphQL APIは、1つの疾患・ターゲット・ターゲット-疾患ペアを探索的に調べる用途に向いています。数百〜数千の疾患を横断して全ターゲットを集めるような処理には向きません。

用途推奨アクセス方法理由
1疾患の上位ターゲットを確認GraphQL API必要なフィールドだけを柔軟に取得できる
UIで見つけたターゲットの詳細確認GraphQL APIEvidence、known drugs、annotationを追加で取得しやすい
多数の疾患・ターゲットを系統的に集計Parquet / BigQueryAPI連打を避け、再現性の高いバルク解析ができる
社内パイプラインに組み込むParquet / BigQueryバージョン固定、差分管理、SQL処理に向く

Open TargetsのバルクデータはGoogle Cloud Storageでも公開されています。

gs://open-targets-data-releases/
ポイント

全疾患×全ターゲットのassociation matrix、全evidence、全target annotationを扱う場合は、最初からParquet/BigQueryを前提に設計した方が安定します。APIをループで叩き続けるのは避けてください。

RユーザーはotargenのAPIを確認する

メモ

Rから同じGraphQL APIを呼ぶためのパッケージとして otargen(CRANで公開)があります。ただし、v2.0.0(2025年7月リリース)はOpen Targets GeneticsのPlatform統合に伴う大幅な作り直しが行われており、v1.x系にあった associatedTargets() などの高レベル関数が廃止されています。v2.0.0では clinVarQuery()gwasCredibleSetsQuery()chemblQuery() などデータソース別の関数群に再編されており、「疾患からターゲット一覧をoverall score付きで取得する」ような一発関数は現時点では存在しません。

Rを使う場合は本記事のGraphQLクエリをそのまま httr2jsonlite で呼び出すか、v2.0.0以降のotargenの動向を確認してください。


まとめ:API・UI・Parquetの使い分け

本記事では、Open Targets PlatformのGraphQL APIを使って、アルツハイマー病に関連するターゲット一覧をPythonで取得しました。

ポイント内容
API endpointhttps://api.platform.opentargets.org/api/v4/graphql
クエリ対象disease(efoId: "MONDO_0004975")associatedTargets
ページネーションpage: { index, size } を使う
Python実装requests.post() でqueryとvariablesを送る
整形datatypeScoresscore_{id} 列へ展開する
解釈overall scoreだけでなくdatatype別スコアを見る
大量取得GraphQL APIではなくParquet/BigQueryを使う

Open Targets Platformは、UIで仮説を立て、APIで小規模に検証し、Parquet/BigQueryで大規模解析へ広げるという流れで使うと実務に組み込みやすいツールです。


関連記事

関連記事Open Targets入門 #1:概要と仕組みを理解する

関連記事Open Targets入門 #2:Platform UIで疾患から創薬ターゲットを探す


参考: - Open Targets Platform - GraphQL API Documentation - Data and code access - Target–disease associations Documentation