Mercurial > repos > galaxy-australia > alphafold2
diff alphafold.html @ 20:6ab1a261520a draft default tip
planemo upload for repository https://github.com/usegalaxy-au/tools-au commit c3a90eb12ada44d477541baa4dd6182be29cd554-dirty
author | galaxy-australia |
---|---|
date | Sun, 28 Jul 2024 20:09:55 +0000 |
parents | 2f7702fd0a4c |
children |
line wrap: on
line diff
--- a/alphafold.html Wed May 08 06:26:55 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,656 +0,0 @@ -<!DOCTYPE html> -<html lang="en" dir="ltr"> - - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - - <title> Alphafold structure prediction </title> - - <link rel="preconnect" href="https://fonts.googleapis.com"> - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> - <link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&display=swap" rel="stylesheet"> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> - <script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.1.0/chroma.min.js" integrity="sha512-yocoLferfPbcwpCMr8v/B0AB4SWpJlouBwgE0D3ZHaiP1nuu5djZclFEIj9znuqghaZ3tdCMRrreLoM8km+jIQ==" crossorigin="anonymous"></script> - - <style type="text/css"> - * { - margin: 0; - padding: 0; - } - html, body { - width: 100%; - font-size: 1rem; - } - body { - font-family: 'Ubuntu', sans-serif; - } - canvas { - background-color: white; - } - h1, h2, h3, h4, h5, h6 { - color: dodgerblue; - text-align: center; - font-weight: lighter; - } - h1 { - margin: 2rem; - font-size: 3rem; - } - h2 { - font-size: 2rem; - margin-top: 1rem; - margin-bottom: .5rem; - } - button.btn { - color: #ccc; - margin: 1rem; - padding: .5rem; - font-size: 1rem; - min-width: 4rem; - border: none; - border-radius: .5rem; - background-color: grey; - transition-duration: 0.25s; - cursor: pointer; - } - button.btn.selected { - color: #eee; - background-color: dodgerblue; - } - button.btn.green { - color: #eee; - background-color: #10941f; - } - button.btn:focus { - outline: none; - color: inherit; - } - button.btn:hover { - color: white; - box-shadow: 0 0 10px dodgerblue; - } - button.btn.green:hover { - color: white; - box-shadow: 0 0 10px limegreen; - } - .main { - min-height: 90vh; - position: relative; - } - .flex { - display: flex; - justify-content: center; - align-items: center; - padding: 1rem; - } - .col { - flex-direction: column; - flex-grow: 0; - } - .controls { - padding-bottom: 10vh; - } - .box { - padding: .5rem 1rem; - margin: .5rem auto; - width: fit-content; - border-radius: 1rem; - } - .mono { - font-family: monospace; - color: #555; - background-color: #ddd; - padding: .25rem; - border-radius: .25rem; - } - .space-1 { - line-height: 1.2; - } - .space-2 { - line-height: 1.5; - } - .relative { - position: relative; - } - .legend { - max-width: 350px; - } - .legend .scale { - display: flex; - flex-direction: column; - align-items: center; - } - .legend .color { - width: 150px; - height: 30px; - justify-content: space-between; - background: linear-gradient( - 90deg, - rgba(255,55,0,1) 0%, - rgba(216,224,6,1) 33%, - rgba(34,213,238,1) 66%, - rgba(3,30,148,1) 100% - ); - } - .legend .ticks { - margin-top: -1rem; - width: 180px; - justify-content: space-between; - } - #ngl-root-parent { - width: 40vw; - height: 30vw; - margin: auto; - position: relative; - } - #ngl-root { - width: 40vw; - height: 30vw; - border-radius: 15px; - border: 1px solid grey; - } - #ngl-nothing { - position: absolute; - top: 0; - left: 0; - display: none; - text-align: center; - width: 40vw; - height: 30vw; - padding-top: 12vw; - } - #ngl-loading { - position: absolute; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - width: 800px; - height: 600px; - width: 40vw; - height: 30vw; - } - #ngl-loading svg { - width: 30%; - height: 30%; - width: 10vw; - height: 10vw; - } - - /* Responsive */ - @media (max-width: 1400px) { - :root { - font-size: 10pt; - } - button.btn { - margin: .5rem; - padding: .25rem; - } - .box { - padding: .5rem; - margin: .5rem auto; - } - .legend { - max-width: 200px; - } - .help-text { - font-size: 0.8rem; - } - .mono { - padding: .25rem .5rem; - } - } - @media (max-width: 1000px) { - :root { - font-size: 8pt; - } - } - @media (max-width: 800px) { - :root { - font-size: 6pt; - } - } - </style> - - <script src="https://cdn.rawgit.com/arose/ngl/v2.0.0-dev.37/dist/ngl.js"></script> - </head> - - - <body> - <h1> Alphafold structure prediction </h1> - - <div class="main flex"> - <div class="col relative"> - <div id="ngl-root-parent"> - - <div id="ngl-root"></div> - - <div id="ngl-nothing"> - Select a representation to display - </div> - - <div id="ngl-loading"> - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"> - <g transform="rotate(0 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(30 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(60 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(90 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(120 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(150 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(180 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(210 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(240 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(270 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(300 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite"></animate> - </rect> - </g><g transform="rotate(330 50 50)"> - <rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#88879e"> - <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animate> - </rect> - </g> - </svg> - </div> - </div> - - <div class="flex"> - <div class="box space-1"> - <p> - <span class="mono">Scroll up/down</span> - to zoom in and out - </p> - <p> - <span class="mono">Click + drag</span> - to rotate the structure - </p> - <p> - <span class="mono">CTRL + click + drag</span> - to move the structure - </p> - <p> - <span class="mono">Click</span> - an atom to bring it into focus - </p> - </div> - - <div class="box legend"> - <div class="scale"> - <div class="color"></div> - <div class="flex ticks"> - <div><50</div> - <div>70</div> - <div>90+</div> - </div> - </div> - - <div> - <p class="text-center"> - <small> - Alphafold produces a - <a href="https://alphafold.ebi.ac.uk/faq#faq-5" target="_blank"> - per-residue confidence score (pLDDT) - </a> - between 0 and 100. Some regions below 50 pLDDT may be - unstructured in isolation. - </small> - </p> - </div> - </div> - </div> - </div> - - <div class="flex col controls"> - <div class="box text-center"> - <h3> Select model </h3> - <p>The top-ranked structures predicted by Alphafold</p> - <div> - <button class="btn selected" id="btn-ranked_0" onclick="setModel(0);"> - Ranked 0 - </button> - - <button class="btn" id="btn-ranked_1" onclick="setModel(1);"> - Ranked 1 - </button> - - <button class="btn" id="btn-ranked_2" onclick="setModel(2);"> - Ranked 2 - </button> - - <button class="btn" id="btn-ranked_3" onclick="setModel(3);"> - Ranked 3 - </button> - - <button class="btn" id="btn-ranked_4" onclick="setModel(4);"> - Ranked 4 - </button> - </div> - </div> - - <div class="box text-center"> - <h3> Toggle representations </h3> - <div> - <button class="btn selected" id="btn-cartoon" onclick="toggleModelRepresentation('cartoon');"> - Cartoon - </button> - - <button class="btn" id="btn-ball-stick" onclick="toggleModelRepresentation('ball+stick');"> - Ball + stick - </button> - - <button class="btn" id="btn-surface" onclick="toggleModelRepresentation('surface');"> - Surface - </button> - - <button class="btn" id="btn-backbone" onclick="toggleModelRepresentation('backbone');"> - Backbone - </button> - </div> - </div> - - <div class="box text-center"> - <h3> Actions </h3> - <div> - <button class="btn selected" id="btn-toggle-spin" onclick="toggleSpin();"> - Toggle spin - </button> - - <button class="btn" id="btn-toggle-dark" onclick="toggleDark();"> - Dark mode - </button> - </div> - </div> - - <div class="box text-center"> - <h3> Download </h3> - <div> - <button class="btn green" onclick="downloadPng();"> - Snapshot - </button> - - <button class="btn green" onclick="downloadPdb();"> - PDB - </button> - </div> - </div> - </div> - </div> - </body> - - - <script type="text/javascript"> - - // Render NGLviewer for PDB files - - // State management has been implemented with vanilla Js but could have used - // Vue - it's a fairly simple use case so a global 'state' object works fine - // without complicating things too much. - - - // Define a custom color scheme to represent model confidence consistently - // across different representations - // ------------------------------------------------------------------------ - const colorScale = chroma.scale([ - 'red', 'yellow', 'green', 'cyan', 'blue' - ]).mode('lab').domain([0, 0.9]); - - const confidenceScheme = NGL.ColormakerRegistry.addScheme(function (params) { - this.atomColor = function (atom) { - // Actually model confidence (pLDDT) - const c = atom.bfactor; - const BREAK_RED = 40; // Below this is just plain red - let range, r, g, b; - - if (c < BREAK_RED) { - return 0xFF0000; - } - const p = (c - BREAK_RED) / (100 - BREAK_RED) - return eval(colorScale(p).hex().replace('#', '0x')); - }; - }); - - // NGL color schemes https://nglviewer.org/ngl/api/manual/usage/coloring.html - const COLORSCHEME = confidenceScheme; //'bfactor' - - const MODELS = [ - 'ranked_0.pdb', - 'ranked_1.pdb', - 'ranked_2.pdb', - 'ranked_3.pdb', - 'ranked_4.pdb', - ] - - const REPRESENTATIONS = [ - 'cartoon', - 'ball+stick', - 'surface', - 'backbone', - ] - - const DEFAULT_REPRESENTATION = REPRESENTATIONS[0]; - const MAX_CLICK_INTERVAL_MS = 500; // For debouncing model clicks - - let stage; - let nonceSetModel; - - let state = { - model: 0, - modelObject: null, - representations: {}, - colorScheme: 'bfactor', - darkMode: false, - loading: 1, - spin: true, - } - - const uri = (i) => MODELS[i]; - // Switch to this function to return sample model URI (local dev) - // const uri = (i) => `https://raw.githubusercontent.com/neoformit/alphafold-galaxy/main/data/${MODELS[i]}`; - - document.addEventListener("DOMContentLoaded", async function () { - // Can set debug for development if NGL is being... funny - // NGL.setDebug(true) - - // Create NGL Stage object - stage = new NGL.Stage("ngl-root", { backgroundColor: 'white' }); - - // Handle window resizing - window.addEventListener("resize", () => stage.handleResize()); - - loadModel(); - while (true) { - if (!state.loading) { - // Reload page if NGL failed to display. Weird occassional bug. - const canvas = document.querySelector('#ngl-root canvas'); - canvas.height < 50 && window.reload(); - break - } - await new Promise(resolve => setTimeout(resolve, 500)); - } - }); - - // Models ------------------------------------------------------------------ - - const setModel = (ix) => { - state.model = ix; - stage.removeComponent(state.modelObject); - setLoading(1); - - // Debounce rapid model clicking with a nonce - nonceSetModel = new Object(); - const localNonce = nonceSetModel; - setTimeout( () => { - if (localNonce === nonceSetModel) { - // The user has stopped clicking, hurray... - loadModel().then(updateButtons); - } - }, MAX_CLICK_INTERVAL_MS); - } - - const loadModel = () => { - reps = Object.keys(state.representations); - if (reps.length) { - state.representations = {}; - } else { - reps = [DEFAULT_REPRESENTATION]; - } - - // Load PDB entry - return stage.loadFile(uri(state.model)).then( (o) => { - state.modelObject = o; - reps.forEach( (r) => addModelRepresentation(r) ); - stage.setSpin(state.spin); - o.autoView(); - setLoading(0); - }) - } - - // Representations --------------------------------------------------------- - - const toggleModelRepresentation = (rep) => { - rep in state.representations ? - removeModelRepresentation(rep) - : addModelRepresentation(rep) - } - - const addModelRepresentation = (rep) => { - state.representations[rep] = - state.modelObject.addRepresentation(rep, {colorScheme: COLORSCHEME}); - updateButtons(); - } - - const removeModelRepresentation = (rep) => { - o = state.representations[rep]; - state.modelObject.removeRepresentation(o); - delete state.representations[rep]; - updateButtons(); - } - - const clearModelRepresentations = () => { - state.modelObject && state.modelObject.removeAllRepresentations(); - state.representations = {}; - } - - // Actions ----------------------------------------------------------------- - - const toggleDark = () => { - state.darkMode = !state.darkMode; - stage.setParameters({ - backgroundColor: state.darkMode ? 'black' : 'white', - }); - const btn = document.querySelector('#btn-toggle-dark'); - btn && btn.classList.toggle('selected'); - } - - const setLoading = (state) => { - document.getElementById('ngl-loading') - .style.display = state ? 'flex' : 'none'; - state.loading = state; - } - - const toggleSpin = () => { - stage.toggleSpin(); - const btn = document.querySelector('#btn-toggle-spin'); - btn && btn.classList.toggle('selected'); - state.spin = !state.spin; - } - - const downloadPng = () => { - const params = { - factor: 3, - antialias: true, - } - stage.makeImage(params).then( (blob) => { - const name = MODELS[state.model].replace('.pdb', '.png'); - const url = URL.createObjectURL(blob); - makeDownload(url, name); - }) - } - - const downloadPdb = () => { - const url = uri(state.model); - const name = `alphafold_${MODELS[state.model]}`; - makeDownload(url, name); - } - - const makeDownload = (url, name) => { - // Will not work with cross-origin urls (i.e. during development) - console.log(`Creating file download for ${name}, href ${url}`); - const saveLink = document.createElement('a'); - saveLink.href = url; - saveLink.download = name; - document.body.appendChild(saveLink); - saveLink.dispatchEvent( - new MouseEvent('click', { - bubbles: true, - cancelable: true, - view: window - }) - ); - document.body.removeChild(saveLink); - } - - const updateButtons = () => { - MODELS.forEach( (name, i) => { - const id = `#btn-${name.replace('.pdb', '')}`; - const btn = document.querySelector(id); - if (!btn) return - i == state.model ? - btn.classList.add('selected') - : btn.classList.remove('selected'); - }) - - REPRESENTATIONS.forEach( (name) => { - const id = `#btn-${name}`.replace('+', '-'); - const btn = document.querySelector(id); - if (!btn) return - if (name in state.representations) { - btn.classList.add('selected') - } else { - btn.classList.remove('selected'); - } - }); - - // Show "Nothing to display" if no representations are selected - document.querySelector('#ngl-nothing').style.display = - Object.keys(state.representations).length ? - 'none' - : 'block'; - } - - </script> - -</html>