Spaces:
Running
on
T4
Running
on
T4
Simon Duerr
commited on
Commit
•
965a7b8
1
Parent(s):
4559fd7
add fixed positions
Browse files- app.py +168 -37
- requirements.txt +2 -0
app.py
CHANGED
@@ -26,6 +26,9 @@ import urllib
|
|
26 |
import jax.numpy as jnp
|
27 |
import tensorflow as tf
|
28 |
|
|
|
|
|
|
|
29 |
if "/home/user/app/af_backprop" not in sys.path:
|
30 |
sys.path.append("/home/user/app/af_backprop")
|
31 |
|
@@ -250,7 +253,9 @@ def setup_proteinmpnn(model_name="v_48_020", backbone_noise=0.00):
|
|
250 |
)
|
251 |
from protein_mpnn_utils import StructureDataset, StructureDatasetPDB, ProteinMPNN
|
252 |
|
253 |
-
device = torch.device(
|
|
|
|
|
254 |
# ProteinMPNN model name: v_48_002, v_48_010, v_48_020, v_48_030, v_32_002, v_32_010; v_32_020, v_32_030; v_48_010=version with 48 edges 0.10A noise
|
255 |
# Standard deviation of Gaussian noise to add to backbone atoms
|
256 |
hidden_dim = 128
|
@@ -291,6 +296,61 @@ def get_pdb(pdb_code="", filepath=""):
|
|
291 |
return f"{pdb_code}.pdb"
|
292 |
|
293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
def update(
|
295 |
inp,
|
296 |
file,
|
@@ -301,6 +361,7 @@ def update(
|
|
301 |
sampling_temp,
|
302 |
model_name,
|
303 |
backbone_noise,
|
|
|
304 |
):
|
305 |
from protein_mpnn_utils import (
|
306 |
loss_nll,
|
@@ -316,7 +377,9 @@ def update(
|
|
316 |
)
|
317 |
from protein_mpnn_utils import StructureDataset, StructureDatasetPDB, ProteinMPNN
|
318 |
|
319 |
-
pdb_path = get_pdb(pdb_code=inp, filepath=file)
|
|
|
|
|
320 |
|
321 |
if pdb_path == None:
|
322 |
return "Error processing PDB"
|
@@ -368,7 +431,11 @@ def update(
|
|
368 |
omit_AAs_np = np.array([AA in omit_AAs_list for AA in alphabet]).astype(np.float32)
|
369 |
|
370 |
chain_id_dict = None
|
371 |
-
|
|
|
|
|
|
|
|
|
372 |
pssm_dict = None
|
373 |
omit_AA_dict = None
|
374 |
bias_AA_dict = None
|
@@ -385,6 +452,7 @@ def update(
|
|
385 |
tied_positions_dict = make_tied_positions_for_homomers(pdb_dict_list)
|
386 |
else:
|
387 |
tied_positions_dict = None
|
|
|
388 |
chain_id_dict = {}
|
389 |
chain_id_dict[pdb_dict_list[0]["name"]] = (designed_chain_list, fixed_chain_list)
|
390 |
with torch.no_grad():
|
@@ -629,6 +697,8 @@ def update(
|
|
629 |
)
|
630 |
seq_list.append(seq + chain_s)
|
631 |
message += f"{line}\n"
|
|
|
|
|
632 |
# somehow sequences still contain X, remove again
|
633 |
for i, x in enumerate(seq_list):
|
634 |
for aa in omit_AAs:
|
@@ -667,10 +737,11 @@ def update(
|
|
667 |
gr.File.update(value="all_probs_concat.csv", visible=True),
|
668 |
pdb_path,
|
669 |
gr.Dropdown.update(choices=seq_list),
|
|
|
670 |
)
|
671 |
|
672 |
|
673 |
-
def update_AF(startsequence, pdb, num_recycles):
|
674 |
|
675 |
# # run alphafold using ray
|
676 |
# plddts, pae, num_res = run_alphafold(
|
@@ -720,17 +791,19 @@ def update_AF(startsequence, pdb, num_recycles):
|
|
720 |
plt.colorbar()
|
721 |
plt.xlabel("Scored residue")
|
722 |
plt.ylabel("Aligned residue")
|
|
|
|
|
723 |
# doesnt work (likely because too large)
|
724 |
# plotAF_pae = px.imshow(
|
725 |
# pae,
|
726 |
# labels=dict(x="Scored residue", y="Aligned residue", color=""),
|
727 |
# template="simple_white",
|
728 |
-
# y=np.arange(len(
|
729 |
# )
|
730 |
# plotAF_pae.write_html("test.html")
|
731 |
# plotAF_pae.update_layout(title="Predicted Aligned Error", template="simple_white")
|
732 |
|
733 |
-
return molecule(pdb, "out.pdb", num_res), plotAF_plddt,
|
734 |
|
735 |
|
736 |
def read_mol(molpath):
|
@@ -742,7 +815,7 @@ def read_mol(molpath):
|
|
742 |
return mol
|
743 |
|
744 |
|
745 |
-
def molecule(pdb, afpdb, num_res):
|
746 |
|
747 |
rms, input_pdb, aligned_pdb = align_structures(pdb, afpdb, num_res)
|
748 |
mol = read_mol(input_pdb)
|
@@ -768,10 +841,6 @@ def molecule(pdb, afpdb, num_res):
|
|
768 |
.p-1{
|
769 |
padding:0.5rem;
|
770 |
}
|
771 |
-
.flex{
|
772 |
-
display:flex;
|
773 |
-
align-items: center;
|
774 |
-
}
|
775 |
.w-4{
|
776 |
width:1rem;
|
777 |
}
|
@@ -802,7 +871,7 @@ select{
|
|
802 |
<label for="startstructure" class="relative inline-flex items-center mb-4 cursor-pointer ">
|
803 |
<input id="startstructure" type="checkbox" class="sr-only peer" checked>
|
804 |
<div class="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
|
805 |
-
<span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show
|
806 |
</label>
|
807 |
</div>
|
808 |
<button type="button" class="text-gray-900 bg-white hover:bg-gray-100 border border-gray-200 focus:ring-4 focus:outline-none focus:ring-gray-100 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-gray-600 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:bg-gray-700 mr-2 mb-2" id="download">
|
@@ -814,23 +883,31 @@ select{
|
|
814 |
<div> RMSD AlphaFold vs. native: """
|
815 |
+ f"{rms:.2f}"
|
816 |
+ """Å computed using CEAlign on the aligned fragment</div>
|
817 |
-
|
818 |
-
|
819 |
-
|
|
|
|
|
|
|
|
|
820 |
(pLDDT > 90)</span></div>
|
821 |
-
<div class="flex space-x-2 py-1"><span class="w-4 h-4"
|
822 |
-
style="background-color: rgb(101, 203, 243);"> </span><span class="legendlabel">Confident
|
823 |
(90 > pLDDT > 70)</span></div>
|
824 |
-
<div class="flex space-x-2 py-1"><span class="w-4 h-4"
|
825 |
-
style="background-color: rgb(255, 219, 19);"> </span><span class="legendlabel">Low (70 >
|
826 |
pLDDT > 50)</span></div>
|
827 |
-
<div class="flex space-x-2 py-1"><span class="w-4 h-4"
|
828 |
-
style="background-color: rgb(255, 125, 69);"> </span><span class="legendlabel">Very low
|
829 |
(pLDDT < 50)</span></div>
|
830 |
<div class="row column legendDesc"> AlphaFold produces a per-residue confidence
|
831 |
score (pLDDT) between 0 and 100. Some regions below 50 pLDDT may be unstructured in isolation.
|
832 |
</div>
|
833 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
834 |
<script>
|
835 |
let viewer = null;
|
836 |
let voldata = null;
|
@@ -859,14 +936,38 @@ select{
|
|
859 |
return "Blue";
|
860 |
}
|
861 |
};
|
862 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
863 |
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } });
|
864 |
viewer.zoomTo();
|
865 |
viewer.render();
|
866 |
viewer.zoom(0.8, 2000);
|
867 |
viewer.getModel(0).setHoverable({}, true,
|
868 |
function (atom, viewer, event, container) {
|
869 |
-
console.log(atom)
|
870 |
if (!atom.label) {
|
871 |
atom.label = viewer.addLabel(atom.resn+atom.resi+" pLDDT=" + atom.b, { position: atom, backgroundColor: "mintcream", fontColor: "black" });
|
872 |
}
|
@@ -881,12 +982,24 @@ select{
|
|
881 |
$("#sidechain").change(function () {
|
882 |
if (this.checked) {
|
883 |
BB = ["C", "O", "N"]
|
884 |
-
|
885 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
886 |
viewer.render()
|
887 |
} else {
|
|
|
888 |
viewer.getModel(0).setStyle({cartoon: { colorfunc: colorAlpha }});
|
889 |
-
viewer.getModel(1).setStyle({cartoon: {
|
|
|
|
|
|
|
|
|
890 |
viewer.render()
|
891 |
}
|
892 |
});
|
@@ -894,7 +1007,7 @@ select{
|
|
894 |
$("#startstructure").change(function () {
|
895 |
if (this.checked) {
|
896 |
$("#sidechain").prop( "checked", false );
|
897 |
-
viewer.getModel(1).setStyle({},{
|
898 |
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } });
|
899 |
viewer.render()
|
900 |
} else {
|
@@ -931,7 +1044,7 @@ select{
|
|
931 |
|
932 |
|
933 |
def set_examples(example):
|
934 |
-
label, inp, designed_chain, fixed_chain, homomer, num_seqs, sampling_temp = example
|
935 |
return [
|
936 |
label,
|
937 |
inp,
|
@@ -940,6 +1053,7 @@ def set_examples(example):
|
|
940 |
homomer,
|
941 |
gr.Slider.update(value=num_seqs),
|
942 |
gr.Radio.update(value=sampling_temp),
|
|
|
943 |
]
|
944 |
|
945 |
|
@@ -976,6 +1090,9 @@ with proteinMPNN:
|
|
976 |
value=0.1,
|
977 |
label="Sampling temperature",
|
978 |
)
|
|
|
|
|
|
|
979 |
with gr.Row():
|
980 |
model_name = gr.Dropdown(
|
981 |
choices=[
|
@@ -995,6 +1112,17 @@ with proteinMPNN:
|
|
995 |
gr.Markdown(
|
996 |
"for correct symmetric tying lenghts of homomer chains should be the same"
|
997 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
998 |
|
999 |
btn = gr.Button("Run")
|
1000 |
label = gr.Textbox(label="Label", visible=False)
|
@@ -1007,17 +1135,17 @@ with proteinMPNN:
|
|
1007 |
homomer,
|
1008 |
num_seqs,
|
1009 |
sampling_temp,
|
|
|
1010 |
],
|
1011 |
samples=[
|
1012 |
-
["Homomer design", "1O91", "A,B,C", "", True, 2, 0.1],
|
1013 |
-
["Monomer design", "6MRR", "A", "", False, 2, 0.1],
|
1014 |
-
["Redesign of Homomer to Heteromer", "3HTN", "A,B", "C", False, 2, 0.1],
|
|
|
|
|
1015 |
],
|
1016 |
)
|
1017 |
-
|
1018 |
-
""" Sampling temperature for amino acids, `T=0.0` means taking argmax, `T>>1.0` means sample randomly. Suggested values `0.1, 0.15, 0.2, 0.25, 0.3`. Higher values will lead to more diversity.
|
1019 |
-
"""
|
1020 |
-
)
|
1021 |
|
1022 |
gr.Markdown("# Output")
|
1023 |
|
@@ -1064,8 +1192,9 @@ with proteinMPNN:
|
|
1064 |
with gr.Column():
|
1065 |
plotAF_plddt = gr.Plot(label="pLDDT")
|
1066 |
# remove maxh80 class from css
|
1067 |
-
plotAF_pae = gr.Plot(label="PAE")
|
1068 |
tempFile = gr.Variable()
|
|
|
1069 |
btn.click(
|
1070 |
fn=update,
|
1071 |
inputs=[
|
@@ -1078,6 +1207,7 @@ with proteinMPNN:
|
|
1078 |
sampling_temp,
|
1079 |
model_name,
|
1080 |
backbone_noise,
|
|
|
1081 |
],
|
1082 |
outputs=[
|
1083 |
out,
|
@@ -1087,11 +1217,12 @@ with proteinMPNN:
|
|
1087 |
all_probs,
|
1088 |
tempFile,
|
1089 |
chosen_seq,
|
|
|
1090 |
],
|
1091 |
)
|
1092 |
btnAF.click(
|
1093 |
fn=update_AF,
|
1094 |
-
inputs=[chosen_seq, tempFile, num_recycles],
|
1095 |
outputs=[mol, plotAF_plddt, plotAF_pae],
|
1096 |
)
|
1097 |
examples.click(fn=set_examples, inputs=examples, outputs=examples.components)
|
|
|
26 |
import jax.numpy as jnp
|
27 |
import tensorflow as tf
|
28 |
|
29 |
+
|
30 |
+
from moleculekit.molecule import Molecule
|
31 |
+
|
32 |
if "/home/user/app/af_backprop" not in sys.path:
|
33 |
sys.path.append("/home/user/app/af_backprop")
|
34 |
|
|
|
253 |
)
|
254 |
from protein_mpnn_utils import StructureDataset, StructureDatasetPDB, ProteinMPNN
|
255 |
|
256 |
+
device = torch.device(
|
257 |
+
"cpu"
|
258 |
+
) # torch.device("cuda:0" if (torch.cuda.is_available()) else "cpu") #fix for memory issues
|
259 |
# ProteinMPNN model name: v_48_002, v_48_010, v_48_020, v_48_030, v_32_002, v_32_010; v_32_020, v_32_030; v_48_010=version with 48 edges 0.10A noise
|
260 |
# Standard deviation of Gaussian noise to add to backbone atoms
|
261 |
hidden_dim = 128
|
|
|
296 |
return f"{pdb_code}.pdb"
|
297 |
|
298 |
|
299 |
+
def preprocess_mol(pdb_code="", filepath=""):
|
300 |
+
if pdb_code is None or pdb_code == "":
|
301 |
+
try:
|
302 |
+
mol = Molecule(filepath.name)
|
303 |
+
except AttributeError as e:
|
304 |
+
return None
|
305 |
+
else:
|
306 |
+
mol = Molecule(pdb_code)
|
307 |
+
mol.write('original.pdb')
|
308 |
+
# clean messy files and only include protein itself
|
309 |
+
mol.filter("protein")
|
310 |
+
# renumber using moleculekit 0...len(protein)
|
311 |
+
df = mol.renumberResidues(returnMapping=True)
|
312 |
+
# add proteinMPNN index col which used 1..len(chain), 1...len(chain)
|
313 |
+
indexes = []
|
314 |
+
for chain, g in df.groupby("chain"):
|
315 |
+
j = 1
|
316 |
+
for i, row in g.iterrows():
|
317 |
+
indexes.append(j)
|
318 |
+
j += 1
|
319 |
+
df["proteinMPNN_index"] = indexes
|
320 |
+
mol.write("cleaned.pdb")
|
321 |
+
return "cleaned.pdb", df
|
322 |
+
|
323 |
+
def make_fixed_positions_dict(atomsel, residue_index_df):
|
324 |
+
# we use the uploaded file for the selection
|
325 |
+
mol = Molecule('original.pdb')
|
326 |
+
# use index for selection as resids will change
|
327 |
+
selected_residues = mol.get("index",atomsel)
|
328 |
+
|
329 |
+
# clean up
|
330 |
+
mol.filter("protein")
|
331 |
+
mol.renumberResidues()
|
332 |
+
# based on selected index now get resids
|
333 |
+
selected_residues = [str(i) for i in selected_residues]
|
334 |
+
if len(selected_residues)==0:
|
335 |
+
return None, []
|
336 |
+
selected_residues_str = " ".join(selected_residues)
|
337 |
+
selected_residues=set(mol.get('resid', sel=f"index {selected_residues_str}"))
|
338 |
+
|
339 |
+
# use the proteinMPNN index nomenclature to assemble fixed_positions_dict
|
340 |
+
fixed_positions_df = residue_index_df[residue_index_df['new_resid'].isin(selected_residues)]
|
341 |
+
|
342 |
+
chains = set(mol.get('chain', sel="all"))
|
343 |
+
fixed_position_dict = {'cleaned':{}}
|
344 |
+
#store the selected residues in a list for the visualization later with cleaned.pdb
|
345 |
+
selected_residues = list(fixed_positions_df['new_resid'])
|
346 |
+
|
347 |
+
for c in chains:
|
348 |
+
fixed_position_dict['cleaned'][c]=[]
|
349 |
+
|
350 |
+
for i, row in fixed_positions_df.iterrows():
|
351 |
+
fixed_position_dict['cleaned'][row['chain']].append(row['proteinMPNN_index'])
|
352 |
+
return fixed_position_dict, selected_residues
|
353 |
+
|
354 |
def update(
|
355 |
inp,
|
356 |
file,
|
|
|
361 |
sampling_temp,
|
362 |
model_name,
|
363 |
backbone_noise,
|
364 |
+
atomsel
|
365 |
):
|
366 |
from protein_mpnn_utils import (
|
367 |
loss_nll,
|
|
|
377 |
)
|
378 |
from protein_mpnn_utils import StructureDataset, StructureDatasetPDB, ProteinMPNN
|
379 |
|
380 |
+
# pdb_path = get_pdb(pdb_code=inp, filepath=file)
|
381 |
+
|
382 |
+
pdb_path, mol_index = preprocess_mol(pdb_code=inp, filepath=file)
|
383 |
|
384 |
if pdb_path == None:
|
385 |
return "Error processing PDB"
|
|
|
431 |
omit_AAs_np = np.array([AA in omit_AAs_list for AA in alphabet]).astype(np.float32)
|
432 |
|
433 |
chain_id_dict = None
|
434 |
+
if atomsel == "":
|
435 |
+
fixed_positions_dict, selected_residues = None, []
|
436 |
+
else:
|
437 |
+
fixed_positions_dict, selected_residues=make_fixed_positions_dict(atomsel, mol_index)
|
438 |
+
|
439 |
pssm_dict = None
|
440 |
omit_AA_dict = None
|
441 |
bias_AA_dict = None
|
|
|
452 |
tied_positions_dict = make_tied_positions_for_homomers(pdb_dict_list)
|
453 |
else:
|
454 |
tied_positions_dict = None
|
455 |
+
|
456 |
chain_id_dict = {}
|
457 |
chain_id_dict[pdb_dict_list[0]["name"]] = (designed_chain_list, fixed_chain_list)
|
458 |
with torch.no_grad():
|
|
|
697 |
)
|
698 |
seq_list.append(seq + chain_s)
|
699 |
message += f"{line}\n"
|
700 |
+
|
701 |
+
message += f"\nfixed positions:* {fixed_positions_dict['cleaned']} \n\n*uses CHAIN:[1..len(chain)] residue numbering"
|
702 |
# somehow sequences still contain X, remove again
|
703 |
for i, x in enumerate(seq_list):
|
704 |
for aa in omit_AAs:
|
|
|
737 |
gr.File.update(value="all_probs_concat.csv", visible=True),
|
738 |
pdb_path,
|
739 |
gr.Dropdown.update(choices=seq_list),
|
740 |
+
selected_residues
|
741 |
)
|
742 |
|
743 |
|
744 |
+
def update_AF(startsequence, pdb, num_recycles,selectedResidues):
|
745 |
|
746 |
# # run alphafold using ray
|
747 |
# plddts, pae, num_res = run_alphafold(
|
|
|
791 |
plt.colorbar()
|
792 |
plt.xlabel("Scored residue")
|
793 |
plt.ylabel("Aligned residue")
|
794 |
+
plt.savefig("pae_plot.png", dpi=300)
|
795 |
+
plt.close()
|
796 |
# doesnt work (likely because too large)
|
797 |
# plotAF_pae = px.imshow(
|
798 |
# pae,
|
799 |
# labels=dict(x="Scored residue", y="Aligned residue", color=""),
|
800 |
# template="simple_white",
|
801 |
+
# y=np.arange(len(plddts_val)),
|
802 |
# )
|
803 |
# plotAF_pae.write_html("test.html")
|
804 |
# plotAF_pae.update_layout(title="Predicted Aligned Error", template="simple_white")
|
805 |
|
806 |
+
return molecule(pdb, "out.pdb", num_res, selectedResidues), plotAF_plddt, "pae_plot.png"
|
807 |
|
808 |
|
809 |
def read_mol(molpath):
|
|
|
815 |
return mol
|
816 |
|
817 |
|
818 |
+
def molecule(pdb, afpdb, num_res, selectedResidues):
|
819 |
|
820 |
rms, input_pdb, aligned_pdb = align_structures(pdb, afpdb, num_res)
|
821 |
mol = read_mol(input_pdb)
|
|
|
841 |
.p-1{
|
842 |
padding:0.5rem;
|
843 |
}
|
|
|
|
|
|
|
|
|
844 |
.w-4{
|
845 |
width:1rem;
|
846 |
}
|
|
|
871 |
<label for="startstructure" class="relative inline-flex items-center mb-4 cursor-pointer ">
|
872 |
<input id="startstructure" type="checkbox" class="sr-only peer" checked>
|
873 |
<div class="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
|
874 |
+
<span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show input structure</span>
|
875 |
</label>
|
876 |
</div>
|
877 |
<button type="button" class="text-gray-900 bg-white hover:bg-gray-100 border border-gray-200 focus:ring-4 focus:outline-none focus:ring-gray-100 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-gray-600 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:bg-gray-700 mr-2 mb-2" id="download">
|
|
|
883 |
<div> RMSD AlphaFold vs. native: """
|
884 |
+ f"{rms:.2f}"
|
885 |
+ """Å computed using CEAlign on the aligned fragment</div>
|
886 |
+
</div>
|
887 |
+
<div class="text-sm flex items-start">
|
888 |
+
<div class="w-1/2">
|
889 |
+
|
890 |
+
<div class="font-medium mt-4 flex items-center space-x-2"><b>AF2 model of redesigned sequence</b></div>
|
891 |
+
<div>AlphaFold model confidence:</div>
|
892 |
+
<div class="flex space-x-2 py-1"><span class="w-4 h-4" style="background-color: rgb(0, 83, 214);"> </span><span class="legendlabel">Very high
|
893 |
(pLDDT > 90)</span></div>
|
894 |
+
<div class="flex space-x-2 py-1"><span class="w-4 h-4" style="background-color: rgb(101, 203, 243);"> </span><span class="legendlabel">Confident
|
|
|
895 |
(90 > pLDDT > 70)</span></div>
|
896 |
+
<div class="flex space-x-2 py-1"><span class="w-4 h-4" style="background-color: rgb(255, 219, 19);"> </span><span class="legendlabel">Low (70 >
|
|
|
897 |
pLDDT > 50)</span></div>
|
898 |
+
<div class="flex space-x-2 py-1"><span class="w-4 h-4" style="background-color: rgb(255, 125, 69);"> </span><span class="legendlabel">Very low
|
|
|
899 |
(pLDDT < 50)</span></div>
|
900 |
<div class="row column legendDesc"> AlphaFold produces a per-residue confidence
|
901 |
score (pLDDT) between 0 and 100. Some regions below 50 pLDDT may be unstructured in isolation.
|
902 |
</div>
|
903 |
</div>
|
904 |
+
<div class="w-1/2">
|
905 |
+
<div class="font-medium mt-4 flex items-center space-x-2"><b>Input structure </b><span class="w-4 h-4 bg-gray-300 inline-flex" ></span></div>
|
906 |
+
|
907 |
+
<div class="flex space-x-2 py-1"><span class="w-4 h-4" style="background-color:hotpink" > </span><span class="legendlabel">Fixed positions</span></div>
|
908 |
+
|
909 |
+
</div>
|
910 |
+
</div>
|
911 |
<script>
|
912 |
let viewer = null;
|
913 |
let voldata = null;
|
|
|
936 |
return "Blue";
|
937 |
}
|
938 |
};
|
939 |
+
var selectedResidues = """+
|
940 |
+
f"{selectedResidues}"
|
941 |
+
+"""
|
942 |
+
let colors = {}
|
943 |
+
for (let i=0; i<"""+str(num_res)+""";i++){
|
944 |
+
if (selectedResidues.includes(i)){
|
945 |
+
colors[i]="hotpink"
|
946 |
+
}else{
|
947 |
+
colors[i]="lightgray"
|
948 |
+
}}
|
949 |
+
|
950 |
+
let colorFixedSidechain = function(atom){
|
951 |
+
if (selectedResidues.includes(atom.resi)){
|
952 |
+
return "hotpink"
|
953 |
+
}else if (atom.elem == "O"){
|
954 |
+
return "red"
|
955 |
+
}else if (atom.elem == "N"){
|
956 |
+
return "blue"
|
957 |
+
}else if (atom.elem == "S"){
|
958 |
+
return "yellow"
|
959 |
+
}else{
|
960 |
+
return "lightgray"
|
961 |
+
}
|
962 |
+
}
|
963 |
+
|
964 |
+
viewer.getModel(1).setStyle({},{ cartoon: {colorscheme:{prop:"resi",map:colors} } })
|
965 |
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } });
|
966 |
viewer.zoomTo();
|
967 |
viewer.render();
|
968 |
viewer.zoom(0.8, 2000);
|
969 |
viewer.getModel(0).setHoverable({}, true,
|
970 |
function (atom, viewer, event, container) {
|
|
|
971 |
if (!atom.label) {
|
972 |
atom.label = viewer.addLabel(atom.resn+atom.resi+" pLDDT=" + atom.b, { position: atom, backgroundColor: "mintcream", fontColor: "black" });
|
973 |
}
|
|
|
982 |
$("#sidechain").change(function () {
|
983 |
if (this.checked) {
|
984 |
BB = ["C", "O", "N"]
|
985 |
+
|
986 |
+
if ($("#startstructure").prop("checked")) {
|
987 |
+
viewer.getModel(0).setStyle( {"and": [{resn: ["GLY", "PRO"], invert: true},{atom: BB, invert: true},]},{stick: {colorscheme: "WhiteCarbon", radius: 0.3}, cartoon: { colorfunc: colorAlpha }});
|
988 |
+
viewer.getModel(1).setStyle( {"and": [{resn: ["GLY", "PRO"], invert: true},{atom: BB, invert: true},]},{stick: {colorfunc:colorFixedSidechain, radius: 0.3}, cartoon: {colorscheme:{prop:"resi",map:colors} }});
|
989 |
+
}else{
|
990 |
+
viewer.getModel(0).setStyle( {"and": [{resn: ["GLY", "PRO"], invert: true},{atom: BB, invert: true},]},{stick: {colorscheme: "WhiteCarbon", radius: 0.3}, cartoon: { colorfunc: colorAlpha }});
|
991 |
+
viewer.getModel(1).setStyle();
|
992 |
+
}
|
993 |
+
|
994 |
viewer.render()
|
995 |
} else {
|
996 |
+
if ($("#startstructure").prop("checked")) {
|
997 |
viewer.getModel(0).setStyle({cartoon: { colorfunc: colorAlpha }});
|
998 |
+
viewer.getModel(1).setStyle({cartoon: {colorscheme:{prop:"resi",map:colors} }});
|
999 |
+
}else{
|
1000 |
+
viewer.getModel(0).setStyle({cartoon: { colorfunc: colorAlpha }});
|
1001 |
+
viewer.getModel(1).setStyle();
|
1002 |
+
}
|
1003 |
viewer.render()
|
1004 |
}
|
1005 |
});
|
|
|
1007 |
$("#startstructure").change(function () {
|
1008 |
if (this.checked) {
|
1009 |
$("#sidechain").prop( "checked", false );
|
1010 |
+
viewer.getModel(1).setStyle({},{cartoon: {colorscheme:{prop:"resi",map:colors} } })
|
1011 |
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } });
|
1012 |
viewer.render()
|
1013 |
} else {
|
|
|
1044 |
|
1045 |
|
1046 |
def set_examples(example):
|
1047 |
+
label, inp, designed_chain, fixed_chain, homomer, num_seqs, sampling_temp, atomsel = example
|
1048 |
return [
|
1049 |
label,
|
1050 |
inp,
|
|
|
1053 |
homomer,
|
1054 |
gr.Slider.update(value=num_seqs),
|
1055 |
gr.Radio.update(value=sampling_temp),
|
1056 |
+
atomsel
|
1057 |
]
|
1058 |
|
1059 |
|
|
|
1090 |
value=0.1,
|
1091 |
label="Sampling temperature",
|
1092 |
)
|
1093 |
+
gr.Markdown(""" Sampling temperature for amino acids, `T=0.0` means taking argmax, `T>>1.0` means sample randomly. Suggested values `0.1, 0.15, 0.2, 0.25, 0.3`. Higher values will lead to more diversity.
|
1094 |
+
"""
|
1095 |
+
)
|
1096 |
with gr.Row():
|
1097 |
model_name = gr.Dropdown(
|
1098 |
choices=[
|
|
|
1112 |
gr.Markdown(
|
1113 |
"for correct symmetric tying lenghts of homomer chains should be the same"
|
1114 |
)
|
1115 |
+
gr.Markdown('## Fixed positions')
|
1116 |
+
gr.Markdown("""You can fix important positions in the protein. Resid should be specified with the same numbering as in the input pdb file. The fixed residues will be highlighted in the output.
|
1117 |
+
The [VMD selection](http://www.ks.uiuc.edu/Research/vmd/vmd-1.9.2/ug/node89.html) synthax is used. You can also select based on ligands or chains in the input structure to specify interfaces to be fixed.
|
1118 |
+
|
1119 |
+
- <code>within 5 of resid 94</code> All residues that have >1 atom closer than 5 Å to any atom of residue 94
|
1120 |
+
- <code>name CA and within 5 of resid 94</code> All residues that have CA atom closer than 5 Å to any atom of residue 94
|
1121 |
+
- <code>resid 94 96 119</code> Residues 94, 94 and 119
|
1122 |
+
- <code>within 5 of resname ZN</code> All residues with any atom <5 Å of zinc ion
|
1123 |
+
- <code>chain A and within 5 of chain B </code> All residues of chain A that are part of the interface with chain B
|
1124 |
+
- <code>protein and within 5 of nucleic </code> All residues that bind to DNA (if present in structure)""")
|
1125 |
+
atomsel = gr.Textbox(placeholder="Specify atom selection ", label="Fixed positions")
|
1126 |
|
1127 |
btn = gr.Button("Run")
|
1128 |
label = gr.Textbox(label="Label", visible=False)
|
|
|
1135 |
homomer,
|
1136 |
num_seqs,
|
1137 |
sampling_temp,
|
1138 |
+
atomsel
|
1139 |
],
|
1140 |
samples=[
|
1141 |
+
["Homomer design", "1O91", "A,B,C", "", True, 2, 0.1,""],
|
1142 |
+
["Monomer design", "6MRR", "A", "", False, 2, 0.1,""],
|
1143 |
+
["Redesign of Homomer to Heteromer", "3HTN", "A,B", "C", False, 2, 0.1, ""],
|
1144 |
+
["Redesign of MID1 scaffold keeping binding site fixed", "3V1C", "A,B", "", False, 2, 0.1, "within 5 of resname ZN"],
|
1145 |
+
["Redesign of DNA binding protein", "3JRD", "A,B", "", False, 2, 0.1, "within 8 of nucleic"],
|
1146 |
],
|
1147 |
)
|
1148 |
+
|
|
|
|
|
|
|
1149 |
|
1150 |
gr.Markdown("# Output")
|
1151 |
|
|
|
1192 |
with gr.Column():
|
1193 |
plotAF_plddt = gr.Plot(label="pLDDT")
|
1194 |
# remove maxh80 class from css
|
1195 |
+
plotAF_pae = gr.Image(label="PAE") #gr.Plot(label="PAE")
|
1196 |
tempFile = gr.Variable()
|
1197 |
+
selectedResidues = gr.Variable()
|
1198 |
btn.click(
|
1199 |
fn=update,
|
1200 |
inputs=[
|
|
|
1207 |
sampling_temp,
|
1208 |
model_name,
|
1209 |
backbone_noise,
|
1210 |
+
atomsel,
|
1211 |
],
|
1212 |
outputs=[
|
1213 |
out,
|
|
|
1217 |
all_probs,
|
1218 |
tempFile,
|
1219 |
chosen_seq,
|
1220 |
+
selectedResidues
|
1221 |
],
|
1222 |
)
|
1223 |
btnAF.click(
|
1224 |
fn=update_AF,
|
1225 |
+
inputs=[chosen_seq, tempFile, num_recycles, selectedResidues],
|
1226 |
outputs=[mol, plotAF_plddt, plotAF_pae],
|
1227 |
)
|
1228 |
examples.click(fn=set_examples, inputs=examples, outputs=examples.components)
|
requirements.txt
CHANGED
@@ -19,4 +19,6 @@ ray
|
|
19 |
tqdm
|
20 |
gradio==3.0.11
|
21 |
protobuf<4
|
|
|
|
|
22 |
-f https://storage.googleapis.com/jax-releases/jax_releases.html
|
|
|
19 |
tqdm
|
20 |
gradio==3.0.11
|
21 |
protobuf<4
|
22 |
+
moleculekit
|
23 |
+
--use-deprecated=legacy-resolver
|
24 |
-f https://storage.googleapis.com/jax-releases/jax_releases.html
|