pyfurnace 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyfurnace/__init__.py +5 -0
- pyfurnace/__main__.py +33 -0
- pyfurnace/app/__init__.py +0 -0
- pyfurnace/app/pages/0_Home.py +37 -0
- pyfurnace/app/pages/1_Design.py +77 -0
- pyfurnace/app/pages/2_Generate.py +378 -0
- pyfurnace/app/pages/3_Convert.py +212 -0
- pyfurnace/app/pages/4_Prepare.py +565 -0
- pyfurnace/app/pages/__init__.py +0 -0
- pyfurnace/app/static/logo_hr.png +0 -0
- pyfurnace/app/static/logo_lr.png +0 -0
- pyfurnace/app/static/logo_text.png +0 -0
- pyfurnace/app/static/logo_text_hr.png +0 -0
- pyfurnace/app/static/pyfurnace.svg +692 -0
- pyfurnace/app/streamlit_app.py +12 -0
- pyfurnace/app/utils/__init__.py +211 -0
- pyfurnace/app/utils/commands/__init__.py +24 -0
- pyfurnace/app/utils/commands/aptamers_command.py +58 -0
- pyfurnace/app/utils/commands/connections_command.py +88 -0
- pyfurnace/app/utils/commands/dovetail_command.py +93 -0
- pyfurnace/app/utils/commands/general_edit_command.py +49 -0
- pyfurnace/app/utils/commands/kissing_loops_command.py +123 -0
- pyfurnace/app/utils/commands/motif_command.py +7 -0
- pyfurnace/app/utils/commands/stem_command.py +70 -0
- pyfurnace/app/utils/commands/structural_command.py +44 -0
- pyfurnace/app/utils/commands/tetraloop_command.py +45 -0
- pyfurnace/app/utils/design_functions.py +1424 -0
- pyfurnace/app/utils/motifs_icons.py +34 -0
- pyfurnace/app/utils/st_fixed_container.py +59 -0
- pyfurnace/app/utils/template_functions.py +71 -0
- pyfurnace/design/__init__.py +3 -0
- pyfurnace/design/core/__init__.py +14 -0
- pyfurnace/design/core/basepair.py +214 -0
- pyfurnace/design/core/callback.py +103 -0
- pyfurnace/design/core/coordinates_3d.py +1195 -0
- pyfurnace/design/core/motif.py +2771 -0
- pyfurnace/design/core/origami.py +1570 -0
- pyfurnace/design/core/position.py +284 -0
- pyfurnace/design/core/sequence.py +534 -0
- pyfurnace/design/core/strand.py +1924 -0
- pyfurnace/design/core/symbols.py +953 -0
- pyfurnace/design/motifs/__init__.py +25 -0
- pyfurnace/design/motifs/aptamers.py +229 -0
- pyfurnace/design/motifs/conf_files/Bend90.dat +12 -0
- pyfurnace/design/motifs/conf_files/Bend90_2.dat +7 -0
- pyfurnace/design/motifs/conf_files/Biotin.dat +36 -0
- pyfurnace/design/motifs/conf_files/BranchedKissingLoop.dat +10 -0
- pyfurnace/design/motifs/conf_files/BranchedKissingLoop_1.dat +11 -0
- pyfurnace/design/motifs/conf_files/BranchedKissingLoop_2.dat +5 -0
- pyfurnace/design/motifs/conf_files/BranchedKissingLoop_3.dat +12 -0
- pyfurnace/design/motifs/conf_files/Broccoli_1.dat +21 -0
- pyfurnace/design/motifs/conf_files/Broccoli_2.dat +26 -0
- pyfurnace/design/motifs/conf_files/Ispinach_1.dat +25 -0
- pyfurnace/design/motifs/conf_files/Ispinach_2.dat +20 -0
- pyfurnace/design/motifs/conf_files/KissingLoop120.dat +12 -0
- pyfurnace/design/motifs/conf_files/KissingLoop120_2.dat +12 -0
- pyfurnace/design/motifs/conf_files/KissingLoop180.dat +12 -0
- pyfurnace/design/motifs/conf_files/KissingLoop180_2.dat +12 -0
- pyfurnace/design/motifs/conf_files/L7Ae_1.dat +10 -0
- pyfurnace/design/motifs/conf_files/L7Ae_2.dat +130 -0
- pyfurnace/design/motifs/conf_files/L7Ae_2.top +3 -0
- pyfurnace/design/motifs/conf_files/LambdaTurn_1.dat +13 -0
- pyfurnace/design/motifs/conf_files/LambdaTurn_2.dat +11 -0
- pyfurnace/design/motifs/conf_files/MS2.dat +151 -0
- pyfurnace/design/motifs/conf_files/MS2.top +3 -0
- pyfurnace/design/motifs/conf_files/MalachiteGreen.dat +41 -0
- pyfurnace/design/motifs/conf_files/MalachiteGreenShort_1.dat +11 -0
- pyfurnace/design/motifs/conf_files/MalachiteGreenShort_2.dat +17 -0
- pyfurnace/design/motifs/conf_files/Mango.dat +34 -0
- pyfurnace/design/motifs/conf_files/PP7.dat +266 -0
- pyfurnace/design/motifs/conf_files/PP7.top +4 -0
- pyfurnace/design/motifs/conf_files/Pepper_1.dat +29 -0
- pyfurnace/design/motifs/conf_files/Pepper_2.dat +22 -0
- pyfurnace/design/motifs/conf_files/Pip3.dat +17 -0
- pyfurnace/design/motifs/conf_files/Pip3_mut1.dat +17 -0
- pyfurnace/design/motifs/conf_files/Pip3_mut3.dat +17 -0
- pyfurnace/design/motifs/conf_files/Pip3_mut5.dat +17 -0
- pyfurnace/design/motifs/conf_files/Streptavidin.dat +63 -0
- pyfurnace/design/motifs/conf_files/TAR_TAT.dat +50 -0
- pyfurnace/design/motifs/conf_files/TAR_TAT.top +3 -0
- pyfurnace/design/motifs/conf_files/TetraLoop.dat +9 -0
- pyfurnace/design/motifs/conf_files/ThreeWayJunction_1.dat +11 -0
- pyfurnace/design/motifs/conf_files/ThreeWayJunction_2.dat +10 -0
- pyfurnace/design/motifs/conf_files/ThreeWayJunction_3.dat +8 -0
- pyfurnace/design/motifs/conf_files/Thrombin_exosite1.dat +61 -0
- pyfurnace/design/motifs/conf_files/Thrombin_exosite2.dat +316 -0
- pyfurnace/design/motifs/conf_files/Thrombin_exosite2.top +4 -0
- pyfurnace/design/motifs/dovetail.py +244 -0
- pyfurnace/design/motifs/kissing_loops.py +417 -0
- pyfurnace/design/motifs/loops.py +60 -0
- pyfurnace/design/motifs/stem.py +192 -0
- pyfurnace/design/motifs/structural.py +58 -0
- pyfurnace/design/utils/__init__.py +2 -0
- pyfurnace/design/utils/motif_lib.py +69 -0
- pyfurnace/design/utils/origami_lib.py +175 -0
- pyfurnace/generate/__init__.py +2 -0
- pyfurnace/generate/pk_utils.py +178 -0
- pyfurnace/generate/road.py +291 -0
- pyfurnace/generate/road_bin/revolvr.pl +2503 -0
- pyfurnace/generate/road_bin/viennarna_funcs.py +44 -0
- pyfurnace/generate/utils.py +60 -0
- pyfurnace/generate/viennarna.py +87 -0
- pyfurnace/prepare/__init__.py +1 -0
- pyfurnace/prepare/oxdna_inputs/MC_relax.txt +46 -0
- pyfurnace/prepare/oxdna_inputs/MD_equil.txt +50 -0
- pyfurnace/prepare/oxdna_inputs/MD_prod.txt +49 -0
- pyfurnace/prepare/oxdna_inputs/MD_relax.txt +52 -0
- pyfurnace/prepare/oxdna_sim.py +142 -0
- pyfurnace-0.0.1.dist-info/METADATA +186 -0
- pyfurnace-0.0.1.dist-info/RECORD +113 -0
- pyfurnace-0.0.1.dist-info/WHEEL +5 -0
- pyfurnace-0.0.1.dist-info/licenses/LICENSE +674 -0
- pyfurnace-0.0.1.dist-info/top_level.txt +1 -0
pyfurnace/__init__.py
ADDED
pyfurnace/__main__.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import pathlib
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
config_options = {'theme.base': 'light',
|
|
8
|
+
'theme.font': "monospace",
|
|
9
|
+
'theme.primaryColor': "#00856A",
|
|
10
|
+
'server.enableStaticServing': True,
|
|
11
|
+
'logger.level': 'error',
|
|
12
|
+
'global.showWarningOnDirectExecution': False,
|
|
13
|
+
'client.toolbarMode': "minimal",
|
|
14
|
+
}
|
|
15
|
+
config_str = ' '.join([f'--{key} "{value}"'
|
|
16
|
+
for key, value in config_options.items()])
|
|
17
|
+
|
|
18
|
+
app_path = str(pathlib.Path(__file__).parent.resolve()/'app'/'streamlit_app.py')
|
|
19
|
+
|
|
20
|
+
### COPY THE PYTHON PATH AND ADD RNAfold
|
|
21
|
+
python_path = sys.executable # Get path to the current Python interpreter
|
|
22
|
+
python_dir = os.path.dirname(python_path)
|
|
23
|
+
|
|
24
|
+
# Prepend it to PATH, to make sure the correct Python is used
|
|
25
|
+
env = os.environ.copy()
|
|
26
|
+
env["PATH"] = python_dir + os.pathsep + os.environ["PATH"]
|
|
27
|
+
|
|
28
|
+
subprocess.run(f'streamlit run "{app_path}" {config_str}',
|
|
29
|
+
shell=True,
|
|
30
|
+
env=env)
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
from utils import load_logo
|
|
3
|
+
|
|
4
|
+
if __name__ == '__main__':
|
|
5
|
+
load_logo()
|
|
6
|
+
|
|
7
|
+
st.write("# Hello and Welcome to pyFuRNAce!")
|
|
8
|
+
|
|
9
|
+
st.write('Design and generate RNA nanostructures in few simple steps.')
|
|
10
|
+
|
|
11
|
+
st.page_link("pages/1_Design.py",
|
|
12
|
+
label=":orange[Design:]",
|
|
13
|
+
icon=":material/draw:")
|
|
14
|
+
|
|
15
|
+
st.markdown("- Design your RNA nanostructure and download it as "
|
|
16
|
+
"textfile/python script.")
|
|
17
|
+
|
|
18
|
+
st.page_link("pages/2_Generate.py",
|
|
19
|
+
label=":orange[Generate:]",
|
|
20
|
+
icon=":material/network_node:")
|
|
21
|
+
|
|
22
|
+
st.markdown("- Generate the RNA sequence that matches the desired dot-bracket"
|
|
23
|
+
" notation for the nanostructure.")
|
|
24
|
+
|
|
25
|
+
st.page_link("pages/3_Convert.py",
|
|
26
|
+
label=":orange[Template:]",
|
|
27
|
+
icon=":material/genetics:")
|
|
28
|
+
|
|
29
|
+
st.markdown("- Prepare the DNA template for you RNA Origami, search subsequences "
|
|
30
|
+
"and search for dimers.")
|
|
31
|
+
|
|
32
|
+
st.page_link("pages/4_Prepare.py",
|
|
33
|
+
label=":orange[Prepare:]",
|
|
34
|
+
icon=":material/sync_alt:")
|
|
35
|
+
|
|
36
|
+
st.markdown("- Design primers for your DNA template or prepare the Origami for "
|
|
37
|
+
"OxDNA simulation.")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
|
|
4
|
+
### My modules
|
|
5
|
+
from utils import check_import_pyfurnace, load_logo, save_origami
|
|
6
|
+
check_import_pyfurnace()
|
|
7
|
+
import utils.design_functions as des_func
|
|
8
|
+
from utils.st_fixed_container import sticky_container
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
load_logo()
|
|
13
|
+
### initiate the session state
|
|
14
|
+
des_func.initiate_session_state()
|
|
15
|
+
st.header('Design',
|
|
16
|
+
help='Design your RNA nanostructure and '
|
|
17
|
+
'download it as textfile/python script.')
|
|
18
|
+
|
|
19
|
+
### make the general options for the RNA origami
|
|
20
|
+
des_func.origami_general_options(st.session_state.origami,
|
|
21
|
+
expanded=False)
|
|
22
|
+
|
|
23
|
+
cols = st.columns([1.3, 1.3] + [1] * 2 + [2, 1.3],
|
|
24
|
+
vertical_alignment='center')
|
|
25
|
+
with cols[0]:
|
|
26
|
+
with st.popover("Make a simple origami",
|
|
27
|
+
use_container_width=False,
|
|
28
|
+
help='Start by creating a simple origami rather than '
|
|
29
|
+
'starting from scratch'):
|
|
30
|
+
des_func.simple_origami()
|
|
31
|
+
|
|
32
|
+
with cols[2]:
|
|
33
|
+
st.write('OxView 3D colormap:')
|
|
34
|
+
|
|
35
|
+
with cols[3]:
|
|
36
|
+
cmap = st.selectbox('OxView 3D colormap:',
|
|
37
|
+
['Reds', None] + plt.colormaps(),
|
|
38
|
+
key='colormap',
|
|
39
|
+
label_visibility='collapsed',
|
|
40
|
+
help='Change the color of the OxView visualization.')
|
|
41
|
+
st.session_state.oxview_colormap = cmap
|
|
42
|
+
with cols[5]:
|
|
43
|
+
grad = st.toggle('Color gradient path',
|
|
44
|
+
key='grad',
|
|
45
|
+
help='Toggle the gradient color scheme for the nucleotides')
|
|
46
|
+
st.session_state.gradient = grad
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def motif_menu_expander():
|
|
50
|
+
with st.expander("**Add motifs to the origami:**", expanded=True):
|
|
51
|
+
des_func.make_motif_menu(st.session_state.origami)
|
|
52
|
+
|
|
53
|
+
if st.session_state.motif_menu_sticky:
|
|
54
|
+
with sticky_container(mode="top", border=False):
|
|
55
|
+
motif_menu_expander()
|
|
56
|
+
view_opt = des_func.origami_select_display()
|
|
57
|
+
else:
|
|
58
|
+
motif_menu_expander()
|
|
59
|
+
view_opt = des_func.origami_select_display()
|
|
60
|
+
|
|
61
|
+
### select the render mode
|
|
62
|
+
if not st.session_state.origami:
|
|
63
|
+
st.success('The origami is empty, add a motif!')
|
|
64
|
+
st.stop()
|
|
65
|
+
else:
|
|
66
|
+
des_func.origami_build_view(view_opt)
|
|
67
|
+
|
|
68
|
+
### display the dot-bracket notation and sequence constraints
|
|
69
|
+
# and link to the Generate page
|
|
70
|
+
|
|
71
|
+
des_func.display_structure_sequence()
|
|
72
|
+
|
|
73
|
+
### Download the RNA origami structure
|
|
74
|
+
save_origami()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
import streamlit as st
|
|
3
|
+
from colour import Color
|
|
4
|
+
import os
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
### My modules
|
|
8
|
+
from utils import (check_import_pyfurnace,
|
|
9
|
+
load_logo,
|
|
10
|
+
save_origami,
|
|
11
|
+
copy_to_clipboard)
|
|
12
|
+
check_import_pyfurnace()
|
|
13
|
+
from pyfurnace.generate import generate_road, fold_p
|
|
14
|
+
|
|
15
|
+
def format_text(text):
|
|
16
|
+
return "```\n" + text + "\n```"
|
|
17
|
+
|
|
18
|
+
def forna_options(lenght):
|
|
19
|
+
### checkboxes for the options
|
|
20
|
+
col1, col2, col3 = st.columns(3, vertical_alignment='bottom')
|
|
21
|
+
with col1:
|
|
22
|
+
st.session_state.zoomable = st.checkbox("Zoomable",
|
|
23
|
+
value=True,
|
|
24
|
+
help = """Enable zooming in and out the structure""")
|
|
25
|
+
with col2:
|
|
26
|
+
st.session_state.animation = st.checkbox("Interact",
|
|
27
|
+
value=False,
|
|
28
|
+
help = """Enable interaction with the structure""")
|
|
29
|
+
with col3:
|
|
30
|
+
st.session_state.node_label = st.checkbox("Label",
|
|
31
|
+
value=True,
|
|
32
|
+
help = """Show the nucleotide label""")
|
|
33
|
+
|
|
34
|
+
### second row of options
|
|
35
|
+
col1, col2, col3 = st.columns(3, vertical_alignment='center')
|
|
36
|
+
with col1:
|
|
37
|
+
### color scheme options
|
|
38
|
+
scheme_options = ["sequence",
|
|
39
|
+
"structure",
|
|
40
|
+
"positions",
|
|
41
|
+
"color range",
|
|
42
|
+
"custom"]
|
|
43
|
+
st.session_state.color_scheme = st.selectbox("Color scheme",
|
|
44
|
+
scheme_options,
|
|
45
|
+
index=1)
|
|
46
|
+
|
|
47
|
+
with col2:
|
|
48
|
+
st.session_state.height = st.slider("Frame height",
|
|
49
|
+
min_value=10,
|
|
50
|
+
max_value=800,
|
|
51
|
+
value=300,
|
|
52
|
+
help = """Set the height of the frame""")
|
|
53
|
+
|
|
54
|
+
with col3:
|
|
55
|
+
st.session_state.label_interval = st.slider("Label every",
|
|
56
|
+
min_value=0,
|
|
57
|
+
max_value=max(lenght, 10),
|
|
58
|
+
value=min(lenght, 10),
|
|
59
|
+
help = """Show the nucleotide number every n nucleotides""")
|
|
60
|
+
|
|
61
|
+
st.session_state.color_text = ''
|
|
62
|
+
st.session_state.colors = {}
|
|
63
|
+
|
|
64
|
+
### color scheme based on the sequence
|
|
65
|
+
if st.session_state.color_scheme == "color range":
|
|
66
|
+
st.session_state.color_scheme = "custom"
|
|
67
|
+
|
|
68
|
+
with col2: # start color
|
|
69
|
+
first = st.color_picker("Start color", "#ff0000")
|
|
70
|
+
|
|
71
|
+
with col3: # end color
|
|
72
|
+
last = st.color_picker("End color", "#00ff00")
|
|
73
|
+
|
|
74
|
+
# create the colors range
|
|
75
|
+
first = Color(first)
|
|
76
|
+
last = Color(last)
|
|
77
|
+
|
|
78
|
+
color_range = [first] + list(first.range_to(last, lenght))
|
|
79
|
+
|
|
80
|
+
# save the colors in the session state and create the colors string
|
|
81
|
+
for i, c in enumerate(color_range):
|
|
82
|
+
st.session_state.colors[i] = c.hex
|
|
83
|
+
st.session_state.color_text += str(i) + ":" + c.hex + " "
|
|
84
|
+
|
|
85
|
+
### custom colors for each nucleotide
|
|
86
|
+
elif st.session_state.color_scheme == "custom":
|
|
87
|
+
|
|
88
|
+
with col2: # select nucleotide index
|
|
89
|
+
index = st.number_input("Select nucleotide index", 1, lenght, 1)
|
|
90
|
+
|
|
91
|
+
with col3: # select color
|
|
92
|
+
color = st.color_picker("Select a color", "#ffffff")
|
|
93
|
+
|
|
94
|
+
# save the color in the session state
|
|
95
|
+
st.session_state.colors[index] = color
|
|
96
|
+
|
|
97
|
+
# create the colors string
|
|
98
|
+
for i, c in st.session_state.colors.items():
|
|
99
|
+
st.session_state.color_text += str(i) + ":" + c + " "
|
|
100
|
+
|
|
101
|
+
### display the custom colors
|
|
102
|
+
else:
|
|
103
|
+
st.session_state.color_text = None
|
|
104
|
+
|
|
105
|
+
def generate_sequence():
|
|
106
|
+
if not structure:
|
|
107
|
+
st.error('No structure input given')
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
if not sequence_constraint:
|
|
111
|
+
st.error('No sequence constraint input given')
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
# Initialize the UI elements
|
|
115
|
+
progress_bar = st.empty()
|
|
116
|
+
output_status = st.empty()
|
|
117
|
+
|
|
118
|
+
# Initialize the progress bar
|
|
119
|
+
progress_bar.progress(0, "Initializing...")
|
|
120
|
+
|
|
121
|
+
def callback_forna(structure, sequence, step, stage_name, n_stage):
|
|
122
|
+
# Update the progress bar
|
|
123
|
+
progress_bar.progress(n_stage, text = stage_name)
|
|
124
|
+
output_status.markdown(format_text(f"Structure:\n{structure}"
|
|
125
|
+
f"\nSequence:\n{sequence}"
|
|
126
|
+
f"\nSpool:\n{step}"))
|
|
127
|
+
|
|
128
|
+
ori_txt = '\n\n'.join(st.session_state.code)
|
|
129
|
+
opti_sequence, zip_out = generate_road(structure,
|
|
130
|
+
sequence_constraint,
|
|
131
|
+
pseudoknot_info,
|
|
132
|
+
name=filename,
|
|
133
|
+
callback=callback_forna,
|
|
134
|
+
zip_directory=True,
|
|
135
|
+
origami_code=ori_txt,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
st.session_state.rna_origami_seq = opti_sequence
|
|
139
|
+
st.session_state.rna_origami_folds = fold_p(opti_sequence)
|
|
140
|
+
# if there was already a zip file, remove it
|
|
141
|
+
if 'zip_path' in st.session_state:
|
|
142
|
+
if os.path.exists(st.session_state.zip_path):
|
|
143
|
+
os.remove(st.session_state.zip_path)
|
|
144
|
+
# save the new zip file
|
|
145
|
+
st.session_state.zip_path = zip_out
|
|
146
|
+
|
|
147
|
+
# Clear the progress bar
|
|
148
|
+
progress_bar.progress(1.0, text = f"Generation Completed")
|
|
149
|
+
output_status.empty()
|
|
150
|
+
|
|
151
|
+
if ('origami' in st.session_state
|
|
152
|
+
and st.session_state.origami
|
|
153
|
+
and len(st.session_state.origami.sequence) == len(st.session_state.rna_origami_seq)):
|
|
154
|
+
# try:
|
|
155
|
+
st.session_state.origami.sequence = st.session_state.rna_origami_seq
|
|
156
|
+
if 'code' in st.session_state:
|
|
157
|
+
code_text = 'origami.sequence = "' + st.session_state.rna_origami_seq + '"'
|
|
158
|
+
st.session_state.code.append(code_text)
|
|
159
|
+
st.success("Sequence loaded to the origami design!")
|
|
160
|
+
# except Exception as e:
|
|
161
|
+
# st.error(f"Error while loading the sequence into the origami design: {e}")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
if __name__ == "__main__":
|
|
165
|
+
# somehow st components cause `Thread 'MainThread': missing ScriptRunContext!`
|
|
166
|
+
# warning when using multiprocessing
|
|
167
|
+
from st_forna_component import forna_component
|
|
168
|
+
|
|
169
|
+
load_logo()
|
|
170
|
+
|
|
171
|
+
### ignore warnings
|
|
172
|
+
warnings.filterwarnings("ignore")
|
|
173
|
+
|
|
174
|
+
### initialize the session state
|
|
175
|
+
|
|
176
|
+
### Forna options
|
|
177
|
+
if 'zoomable' not in st.session_state:
|
|
178
|
+
st.session_state.zoomable = True
|
|
179
|
+
if 'animation' not in st.session_state:
|
|
180
|
+
st.session_state.animation = False
|
|
181
|
+
if 'editable' not in st.session_state:
|
|
182
|
+
st.session_state.editable = False
|
|
183
|
+
if 'labels' not in st.session_state:
|
|
184
|
+
st.session_state.node_label = True
|
|
185
|
+
if 'height' not in st.session_state:
|
|
186
|
+
st.session_state.height = 300
|
|
187
|
+
if 'label_interval' not in st.session_state:
|
|
188
|
+
st.session_state.label_interval = 10
|
|
189
|
+
if 'color_scheme' not in st.session_state:
|
|
190
|
+
st.session_state.color_scheme = "structure"
|
|
191
|
+
if 'color_text' not in st.session_state:
|
|
192
|
+
st.session_state.color_text = ''
|
|
193
|
+
|
|
194
|
+
### RNA origami options
|
|
195
|
+
if 'generate_structure' not in st.session_state:
|
|
196
|
+
st.session_state.generate_structure = ""
|
|
197
|
+
if 'generate_sequence' not in st.session_state:
|
|
198
|
+
st.session_state.generate_sequence = ""
|
|
199
|
+
if 'generate_pseudoknots' not in st.session_state:
|
|
200
|
+
st.session_state.generate_pseudoknots = ""
|
|
201
|
+
if 'rna_origami_seq' not in st.session_state:
|
|
202
|
+
st.session_state.rna_origami_seq = ""
|
|
203
|
+
if 'rna_origami_folds' not in st.session_state:
|
|
204
|
+
st.session_state.rna_origami_folds = ()
|
|
205
|
+
|
|
206
|
+
st.header('Generate', help='Generate the RNA sequence that matches the desired dot-bracket notation (and sequence constraints) for the nanostructure.')
|
|
207
|
+
structure = st.text_input("RNA strucutre (dot-bracket notation)", value=st.session_state.generate_structure)
|
|
208
|
+
sequence_constraint = st.text_input("Sequence constraints", value=st.session_state.generate_sequence)
|
|
209
|
+
pseudoknot_info = st.text_input("Pseudoknot constraints (semicolon-separated)", value=st.session_state.generate_pseudoknots)
|
|
210
|
+
|
|
211
|
+
if not sequence_constraint:
|
|
212
|
+
sequence_constraint = "N" * len(structure.replace("&", ""))
|
|
213
|
+
|
|
214
|
+
# check if the dot-bracket notation contains multiple strands
|
|
215
|
+
if "&" in structure:
|
|
216
|
+
st.warning("Experimental: the dot-bracket notation contains multiple strands")
|
|
217
|
+
|
|
218
|
+
with st.columns([1.3, 3])[0]:
|
|
219
|
+
with st.popover("RNA display options", use_container_width=True):
|
|
220
|
+
forna_options(len(structure))
|
|
221
|
+
|
|
222
|
+
partial_forna = partial(forna_component,
|
|
223
|
+
height = st.session_state.height,
|
|
224
|
+
animation = st.session_state.animation,
|
|
225
|
+
zoomable = st.session_state.zoomable,
|
|
226
|
+
label_interval = st.session_state.label_interval,
|
|
227
|
+
node_label = st.session_state.node_label,
|
|
228
|
+
editable = st.session_state.editable,
|
|
229
|
+
color_scheme = st.session_state.color_scheme,
|
|
230
|
+
colors = st.session_state.color_text)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# # Initialize the FORNA link for the target structure
|
|
234
|
+
if structure:
|
|
235
|
+
# st.markdown("#### Target Structure")
|
|
236
|
+
# st.markdown(format_text(structure))
|
|
237
|
+
edited = partial_forna(structure = structure,
|
|
238
|
+
sequence = sequence_constraint,
|
|
239
|
+
key='target_forna')
|
|
240
|
+
|
|
241
|
+
if sequence_constraint and sequence_constraint[0] != 'G':
|
|
242
|
+
col1, col2, col3 = st.columns(3, vertical_alignment='bottom')
|
|
243
|
+
with col1:
|
|
244
|
+
st.warning("The RNA sequence doens't start with G.")
|
|
245
|
+
with col2:
|
|
246
|
+
new_start = st.text_input("Start the sequence with", value='GGGA',
|
|
247
|
+
help='The transcription of the RNA sequence often '
|
|
248
|
+
'often requires at least one G at the start of the sequence.')
|
|
249
|
+
with col3:
|
|
250
|
+
if st.button('Apply the sequence start'):
|
|
251
|
+
|
|
252
|
+
seq_list = list(sequence_constraint)
|
|
253
|
+
# pair_map = pf.dot_bracket_to_pair_map(structure) # unnecessary
|
|
254
|
+
|
|
255
|
+
for i in range(len(new_start)):
|
|
256
|
+
seq_list[i] = new_start[i]
|
|
257
|
+
### NOT NECESSARY
|
|
258
|
+
# paired = pair_map[i]
|
|
259
|
+
# if paired is not None:
|
|
260
|
+
# paired_nucl = new_start[i].translate(pf.nucl_to_pair)
|
|
261
|
+
# seq_list[paired] = paired_nucl
|
|
262
|
+
|
|
263
|
+
st.session_state.generate_sequence = "".join(seq_list)
|
|
264
|
+
st.rerun()
|
|
265
|
+
|
|
266
|
+
col1, col2 = st.columns(2, vertical_alignment='bottom')
|
|
267
|
+
with col1:
|
|
268
|
+
filename = st.text_input('Name of RNA origami', value='Origami')
|
|
269
|
+
with col2:
|
|
270
|
+
generate = False
|
|
271
|
+
if st.button("Generate RNA sequence"):
|
|
272
|
+
generate = True
|
|
273
|
+
if generate:
|
|
274
|
+
generate_sequence()
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
if not st.session_state.rna_origami_seq:
|
|
278
|
+
st.stop()
|
|
279
|
+
|
|
280
|
+
st.divider()
|
|
281
|
+
sequence = st.session_state.rna_origami_seq
|
|
282
|
+
folds = st.session_state.rna_origami_folds
|
|
283
|
+
|
|
284
|
+
diversity = round(folds[6], 1)
|
|
285
|
+
if diversity < 30:
|
|
286
|
+
diversity_text = f":green[low {diversity}]"
|
|
287
|
+
elif diversity < 50:
|
|
288
|
+
diversity_text = f":orange[medium {diversity}]"
|
|
289
|
+
else:
|
|
290
|
+
diversity_text = f":red[high {diversity}]"
|
|
291
|
+
|
|
292
|
+
cols = st.columns(4, vertical_alignment='bottom')
|
|
293
|
+
st.markdown("### Last Optimized sequence "
|
|
294
|
+
f"(ensemble diversity: {diversity_text})",
|
|
295
|
+
help='The ensemble diversity is the average distance between the '
|
|
296
|
+
'structures in the ensemble (the set of all the possible structures '
|
|
297
|
+
'that can be formed by the sequence). A lower value means that the '
|
|
298
|
+
'structures are more similar to each other (and therefore more '
|
|
299
|
+
'similar to the Minimum Free Energy structure). A higher value '
|
|
300
|
+
'means that the structures are more diverse and there are less '
|
|
301
|
+
'chances to obtain the minimum free energy structure. '
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
col1, col2 = st.columns(2)
|
|
306
|
+
with col1:
|
|
307
|
+
with st.columns(3)[1]:
|
|
308
|
+
st.markdown("#### MFE Structure",
|
|
309
|
+
help='The Minimum Free Energy (MFE) structure is the structure with '
|
|
310
|
+
'the lowest free energy. It is the most stable structure that can be '
|
|
311
|
+
'formed by the sequence. '
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
subcol1, subcol2 = st.columns(2)
|
|
315
|
+
with subcol1:
|
|
316
|
+
st.markdown(f'Energy: {round(folds[1], 2)} Kcal/mol')
|
|
317
|
+
with subcol2:
|
|
318
|
+
st.markdown(f'Frequency in the ensemble: {round(folds[2] * 100, 4)} %',
|
|
319
|
+
help = 'The MFE frequency in the ensemble is the probability of '
|
|
320
|
+
'obtaining the MFE structure among all the possible structures '
|
|
321
|
+
'that can be formed by the sequence.'
|
|
322
|
+
)
|
|
323
|
+
partial_forna(structure = folds[0],
|
|
324
|
+
sequence = sequence,
|
|
325
|
+
key='struct_mfe')
|
|
326
|
+
with col2:
|
|
327
|
+
with st.columns(3)[1]:
|
|
328
|
+
st.markdown("#### Centroid",
|
|
329
|
+
help='The centroid structure is the structure that is the most similar to '
|
|
330
|
+
'the average structure of the ensemble. It is the closest structure to '
|
|
331
|
+
'represent the average of all the possible structures that can be '
|
|
332
|
+
'formed by the sequence. '
|
|
333
|
+
)
|
|
334
|
+
subcol1, subcol2 = st.columns(2)
|
|
335
|
+
with subcol1:
|
|
336
|
+
st.markdown(f'Energy: {round(folds[4], 2)} Kcal/mol')
|
|
337
|
+
with subcol2:
|
|
338
|
+
st.markdown(f'Frequency in the ensemble: {round(folds[5] * 100, 4)} %',
|
|
339
|
+
help = 'The centroid frequency in the ensemble is the probability of '
|
|
340
|
+
'obtaining the centroid structure among all the possible structures '
|
|
341
|
+
'that can be formed by the sequence.'
|
|
342
|
+
)
|
|
343
|
+
partial_forna(structure = folds[3],
|
|
344
|
+
sequence = sequence,
|
|
345
|
+
key='struct_centroid')
|
|
346
|
+
|
|
347
|
+
st.divider()
|
|
348
|
+
|
|
349
|
+
st.markdown(format_text(st.session_state.rna_origami_seq))
|
|
350
|
+
col1, col2, col3, col4 = st.columns(4)
|
|
351
|
+
with col1:
|
|
352
|
+
st.page_link("pages/3_Convert.py",
|
|
353
|
+
label=":orange[Convert the RNA to the DNA template]",
|
|
354
|
+
icon=":material/genetics:")
|
|
355
|
+
with col2:
|
|
356
|
+
copy_to_clipboard(folds[0], 'Structure')
|
|
357
|
+
with col3:
|
|
358
|
+
copy_to_clipboard(sequence, 'Sequence')
|
|
359
|
+
with col4:
|
|
360
|
+
with open(st.session_state.zip_path, "rb") as fp:
|
|
361
|
+
st.download_button("Download Optimization Files",
|
|
362
|
+
data=fp,
|
|
363
|
+
file_name = f"{filename}.zip",
|
|
364
|
+
mime = "application/zip",
|
|
365
|
+
on_click='ignore',
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if ('origami' in st.session_state
|
|
369
|
+
and st.session_state.origami
|
|
370
|
+
and str(st.session_state.origami.sequence) == st.session_state.rna_origami_seq):
|
|
371
|
+
|
|
372
|
+
st.session_state.prepare_ind = 1
|
|
373
|
+
st.page_link("pages/4_Prepare.py",
|
|
374
|
+
label=":orange[Prepare MD simulations]",
|
|
375
|
+
icon=":material/sync_alt:")
|
|
376
|
+
|
|
377
|
+
save_origami(filename)
|
|
378
|
+
|