Simon Duerr commited on
Commit
349d16a
1 Parent(s): df23d91

feature: all alphafold, reduce nSeqs that can be predicted

Browse files
Files changed (3) hide show
  1. app.py +223 -144
  2. outputs/README.md +1 -0
  3. packages.txt +0 -1
app.py CHANGED
@@ -157,15 +157,15 @@ def make_tied_positions_for_homomers(pdb_dict_list):
157
  return my_dict
158
 
159
 
160
- def align_structures(pdb1, pdb2, lenRes):
161
  """Take two structure and superimpose pdb1 on pdb2"""
162
  import Bio.PDB
163
  import subprocess
164
 
165
  pdb_parser = Bio.PDB.PDBParser(QUIET=True)
166
  # Get the structures
167
- ref_structure = pdb_parser.get_structure("samle", pdb1)
168
- sample_structure = pdb_parser.get_structure("reference", pdb2)
169
 
170
  aligner = Bio.PDB.CEAligner()
171
  aligner.set_reference(ref_structure)
@@ -173,11 +173,13 @@ def align_structures(pdb1, pdb2, lenRes):
173
 
174
  io = Bio.PDB.PDBIO()
175
  io.set_structure(ref_structure)
176
- io.save(f"reference.pdb")
 
 
177
  # Doing this to get around biopython CEALIGN bug
178
- subprocess.call("pymol -c -Q -r cealign.pml", shell=True)
179
 
180
- return aligner.rms, "reference.pdb", "out_aligned.pdb"
181
 
182
 
183
  def save_pdb(outs, filename, LEN):
@@ -196,39 +198,40 @@ def save_pdb(outs, filename, LEN):
196
 
197
 
198
  @ray.remote(num_gpus=1, max_calls=1)
199
- def run_alphafold(sequence, num_recycles):
200
  recycles = num_recycles
201
- RUNNER, OPT = setup_af(sequence)
202
-
203
- SEQ = re.sub("[^A-Z]", "", sequence.upper())
204
- MAX_LEN = len(SEQ)
205
- LEN = len(SEQ)
206
-
207
- x = np.array([residue_constants.restype_order.get(aa, -1) for aa in SEQ])
208
- x = np.pad(x, [0, MAX_LEN - LEN], constant_values=-1)
209
- x = jax.nn.one_hot(x, 20)
210
-
211
- OPT["prev"] = {
212
- "init_msa_first_row": np.zeros([1, MAX_LEN, 256]),
213
- "init_pair": np.zeros([1, MAX_LEN, MAX_LEN, 128]),
214
- "init_pos": np.zeros([1, MAX_LEN, 37, 3]),
215
- }
216
-
217
- positions = []
218
  plddts = []
219
- for r in range(recycles + 1):
220
- outs = RUNNER(x, OPT)
221
- outs = jax.tree_map(lambda x: np.asarray(x), outs)
222
- positions.append(outs["prev"]["init_pos"][0, :LEN])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  plddts.append(outs["plddt"][:LEN])
224
- OPT["prev"] = outs["prev"]
225
- if recycles > 0:
226
- print(r, plddts[-1].mean())
227
- if os.path.exists("/home/duerr/phd/08_Code/ProteinMPNN"):
228
- save_pdb(outs, "/home/duerr/phd/08_Code/ProteinMPNN/out.pdb", LEN)
229
- else:
230
- save_pdb(outs, "/home/user/app/out.pdb", LEN)
231
- return plddts, outs["pae"], LEN
232
 
233
 
234
  if os.path.exists("/home/duerr/phd/08_Code/ProteinMPNN"):
