CoolFace
Apppublic

simonduerr/pdb2vector

sourceHugging Facemitupdated 1y agoView on Hugging Face
1likes
app.py378 linesDownload Raw Back to root
1 2import os3import json4import uuid5 6import gradio as gr7from gradio_moleculeview import moleculeview8 9 10import cellscape11 12 13def html_output(input_file):14    with open(input_file, "r") as f:15        svg = f.read().replace("<svg", "<svg id='svgElement'")16        17    x = (18        """<!DOCTYPE html>19<html lang="en">20  <head>21    <meta charset="UTF-8" />22    <meta name="viewport" content="width=device-width, initial-scale=1.0" />23    <title>Document</title>24    <script src="https://cdn.tailwindcss.com"></script>25 26    <style>27    #snackbar {28  visibility: hidden;29  color: #fff;30  background-color: #333;31  min-width: 250px;32  margin-left: -125px;33  border-radius: 2px;34  padding: 16px;35  text-align: center;36  left: 50%;37  bottom: 30px;38  z-index: 1;39  position: fixed;40}41 42/* This will be activated when the snackbar's class is 'show' which will be added through JS */43#snackbar.show {44  visibility: visible;45  -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;46  animation: fadein 0.5s, fadeout 0.5s 2.5s;47}48 49/* Animations for fading in and out */50@-webkit-keyframes fadein {51  from {bottom: 0; opacity: 0;}52  to {bottom: 30px; opacity: 1;}53}54 55@keyframes fadein {56  from {bottom: 0; opacity: 0;}57  to {bottom: 30px; opacity: 1;}58}59 60@-webkit-keyframes fadeout {61  from {bottom: 30px; opacity: 1;}62  to {bottom: 0; opacity: 0;}63}64 65@keyframes fadeout {66  from {bottom: 30px; opacity: 1;}67  to {bottom: 0; opacity: 0;}68}69    </style>70  </head>71  <body>72 73    <div class="flex container mx-auto max-w-3xl">74      <div class="w-1/2">75        76     77 78 79    """80        + svg81        + """82         </div>83 84      <div class="w-1/2 space-y-4 justify-center items-center flex flex-col">85        <div class="w-3/4">86          <div87            class="w-full flex space-x-2 items-center text-xl justify-center font-light mb-3"88          >89            <svg90              xmlns="http://www.w3.org/2000/svg"91              class="w-4 h-4"92              viewBox="0 0 16 16"93            >94              <path95                fill="currentColor"96                fill-rule="evenodd"97                d="M6.091 5.194q.2-.322.305-.694h3.208c.259.916.98 1.637 1.896 1.896v3.208A2.76 2.76 0 0 0 9.604 11.5H6.396A2.76 2.76 0 0 0 4.5 9.604V6.396a2.76 2.76 0 0 0 1.591-1.202M13 6.396v3.208q.372.106.694.305a2.75 2.75 0 0 1 .897 3.785A2.751 2.751 0 0 1 9.603 13H6.397q-.106.372-.305.694A2.75 2.75 0 1 1 3 9.604V6.396A2.751 2.751 0 1 1 6.396 3h3.208A2.751 2.751 0 1 1 13 6.396M3.75 2.5a1.25 1.25 0 1 1 0 2.5a1.25 1.25 0 0 1 0-2.5M5 12.25a1.25 1.25 0 1 0-2.5 0a1.25 1.25 0 0 0 2.5 0M12.25 11a1.25 1.25 0 1 1 0 2.5a1.25 1.25 0 0 1 0-2.5m1.25-7.25a1.25 1.25 0 1 0-2.5 0a1.25 1.25 0 0 0 2.5 0"98                clip-rule="evenodd"99              />100            </svg>101            <div>SVG</div>102          </div>103          <div class="w-full flex space-x-5">104            <button105              id="copySvgBtn"106              class="flex items-center justify-center space-x-2 w-full p-3 border border-gray-300 rounded bg-gray-100"107            >108              <svg109                xmlns="http://www.w3.org/2000/svg"110                class="w-4 h-4"111                viewBox="0 0 16 16"112              >113                <path114                  fill="currentColor"115                  fill-rule="evenodd"116                  d="M12 2.5H8A1.5 1.5 0 0 0 6.5 4v1H8a3 3 0 0 1 3 3v1.5h1A1.5 1.5 0 0 0 13.5 8V4A1.5 1.5 0 0 0 12 2.5M11 11h1a3 3 0 0 0 3-3V4a3 3 0 0 0-3-3H8a3 3 0 0 0-3 3v1H4a3 3 0 0 0-3 3v4a3 3 0 0 0 3 3h4a3 3 0 0 0 3-3zM4 6.5h4A1.5 1.5 0 0 1 9.5 8v4A1.5 1.5 0 0 1 8 13.5H4A1.5 1.5 0 0 1 2.5 12V8A1.5 1.5 0 0 1 4 6.5"117                  clip-rule="evenodd"118                />119              </svg>120              <div>Copy*</div>121            </button>122            <button123              id="downloadSvgBtn"124              class="w-full flex items-center justify-center space-x-2 p-3 border border-gray-300 rounded bg-gray-100"125            >126              <svg127                xmlns="http://www.w3.org/2000/svg"128                class="h-4 w-4"129                viewBox="0 0 16 16"130              >131                <path132                  fill="currentColor"133                  fill-rule="evenodd"134                  d="M6.5 6H4.029l3.499 4.276a.61.61 0 0 0 .944 0L11.971 6H9.5V2.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25zm1.498 7.5H1.75a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5zm0-1.5a2.11 2.11 0 0 1-1.631-.774L2.833 6.907A1.474 1.474 0 0 1 3.973 4.5H5V2.75C5 1.784 5.784 1 6.75 1h2.5c.966 0 1.75.784 1.75 1.75V4.5h1.026a1.474 1.474 0 0 1 1.14 2.407l-3.533 4.319c-.4.49-1 .774-1.632.774H8"135                  clip-rule="evenodd"136                />137              </svg>138              <div>Download</div>139            </button>140          </div>141 142          <div class="text-xs mt-3 text-center w-full">143            *Only works in in Adobe Illustrator.144          </div>145 146          <div147            class="flex space-x-2 items-center text-xl justify-center font-light mb-3 mt-10"148          >149            <svg150              xmlns="http://www.w3.org/2000/svg"151              class="w-4 h-4"152              viewBox="0 0 16 16"153            >154              <path155                fill="currentColor"156                fill-rule="evenodd"157                d="M11.5 3h-7A1.5 1.5 0 0 0 3 4.5v5.027l.962-.7a1.75 1.75 0 0 1 2.079.016l.928.696l2.368-2.03a1.75 1.75 0 0 1 2.325.043L13 8.787V4.5A1.5 1.5 0 0 0 11.5 3m3 7.498V4.5a3 3 0 0 0-3-3h-7a3 3 0 0 0-3 3v7a3 3 0 0 0 3 3h7a3 3 0 0 0 3-3zm-1.5.33l-2.355-2.174a.25.25 0 0 0-.332-.006L7.488 11.07l-.457.392l-.481-.361l-1.41-1.057a.25.25 0 0 0-.296-.002L3 11.381v.119A1.5 1.5 0 0 0 4.5 13h7a1.5 1.5 0 0 0 1.5-1.5zM7.5 6a1.5 1.5 0 1 1-3 0a1.5 1.5 0 0 1 3 0"158                clip-rule="evenodd"159              />160            </svg>161            <div>PNG</div>162          </div>163 164          <div class="flex space-x-5">165            <!-- Buttons for Download -->166            <button167              id="copyPngBtn"168              class="w-full flex items-center justify-center space-x-2 p-3 border border-gray-300 rounded bg-gray-100"169            >170              <svg171                xmlns="http://www.w3.org/2000/svg"172                class="w-4 h-4"173                viewBox="0 0 16 16"174              >175                <path176                  fill="currentColor"177                  fill-rule="evenodd"178                  d="M12 2.5H8A1.5 1.5 0 0 0 6.5 4v1H8a3 3 0 0 1 3 3v1.5h1A1.5 1.5 0 0 0 13.5 8V4A1.5 1.5 0 0 0 12 2.5M11 11h1a3 3 0 0 0 3-3V4a3 3 0 0 0-3-3H8a3 3 0 0 0-3 3v1H4a3 3 0 0 0-3 3v4a3 3 0 0 0 3 3h4a3 3 0 0 0 3-3zM4 6.5h4A1.5 1.5 0 0 1 9.5 8v4A1.5 1.5 0 0 1 8 13.5H4A1.5 1.5 0 0 1 2.5 12V8A1.5 1.5 0 0 1 4 6.5"179                  clip-rule="evenodd"180                />181              </svg>182              <div>Copy</div>183            </button>184            <button185              id="downloadPngBtn"186              class="w-full flex items-center justify-center space-x-2 p-3 border border-gray-300 rounded bg-gray-100"187            >188              <svg189                xmlns="http://www.w3.org/2000/svg"190                class="h-4 w-4"191                viewBox="0 0 16 16"192              >193                <path194                  fill="currentColor"195                  fill-rule="evenodd"196                  d="M6.5 6H4.029l3.499 4.276a.61.61 0 0 0 .944 0L11.971 6H9.5V2.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25zm1.498 7.5H1.75a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5zm0-1.5a2.11 2.11 0 0 1-1.631-.774L2.833 6.907A1.474 1.474 0 0 1 3.973 4.5H5V2.75C5 1.784 5.784 1 6.75 1h2.5c.966 0 1.75.784 1.75 1.75V4.5h1.026a1.474 1.474 0 0 1 1.14 2.407l-3.533 4.319c-.4.49-1 .774-1.632.774H8"197                  clip-rule="evenodd"198                />199              </svg>200              <div>Download</div>201            </button>202          </div>203        </div>204      </div>205    </div>206 207  <span id="snackbar">Copied to clipboard</span>208 209 210      211    <script type="text/javascript">212    function copySvgToClipboard() {213    const svgElement = document.getElementById('svgElement');214    const svgData = new XMLSerializer().serializeToString(svgElement);215 216    // Copy the serialized SVG text to the clipboard217    navigator.clipboard.writeText(svgData).then(() => {218     var sb = document.getElementById("snackbar");219              sb.className = "show";220              setTimeout(()=>{ sb.className = sb.className.replace("show", ""); }, 3000);221    }).catch(err => {222        console.error("Could not copy SVG text to clipboard: ", err);223    });224}225 226// Function to convert SVG to PNG and copy to clipboard227function copyPngToClipboard() {228    const svgElement = document.getElementById('svgElement');229    const svgData = new XMLSerializer().serializeToString(svgElement);230    const canvas = document.createElement('canvas');231    const ctx = canvas.getContext('2d');232    const img = new Image();233 234    img.onload = function () {235        // Ensure canvas size matches the SVG236        canvas.width = svgElement.clientWidth;237        canvas.height = svgElement.clientHeight;238 239        // Clear the canvas (transparent background)240        ctx.clearRect(0, 0, canvas.width, canvas.height);241 242        // Draw the SVG image on the canvas243        ctx.drawImage(img, 0, 0);244 245        // Convert the canvas content to a PNG blob246        canvas.toBlob(blob => {247            const clipboardItem = [new ClipboardItem({ 'image/png': blob })];248            navigator.clipboard.write(clipboardItem).then(() => {249             var sb = document.getElementById("snackbar");250              sb.className = "show";251              setTimeout(()=>{ sb.className = sb.className.replace("show", ""); }, 3000);252  253            }).catch(err => {254                console.error("Could not copy PNG to clipboard: ", err);255            });256        }, 'image/png');257    };258 259    // Set the image source to the serialized SVG data260    img.src = 'data:image/svg+xml;base64,' + btoa(svgData);261}262 263// Function to download SVG264function downloadSvg() {265    const svgElement = document.getElementById('svgElement');266    const svgData = new XMLSerializer().serializeToString(svgElement);267    const blob = new Blob([svgData], { type: 'image/svg+xml' });268    const url = URL.createObjectURL(blob);269 270    const a = document.createElement('a');271    a.href = url;272    a.download = 'image.svg';273    document.body.appendChild(a);274    a.click();275    document.body.removeChild(a);276    URL.revokeObjectURL(url);277}278 279// Function to download PNG280function downloadPng() {281    const svgElement = document.getElementById('svgElement');282    const svgData = new XMLSerializer().serializeToString(svgElement);283    const canvas = document.createElement('canvas');284    const ctx = canvas.getContext('2d');285    const img = new Image();286 287    img.onload = function () {288        canvas.width = svgElement.clientWidth;289        canvas.height = svgElement.clientHeight;290        ctx.drawImage(img, 0, 0);291        canvas.toBlob(blob => {292            const url = URL.createObjectURL(blob);293            const a = document.createElement('a');294            a.href = url;295            a.download = 'image.png';296            document.body.appendChild(a);297            a.click();298            document.body.removeChild(a);299            URL.revokeObjectURL(url);300        }, 'image/png');301    };302 303    img.src = 'data:image/svg+xml;base64,' + btoa(svgData);304}305 306// Button event listeners307document.getElementById('copySvgBtn').addEventListener('click', copySvgToClipboard);308document.getElementById('copyPngBtn').addEventListener('click', copyPngToClipboard);309document.getElementById('downloadSvgBtn').addEventListener('click', downloadSvg);310document.getElementById('downloadPngBtn').addEventListener('click', downloadPng);311    </script>312           313        </body></html>"""314    )315    x = x.replace('"', "&quot;")316    x = x.replace("'", "&quot;")317    return f"""<iframe style="width: 100%; height: 600px" name="result" allow="midi; geolocation; microphone; camera; 318    display-capture; encrypted-media;" sandbox="allow-modals allow-forms 319    allow-scripts allow-same-origin allow-popups 320    allow-top-navigation-by-user-activation allow-downloads" allowfullscreen="" 321    allowpaymentrequest="" frameborder="0" srcdoc='{x}'></iframe>"""322 323def predict(input_mol, style, contour_level, view_str, chains):324    # write view to file325    with open("view_matrix", "w") as f:326        f.write(json.loads(view_str))327 328    chain_str = ""329    chain_dict = json.loads(chains)330 331    outputfile = os.path.basename(input_mol).replace(".pdb",".svg")332    # sort keys in dict and add colors to chain_str333    for chain in sorted(chain_dict.keys()):334        chain_str += f" '{chain_dict[chain]}'"335    if style == "Goodsell3D":336        os.system(f"cellscape cartoon --pdb {input_mol.name} --outline residue --color_by chain --depth_shading --depth_lines --colors {chain_str}  --depth flat --back_outline --view view_matrix --save {outputfile}")337    elif style == "Contour":338        os.system(f"cellscape cartoon --pdb {input_mol.name} --outline chain --color_by chain  --depth_contour_interval {contour_level} --colors {chain_str}  --depth contours --back_outline --view view_matrix --save {outputfile}")339    else:340        os.system(f"cellscape cartoon --pdb {input_mol.name} --outline chain --colors {chain_str}  --depth flat --back_outline --view view_matrix --save {outputfile}")341    342    #read content of file343    os.system(f"inkscape {outputfile} --actions='select-all;path-simplify;export-plain-svg' --export-filename {outputfile.replace('.svg', '_opt.svg')}")344 345    346    return html_output(outputfile.replace('.svg', '_opt.svg'))347 348 349 350 351def show_contour_level(style):352    if style=="Contour":353        return gr.Slider(minimum=1,maximum=50,step=1, value=10, label="Contour level", visible=True)354    else:355        return gr.Slider(minimum=1,maximum=50,step=1, value=10, label="Contour level", visible=False)356 357with gr.Blocks() as demo:358    style = gr.Radio(value="Flat", choices=["Flat", "Contour", "Goodsell3D"], label="Style")359    contour_level = gr.Slider(minimum=1,maximum=50,step=1, value=10, label="Contour level", visible=False)360    style.change(show_contour_level, style, contour_level)361    inp = moleculeview(label="Molecule3D")362 363    view_str = gr.Textbox("viewMatrixResult", label="View Matrix", visible=False)364    chains = gr.Textbox("chainsResult", label="Chains", visible=False) 365    hidden_style = gr.Textbox(visible=False)366    timestamp = gr.Textbox(visible=False)367    368    btn = gr.Button("Vectorize")369    html = gr.HTML("")370    btn.click(None, style, [view_str, chains, hidden_style, timestamp], js="(style) => [document.getElementById('viewMatrixResult').value, document.getElementById('chains').value, style, Date.now()]")  #371    372    timestamp.change(predict, [inp, style, contour_level, view_str, chains], [html])373    # on change of chains trigger, rendering374    375 376if __name__ == "__main__":377    demo.launch()378