Optimize nupack service startup and compute
This commit is contained in:
commit
e1b3156754
25 changed files with 9435 additions and 0 deletions
460
rna/TrnaStructureBeautifier.py
Normal file
460
rna/TrnaStructureBeautifier.py
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
# _*_ coding:utf-8 _*_
|
||||
#
|
||||
# @Version : 1.1
|
||||
# @Project : https://github.com/shueho/BioDataTools
|
||||
# @Time : 2025/7/23 20:00
|
||||
# @Update : 2025/8/13 14:00
|
||||
# @Author : Hao Xue
|
||||
# @E-mail : studid@163.com
|
||||
# @File : TrnaStructureBeautifier.py
|
||||
#
|
||||
# Enhancement of tRNA secondary structure diagrams generated using the ViennaRNA package.
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
|
||||
|
||||
# old = sys.argv[1]
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description="RNA结构图美化参数配置")
|
||||
|
||||
# === 输入控制 ===
|
||||
parser.add_argument(
|
||||
"-i", "--input",
|
||||
type=str,
|
||||
required=True,
|
||||
help="SVG文件或者SVG文件存放的文件夹路径"
|
||||
)
|
||||
|
||||
# === 基础布局 ===
|
||||
parser.add_argument(
|
||||
"-s", "--size-weight",
|
||||
type=float,
|
||||
default=1.4,
|
||||
help="图形缩放比例(默认 1.4)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p", "--per-row",
|
||||
type=int,
|
||||
default=4,
|
||||
help="每行图片数量(默认 4)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-hg", "--horizontal-gap",
|
||||
type=int,
|
||||
default=8,
|
||||
help="图片水平间隔(默认 8)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-vg", "--vertical-gap",
|
||||
type=int,
|
||||
default=5,
|
||||
help="图片垂直间隔(默认 5)"
|
||||
)
|
||||
|
||||
# === 碱基连线颜色 ===
|
||||
parser.add_argument(
|
||||
"-ac", "--adjacent-color",
|
||||
type=str,
|
||||
default="blue",
|
||||
help='相邻碱基连线颜色(支持名称或 HEX,如 "blue" 或 "#00FF00",默认 "blue")'
|
||||
)
|
||||
parser.add_argument(
|
||||
"-pc", "--pair-color",
|
||||
type=str,
|
||||
default="red",
|
||||
help='配对碱基连线颜色(支持名称或 HEX,如 "red" 或 "#FF0000",默认 "red")'
|
||||
)
|
||||
|
||||
# === 碱基圆圈样式 ===
|
||||
parser.add_argument(
|
||||
"-bf", "--base-fill",
|
||||
type=str,
|
||||
default="white",
|
||||
help='碱基圆圈填充色(默认 "white")'
|
||||
)
|
||||
parser.add_argument(
|
||||
"-bs", "--base-stroke",
|
||||
type=str,
|
||||
default="black",
|
||||
help='碱基圆圈轮廓色(默认 "black")'
|
||||
)
|
||||
|
||||
# === 碱基美化图 ===
|
||||
parser.add_argument(
|
||||
"-A", "--base-a",
|
||||
type=str,
|
||||
default="red",
|
||||
help='美化A碱基圆圈填充色(默认 "red")'
|
||||
)
|
||||
parser.add_argument(
|
||||
"-U", "--base-u",
|
||||
type=str,
|
||||
default="blue",
|
||||
help='美化U/T碱基圆圈填充色(默认 "blue")'
|
||||
)
|
||||
parser.add_argument(
|
||||
"-G", "--base-g",
|
||||
type=str,
|
||||
default="green",
|
||||
help='美化G碱基圆圈填充色(默认 "green")'
|
||||
)
|
||||
parser.add_argument(
|
||||
"-C", "--base-c",
|
||||
type=str,
|
||||
default="yellow",
|
||||
help='美化C碱基圆圈填充色(默认 "yellow")'
|
||||
)
|
||||
|
||||
# === 反密码子控制 ===
|
||||
# parser.add_argument(
|
||||
# "-af", "--anticodon-file",
|
||||
# type=str,
|
||||
# default=None,
|
||||
# help="反密码子位点文件路径(文本文件,每行一个位置)"
|
||||
# )
|
||||
# parser.add_argument(
|
||||
# "-aF", "--anti-fill",
|
||||
# type=str,
|
||||
# default="red",
|
||||
# help='反密码子圆圈填充色(默认 "red")'
|
||||
# )
|
||||
# parser.add_argument(
|
||||
# "-aS", "--anti-stroke",
|
||||
# type=str,
|
||||
# default="black",
|
||||
# help='反密码子圆圈轮廓色(默认 "black")'
|
||||
# )
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
|
||||
args = parse_arguments()
|
||||
base_color = {"A": args.base_a, "U": args.base_u, "G": args.base_g, "C": args.base_c, }
|
||||
# 设置目标文件夹名称
|
||||
modified_folder = "modified"
|
||||
# 创建文件夹(如果已存在则忽略)
|
||||
os.makedirs(modified_folder, exist_ok=True)
|
||||
print("已创建文件夹: modified")
|
||||
|
||||
|
||||
def read_svg(spath):
|
||||
with open(spath) as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def set_new_text(x_y_char, fill_=args.base_fill, stroke_=args.base_stroke):
|
||||
x = x_y_char[0]
|
||||
y = x_y_char[1]
|
||||
t = x_y_char[2].upper().replace("T", "U")
|
||||
# 核心修改:保持圆圈半径r=5不变,调整dy=0使字母在垂直方向也居中(结合text-anchor=middle实现正中心)
|
||||
return '<circle cx="{}" cy="{}" r="5" fill="{}" stroke="{}" />\n <text x="{}" y="{}" text-anchor="middle" dy="2"\n font-size="8" fill="black">{}</text>\n'.format(
|
||||
x, y, fill_, stroke_, x, y, t)
|
||||
# r=圆圈半径,dy=字体垂直位移,font-size=字体大小
|
||||
|
||||
def set_new_lines(x_y_char_1, x_y_char_2, stroke_):
|
||||
x1, y1, _ = x_y_char_1
|
||||
x2, y2, _ = x_y_char_2
|
||||
xy = (x1, y1, x2, y2)
|
||||
return '<line x1="{}" y1="{}" x2="{}" y2="{}" stroke="{}" stroke-width="1"/>\n'.format(*xy, stroke_)
|
||||
|
||||
|
||||
# 保留原有 get_add_line 函数,不修改(保持代码秩序)
|
||||
def get_add_line(svg_text):
|
||||
# pattern = r'<line.*?x1="([^"]+)"[^>]*?y1="([^"]+)"[^>]*?x2="([^"]+)"[^>]*?y2="([^"]+)"'
|
||||
pattern = r'<line\b[^>]*\s*x1="([^"]+)"[^>]*\s*y1="([^"]+)"[^>]*\s*x2="([^"]+)"[^>]*\s*y2="([^"]+)"'
|
||||
matches = re.findall(pattern, svg_text)
|
||||
result = []
|
||||
for x1_str, y1_str, x2_str, y2_str in matches:
|
||||
try:
|
||||
x1 = float(x1_str)
|
||||
y1 = float(y1_str)
|
||||
x2 = float(x2_str)
|
||||
y2 = float(y2_str)
|
||||
result.append(set_new_lines((x1, y1, ""), (x2, y2, ""), args.pair_color))
|
||||
except ValueError:
|
||||
# 如果坐标无法转换为 float,跳过该元素
|
||||
continue
|
||||
return "".join(result)
|
||||
|
||||
|
||||
# 核心修改1:extract_text_info 补充返回坐标边界(用于居中计算),生成内容逻辑完全不变
|
||||
def extract_text_info(svg_text):
|
||||
# 正则表达式匹配 <text> 标签中的 x、y 和字符内容
|
||||
# pattern = r'<text\s+x="([^"]+)"\s+y="([^"]+)"[^>]*>([^<]+)</text>'
|
||||
pattern = r'<text\b[^>]*\s*x="([^"]+)"[^>]*\s*y="([^"]+)"[^>]*>(.*?)<\/text>'
|
||||
matches = re.findall(pattern, svg_text)
|
||||
result = []
|
||||
for x_str, y_str, char in matches:
|
||||
try:
|
||||
x = float(x_str)
|
||||
y = float(y_str)
|
||||
result.append((x, y, char))
|
||||
except ValueError:
|
||||
# 如果 x 或 y 无法转换为 float,跳过该元素
|
||||
continue
|
||||
|
||||
# 计算坐标边界(新增:用于后续居中)
|
||||
if not result:
|
||||
min_x = max_x = min_y = max_y = 0
|
||||
else:
|
||||
xs = [p[0] for p in result]
|
||||
ys = [p[1] for p in result]
|
||||
min_x, max_x = min(xs), max(xs)
|
||||
min_y, max_y = min(ys), max(ys)
|
||||
|
||||
# 原有生成内容逻辑完全不变(保证字母在圆圈内)
|
||||
content = '<g style="font-family: Times New Roman" transform="translate(-4.6, 4)" id="seq">\n'
|
||||
content += get_add_line(svg_text)
|
||||
for i in range(1, len(result)):
|
||||
# content += set_new_text(result[i])
|
||||
content += set_new_lines(result[i - 1], result[i], args.adjacent_color)
|
||||
content += set_new_text(result[i - 1])
|
||||
|
||||
content += set_new_text(result[len(result) - 1]) + '</g>\n'
|
||||
|
||||
# 新增返回坐标边界,用于居中计算
|
||||
return content, min_x, max_x, min_y, max_y
|
||||
|
||||
|
||||
def save_svg(content, outpath):
|
||||
with open(outpath, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
# 核心修改2:modi_svg 改为超大画布 + 自动居中,保留原有逻辑框架
|
||||
def modi_svg(path):
|
||||
t = read_svg(path)
|
||||
name_ = os.path.basename(path)
|
||||
if "-" in name_:
|
||||
name_ = name_.split("-")[0]
|
||||
else:
|
||||
name_ = name_.split(".")[0]
|
||||
|
||||
# 提取内容 + 坐标边界(新增)
|
||||
mid_, min_x, max_x, min_y, max_y = extract_text_info(t)
|
||||
scale = args.size_weight
|
||||
|
||||
# 1. 超大画布(2000×2000,可自行调大)
|
||||
canvas_w = 2000
|
||||
canvas_h = 2000
|
||||
|
||||
# 2. 计算结构中心(用于居中)
|
||||
if min_x == max_x and min_y == max_y:
|
||||
cx, cy = 0, 0
|
||||
else:
|
||||
cx = (min_x + max_x) / 2 # 结构水平中心
|
||||
cy = (min_y + max_y) / 2 # 结构垂直中心
|
||||
|
||||
# 3. 计算居中偏移量(保证结构在画布正中间)
|
||||
translate_x = (canvas_w / 2) / scale - cx # 水平居中
|
||||
translate_y = (canvas_h / 2) / scale - cy # 垂直居中
|
||||
|
||||
# 保留原有 head_ 结构,仅替换画布尺寸和偏移量,同时修改名称位置避免重叠
|
||||
head_ = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="{}" width="{}" viewBox="0 0 {} {}">
|
||||
<rect style="stroke: none; fill: none" height="{}" x="0" y="0" width="{}" onclick="click(evt)" />
|
||||
<g transform="scale({},{}) translate({:.2f},{:.2f})">
|
||||
<g style="font-family: Times New Roman" id="name">
|
||||
<text font-size="20" x="{:.2f}" y="{:.2f}" text-anchor="middle">{}</text>
|
||||
</g>
|
||||
'''.format(canvas_h, canvas_w, canvas_w, canvas_h, canvas_h, canvas_w, scale, scale, translate_x, translate_y, cx, min_y - 20, name_)
|
||||
|
||||
tail_ = ' </g>\n</svg>'
|
||||
save_svg(head_ + mid_ + tail_, "modified/modified_" + name_ + ".svg")
|
||||
return name_
|
||||
|
||||
|
||||
# save_svg(modi_svg(old), "new.svg")
|
||||
def remove_xml_declaration(content):
|
||||
"""Remove XML declaration from SVG content."""
|
||||
return re.sub(r'<\?xml[^>]*\?>\s*', '', content)
|
||||
|
||||
|
||||
def extract_dimensions(svg_content):
|
||||
"""Extract width and height from SVG content."""
|
||||
width_match = re.search(r'width="([^"]+)"', svg_content)
|
||||
height_match = re.search(r'height="([^"]+)"', svg_content)
|
||||
if not width_match or not height_match:
|
||||
raise ValueError("Could not extract width or height")
|
||||
return width_match.group(1), height_match.group(1)
|
||||
|
||||
|
||||
def merge_horizontal_group(svg_files, output_file):
|
||||
"""Merge SVGs in a group horizontally."""
|
||||
svgs = []
|
||||
total_width = 0
|
||||
max_height = 0
|
||||
gap = args.horizontal_gap
|
||||
|
||||
for filename in svg_files:
|
||||
with open(filename, 'r') as f:
|
||||
content = f.read()
|
||||
content = remove_xml_declaration(content)
|
||||
width, height = extract_dimensions(content)
|
||||
try:
|
||||
width_px = float(width.strip('px'))
|
||||
height_px = float(height.strip('px'))
|
||||
except ValueError:
|
||||
raise ValueError(f"Invalid unit in file {filename}")
|
||||
|
||||
svgs.append({
|
||||
'filename': filename,
|
||||
'content': content,
|
||||
'width': width,
|
||||
'height': height,
|
||||
'width_px': width_px,
|
||||
'height_px': height_px
|
||||
})
|
||||
|
||||
total_width += sum(svg_info['width_px'] for svg_info in svgs) + gap * (len(svgs) - 1)
|
||||
max_height = max(max_height, height_px)
|
||||
|
||||
new_svg = [
|
||||
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>',
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}">'.format(total_width, max_height)
|
||||
]
|
||||
|
||||
current_x = 0.0
|
||||
for svg_info in svgs:
|
||||
inner_content = re.sub(r'<svg[^>]*>', '', svg_info['content'])
|
||||
inner_content = re.sub(r'</svg>', '', inner_content)
|
||||
new_svg.append('<g transform="translate({:.2f}, 0)">'.format(current_x))
|
||||
new_svg.append(inner_content)
|
||||
new_svg.append('</g>')
|
||||
current_x += svg_info['width_px'] + gap
|
||||
|
||||
new_svg.append('</svg>')
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.write('\n'.join(new_svg))
|
||||
|
||||
|
||||
def merge_vertical_groups(group_files, output_file):
|
||||
"""Merge all horizontal groups vertically."""
|
||||
svgs = []
|
||||
max_width = 0
|
||||
total_height = 0
|
||||
gap = args.vertical_gap
|
||||
|
||||
for filename in group_files:
|
||||
with open(filename, 'r') as f:
|
||||
content = f.read()
|
||||
content = remove_xml_declaration(content)
|
||||
width, height = extract_dimensions(content)
|
||||
try:
|
||||
width_px = float(width.strip('px'))
|
||||
height_px = float(height.strip('px'))
|
||||
except ValueError:
|
||||
raise ValueError(f"Invalid unit in file {filename}")
|
||||
|
||||
svgs.append({
|
||||
'filename': filename,
|
||||
'content': content,
|
||||
'width': width,
|
||||
'height': height,
|
||||
'width_px': width_px,
|
||||
'height_px': height_px
|
||||
})
|
||||
|
||||
max_width = max(max_width, width_px)
|
||||
total_height += sum(svg_info['height_px'] for svg_info in svgs) + gap * (len(svgs) - 1)
|
||||
|
||||
new_svg = [
|
||||
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>',
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}">'.format(max_width, total_height)
|
||||
]
|
||||
|
||||
current_y = 0.0
|
||||
for svg_info in svgs:
|
||||
inner_content = re.sub(r'<svg[^>]*>', '', svg_info['content'])
|
||||
inner_content = re.sub(r'</svg>', '', inner_content)
|
||||
new_svg.append('<g transform="translate(0, {:.2f})">'.format(current_y))
|
||||
new_svg.append(inner_content)
|
||||
new_svg.append('</g>')
|
||||
current_y += svg_info['height_px'] + gap
|
||||
|
||||
new_svg.append('</svg>')
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.write('\n'.join(new_svg))
|
||||
|
||||
|
||||
def update_circle_colors(svg_content, base_color_map):
|
||||
new_ = ""
|
||||
ls = svg_content.split("\n")
|
||||
for i in range(len(ls)):
|
||||
if "<circle cx" in ls[i]:
|
||||
flag = re.findall(r'(?<=>)[A-Z](?=<\/text>)', ls[i + 2])[0]
|
||||
if flag not in base_color_map:
|
||||
new_ += ls[i] + "\n"
|
||||
continue
|
||||
new_ += ls[i].replace(args.base_fill, base_color_map[flag]) + "\n"
|
||||
else:
|
||||
new_ += ls[i] + "\n"
|
||||
return new_
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 示例调用
|
||||
print("参数解析结果:")
|
||||
# print(f"主数据文件: {args.input}")
|
||||
print(f"大小权重: {args.size_weight}")
|
||||
print(f"每行图片数量: {args.per_row}")
|
||||
print(f"图片水平间隔: {args.horizontal_gap}")
|
||||
print(f"图片垂直间隔: {args.vertical_gap}")
|
||||
print(f"相邻碱基连线颜色: {args.adjacent_color}")
|
||||
print(f"配对碱基连线颜色: {args.pair_color}")
|
||||
print(f"碱基填充色: {args.base_fill}")
|
||||
print(f"碱基轮廓色: {args.base_stroke}")
|
||||
# print(f"反密码子文件: {args.anticodon_file}")
|
||||
# print(f"反密码子填充色: {args.anti_fill}")
|
||||
# print(f"反密码子轮廓色: {args.anti_stroke}")
|
||||
# 如果是文件,直接添加到列表
|
||||
file_list = []
|
||||
group_size = args.per_row
|
||||
if os.path.isfile(args.input):
|
||||
file_list.append(args.input)
|
||||
print(f"已添加文件: {args.input}")
|
||||
|
||||
# 如果是文件夹,添加文件夹内所有文件(不递归子文件夹)
|
||||
elif os.path.isdir(args.input):
|
||||
for filename in os.listdir(args.input):
|
||||
file_path = os.path.join(args.input, filename)
|
||||
if os.path.isfile(file_path) and "modified_" not in file_path and ".svg" == file_path[-4:]: # 只处理文件
|
||||
file_list.append(file_path)
|
||||
file_list.sort()
|
||||
print(f"已添加文件夹内所有文件: {args.input}")
|
||||
modi_files = []
|
||||
for i in file_list:
|
||||
n = modi_svg(i)
|
||||
modi_files.append("modified/modified_" + n + ".svg")
|
||||
|
||||
# Step 2: Merge into horizontal groups
|
||||
group_index = 0
|
||||
group_files = []
|
||||
for i in range(0, len(modi_files), group_size):
|
||||
group = modi_files[i:i + group_size]
|
||||
if not group:
|
||||
break
|
||||
group_output = f"modified/group_{group_index}.svg"
|
||||
merge_horizontal_group(group, str(group_output))
|
||||
group_files.append(group_output)
|
||||
group_index += 1
|
||||
|
||||
# Step 3: Merge all groups vertically
|
||||
final_output = "modified/final.svg"
|
||||
merge_vertical_groups(group_files, str(final_output))
|
||||
print(f"未上色SVG保存到: {final_output}")
|
||||
print(f"美化A碱基填充色: {args.base_a}")
|
||||
print(f"美化U碱基填充色: {args.base_u}")
|
||||
print(f"美化G碱基填充色: {args.base_g}")
|
||||
print(f"美化C碱基填充色: {args.base_c}")
|
||||
fisvg = read_svg(str(final_output))
|
||||
cosvg = update_circle_colors(fisvg, base_color)
|
||||
save_svg(cosvg, "modified/final_color.svg")
|
||||
# 核心修改3:修复打印路径错误(原写成 final.svg,改为 final_color.svg)
|
||||
print(f"上色SVG保存到: modified/final_color.svg")
|
||||
# print(modi_files)
|
||||
BIN
rna/ViennaRNA-2.7.2.tar.gz
Normal file
BIN
rna/ViennaRNA-2.7.2.tar.gz
Normal file
Binary file not shown.
10
rna/nupack代码示例.txt
Normal file
10
rna/nupack代码示例.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
model1 = Model(material='dna', celsius=37,sodium=0.1, magnesium=0.02)
|
||||
Y1 = Strand('CGTTAACGCAGTGAGGACGGTAGTTTGTCGTTCCATCGCACC', name='Y1')
|
||||
Y2 = Strand('CGTTAACGGGTGCGATGGAACGACTTTCGACAGGCCTGGTGTAATTTCACCCATGTTAGTCGA', name='Y2')
|
||||
Y3 = Strand('ATACGGAAAATGGAGATAGGAAGAGTACAATGTCAGCGATAAATTCCGTATACGACACCAGGCCTGTCGATTACTACCGTCCTCACTG', name='Y3')
|
||||
|
||||
t1 = Tube({Y1: 1e-8, Y2: 1e-8, Y3:1e-8 },complexes=SetSpec(max_size=4), name='Tube 1')
|
||||
|
||||
my_result = tube_analysis(tubes=[t1], model=model1,
|
||||
compute=['pfunc', 'pairs', 'mfe', 'sample', 'subopt'])
|
||||
print(my_result)
|
||||
139
rna/工具调用.txt
Normal file
139
rna/工具调用.txt
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
from nupack import *
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
# ---------- 独立的辅助函数 ----------
|
||||
def get_sequence(Complex, result, skip_errors=True):
|
||||
"""
|
||||
获取复合物的序列。
|
||||
- 若 Complex 为 None,返回字典 {复合物名: 序列},跳过解析失败的复合物。
|
||||
- 若 Complex 为字符串或 Complex 对象,返回该复合物的序列字符串;失败时抛出异常(除非 skip_errors=False 时由调用者处理)。
|
||||
"""
|
||||
# 统一转换为字符串名称
|
||||
if Complex is not None and not isinstance(Complex, str):
|
||||
Complex = Complex.name if hasattr(Complex, 'name') else str(Complex)
|
||||
|
||||
def _get_seq_from_strands(strand_names, comp_name=None):
|
||||
"""从链名列表获取拼接后的序列,如果失败则抛出异常"""
|
||||
seq_parts = []
|
||||
for s in strand_names:
|
||||
if not s.isidentifier():
|
||||
raise NameError(
|
||||
f"复合物 '{comp_name}' 中的链名 '{s}' 不是有效的 Python 标识符,"
|
||||
"请检查链的 name 属性是否包含空格或特殊字符。"
|
||||
)
|
||||
try:
|
||||
strand_obj = eval(s)
|
||||
if not isinstance(strand_obj, Strand):
|
||||
raise TypeError(f"'{s}' 不是 Strand 对象")
|
||||
seq_parts.append(str(strand_obj))
|
||||
except NameError:
|
||||
raise NameError(f"链名 '{s}' 未定义,请确保该变量已创建为 Strand 对象。")
|
||||
return ''.join(seq_parts)
|
||||
|
||||
if Complex is None:
|
||||
# 批量模式
|
||||
sequences = {}
|
||||
for comp in result:
|
||||
name = comp.name if hasattr(comp, 'name') else str(comp)
|
||||
try:
|
||||
# 去除括号,按 '+' 分割
|
||||
inp = ''.join([ch for ch in name if ch not in '()'])
|
||||
strands = inp.split('+')
|
||||
sequences[name] = _get_seq_from_strands(strands, comp_name=name)
|
||||
except Exception as e:
|
||||
if skip_errors:
|
||||
print(f"⚠️ 跳过复合物 '{name}',原因:{e}")
|
||||
else:
|
||||
raise # 如果不跳过,则抛出异常
|
||||
return sequences
|
||||
else:
|
||||
# 单复合物模式
|
||||
inp = ''.join([ch for ch in Complex if ch not in '()'])
|
||||
strands = inp.split('+')
|
||||
return _get_seq_from_strands(strands, comp_name=Complex)
|
||||
|
||||
def get_structure(Complex, result, skip_errors=True):
|
||||
"""
|
||||
获取复合物的 MFE 结构(已去除 '+')。
|
||||
- 若 Complex 为 None,返回字典 {复合物名: 结构},跳过 result 中不存在的复合物。
|
||||
- 若 Complex 为字符串或 Complex 对象,返回该复合物的结构字符串;失败时抛出异常。
|
||||
"""
|
||||
if Complex is not None and not isinstance(Complex, str):
|
||||
Complex = Complex.name if hasattr(Complex, 'name') else str(Complex)
|
||||
|
||||
if Complex is None:
|
||||
structures = {}
|
||||
for comp in result:
|
||||
name = comp.name if hasattr(comp, 'name') else str(comp)
|
||||
try:
|
||||
structure = result[comp].mfe[0].structure
|
||||
structures[name] = str(structure).replace('+', '')
|
||||
except Exception as e:
|
||||
if skip_errors:
|
||||
print(f"⚠️ 跳过复合物 '{name}',获取结构失败:{e}")
|
||||
else:
|
||||
raise
|
||||
return structures
|
||||
else:
|
||||
structure = result[Complex].mfe[0].structure
|
||||
return str(structure).replace('+', '')
|
||||
|
||||
# ---------- 绘图函数(带错误跳过) ----------
|
||||
def danlian(Complex, result, output_folder="/home/zsy"):
|
||||
"""
|
||||
绘制单个复合物的二级结构图。如果处理过程中出现错误,打印错误信息并返回,不中断程序。
|
||||
Complex 可为复合物名称字符串或 Complex 对象。
|
||||
"""
|
||||
try:
|
||||
sequence = get_sequence(Complex, result, skip_errors=False) # 这里不跳过,让异常抛出以便捕获
|
||||
best_structure = get_structure(Complex, result, skip_errors=False)
|
||||
except Exception as e:
|
||||
name = Complex if isinstance(Complex, str) else (Complex.name if hasattr(Complex, 'name') else str(Complex))
|
||||
print(f"❌ 处理复合物 '{name}' 时出错:{e},已跳过绘图")
|
||||
return
|
||||
|
||||
# 获取用于文件名的字符串名称
|
||||
if isinstance(Complex, str):
|
||||
seq_name = Complex
|
||||
else:
|
||||
seq_name = Complex.name if hasattr(Complex, 'name') else str(Complex)
|
||||
|
||||
temp_file_path = os.path.join(output_folder, f"{seq_name}.seq")
|
||||
try:
|
||||
with open(temp_file_path, "w", newline='\n') as f:
|
||||
f.write(f">{seq_name}\n")
|
||||
f.write(f"{sequence}\n")
|
||||
f.write(f"{best_structure}\n")
|
||||
except Exception as e:
|
||||
print(f"❌ 写入临时文件失败:{e}")
|
||||
return
|
||||
|
||||
try:
|
||||
input_filename = f"{seq_name}.seq"
|
||||
process = subprocess.run(["RNAplot", "--o", "svg", input_filename], cwd=output_folder, capture_output=True, text=True)
|
||||
if process.returncode == 0:
|
||||
print(f"🎉 绘图成功!请前往 {output_folder} 文件夹查看 {seq_name}_ss.svg")
|
||||
os.remove(temp_file_path)
|
||||
else:
|
||||
print(f"❌ RNAplot 运行失败,报错信息:\n{process.stderr}")
|
||||
except FileNotFoundError:
|
||||
print("❌ 找不到 RNAplot 命令,请确认环境变量。")
|
||||
except Exception as e:
|
||||
print(f"❌ 绘图过程中出现未知错误:{e}")
|
||||
|
||||
|
||||
使用方法
|
||||
算全部结果
|
||||
for comp in my_result:
|
||||
danlian(comp, my_result, output_folder="/home/zsy")
|
||||
|
||||
算单个结果
|
||||
# 假设您的计算结果保存在 my_result 中
|
||||
target = '(Y2+Y3)' # 替换为您的目标复合物名称
|
||||
# 输出结构
|
||||
print(get_structure(target, my_result))
|
||||
# 输出序列
|
||||
print(get_sequence(target, my_result))
|
||||
# 绘制二级结构图
|
||||
danlian(target, my_result, output_folder="/home/zsy")
|
||||
44
rna/操作流程.txt
Normal file
44
rna/操作流程.txt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
准备工作:
|
||||
在 Windows 界面中搜索 控制面板 打开 程序-程序和功能-启动或关闭 Windows 功能-勾选‘适用于 Linux 的 Windows 子系统’与‘虚拟机平台’后点击确定后重启电脑
|
||||
在 Microsoft Store 中下载 Ubunut
|
||||
按 Win+X 键 点击 ‘命令提示符(管理员)’ 输入 wsl --install 后回车。下载完毕后关闭即可。 如果遇到链接失败就是网络问题,链接手机热点后重新输入+回车即可
|
||||
|
||||
安装:打开 Ubunut
|
||||
将群内的所有压缩包直接保存在D盘
|
||||
nupack 安装
|
||||
mkdir nupack-latest
|
||||
cd nupack-latest
|
||||
cp /mnt/d/nupack-4.0.2.0.zip ./
|
||||
sudo apt install unzip
|
||||
unzip nupack-4.0.2.0.zip
|
||||
cd ..
|
||||
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
|
||||
/bin/bash Miniconda3-latest-Linux-x86_64.sh -b
|
||||
miniconda3/bin/conda update -n base -c defaults conda
|
||||
rm Miniconda3-latest-Linux-x86_64.sh
|
||||
export PATH=$HOME/miniconda3/bin:$PATH
|
||||
echo 'export PATH=$HOME/miniconda3/bin:$PATH' >> ~/.bashrc
|
||||
conda install numpy scipy pip matplotlib pandas jupyterlab
|
||||
pip install -U nupack -f ./nupack-latest/nupack-4.0.2.0/package
|
||||
jupyter lab
|
||||
|
||||
RNAplot 安装
|
||||
mkdir rna
|
||||
cd rna
|
||||
cp /mnt/d/ViennaRNA-2.7.2.tar.gz ./
|
||||
tar -zxvf ViennaRNA-2.7.2.tar.gz
|
||||
cd ViennaRNA-2.7.2
|
||||
(可能出现报错的解决方法
|
||||
sudo apt update
|
||||
sudo apt install build-essentia
|
||||
sudo apt install pkg-config)
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
|
||||
图片美化方法
|
||||
|
||||
将生成后的svg图片保存在一个文件夹内,并将该文件夹与群内的 py 文件保存在一个文件夹。后 Shift+鼠标右键 点击在此处打开 Powershell 窗口后
|
||||
输入命令
|
||||
python TrnaStructureBeautifier.py -i 文件夹名称 用于指定一个文件夹
|
||||
python TrnaStructureBeautifier.py -i 文件名称 用于指定一个文件
|
||||
46
rna/调用RNAplot的代码.txt
Normal file
46
rna/调用RNAplot的代码.txt
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
from nupack import *
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
def huatu(Complex,result):#Complex是你想查看的复合物,eg: '(StrandA+StrandB)' 引号和括号都要有;
|
||||
#result是nupack计算(tube_analysis)的结果,eg: nupack指南里用过my_result、my_results和tube_results等, 或者你自己有其他命名
|
||||
def jiegou(Complex,result):
|
||||
m=str(result[Complex].mfe[0].structure)
|
||||
mm=""
|
||||
for i in m:
|
||||
if i != "+":
|
||||
mm=mm+i
|
||||
if i=="":
|
||||
continue
|
||||
return mm
|
||||
def xulie(Complex):
|
||||
inp=''
|
||||
for i in Complex:
|
||||
if i != '(' and i != ')':
|
||||
inp=inp+i
|
||||
else:
|
||||
continue
|
||||
l=inp.split('+',-1)
|
||||
xulie=''
|
||||
for i in l:
|
||||
xulie=xulie+str(eval(i))
|
||||
return xulie
|
||||
sequence=xulie(Complex)
|
||||
best_structure=jiegou(Complex,result)
|
||||
seq_name =Complex
|
||||
output_folder="/home/liusiye/桌面/nupack-4.0.2.0"#指定图片保存在哪个文件夹,需自己更改
|
||||
temp_file_path = os.path.join(output_folder, f"{seq_name}.seq")
|
||||
with open(temp_file_path, "w", newline='\n') as f:
|
||||
f.write(f">{seq_name}\n")
|
||||
f.write(f"{sequence}\n")
|
||||
f.write(f"{best_structure}\n")
|
||||
try:
|
||||
input_filename = f"{seq_name}.seq"
|
||||
process = subprocess.run(["RNAplot", "--o", "svg", input_filename], cwd=output_folder, capture_output=True, text=True)
|
||||
if process.returncode == 0:
|
||||
print(f"🎉 绘图成功!请前往 {output_folder} 文件夹查看 {seq_name}_ss.svg")
|
||||
os.remove(temp_file_path)
|
||||
else:
|
||||
print("❌ RNAplot 运行失败,报错信息:\n", process.stderr)
|
||||
except FileNotFoundError:
|
||||
print("❌ 找不到 RNAplot 命令,请确认环境变量。")
|
||||
Loading…
Add table
Add a link
Reference in a new issue