@@ -547,6 +550,8 @@ def update(
547
  native_score = scores.cpu().data.numpy()
548
  message = ""
549
  seq_list = []
 
 
550
  for temp in temperatures:
551
  for j in range(NUM_BATCHES):
552
  randn_2 = torch.randn(chain_M.shape, device=X.device)
@@ -724,6 +729,8 @@ def update(
724
  for i, x in enumerate(not_designed):
725
  if nd_mask[i]:
726
  chain_s += x
 
 
727
  line = (
728
  ">T={}, sample={}, score={}, seq_recovery={}\n{}\n".format(
729
  temp, b_ix, score_print, seq_rec_print, seq
@@ -762,7 +769,7 @@ def update(
762
  )
763
 
764
  fig_tadjusted.update_xaxes(side="top")
765
-
766
  return (
767
  message,
768
  fig,
@@ -771,17 +778,20 @@ def update(
771
  gr.File.update(value="all_probs_concat.csv", visible=True),
772
  pdb_path,
773
  gr.Dropdown.update(choices=seq_list),
774
- selected_residues
 
775
  )
776
 
777
 
778
- def update_AF(startsequence, pdb, num_recycles,selectedResidues):
779
 
780
  # # run alphafold using ray
781
  # plddts, pae, num_res = run_alphafold(
782
  # startsequence, num_recycles
783
  # )
784
- if len(startsequence) > 700:
 
 
785
  return (
786
  """
787
  <div class="p-4 mb-4 text-sm text-yellow-700 bg-orange-50 rounded-lg" role="alert">
@@ -791,21 +801,29 @@ def update_AF(startsequence, pdb, num_recycles,selectedResidues):
791
  plt.figure(),
792
  plt.figure(),
793
  )
794
- plddts, pae, num_res = ray.get(run_alphafold.remote(startsequence, num_recycles))
795
- x = np.arange(10)
 
 
 
 
 
 
 
796
  plots = []
797
- for recycle, plddts_val in enumerate(plddts):
798
- if recycle == 0 or recycle == len(plddts) - 1:
799
- visible = True
800
- else:
801
- visible = "legendonly"
 
802
  plots.append(
803
  go.Scatter(
804
  x=np.arange(len(plddts_val)),
805
  y=plddts_val,
806
- hovertemplate="<i>pLDDT</i>: %{y:.2f} <br><i>Residue index:</i> %{x}<br>Recycle "
807
- + str(recycle),
808
- name=f"Recycle {recycle}",
809
  visible=visible,
810
  )
811
  )
@@ -818,15 +836,18 @@ def update_AF(startsequence, pdb, num_recycles,selectedResidues):
818
  template="simple_white",
819
  legend=dict(yanchor="bottom", y=0.01, xanchor="left", x=0.99),
820
  )
821
- plt.figure()
822
- plt.title("Predicted Aligned Error")
823
- Ln = pae.shape[0]
824
- plt.imshow(pae, cmap="bwr", vmin=0, vmax=30, extent=(0, Ln, Ln, 0))
825
- plt.colorbar()
826
- plt.xlabel("Scored residue")
827
- plt.ylabel("Aligned residue")
828
- plt.savefig("pae_plot.png", dpi=300)
829
- plt.close()
 
 
 
830
  # doesnt work (likely because too large)
831
  # plotAF_pae = px.imshow(
832
  # pae,
@@ -837,7 +858,7 @@ def update_AF(startsequence, pdb, num_recycles,selectedResidues):
837
  # plotAF_pae.write_html("test.html")
838
  # plotAF_pae.update_layout(title="Predicted Aligned Error", template="simple_white")
839
 
840
- return molecule(pdb, "out.pdb", num_res, selectedResidues), plotAF_plddt, "pae_plot.png"
841
 
842
 
843
  def read_mol(molpath):
@@ -849,11 +870,27 @@ def read_mol(molpath):
849
  return mol
850
 
851
 
852
- def molecule(pdb, afpdb, num_res, selectedResidues):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
- rms, input_pdb, aligned_pdb = align_structures(pdb, afpdb, num_res)
855
- mol = read_mol(input_pdb)
856
- pred_mol = read_mol(aligned_pdb)
857
  x = (
858
  """<!DOCTYPE html>
859
  <html>
@@ -864,61 +901,74 @@ def molecule(pdb, afpdb, num_res, selectedResidues):
864
  body{
865
  font-family:sans-serif
866
  }
867
- .mol-container {
868
- width: 100%;
869
- height: 700px;
870
- position: relative;
871
- }
872
- .space-x-2 > * + *{
873
- margin-left: 0.5rem;
874
- }
875
- .p-1{
876
- padding:0.5rem;
877
- }
878
- .w-4{
879
- width:1rem;
880
- }
881
- .h-4{
882
- height:1rem;
883
- }
884
- .mt-4{
885
- margin-top:1rem;
886
- }
887
- select{
888
- background-image:None;
889
- }
890
- </style>
891
- <script src="https://3Dmol.csb.pitt.edu/build/3Dmol-min.js"></script>
892
  </head>
893
  <body>
894
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
  <div id="container" class="mol-container"></div>
896
- <div class="flex">
897
- <div class="px-4">
898
  <label for="sidechain" class="relative inline-flex items-center mb-4 cursor-pointer ">
899
  <input id="sidechain" type="checkbox" class="sr-only peer">
900
  <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>
901
  <span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show side chains</span>
902
  </label>
903
  </div>
904
- <div class="px-4">
905
  <label for="startstructure" class="relative inline-flex items-center mb-4 cursor-pointer ">
906
  <input id="startstructure" type="checkbox" class="sr-only peer" checked>
907
  <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>
908
  <span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show input structure</span>
909
  </label>
910
  </div>
911
- <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">
912
  <svg class="w-6 h-6 mr-2 -ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
913
  Download predicted structure
914
  </button>
915
  </div>
916
- <div class="text-sm">
917
- <div> RMSD AlphaFold vs. native: """
918
- + f"{rms:.2f}"
919
- + """Å computed using CEAlign on the aligned fragment</div>
920
- </div>
921
- <div class="text-sm flex items-start">
922
  <div class="w-1/2">
923
 
924
  <div class="font-medium mt-4 flex items-center space-x-2"><b>AF2 model of redesigned sequence</b></div>
@@ -943,21 +993,56 @@ select{
943
  </div>
944
  </div>
945
  <script>
946
- let viewer = null;
947
- let voldata = null;
948
- $(document).ready(function () {
949
- let element = $("#container");
950
- let config = { backgroundColor: "white" };
951
- viewer = $3Dmol.createViewer( element, config );
952
- viewer.ui.initiateUI();
953
- let data = `"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
954
  + pred_mol
955
- + """`
956
  let pdb = `"""
957
  + mol
958
  + """`
959
- viewer.addModel( data, "pdb" );
960
- viewer.addModel( pdb, "pdb" );
 
961
  //AlphaFold code from https://gist.github.com/piroyon/30d1c1099ad488a7952c3b21a5bebc96
962
  let colorAlpha = function (atom) {
963
  if (atom.b < 50) {
@@ -970,9 +1055,7 @@ select{
970
  return "Blue";
971
  }
972
  };
973
- var selectedResidues = """+
974
- f"{selectedResidues}"
975
- +"""
976
  let colors = {}
977
  for (let i=0; i<"""+str(num_res)+""";i++){
978
  if (selectedResidues.includes(i)){
@@ -995,24 +1078,12 @@ select{
995
  }
996
  }
997
 
998
- viewer.getModel(1).setStyle({},{ cartoon: {colorscheme:{prop:"resi",map:colors} } })
999
- viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } });
1000
- viewer.zoomTo();
1001
- viewer.render();
1002
- viewer.zoom(0.8, 2000);
1003
- viewer.getModel(0).setHoverable({}, true,
1004
- function (atom, viewer, event, container) {
1005
- if (!atom.label) {
1006
- atom.label = viewer.addLabel(atom.resn+atom.resi+" pLDDT=" + atom.b, { position: atom, backgroundColor: "mintcream", fontColor: "black" });
1007
- }
1008
- },
1009
- function (atom, viewer) {
1010
- if (atom.label) {
1011
- viewer.removeLabel(atom.label);
1012
- delete atom.label;
1013
- }
1014
- }
1015
- );
1016
  $("#sidechain").change(function () {
1017
  if (this.checked) {
1018
  BB = ["C", "O", "N"]
@@ -1037,7 +1108,12 @@ select{
1037
  viewer.render()
1038
  }
1039
  });
1040
-
 
 
 
 
 
1041
  $("#startstructure").change(function () {
1042
  if (this.checked) {
1043
  $("#sidechain").prop( "checked", false );
@@ -1052,9 +1128,7 @@ select{
1052
  }
1053
  });
1054
  $("#download").click(function () {
1055
- download(\""""
1056
- + aligned_pdb
1057
- + """\", data);
1058
  })
1059
  });
1060
  function download(filename, text) {
@@ -1070,7 +1144,7 @@ select{
1070
  </body></html>"""
1071
  )
1072
 
1073
- return f"""<iframe style="width: 800px; height: 1000px" name="result" allow="midi; geolocation; microphone; camera;
1074
  display-capture; encrypted-media;" sandbox="allow-modals allow-forms
1075
  allow-scripts allow-same-origin allow-popups
1076
  allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
@@ -1117,7 +1191,7 @@ with proteinMPNN:
1117
  )
1118
  with gr.Row():
1119
  num_seqs = gr.Slider(
1120
- minimum=1, maximum=50, value=1, step=1, label="Number of sequences"
1121
  )
1122
  sampling_temp = gr.Radio(
1123
  choices=[0.1, 0.15, 0.2, 0.25, 0.3],
@@ -1222,20 +1296,24 @@ with proteinMPNN:
1222
  with gr.Row():
1223
  with gr.Row():
1224
  chosen_seq = gr.Dropdown(
1225
- choices=[], label="Select a sequence for validation"
 
1226
  )
1227
  num_recycles = gr.Dropdown(
1228
  choices=[0, 1, 3, 5], value=3, label="num Recycles"
1229
  )
1230
- btnAF = gr.Button("Run AF2 on sequence")
1231
  with gr.Row():
1232
  mol = gr.HTML()
1233
  with gr.Column():
 
 
1234
  plotAF_plddt = gr.Plot(label="pLDDT")
1235
  # remove maxh80 class from css
1236
- plotAF_pae = gr.Image(label="PAE") #gr.Plot(label="PAE")
1237
  tempFile = gr.Variable()
1238
  selectedResidues = gr.Variable()
 
1239
  btn.click(
1240
  fn=update,
1241
  inputs=[
@@ -1258,13 +1336,14 @@ with proteinMPNN:
1258
  all_probs,
1259
  tempFile,
1260
  chosen_seq,
1261
- selectedResidues
 
1262
  ],
1263
  )
1264
  btnAF.click(
1265
  fn=update_AF,
1266
- inputs=[chosen_seq, tempFile, num_recycles, selectedResidues],
1267
- outputs=[mol, plotAF_plddt, plotAF_pae],
1268
  )
1269
  examples.click(fn=set_examples, inputs=examples, outputs=examples.components)
1270
  gr.Markdown(
 
157
  return my_dict
158
 
159
 
160
+ def align_structures(pdb1, pdb2, lenRes, index):
161
  """Take two structure and superimpose pdb1 on pdb2"""
162
  import Bio.PDB
163
  import subprocess
164
 
165
  pdb_parser = Bio.PDB.PDBParser(QUIET=True)
166
  # Get the structures
167
+ ref_structure = pdb_parser.get_structure("ref", pdb1)
168
+ sample_structure = pdb_parser.get_structure("sample", pdb2)
169
 
170
  aligner = Bio.PDB.CEAligner()
171
  aligner.set_reference(ref_structure)
 
173
 
174
  io = Bio.PDB.PDBIO()
175
  io.set_structure(ref_structure)
176
+ io.save(f"outputs/reference.pdb")
177
+ io.set_structure(sample_structure)
178
+ io.save(f"outputs/out_{index}_aligned.pdb")
179
  # Doing this to get around biopython CEALIGN bug
180
+ #subprocess.call("pymol -c -Q -r cealign.pml", shell=True)
181
 
182
+ return aligner.rms, "outputs/reference.pdb", f"outputs/out_{index}_aligned.pdb"
183
 
184
 
185
  def save_pdb(outs, filename, LEN):
 
198
 
199
 
200
  @ray.remote(num_gpus=1, max_calls=1)
201
+ def run_alphafold(sequences, num_recycles):
202
  recycles = num_recycles
203
+ RUNNER, OPT = setup_af(sequences[0])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  plddts = []
205
+ paes = []
206
+ for i, sequence in enumerate(sequences):
207
+ SEQ = re.sub("[^A-Z]", "", sequence.upper())
208
+ MAX_LEN = len(SEQ)
209
+ LEN = len(SEQ)
210
+
211
+ x = np.array([residue_constants.restype_order.get(aa, -1) for aa in SEQ])
212
+ x = np.pad(x, [0, MAX_LEN - LEN], constant_values=-1)
213
+ x = jax.nn.one_hot(x, 20)
214
+
215
+ OPT["prev"] = {
216
+ "init_msa_first_row": np.zeros([1, MAX_LEN, 256]),
217
+ "init_pair": np.zeros([1, MAX_LEN, MAX_LEN, 128]),
218
+ "init_pos": np.zeros([1, MAX_LEN, 37, 3]),
219
+ }
220
+
221
+ positions = []
222
+
223
+ for r in range(recycles + 1):
224
+ outs = RUNNER(x, OPT)
225
+ outs = jax.tree_map(lambda x: np.asarray(x), outs)
226
+ positions.append(outs["prev"]["init_pos"][0, :LEN])
227
+ OPT["prev"] = outs["prev"]
228
  plddts.append(outs["plddt"][:LEN])
229
+ paes.append(outs["pae"])
230
+ if os.path.exists("/home/duerr/phd/08_Code/ProteinMPNN"):
231
+ save_pdb(outs, f"/home/duerr/phd/08_Code/ProteinMPNN/outputs/out_{i}.pdb", LEN)
232
+ else:
233
+ save_pdb(outs, "/home/user/app/out.pdb", LEN)
234
+ return plddts,paes, LEN
 
 
235
 
236
 
237
  if os.path.exists("/home/duerr/phd/08_Code/ProteinMPNN"):
 
550
  native_score = scores.cpu().data.numpy()
551
  message = ""
552
  seq_list = []
553
+ seq_recovery = []
554
+ seq_score = []
555
  for temp in temperatures:
556
  for j in range(NUM_BATCHES):
557
  randn_2 = torch.randn(chain_M.shape, device=X.device)
 
729
  for i, x in enumerate(not_designed):
730
  if nd_mask[i]:
731
  chain_s += x
732
+ seq_recovery.append(seq_rec_print)
733
+ seq_score.append(score_print)
734
  line = (
735
  ">T={}, sample={}, score={}, seq_recovery={}\n{}\n".format(
736
  temp, b_ix, score_print, seq_rec_print, seq
 
769
  )
770
 
771
  fig_tadjusted.update_xaxes(side="top")
772
+ seq_dict = {"seq_list":seq_list, "recovery":seq_recovery, "seq_score":seq_score}
773
  return (
774
  message,
775
  fig,
 
778
  gr.File.update(value="all_probs_concat.csv", visible=True),
779
  pdb_path,
780
  gr.Dropdown.update(choices=seq_list),
781
+ selected_residues,
782
+ seq_dict
783
  )
784
 
785
 
786
+ def update_AF(seq_dict, pdb, num_recycles,selectedResidues):
787
 
788
  # # run alphafold using ray
789
  # plddts, pae, num_res = run_alphafold(
790
  # startsequence, num_recycles
791
  # )
792
+ allSeqs = seq_dict['seq_list']
793
+ lenSeqs = len(allSeqs)
794
+ if len(allSeqs[0]) > 700:
795
  return (
796
  """
797
  <div class="p-4 mb-4 text-sm text-yellow-700 bg-orange-50 rounded-lg" role="alert">
 
801
  plt.figure(),
802
  plt.figure(),
803
  )
804
+
805
+ plddts, paes, num_res = ray.get(run_alphafold.remote(allSeqs, num_recycles))
806
+
807
+ sequences = {}
808
+ for i in range(lenSeqs):
809
+ rms, input_pdb, aligned_pdb = align_structures(pdb, f"outputs/out_{i}.pdb", num_res,i)
810
+ sequences[i]={"Seq":i,"RMSD":f"{rms:.2f}","Score":seq_dict['seq_score'][i],"Recovery":seq_dict["recovery"][i],"Mean pLDDT":f"{np.mean(plddts[i]):.4f}"}
811
+ results=pd.DataFrame.from_dict(sequences, orient="index")
812
+ print(results)
813
  plots = []
814
+ for index, plddts_val in enumerate(plddts):
815
+ # if recycle == 0 or recycle == len(plddts) - 1:
816
+ # visible = True
817
+ # else:
818
+ # visible = "legendonly"
819
+ visible = True
820
  plots.append(
821
  go.Scatter(
822
  x=np.arange(len(plddts_val)),
823
  y=plddts_val,
824
+ hovertemplate="<i>pLDDT</i>: %{y:.2f} <br><i>Residue index:</i> %{x}<br>Sequence "
825
+ + str(index),
826
+ name=f"seq {index}",
827
  visible=visible,
828
  )
829
  )
 
836
  template="simple_white",
837
  legend=dict(yanchor="bottom", y=0.01, xanchor="left", x=0.99),
838
  )
839
+ pae_plots = []
840
+ for i,pae in enumerate(paes):
841
+ plt.figure()
842
+ plt.title(f"Predicted Aligned Error sequence {i}")
843
+ Ln = pae.shape[0]
844
+ plt.imshow(pae, cmap="bwr", vmin=0, vmax=30, extent=(0, Ln, Ln, 0))
845
+ plt.colorbar()
846
+ plt.xlabel("Scored residue")
847
+ plt.ylabel("Aligned residue")
848
+ plt.savefig(f"outputs/pae_plot_{i}.png", dpi=300)
849
+ plt.close()
850
+ pae_plots.append(f"outputs/pae_plot_{i}.png")
851
  # doesnt work (likely because too large)
852
  # plotAF_pae = px.imshow(
853
  # pae,
 
858
  # plotAF_pae.write_html("test.html")
859
  # plotAF_pae.update_layout(title="Predicted Aligned Error", template="simple_white")
860
 
861
+ return molecule(input_pdb, aligned_pdb, lenSeqs, num_res, selectedResidues, allSeqs, sequences), plotAF_plddt, pae_plots, results
862
 
863
 
864
  def read_mol(molpath):
 
870
  return mol
871
 
872
 
873
+ def molecule(input_pdb, aligned_pdb, lenSeqs, num_res, selectedResidues, allSeqs, sequences):
874
+
875
+ mol = read_mol("outputs/reference.pdb")
876
+ options =""
877
+ pred_mol = "["
878
+ seqdata = "{"
879
+ selected = "selected"
880
+ for i in range(lenSeqs):
881
+ seqdata+=str(i)+': { "score": '+sequences[i]["Score"]+', "rmsd": '+sequences[i]["RMSD"]+', "recovery": '+sequences[i]["Recovery"]+', "plddt": '+sequences[i]["Mean pLDDT"]+', "seq":"'+allSeqs[i]+'"}'
882
+ options+=f'<option {selected} value="{i}">sequence {i} </option>' #RMSD {sequences[i]["RMSD"]}, score {sequences[i]["Score"]}, recovery {sequences[i]["Recovery"]} pLDDT {sequences[i]["Mean pLDDT"]}
883
+ p=f"outputs/out_{i}_aligned.pdb"
884
+ pred_mol+=f"`{read_mol(p)}`"
885
+ selected = ""
886
+ if i!=lenSeqs-1:
887
+ pred_mol+=","
888
+ seqdata+=","
889
+ pred_mol+="]"
890
+ seqdata+="}"
891
+
892
+
893
 
 
 
 
894
  x = (
895
  """<!DOCTYPE html>
896
  <html>
 
901
  body{
902
  font-family:sans-serif
903
  }
904
+ .mol-container {
905
+ width: 100%;
906
+ height: 700px;
907
+ position: relative;
908
+ }
909
+ .space-x-2 > * + *{
910
+ margin-left: 0.5rem;
911
+ }
912
+ .p-1{
913
+ padding:0.5rem;
914
+ }
915
+ .w-4{
916
+ width:1rem;
917
+ }
918
+ .h-4{
919
+ height:1rem;
920
+ }
921
+ .mt-4{
922
+ margin-top:1rem;
923
+ }
924
+ .mol-container select{
925
+ background-image:None;
926
+ }
927
+ </style>
928
+ <script src="https://3Dmol.csb.pitt.edu/build/3Dmol-min.js"></script>
929
  </head>
930
  <body>
931
+ <div class="max-w-2xl flex items-center space-x-2 py-3">
932
+ <label for="seq"
933
+ class=" text-right whitespace-nowrap block text-base font-medium text-gray-900 dark:text-gray-400">Select
934
+ a sequence</label>
935
+ <select id="seq"
936
+ class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
937
+ """+options+"""
938
+ </select>
939
+ </div>
940
+ <div class="font-mono bg-gray-100 py-3 px-2 font-sm rounded">
941
+ <code>> seq <span id="id"></span>, score <span id="score"></span>, RMSD <span id="seqrmsd"></span>, Recovery
942
+ <span id="recovery"></span>, pLDDT <span id="plddt"></span></code><br>
943
+ <p id="seqText" class="max-w-4xl font-xs block" style="word-break: break-all;">
944
+
945
+ </p>
946
+ </div>
947
  <div id="container" class="mol-container"></div>
948
+ <div class="flex items-center">
949
+ <div class="px-4 pt-2">
950
  <label for="sidechain" class="relative inline-flex items-center mb-4 cursor-pointer ">
951
  <input id="sidechain" type="checkbox" class="sr-only peer">
952
  <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>
953
  <span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show side chains</span>
954
  </label>
955
  </div>
956
+ <div class="px-4 pt-2">
957
  <label for="startstructure" class="relative inline-flex items-center mb-4 cursor-pointer ">
958
  <input id="startstructure" type="checkbox" class="sr-only peer" checked>
959
  <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>
960
  <span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show input structure</span>
961
  </label>
962
  </div>
963
+ <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">
964
  <svg class="w-6 h-6 mr-2 -ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
965
  Download predicted structure
966
  </button>
967
  </div>
968
+ <div class="text-sm">
969
+ <div> RMSD AlphaFold vs. native: <span id="rmsd"></span> Å computed using CEAlign on the aligned fragment</div>
970
+ </div>
971
+ <div class="text-sm flex items-start">
 
 
972
  <div class="w-1/2">
973
 
974
  <div class="font-medium mt-4 flex items-center space-x-2"><b>AF2 model of redesigned sequence</b></div>
 
993
  </div>
994
  </div>
995
  <script>
996
+
997
+ function drawStructures(i, selectedResidues) {
998
+ $("#rmsd").text(seqs[i]["rmsd"])
999
+ $("#seqText").text(seqs[i]["seq"])
1000
+ $("#seqrmsd").text(seqs[i]["rmsd"])
1001
+ $("#id").text(i)
1002
+ $("#score").text(seqs[i]["score"])
1003
+ $("#recovery").text(seqs[i]["recovery"])
1004
+ $("#plddt").text(seqs[i]["plddt"])
1005
+
1006
+ viewer = $3Dmol.createViewer(element, config);
1007
+ viewer.addModel(data[i], "pdb");
1008
+ viewer.addModel(pdb, "pdb");
1009
+
1010
+
1011
+
1012
+ viewer.getModel(1).setStyle({}, { cartoon: { colorscheme: { prop: "resi", map: colors } } })
1013
+ viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } });
1014
+ viewer.zoomTo();
1015
+ viewer.render();
1016
+ viewer.zoom(0.8, 2000);
1017
+ viewer.getModel(0).setHoverable({}, true,
1018
+ function (atom, viewer, event, container) {
1019
+ if (!atom.label) {
1020
+ atom.label = viewer.addLabel(atom.resn + atom.resi + " pLDDT=" + atom.b, { position: atom, backgroundColor: "mintcream", fontColor: "black" });
1021
+ }
1022
+ },
1023
+ function (atom, viewer) {
1024
+ if (atom.label) {
1025
+ viewer.removeLabel(atom.label);
1026
+ delete atom.label;
1027
+ }
1028
+ }
1029
+ );
1030
+ }
1031
+ let viewer = null;
1032
+ let voldata = null;
1033
+ let element = null;
1034
+ let config = null;
1035
+ let currentIndex = 0;
1036
+ let seqs = """+seqdata+"""
1037
+ let data = """
1038
  + pred_mol
1039
+ + """
1040
  let pdb = `"""
1041
  + mol
1042
  + """`
1043
+ var selectedResidues = """+
1044
+ f"{selectedResidues}"
1045
+ +"""
1046
  //AlphaFold code from https://gist.github.com/piroyon/30d1c1099ad488a7952c3b21a5bebc96
1047
  let colorAlpha = function (atom) {
1048
  if (atom.b < 50) {
 
1055
  return "Blue";
1056
  }
1057
  };
1058
+
 
 
1059
  let colors = {}
1060
  for (let i=0; i<"""+str(num_res)+""";i++){
1061
  if (selectedResidues.includes(i)){
 
1078
  }
1079
  }
1080
 
1081
+ $(document).ready(function () {
1082
+ element = $("#container");
1083
+ config = { backgroundColor: "white" };
1084
+ //viewer.ui.initiateUI();
1085
+
1086
+ drawStructures(currentIndex, selectedResidues)
 
 
 
 
 
 
 
 
 
 
 
 
1087
  $("#sidechain").change(function () {
1088
  if (this.checked) {
1089
  BB = ["C", "O", "N"]
 
1108
  viewer.render()
1109
  }
1110
  });
1111
+ $("#seq").change(function () {
1112
+ drawStructures(this.value, selectedResidues)
1113
+ currentIndex = this.value
1114
+ $("#sidechain").prop( "checked", false );
1115
+ $("#startstructure").prop( "checked", true );
1116
+ });
1117
  $("#startstructure").change(function () {
1118
  if (this.checked) {
1119
  $("#sidechain").prop( "checked", false );
 
1128
  }
1129
  });
1130
  $("#download").click(function () {
1131
+ download("outputs/out_" + currentIndex + "_aligned.pdb", data);
 
 
1132
  })
1133
  });
1134
  function download(filename, text) {
 
1144
  </body></html>"""
1145
  )
1146
 
1147
+ return f"""<iframe style="width: 800px; height: 1300px" name="result" allow="midi; geolocation; microphone; camera;
1148
  display-capture; encrypted-media;" sandbox="allow-modals allow-forms
1149
  allow-scripts allow-same-origin allow-popups
1150
  allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
 
1191
  )
1192
  with gr.Row():
1193
  num_seqs = gr.Slider(
1194
+ minimum=1, maximum=15, value=1, step=1, label="Number of sequences"
1195
  )
1196
  sampling_temp = gr.Radio(
1197
  choices=[0.1, 0.15, 0.2, 0.25, 0.3],
 
1296
  with gr.Row():
1297
  with gr.Row():
1298
  chosen_seq = gr.Dropdown(
1299
+ choices=[], label="Select a sequence for validation",
1300
+ visible=False
1301
  )
1302
  num_recycles = gr.Dropdown(
1303
  choices=[0, 1, 3, 5], value=3, label="num Recycles"
1304
  )
1305
+ btnAF = gr.Button("Run AlphaFold on all sequences")
1306
  with gr.Row():
1307
  mol = gr.HTML()
1308
  with gr.Column():
1309
+ gr.Markdown("## Metrics")
1310
+ results = gr.Dataframe(nteractive=False, row_count=(0, 'dynamic'), headers=["Seq","RMSD","Score","Recovery","Mean pLDDT"])
1311
  plotAF_plddt = gr.Plot(label="pLDDT")
1312
  # remove maxh80 class from css
1313
+ plotAF_pae = gr.Gallery(label="PAE plots") #gr.Plot(label="PAE")
1314
  tempFile = gr.Variable()
1315
  selectedResidues = gr.Variable()
1316
+ seq_dict = gr.Variable()
1317
  btn.click(
1318
  fn=update,
1319
  inputs=[
 
1336
  all_probs,
1337
  tempFile,
1338
  chosen_seq,
1339
+ selectedResidues,
1340
+ seq_dict
1341
  ],
1342
  )
1343
  btnAF.click(
1344
  fn=update_AF,
1345
+ inputs=[seq_dict, tempFile, num_recycles, selectedResidues],
1346
+ outputs=[mol, plotAF_plddt, plotAF_pae, results],
1347
  )
1348
  examples.click(fn=set_examples, inputs=examples, outputs=examples.components)
1349
  gr.Markdown(
outputs/README.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Files are only saved here temporarily, they are not visible to the author
packages.txt DELETED
@@ -1 +0,0 @@
1
- pymol