Files

204 lines
6.3 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""
STRING Database API Client
用于获取蛋白互作网络数据
"""
import requests
import time
from pathlib import Path
from typing import List, Dict, Any, Optional
import json
from gfa_core.ppi_string_policy import STRING_SPECIES_MAP, string_taxon_id
class StringAPI:
"""STRING数据库API客户端"""
BASE_URL = "https://string-db.org/api"
SPECIES_MAP = STRING_SPECIES_MAP
def __init__(self, species: str = "ath", timeout: int = 30):
"""
初始化STRING API客户端
Args:
species: 物种代码(ath, osa, zma等)
timeout: 请求超时时间(秒)
"""
self.species = species
self.species_id = string_taxon_id(species, "3702")
self.timeout = timeout
self.session = requests.Session()
def get_network(self,
proteins: List[str],
required_score: int = 200,
network_type: str = "functional") -> Dict[str, Any]:
"""
获取蛋白互作网络
Args:
proteins: 蛋白ID列表
required_score: 互作置信度阈值(0-1000,默认200=0.7)
network_type: 网络类型(functional/physical)
Returns:
互作网络数据
"""
if not proteins:
return {"error": "No proteins provided"}
# STRING API限制:每次最多2000个蛋白
if len(proteins) > 2000:
proteins = proteins[:2000]
print(f"[WARNING] Protein list truncated to 2000 (STRING API limit)")
params = {
"identifiers": "\r".join(proteins),
"species": self.species_id,
"required_score": required_score,
"network_type": network_type,
"caller_identity": "BotanicalBaseAgent"
}
try:
response = self.session.get(
f"{self.BASE_URL}/json/network",
params=params,
timeout=self.timeout
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {"error": f"API request failed: {str(e)}"}
def get_interaction_partners(self,
protein: str,
required_score: int = 200,
limit: int = 100) -> Dict[str, Any]:
"""
获取指定蛋白的互作伙伴
Args:
protein: 蛋白ID
required_score: 互作置信度阈值
limit: 返回的最大互作数
Returns:
互作伙伴数据
"""
params = {
"identifiers": protein,
"species": self.species_id,
"required_score": required_score,
"limit": limit,
"caller_identity": "BotanicalBaseAgent"
}
try:
response = self.session.get(
f"{self.BASE_URL}/json/interaction_partners",
params=params,
timeout=self.timeout
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {"error": f"API request failed: {str(e)}"}
def get_protein_info(self, proteins: List[str]) -> Dict[str, Any]:
"""
获取蛋白详细信息
Args:
proteins: 蛋白ID列表
Returns:
蛋白信息数据
"""
if not proteins:
return {"error": "No proteins provided"}
params = {
"identifiers": "\r".join(proteins),
"species": self.species_id,
"caller_identity": "BotanicalBaseAgent"
}
try:
response = self.session.get(
f"{self.BASE_URL}/json/protein_info",
params=params,
timeout=self.timeout
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {"error": f"API request failed: {str(e)}"}
def save_network_to_file(self,
network_data: Dict[str, Any],
output_file: Path,
format: str = "tsv"):
"""
保存网络数据到文件
Args:
network_data: 网络数据
output_file: 输出文件路径
format: 输出格式(tsv/json)
"""
output_file = Path(output_file)
output_file.parent.mkdir(parents=True, exist_ok=True)
if format == "json":
with open(output_file, 'w') as f:
json.dump(network_data, f, indent=2)
elif format == "tsv":
# 转换为边列表格式
edges = []
for interaction in network_data:
if isinstance(interaction, dict):
edges.append({
"protein1": interaction.get("preferredName_A", ""),
"protein2": interaction.get("preferredName_B", ""),
"score": interaction.get("score", 0),
"ncbi_tax_id": interaction.get("ncbiTaxonId", ""),
})
import pandas as pd
df = pd.DataFrame(edges)
df.to_csv(output_file, sep="\t", index=False)
print(f"[INFO] Network saved to: {output_file}")
def test_string_api():
"""测试STRING API"""
api = StringAPI(species="ath")
# 测试基因
test_genes = ["AT1G01010", "AT1G01020", "AT1G01030"]
print("Testing STRING API...")
print(f"Species: {api.species} (ID: {api.species_id})")
print(f"Test genes: {test_genes}")
# 获取网络
network = api.get_network(test_genes, required_score=400)
if "error" in network:
print(f"Error: {network['error']}")
else:
print(f"Interactions found: {len(network)}")
if network:
print("Sample interaction:")
print(json.dumps(network[0], indent=2))
if __name__ == "__main__":
test_string_api()