|
import logging |
|
|
|
|
|
logging.basicConfig( |
|
level=logging.INFO, |
|
format='%(asctime)s - %(levelname)s - %(message)s', |
|
handlers=[ |
|
logging.StreamHandler(), |
|
] |
|
) |
|
logger = logging.getLogger(__name__) |
|
|
|
def read_mol(molpath): |
|
with open(molpath, "r") as fp: |
|
lines = fp.readlines() |
|
mol = "" |
|
for l in lines: |
|
mol += l |
|
return mol |
|
|
|
|
|
def molecule( |
|
input_pdb, lenSeqs, num_res, selectedResidues, allSeqs, sequences |
|
): |
|
|
|
options = "" |
|
pred_mol = "[" |
|
seqdata = "{" |
|
selected = "selected" |
|
for i in range(lenSeqs): |
|
seqdata += ( |
|
str(i) |
|
+ ': { "score": ' |
|
+ str(sequences[i]["Score"]) |
|
+ ', "rmsd": ' |
|
+ str(sequences[i]["RMSD"]) |
|
+ ', "recovery": ' |
|
+ str(sequences[i]["Recovery"]) |
|
+ ', "plddt": ' |
|
+ str(sequences[i]["Mean pLDDT"]) |
|
+ ', "seq":"' |
|
+ allSeqs[i] |
|
+ '"}' |
|
) |
|
options += f'<option {selected} value="{i}">sequence {i} </option>' |
|
p = input_pdb |
|
pred_mol += f"`{read_mol(p)}`" |
|
selected = "" |
|
if i != lenSeqs - 1: |
|
pred_mol += "," |
|
seqdata += "," |
|
pred_mol += "]" |
|
seqdata += "}" |
|
logger.info(seqdata) |
|
|
|
x = ( |
|
"""<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8" /> |
|
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/flowbite.min.css" /> |
|
<style> |
|
body{ |
|
font-family:sans-serif |
|
} |
|
.mol-container { |
|
width: 100%; |
|
height: 700px; |
|
position: relative; |
|
} |
|
.space-x-2 > * + *{ |
|
margin-left: 0.5rem; |
|
} |
|
.p-1{ |
|
padding:0.5rem; |
|
} |
|
.w-4{ |
|
width:1rem; |
|
} |
|
.h-4{ |
|
height:1rem; |
|
} |
|
.mt-4{ |
|
margin-top:1rem; |
|
} |
|
.mol-container select{ |
|
background-image:None; |
|
} |
|
</style> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> |
|
<script src="https://3Dmol.csb.pitt.edu/build/3Dmol-min.js"></script> |
|
</head> |
|
<body> |
|
<div class="font-mono bg-gray-100 py-3 px-2 font-sm rounded"> |
|
<p id="seqText" class="max-w-4xl font-xs block" style="word-break: break-all;"> |
|
</p> |
|
</div> |
|
<div id="container" class="mol-container"></div> |
|
<div class="flex items-center"> |
|
<div class="px-4 pt-2"> |
|
<label for="sidechain" class="relative inline-flex items-center mb-4 cursor-pointer "> |
|
<input id="sidechain" type="checkbox" class="sr-only peer"> |
|
<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> |
|
<span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Show side chains</span> |
|
</label> |
|
</div> |
|
<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"> |
|
<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> |
|
Download predicted structure |
|
</button> |
|
</div> |
|
<div class="text-sm"> |
|
<div class="text-sm flex items-start"> |
|
<div class="w-1/2"> |
|
|
|
<div class="font-medium mt-4 flex items-center space-x-2"><b>Boltz-1 model of redesigned sequence</b></div> |
|
<div>Boltz-1 model confidence:</div> |
|
<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 |
|
(pLDDT > 90)</span></div> |
|
<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 |
|
(90 > pLDDT > 70)</span></div> |
|
<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 > |
|
pLDDT > 50)</span></div> |
|
<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 |
|
(pLDDT < 50)</span></div> |
|
<div class="row column legendDesc"> Boltz-1 produces a per-residue confidence |
|
score (pLDDT) between 0 and 100. Some regions below 50 pLDDT may be unstructured in isolation. |
|
</div> |
|
</div> |
|
</div> |
|
<script> |
|
function drawStructures(i, selectedResidues) { |
|
$("#rmsd").text(seqs[i]["rmsd"]) |
|
$("#seqText").text(seqs[i]["seq"]) |
|
$("#seqrmsd").text(seqs[i]["rmsd"]) |
|
$("#id").text(i) |
|
$("#score").text(seqs[i]["score"]) |
|
$("#recovery").text(seqs[i]["recovery"]) |
|
$("#plddt").text(seqs[i]["plddt"]) |
|
viewer = $3Dmol.createViewer(element, config); |
|
viewer.addModel(data[i], "pdb"); |
|
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } }); |
|
viewer.zoomTo(); |
|
viewer.render(); |
|
viewer.zoom(0.8, 2000); |
|
viewer.getModel(0).setHoverable({}, true, |
|
function (atom, viewer, event, container) { |
|
if (!atom.label) { |
|
atom.label = viewer.addLabel(atom.resn + atom.resi + " pLDDT=" + atom.b, { position: atom, backgroundColor: "mintcream", fontColor: "black" }); |
|
} |
|
}, |
|
function (atom, viewer) { |
|
if (atom.label) { |
|
viewer.removeLabel(atom.label); |
|
delete atom.label; |
|
} |
|
} |
|
); |
|
} |
|
let viewer = null; |
|
let voldata = null; |
|
let element = null; |
|
let config = null; |
|
let currentIndex = 0; |
|
let seqs = """ |
|
+ seqdata |
|
+ """ |
|
let data = """ |
|
+ pred_mol |
|
+ """ |
|
var selectedResidues = """ |
|
+ f"{selectedResidues}" |
|
+ """ |
|
//AlphaFold code from https://gist.github.com/piroyon/30d1c1099ad488a7952c3b21a5bebc96 |
|
let colorAlpha = function (atom) { |
|
if (atom.b < 50) { |
|
return "OrangeRed"; |
|
} else if (atom.b < 70) { |
|
return "Gold"; |
|
} else if (atom.b < 90) { |
|
return "MediumTurquoise"; |
|
} else { |
|
return "Blue"; |
|
} |
|
}; |
|
|
|
let colors = {} |
|
for (let i=0; i<""" |
|
+ str(num_res) |
|
+ """;i++){ |
|
if (selectedResidues.includes(i)){ |
|
colors[i]="hotpink" |
|
}else{ |
|
colors[i]="lightgray" |
|
}} |
|
let colorFixedSidechain = function(atom){ |
|
if (selectedResidues.includes(atom.resi)){ |
|
return "hotpink" |
|
}else if (atom.elem == "O"){ |
|
return "red" |
|
}else if (atom.elem == "N"){ |
|
return "blue" |
|
}else if (atom.elem == "S"){ |
|
return "yellow" |
|
}else{ |
|
return "lightgray" |
|
} |
|
} |
|
$(document).ready(function () { |
|
element = $("#container"); |
|
config = { backgroundColor: "white" }; |
|
//viewer.ui.initiateUI(); |
|
|
|
drawStructures(currentIndex, selectedResidues) |
|
$("#sidechain").change(function () { |
|
if (this.checked) { |
|
BB = ["C", "O", "N"] |
|
|
|
if ($("#startstructure").prop("checked")) { |
|
viewer.getModel(0).setStyle( {"and": [{resn: ["GLY", "PRO"], invert: true},{atom: BB, invert: true},]},{stick: {colorscheme: "WhiteCarbon", radius: 0.3}, cartoon: { colorfunc: colorAlpha }}); |
|
}else{ |
|
viewer.getModel(0).setStyle( {"and": [{resn: ["GLY", "PRO"], invert: true},{atom: BB, invert: true},]},{stick: {colorscheme: "WhiteCarbon", radius: 0.3}, cartoon: { colorfunc: colorAlpha }}); |
|
} |
|
|
|
viewer.render() |
|
} else { |
|
if ($("#startstructure").prop("checked")) { |
|
viewer.getModel(0).setStyle({cartoon: { colorfunc: colorAlpha }}); |
|
}else{ |
|
viewer.getModel(0).setStyle({cartoon: { colorfunc: colorAlpha }}); |
|
} |
|
viewer.render() |
|
} |
|
}); |
|
$("#seq").change(function () { |
|
drawStructures(this.value, selectedResidues) |
|
currentIndex = this.value |
|
$("#sidechain").prop( "checked", false ); |
|
$("#startstructure").prop( "checked", true ); |
|
}); |
|
$("#startstructure").change(function () { |
|
if (this.checked) { |
|
$("#sidechain").prop( "checked", false ); |
|
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } }); |
|
viewer.render() |
|
} else { |
|
$("#sidechain").prop( "checked", false ); |
|
viewer.getModel(0).setStyle({}, { cartoon: { colorfunc: colorAlpha } }); |
|
viewer.render() |
|
} |
|
}); |
|
$("#download").click(function () { |
|
download("outputs/out_" + currentIndex + "_aligned.pdb", data[currentIndex]); |
|
}) |
|
}); |
|
function download(filename, text) { |
|
var element = document.createElement("a"); |
|
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text)); |
|
element.setAttribute("download", filename); |
|
element.style.display = "none"; |
|
document.body.appendChild(element); |
|
element.click(); |
|
document.body.removeChild(element); |
|
} |
|
</script> |
|
</body></html>""" |
|
) |
|
|
|
return x |