Files
2026-08-03 18:42:47 +08:00

396 lines
12 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
转录组数据平台 API 客户端
集成多个转录组数据库和工具平台
"""
import requests
import time
from typing import Dict, List, Optional, Any
from dataclasses import dataclass
@dataclass
class ExpressionData:
"""基因表达数据"""
gene_id: str
tpm: Optional[float] = None
fpkm: Optional[float] = None
count: Optional[float] = None
sample: Optional[str] = None
tissue: Optional[str] = None
condition: Optional[str] = None
class EnsemblPlantsClient:
"""
Ensembl Plants API 客户端
植物基因组数据库
URL: https://plants.ensembl.org/
API: https://rest.ensembl.org/
"""
BASE_URL = "https://rest.ensembl.org"
def __init__(self, rate_limit: float = 0.5):
self.rate_limit = rate_limit
self.last_request_time = 0
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'bbav20311/1.0 (Research Tool)',
'Accept': 'application/json'
})
def _rate_limited_request(self, url: str, **kwargs) -> requests.Response:
"""带速率限制的请求"""
elapsed = time.time() - self.last_request_time
if elapsed < self.rate_limit:
time.sleep(self.rate_limit - elapsed)
response = self.session.get(url, **kwargs)
self.last_request_time = time.time()
return response
def get_gene_info(self, species: str, gene_id: str) -> Optional[Dict[str, Any]]:
"""
获取基因信息
Args:
species: 物种名称(如 arabidopsis_thaliana)
gene_id: 基因 ID
Returns:
基因信息
"""
url = f"{self.BASE_URL}/lookup/symbol/{species}/{gene_id}"
try:
response = self._rate_limited_request(url)
if response.status_code == 200:
return response.json()
return None
except Exception as e:
print(f"[WARN] Ensembl API error: {e}")
return None
def get_expression(self, species: str, gene_id: str) -> List[ExpressionData]:
"""
获取基因表达数据
Args:
species: 物种名称
gene_id: 基因 ID
Returns:
表达数据列表
"""
url = f"{self.BASE_URL}/expression/{species}/{gene_id}"
try:
response = self._rate_limited_request(url)
if response.status_code == 200:
data = response.json()
expression_data = []
for item in data.get('data', []):
expr = ExpressionData(
gene_id=gene_id,
tpm=item.get('tpm'),
fpkm=item.get('fpkm'),
sample=item.get('sample'),
tissue=item.get('tissue'),
)
expression_data.append(expr)
return expression_data
return []
except Exception as e:
print(f"[WARN] Ensembl API error: {e}")
return []
def get_homologues(self, species: str, gene_id: str, target_species: str) -> List[Dict[str, Any]]:
"""
获取同源基因
Args:
species: 源物种
gene_id: 基因 ID
target_species: 目标物种
Returns:
同源基因列表
"""
url = f"{self.BASE_URL}/homology/symbol/{species}/{gene_id}"
params = {'target_species': target_species}
try:
response = self._rate_limited_request(url, params=params)
if response.status_code == 200:
return response.json().get('data', [])
return []
except Exception as e:
print(f"[WARN] Ensembl API error: {e}")
return []
class PhytozomeClient:
"""
Phytozome API 客户端
植物比较基因组学平台
URL: https://phytozome-next.jgi.doe.gov/
"""
BASE_URL = "https://phytozome-next.jgi.doe.gov/api"
def __init__(self, api_key: Optional[str] = None, rate_limit: float = 1.0):
self.api_key = api_key
self.rate_limit = rate_limit
self.last_request_time = 0
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'bbav20311/1.0 (Research Tool)',
'Accept': 'application/json'
})
def _rate_limited_request(self, url: str, **kwargs) -> requests.Response:
"""带速率限制的请求"""
elapsed = time.time() - self.last_request_time
if elapsed < self.rate_limit:
time.sleep(self.rate_limit - elapsed)
if self.api_key:
kwargs.setdefault('params', {})
kwargs['params']['api_key'] = self.api_key
response = self.session.get(url, **kwargs)
self.last_request_time = time.time()
return response
def search_gene(self, organism: str, gene_name: str) -> List[Dict[str, Any]]:
"""
搜索基因
Args:
organism: 生物体(如 Athaliana_447_TAIR10)
gene_name: 基因名称
Returns:
基因列表
"""
url = f"{self.BASE_URL}/genes/search"
params = {
'organism': organism,
'name': gene_name,
}
try:
response = self._rate_limited_request(url, params=params)
if response.status_code == 200:
return response.json().get('genes', [])
return []
except Exception as e:
print(f"[WARN] Phytozome API error: {e}")
return []
def get_gene_expression(self, organism: str, gene_id: str) -> Dict[str, Any]:
"""
获取基因表达数据
Args:
organism: 生物体
gene_id: 基因 ID
Returns:
表达数据
"""
url = f"{self.BASE_URL}/expression/{organism}/{gene_id}"
try:
response = self._rate_limited_request(url)
if response.status_code == 200:
return response.json()
return {}
except Exception as e:
print(f"[WARN] Phytozome API error: {e}")
return {}
class TAIRClient:
"""
TAIR (The Arabidopsis Information Resource) API 客户端
拟南芥数据库
URL: https://www.arabidopsis.org/
"""
BASE_URL = "https://www.arabidopsis.org/api"
def __init__(self, rate_limit: float = 1.0):
self.rate_limit = rate_limit
self.last_request_time = 0
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'bbav20311/1.0 (Research Tool)'
})
def _rate_limited_request(self, url: str, **kwargs) -> requests.Response:
"""带速率限制的请求"""
elapsed = time.time() - self.last_request_time
if elapsed < self.rate_limit:
time.sleep(self.rate_limit - elapsed)
response = self.session.get(url, **kwargs)
self.last_request_time = time.time()
return response
def search_locus(self, locus_name: str) -> Optional[Dict[str, Any]]:
"""
搜索基因位点
Args:
locus_name: 位点名称(如 AT1G01010)
Returns:
位点信息
"""
url = f"{self.BASE_URL}/loci/{locus_name}"
try:
response = self._rate_limited_request(url)
if response.status_code == 200:
return response.json()
return None
except Exception as e:
print(f"[WARN] TAIR API error: {e}")
return None
class PlantTFDBClient:
"""
PlantTFDB (Plant Transcription Factor Database) API 客户端
植物转录因子数据库
URL: http://planttfdb.gao-lab.org/
"""
BASE_URL = "http://planttfdb.gao-lab.org/api"
def __init__(self, rate_limit: float = 1.0):
self.rate_limit = rate_limit
self.last_request_time = 0
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'bbav20311/1.0 (Research Tool)'
})
def _rate_limited_request(self, url: str, **kwargs) -> requests.Response:
"""带速率限制的请求"""
elapsed = time.time() - self.last_request_time
if elapsed < self.rate_limit:
time.sleep(self.rate_limit - elapsed)
response = self.session.get(url, **kwargs)
self.last_request_time = time.time()
return response
def search_tf(self, species: str, gene_id: str) -> Optional[Dict[str, Any]]:
"""
搜索转录因子
Args:
species: 物种(如 ath, osa, zma)
gene_id: 基因 ID
Returns:
转录因子信息
"""
url = f"{self.BASE_URL}/tf/{species}/{gene_id}"
try:
response = self._rate_limited_request(url)
if response.status_code == 200:
return response.json()
return None
except Exception as e:
print(f"[WARN] PlantTFDB API error: {e}")
return None
def get_family_info(self, species: str, family: str) -> List[Dict[str, Any]]:
"""
获取转录因子家族信息
Args:
species: 物种
family: 家族名称(如 MYB, bZIP)
Returns:
家族成员列表
"""
url = f"{self.BASE_URL}/family/{species}/{family}"
try:
response = self._rate_limited_request(url)
if response.status_code == 200:
return response.json().get('members', [])
return []
except Exception as e:
print(f"[WARN] PlantTFDB API error: {e}")
return []
# 转录组数据平台汇总
RNASEQ_PLATFORMS = {
'ensembl_plants': {
'name': 'Ensembl Plants',
'url': 'https://plants.ensembl.org/',
'species': ['Arabidopsis', 'Rice', 'Maize', 'Soybean', 'Tomato', ...],
'data_types': ['genome', 'annotation', 'expression', 'variation'],
'client': EnsemblPlantsClient,
},
'phytozome': {
'name': 'Phytozome',
'url': 'https://phytozome-next.jgi.doe.gov/',
'species': ['Arabidopsis', 'Rice', 'Maize', 'Poplar', ...],
'data_types': ['genome', 'annotation', 'expression', 'synteny'],
'client': PhytozomeClient,
},
'tair': {
'name': 'TAIR',
'url': 'https://www.arabidopsis.org/',
'species': ['Arabidopsis'],
'data_types': ['genome', 'annotation', 'phenotype', 'literature'],
'client': TAIRClient,
},
'planttfdb': {
'name': 'PlantTFDB',
'url': 'http://planttfdb.gao-lab.org/',
'species': ['Arabidopsis', 'Rice', 'Maize', 'Soybean', ...],
'data_types': ['transcription_factor', 'regulation'],
'client': PlantTFDBClient,
},
}
# 使用示例
if __name__ == "__main__":
print("转录组数据平台 API 客户端")
print("=" * 60)
# Ensembl Plants
ensembl = EnsemblPlantsClient()
gene_info = ensembl.get_gene_info('arabidopsis_thaliana', 'SPL1')
if gene_info:
print(f"Ensembl: Found {gene_info.get('display_name')}")
# PlantTFDB
planttfdb = PlantTFDBClient()
tf_info = planttfdb.search_tf('ath', 'AT1G01010')
if tf_info:
print(f"PlantTFDB: Found {tf_info.get('family')} family TF")