237 lines
8.4 KiB
Python
237 lines
8.4 KiB
Python
"""
|
||||
|
|
PlantCARE API 客户端
|
|||
|
|
|
|||
|
|
PlantCARE 是一个植物顺式作用调控元件数据库
|
|||
|
|
URL: http://bioinformatics.psb.ugent.be/webtools/plantcare/html/
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import requests
|
|||
|
|
import time
|
|||
|
|
from typing import Dict, List, Optional, Any
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class CisElement:
|
|||
|
|
"""顺式作用元件"""
|
|||
|
|
name: str
|
|||
|
|
sequence: str
|
|||
|
|
function: str
|
|||
|
|
position: Optional[int] = None
|
|||
|
|
strand: Optional[str] = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
class PlantCAREClient:
|
|||
|
|
"""
|
|||
|
|
PlantCARE 数据库客户端
|
|||
|
|
|
|||
|
|
用于查询启动子区域的顺式作用调控元件
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
BASE_URL = "http://bioinformatics.psb.ugent.be/webtools/plantcare/html/"
|
|||
|
|
|
|||
|
|
def __init__(self, rate_limit: float = 1.0):
|
|||
|
|
"""
|
|||
|
|
初始化客户端
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
rate_limit: 请求间隔(秒),避免过载服务器
|
|||
|
|
"""
|
|||
|
|
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, method: str, 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.request(method, url, **kwargs)
|
|||
|
|
self.last_request_time = time.time()
|
|||
|
|
|
|||
|
|
return response
|
|||
|
|
|
|||
|
|
def search_elements(self, sequence: str, element_type: Optional[str] = None) -> List[CisElement]:
|
|||
|
|
"""
|
|||
|
|
搜索顺式作用元件
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
sequence: DNA 序列(启动子区域)
|
|||
|
|
element_type: 元件类型过滤(如 "light", "hormone", "stress")
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
顺式作用元件列表
|
|||
|
|
"""
|
|||
|
|
# PlantCARE 网页版没有公开 REST API
|
|||
|
|
# 这里实现基于本地数据库的查询或网页解析
|
|||
|
|
# 实际使用时可能需要本地部署 PlantCARE 数据库
|
|||
|
|
|
|||
|
|
# 模拟返回(实际应替换为真实查询)
|
|||
|
|
elements = self._parse_sequence_for_elements(sequence)
|
|||
|
|
|
|||
|
|
if element_type:
|
|||
|
|
elements = [e for e in elements if element_type.lower() in e.function.lower()]
|
|||
|
|
|
|||
|
|
return elements
|
|||
|
|
|
|||
|
|
def _parse_sequence_for_elements(self, sequence: str) -> List[CisElement]:
|
|||
|
|
"""
|
|||
|
|
解析序列中的顺式作用元件
|
|||
|
|
|
|||
|
|
基于 PlantCARE 已知元件模式进行匹配
|
|||
|
|
"""
|
|||
|
|
# PlantCARE 常见元件数据库(简化版)
|
|||
|
|
element_patterns = {
|
|||
|
|
'CAAT-box': {'pattern': 'CCAAT', 'function': 'core promoter element'},
|
|||
|
|
'TATA-box': {'pattern': 'TATA', 'function': 'core promoter element'},
|
|||
|
|
'G-box': {'pattern': 'CACGTG', 'function': 'light responsive'},
|
|||
|
|
'ABRE': {'pattern': 'ACGTGG', 'function': 'abscisic acid responsive'},
|
|||
|
|
'W-box': {'pattern': 'TTGAC', 'function': 'WRKY binding site'},
|
|||
|
|
'WUN-motif': {'pattern': 'AAATTTCCT', 'function': 'wound responsive'},
|
|||
|
|
'MYB-binding': {'pattern': 'CNGTT', 'function': 'MYB transcription factor binding'},
|
|||
|
|
'MYC-binding': {'pattern': 'CACATG', 'function': 'MYC transcription factor binding'},
|
|||
|
|
'GT-1 motif': {'pattern': 'GGTTAA', 'function': 'light responsive'},
|
|||
|
|
'I-box': {'pattern': 'GATAA', 'function': 'light responsive'},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
elements = []
|
|||
|
|
sequence_upper = sequence.upper()
|
|||
|
|
|
|||
|
|
for name, info in element_patterns.items():
|
|||
|
|
pattern = info['pattern']
|
|||
|
|
# 支持简并碱基
|
|||
|
|
import re
|
|||
|
|
pattern_regex = pattern.replace('N', '[ATCG]')
|
|||
|
|
|
|||
|
|
for match in re.finditer(pattern_regex, sequence_upper):
|
|||
|
|
elements.append(CisElement(
|
|||
|
|
name=name,
|
|||
|
|
sequence=sequence[match.start():match.end()],
|
|||
|
|
function=info['function'],
|
|||
|
|
position=match.start(),
|
|||
|
|
strand='+'
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
return elements
|
|||
|
|
|
|||
|
|
def get_element_details(self, element_name: str) -> Optional[Dict[str, Any]]:
|
|||
|
|
"""
|
|||
|
|
获取元件详细信息
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
element_name: 元件名称(如 "G-box")
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
元件详细信息字典
|
|||
|
|
"""
|
|||
|
|
# 本地元件数据库
|
|||
|
|
element_db = {
|
|||
|
|
'CAAT-box': {
|
|||
|
|
'name': 'CAAT-box',
|
|||
|
|
'consensus': 'CCAAT',
|
|||
|
|
'function': 'Core promoter element, enhances transcription efficiency',
|
|||
|
|
'factors': ['CTF/NF1', 'CCAAT-binding factors'],
|
|||
|
|
'references': ['Mantovani, 1999'],
|
|||
|
|
},
|
|||
|
|
'TATA-box': {
|
|||
|
|
'name': 'TATA-box',
|
|||
|
|
'consensus': 'TATA(A/T)A(A/T)',
|
|||
|
|
'function': 'Core promoter element, transcription start site selection',
|
|||
|
|
'factors': ['TBP (TATA-binding protein)'],
|
|||
|
|
'references': ['Smale & Kadonaga, 2003'],
|
|||
|
|
},
|
|||
|
|
'G-box': {
|
|||
|
|
'name': 'G-box',
|
|||
|
|
'consensus': 'CACGTG',
|
|||
|
|
'function': 'Light-responsive element, also involved in ABA signaling',
|
|||
|
|
'factors': ['bZIP transcription factors', 'HY5'],
|
|||
|
|
'references': ['Menkens et al., 1995'],
|
|||
|
|
},
|
|||
|
|
'ABRE': {
|
|||
|
|
'name': 'ABRE',
|
|||
|
|
'consensus': 'ACGTGG/TC',
|
|||
|
|
'function': 'Abscisic acid responsive element',
|
|||
|
|
'factors': ['bZIP/ABF transcription factors'],
|
|||
|
|
'references': ['Nakashima & Yamaguchi-Shinozaki, 2013'],
|
|||
|
|
},
|
|||
|
|
'W-box': {
|
|||
|
|
'name': 'W-box',
|
|||
|
|
'consensus': 'TTGAC(C/T)',
|
|||
|
|
'function': 'WRKY transcription factor binding site, defense response',
|
|||
|
|
'factors': ['WRKY transcription factors'],
|
|||
|
|
'references': ['Eulgem et al., 2000'],
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return element_db.get(element_name)
|
|||
|
|
|
|||
|
|
def analyze_promoter(self, promoter_sequence: str, upstream_length: int = 1500) -> Dict[str, Any]:
|
|||
|
|
"""
|
|||
|
|
全面分析启动子区域
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
promoter_sequence: 启动子序列
|
|||
|
|
upstream_length: 上游长度(默认1500bp)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
分析结果字典
|
|||
|
|
"""
|
|||
|
|
elements = self.search_elements(promoter_sequence)
|
|||
|
|
|
|||
|
|
# 分类统计
|
|||
|
|
categories = {}
|
|||
|
|
for elem in elements:
|
|||
|
|
category = self._categorize_element(elem)
|
|||
|
|
if category not in categories:
|
|||
|
|
categories[category] = []
|
|||
|
|
categories[category].append(elem)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'total_elements': len(elements),
|
|||
|
|
'categories': {k: len(v) for k, v in categories.items()},
|
|||
|
|
'elements_by_category': categories,
|
|||
|
|
'core_promoter_elements': [e for e in elements if 'core promoter' in e.function],
|
|||
|
|
'regulatory_elements': [e for e in elements if 'responsive' in e.function or 'binding' in e.function],
|
|||
|
|
'sequence_length': len(promoter_sequence),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _categorize_element(self, element: CisElement) -> str:
|
|||
|
|
"""对元件进行分类"""
|
|||
|
|
function_lower = element.function.lower()
|
|||
|
|
|
|||
|
|
if 'core promoter' in function_lower:
|
|||
|
|
return 'core_promoter'
|
|||
|
|
elif 'light' in function_lower:
|
|||
|
|
return 'light_responsive'
|
|||
|
|
elif 'hormone' in function_lower or 'acid' in function_lower:
|
|||
|
|
return 'hormone_responsive'
|
|||
|
|
elif 'stress' in function_lower or 'wound' in function_lower:
|
|||
|
|
return 'stress_responsive'
|
|||
|
|
elif 'binding' in function_lower:
|
|||
|
|
return 'tf_binding'
|
|||
|
|
else:
|
|||
|
|
return 'other'
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 使用示例
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
client = PlantCAREClient()
|
|||
|
|
|
|||
|
|
# 测试序列
|
|||
|
|
|
|||
|
|
# 测试序列
|
|||
|
|
test_seq = "ATGCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCG"
|
|||
|
|
|
|||
|
|
# 搜索元件
|
|||
|
|
elements = client.search_elements(test_seq)
|
|||
|
|
print(f"Found {len(elements)} cis-elements")
|
|||
|
|
|
|||
|
|
for elem in elements:
|
|||
|
|
print(f" - {elem.name}: {elem.sequence} ({elem.function})")
|
|||
|
|
|