Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Protein Sequence Analysis Toolkit</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500;700&family=Roboto:wght@300;400;500;700&display=swap'); | |
| :root { | |
| --primary: #3b82f6; | |
| --primary-dark: #2563eb; | |
| --secondary: #10b981; | |
| --dark: #1e293b; | |
| --light: #f8fafc; | |
| } | |
| body { | |
| font-family: 'Roboto', sans-serif; | |
| background-color: #f1f5f9; | |
| color: var(--dark); | |
| } | |
| .mono { | |
| font-family: 'Roboto Mono', monospace; | |
| } | |
| .sequence-display { | |
| background-color: #e2e8f0; | |
| border-radius: 0.5rem; | |
| padding: 1rem; | |
| overflow-x: auto; | |
| white-space: nowrap; | |
| } | |
| .amino-acid { | |
| display: inline-block; | |
| width: 1.5rem; | |
| text-align: center; | |
| font-weight: 500; | |
| position: relative; | |
| } | |
| .hydrophobic { color: #1e40af; background-color: #bfdbfe; } | |
| .hydrophilic { color: #166534; background-color: #bbf7d0; } | |
| .neutral { color: #713f12; background-color: #fed7aa; } | |
| .acidic { color: #9d174d; background-color: #f9a8d4; } | |
| .basic { color: #6d28d9; background-color: #ddd6fe; } | |
| .cysteine { color: #854d0e; background-color: #fef08a; } | |
| .proline { color: #0e7490; background-color: #a5f3fc; } | |
| .helix { background-color: rgba(239, 68, 68, 0.2); } | |
| .sheet { background-color: rgba(16, 185, 129, 0.2); } | |
| .coil { background-color: rgba(156, 163, 175, 0.2); } | |
| .tooltip { | |
| position: relative; | |
| display: inline-block; | |
| } | |
| .tooltip .tooltiptext { | |
| visibility: hidden; | |
| width: 120px; | |
| background-color: #555; | |
| color: #fff; | |
| text-align: center; | |
| border-radius: 6px; | |
| padding: 5px; | |
| position: absolute; | |
| z-index: 1; | |
| bottom: 125%; | |
| left: 50%; | |
| margin-left: -60px; | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| font-size: 0.8rem; | |
| } | |
| .tooltip:hover .tooltiptext { | |
| visibility: visible; | |
| opacity: 1; | |
| } | |
| .tab-content { | |
| display: none; | |
| } | |
| .tab-content.active { | |
| display: block; | |
| animation: fadeIn 0.3s ease-in-out; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .feature-badge { | |
| display: inline-flex; | |
| align-items: center; | |
| padding: 0.25rem 0.5rem; | |
| border-radius: 9999px; | |
| font-size: 0.75rem; | |
| font-weight: 500; | |
| margin-right: 0.5rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .feature-badge i { | |
| margin-right: 0.25rem; | |
| } | |
| .chart-container { | |
| position: relative; | |
| height: 300px; | |
| width: 100%; | |
| } | |
| .loading-spinner { | |
| border: 4px solid rgba(0, 0, 0, 0.1); | |
| border-radius: 50%; | |
| border-top: 4px solid var(--primary); | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| margin: 2rem auto; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .result-card { | |
| transition: all 0.3s ease; | |
| } | |
| .result-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
| } | |
| .sequence-input { | |
| min-height: 100px; | |
| font-family: 'Roboto Mono', monospace; | |
| } | |
| .analysis-section { | |
| scroll-margin-top: 100px; | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen"> | |
| <div class="container mx-auto px-4 py-8 max-w-7xl"> | |
| <!-- Header --> | |
| <header class="mb-8 text-center"> | |
| <h1 class="text-4xl font-bold text-blue-600 mb-2">Protein Sequence Analysis Toolkit</h1> | |
| <p class="text-lg text-gray-600">Comprehensive analysis of protein and peptide sequences using advanced protein language models</p> | |
| </header> | |
| <!-- Main Content --> | |
| <div class="bg-white rounded-xl shadow-lg overflow-hidden"> | |
| <!-- Input Section --> | |
| <div class="p-6 border-b border-gray-200"> | |
| <div class="flex flex-col md:flex-row gap-6"> | |
| <div class="flex-1"> | |
| <label for="sequence-input" class="block text-sm font-medium text-gray-700 mb-2">Enter Protein/Peptide Sequence</label> | |
| <textarea id="sequence-input" class="w-full px-4 py-3 border border-gray-300 rounded-lg sequence-input focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Enter amino acid sequence (e.g., MAEGEITTFTALTEKFNLPPGNYKKPKLLYCSNGGHFLRILPDGTVDGTRDRSDQHIQLQLSAESVGEVYIKSTETGQYLAMDTSGLLYGSQTPSEECLFLERLEENHYNTYTSKKHAEKNWFVGLKKNGSCKRGPRTHYGQKAILFLPLPV)"></textarea> | |
| <div class="flex flex-wrap gap-2 mt-3"> | |
| <button id="clear-btn" class="px-3 py-1 bg-gray-200 text-gray-700 rounded-md text-sm hover:bg-gray-300">Clear</button> | |
| <button id="example-btn" class="px-3 py-1 bg-blue-100 text-blue-700 rounded-md text-sm hover:bg-blue-200">Load Example</button> | |
| <button id="analyze-btn" class="px-3 py-1 bg-blue-600 text-white rounded-md text-sm hover:bg-blue-700">Analyze Sequence</button> | |
| </div> | |
| </div> | |
| <div class="flex-1"> | |
| <label class="block text-sm font-medium text-gray-700 mb-2">Sequence Features</label> | |
| <div class="bg-gray-50 p-4 rounded-lg h-full"> | |
| <div id="sequence-stats" class="grid grid-cols-2 gap-2"> | |
| <div class="text-sm"> | |
| <span class="text-gray-500">Length:</span> | |
| <span id="seq-length" class="font-medium">0</span> | |
| </div> | |
| <div class="text-sm"> | |
| <span class="text-gray-500">Molecular Weight:</span> | |
| <span id="mol-weight" class="font-medium">0 Da</span> | |
| </div> | |
| <div class="text-sm"> | |
| <span class="text-gray-500">Isoelectric Point:</span> | |
| <span id="isoelectric-pt" class="font-medium">-</span> | |
| </div> | |
| <div class="text-sm"> | |
| <span class="text-gray-500">Extinction Coefficient:</span> | |
| <span id="ext-coeff" class="font-medium">-</span> | |
| </div> | |
| <div class="text-sm col-span-2"> | |
| <span class="text-gray-500">Amino Acid Composition:</span> | |
| <div id="aa-composition" class="flex flex-wrap gap-1 mt-1"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Results Section --> | |
| <div id="results-section" class="hidden"> | |
| <!-- Tabs Navigation --> | |
| <div class="border-b border-gray-200"> | |
| <nav class="flex overflow-x-auto"> | |
| <button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent hover:text-blue-600 hover:border-blue-300" data-tab="sequence">Sequence</button> | |
| <button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent hover:text-blue-600 hover:border-blue-300" data-tab="physicochemical">Physicochemical</button> | |
| <button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent hover:text-blue-600 hover:border-blue-300" data-tab="structure">Structure</button> | |
| <button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent hover:text-blue-600 hover:border-blue-300" data-tab="functional">Functional</button> | |
| <button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent hover:text-blue-600 hover:border-blue-300" data-tab="optimization">Optimization</button> | |
| </nav> | |
| </div> | |
| <!-- Tab Contents --> | |
| <div class="p-6"> | |
| <!-- Sequence Tab --> | |
| <div id="sequence-tab" class="tab-content active"> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-semibold mb-3">Sequence Visualization</h3> | |
| <div id="sequence-display" class="sequence-display mono"></div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div> | |
| <h3 class="text-lg font-semibold mb-3">Amino Acid Properties</h3> | |
| <div id="property-legend" class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex flex-wrap gap-2 mb-2"> | |
| <span class="feature-badge hydrophobic"><i class="fas fa-water"></i> Hydrophobic</span> | |
| <span class="feature-badge hydrophilic"><i class="fas fa-tint"></i> Hydrophilic</span> | |
| <span class="feature-badge acidic"><i class="fas fa-minus-circle"></i> Acidic</span> | |
| <span class="feature-badge basic"><i class="fas fa-plus-circle"></i> Basic</span> | |
| <span class="feature-badge neutral"><i class="fas fa-circle"></i> Neutral</span> | |
| <span class="feature-badge cysteine"><i class="fas fa-link"></i> Cysteine</span> | |
| <span class="feature-badge proline"><i class="fas fa-undo"></i> Proline</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-lg font-semibold mb-3">Secondary Structure</h3> | |
| <div id="structure-legend" class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex flex-wrap gap-2 mb-2"> | |
| <span class="feature-badge helix"><i class="fas fa-helix"></i> Helix</span> | |
| <span class="feature-badge sheet"><i class="fas fa-layer-group"></i> Sheet</span> | |
| <span class="feature-badge coil"><i class="fas fa-wave-square"></i> Coil</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Physicochemical Tab --> | |
| <div id="physicochemical-tab" class="tab-content"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Isoelectric Point</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-gray-700">Calculated pI:</span> | |
| <span id="pI-value" class="text-xl font-bold text-blue-600">7.2</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-4"> | |
| <div id="pI-bar" class="bg-blue-600 h-4 rounded-full" style="width: 50%"></div> | |
| </div> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>3</span> | |
| <span>7</span> | |
| <span>11</span> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">The isoelectric point (pI) is the pH at which the protein has no net charge.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Molecular Weight</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-gray-700">Calculated MW:</span> | |
| <span id="mw-value" class="text-xl font-bold text-green-600">12,345 Da</span> | |
| </div> | |
| <p class="text-sm text-gray-600">Molecular weight calculated from the sum of amino acid residues.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Extinction Coefficient</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-gray-700">ε<sub>280</sub> (M<sup>-1</sup>cm<sup>-1</sup>):</span> | |
| <span id="ext-coeff-value" class="text-xl font-bold text-purple-600">44,720</span> | |
| </div> | |
| <p class="text-sm text-gray-600">Calculated from the number of Trp, Tyr, and Cys residues.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Hydrophobicity Analysis</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="chart-container"> | |
| <canvas id="hydrophobicity-chart"></canvas> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Hydrophobicity profile calculated using the Kyte-Doolittle scale.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Structure Tab --> | |
| <div id="structure-tab" class="tab-content"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Secondary Structure Prediction</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="chart-container"> | |
| <canvas id="secondary-structure-chart"></canvas> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Predicted using a protein language model (ESM-2).</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Disorder Prediction</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="chart-container"> | |
| <canvas id="disorder-chart"></canvas> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Predicted intrinsic disorder using IUPred2A.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Solvent Accessibility</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="chart-container"> | |
| <canvas id="accessibility-chart"></canvas> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Relative solvent accessible surface area (RSA) prediction.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Transmembrane Regions</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="chart-container"> | |
| <canvas id="transmembrane-chart"></canvas> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Predicted using TMHMM.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Functional Tab --> | |
| <div id="functional-tab" class="tab-content"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Signal Peptide Prediction</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-gray-700">Prediction:</span> | |
| <span id="signal-peptide-value" class="text-xl font-bold text-blue-600">Present (1-24)</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-4"> | |
| <div id="signal-peptide-bar" class="bg-blue-600 h-4 rounded-full" style="width: 20%"></div> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Predicted using SignalP-6.0.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Motif Analysis</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div id="motif-results"> | |
| <div class="mb-3"> | |
| <div class="flex justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">N-glycosylation (N-X-S/T)</span> | |
| <span class="text-sm font-medium text-blue-600">3 sites</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2"> | |
| <div class="bg-blue-600 h-2 rounded-full" style="width: 45%"></div> | |
| </div> | |
| </div> | |
| <div class="mb-3"> | |
| <div class="flex justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">Phosphorylation (S/T/Y)</span> | |
| <span class="text-sm font-medium text-green-600">8 sites</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2"> | |
| <div class="bg-green-600 h-2 rounded-full" style="width: 70%"></div> | |
| </div> | |
| </div> | |
| <div class="mb-3"> | |
| <div class="flex justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">SH3 binding (P-X-X-P)</span> | |
| <span class="text-sm font-medium text-purple-600">2 sites</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2"> | |
| <div class="bg-purple-600 h-2 rounded-full" style="width: 20%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Common functional motifs identified in the sequence.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Cytotoxicity Prediction</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-gray-700">Prediction:</span> | |
| <span id="cytotoxicity-value" class="text-xl font-bold text-red-600">Low risk</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-4"> | |
| <div id="cytotoxicity-bar" class="bg-red-600 h-4 rounded-full" style="width: 30%"></div> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Predicted using a machine learning model trained on cytotoxic peptides.</p> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Saturation Mutagenesis Analysis</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="mb-4"> | |
| <label for="motif-select" class="block text-sm font-medium text-gray-700 mb-2">Select Motif for Mutagenesis</label> | |
| <select id="motif-select" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"> | |
| <option>N-glycosylation (N-X-S/T) at 45-47</option> | |
| <option>Phosphorylation (S/T) at 78</option> | |
| <option>SH3 binding (P-X-X-P) at 102-105</option> | |
| </select> | |
| </div> | |
| <button id="run-mutagenesis-btn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">Run Saturation Mutagenesis</button> | |
| <div id="mutagenesis-results" class="mt-4 hidden"> | |
| <h4 class="font-medium text-gray-700 mb-2">Mutation Impact Summary</h4> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Position</th> | |
| <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Mutation</th> | |
| <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Stability ΔΔG</th> | |
| <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Function Impact</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200 text-sm"> | |
| <tr> | |
| <td class="px-3 py-2">N45</td> | |
| <td class="px-3 py-2">N45A</td> | |
| <td class="px-3 py-2 text-red-600">+1.2</td> | |
| <td class="px-3 py-2">Disrupts glycosylation</td> | |
| </tr> | |
| <tr> | |
| <td class="px-3 py-2">N45</td> | |
| <td class="px-3 py-2">N45D</td> | |
| <td class="px-3 py-2 text-red-600">+0.8</td> | |
| <td class="px-3 py-2">Disrupts glycosylation</td> | |
| </tr> | |
| <tr> | |
| <td class="px-3 py-2">N45</td> | |
| <td class="px-3 py-2">N45Q</td> | |
| <td class="px-3 py-2 text-green-600">-0.2</td> | |
| <td class="px-3 py-2">Maintains glycosylation</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Optimization Tab --> | |
| <div id="optimization-tab" class="tab-content"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Sequence Optimization</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-2">Optimization Goals</label> | |
| <div class="space-y-2"> | |
| <div class="flex items-center"> | |
| <input id="opt-stability" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked> | |
| <label for="opt-stability" class="ml-2 block text-sm text-gray-700">Improve stability</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input id="opt-expression" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked> | |
| <label for="opt-expression" class="ml-2 block text-sm text-gray-700">Improve expression</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input id="opt-solubility" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| <label for="opt-solubility" class="ml-2 block text-sm text-gray-700">Improve solubility</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input id="opt-function" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| <label for="opt-function" class="ml-2 block text-sm text-gray-700">Maintain function</label> | |
| </div> | |
| </div> | |
| </div> | |
| <button id="run-optimization-btn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">Run Optimization</button> | |
| <div id="optimization-results" class="mt-4 hidden"> | |
| <h4 class="font-medium text-gray-700 mb-2">Optimized Sequence</h4> | |
| <div class="sequence-display mono mb-3"></div> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div> | |
| <span class="text-sm text-gray-500">Original Stability Score:</span> | |
| <span class="font-medium">0.65</span> | |
| </div> | |
| <div> | |
| <span class="text-sm text-gray-500">Optimized Stability Score:</span> | |
| <span class="font-medium text-green-600">0.82</span> | |
| </div> | |
| <div> | |
| <span class="text-sm text-gray-500">Original Expression Score:</span> | |
| <span class="font-medium">0.45</span> | |
| </div> | |
| <div> | |
| <span class="text-sm text-gray-500">Optimized Expression Score:</span> | |
| <span class="font-medium text-green-600">0.78</span> | |
| </div> | |
| </div> | |
| <div class="mt-3"> | |
| <h5 class="text-sm font-medium text-gray-700 mb-1">Key Changes:</h5> | |
| <ul class="text-sm list-disc pl-5 space-y-1"> | |
| <li>R32K: Improved stability without affecting function</li> | |
| <li>L45V: Improved solubility</li> | |
| <li>P78A: Removed aggregation-prone proline</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 class="text-lg font-semibold mb-3">Protein Language Model Features</h3> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <div class="mb-4"> | |
| <label for="model-select" class="block text-sm font-medium text-gray-700 mb-2">Select Model</label> | |
| <select id="model-select" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"> | |
| <option>ESM-2 (650M parameters)</option> | |
| <option>ProtT5-XL (3B parameters)</option> | |
| <option>AlphaFold2 (with ESM-1b)</option> | |
| <option>ESM-1v (evolutionary model)</option> | |
| </select> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-2">Feature Extraction</label> | |
| <div class="space-y-2"> | |
| <div class="flex items-center"> | |
| <input id="feat-embedding" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked> | |
| <label for="feat-embedding" class="ml-2 block text-sm text-gray-700">Per-residue embeddings</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input id="feat-contact" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked> | |
| <label for="feat-contact" class="ml-2 block text-sm text-gray-700">Contact map</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input id="feat-conservation" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| <label for="feat-conservation" class="ml-2 block text-sm text-gray-700">Evolutionary conservation</label> | |
| </div> | |
| </div> | |
| </div> | |
| <button id="run-model-btn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">Extract Features</button> | |
| <div id="model-results" class="mt-4 hidden"> | |
| <div class="chart-container"> | |
| <canvas id="model-embedding-chart"></canvas> | |
| </div> | |
| <p class="text-sm text-gray-600 mt-2">Per-residue embeddings reduced to 2D using UMAP.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Loading State --> | |
| <div id="loading-section" class="hidden p-12 text-center"> | |
| <div class="loading-spinner"></div> | |
| <h3 class="text-lg font-medium text-gray-700 mt-4">Analyzing protein sequence...</h3> | |
| <p class="text-sm text-gray-500 mt-1">This may take a few moments as we run multiple predictions.</p> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5 mt-6 max-w-md mx-auto"> | |
| <div id="progress-bar" class="bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div> | |
| </div> | |
| <p id="progress-text" class="text-xs text-gray-500 mt-2">Initializing models...</p> | |
| </div> | |
| </div> | |
| <!-- Footer --> | |
| <footer class="mt-8 text-center text-sm text-gray-500"> | |
| <p>Protein Sequence Analysis Toolkit v1.0 - Powered by ESM-2, ProtT5, and other protein language models</p> | |
| <p class="mt-1">© 2023 Protein Analysis Group. All rights reserved.</p> | |
| </footer> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Tab functionality | |
| const tabButtons = document.querySelectorAll('.tab-btn'); | |
| const tabContents = document.querySelectorAll('.tab-content'); | |
| tabButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| // Remove active class from all buttons and contents | |
| tabButtons.forEach(btn => btn.classList.remove('border-blue-600', 'text-blue-600')); | |
| tabContents.forEach(content => content.classList.remove('active')); | |
| // Add active class to clicked button | |
| button.classList.add('border-blue-600', 'text-blue-600'); | |
| // Show corresponding content | |
| const tabId = button.getAttribute('data-tab') + '-tab'; | |
| document.getElementById(tabId).classList.add('active'); | |
| }); | |
| }); | |
| // Example sequence button | |
| document.getElementById('example-btn').addEventListener('click', function() { | |
| const exampleSeq = "MAEGEITTFTALTEKFNLPPGNYKKPKLLYCSNGGHFLRILPDGTVDGTRDRSDQHIQLQLSAESVGEVYIKSTETGQYLAMDTSGLLYGSQTPSEECLFLERLEENHYNTYTSKKHAEKNWFVGLKKNGSCKRGPRTHYGQKAILFLPLPV"; | |
| document.getElementById('sequence-input').value = exampleSeq; | |
| updateSequenceStats(exampleSeq); | |
| }); | |
| // Clear button | |
| document.getElementById('clear-btn').addEventListener('click', function() { | |
| document.getElementById('sequence-input').value = ''; | |
| document.getElementById('sequence-display').innerHTML = ''; | |
| document.getElementById('seq-length').textContent = '0'; | |
| document.getElementById('mol-weight').textContent = '0 Da'; | |
| document.getElementById('isoelectric-pt').textContent = '-'; | |
| document.getElementById('ext-coeff').textContent = '-'; | |
| document.getElementById('aa-composition').innerHTML = ''; | |
| document.getElementById('results-section').classList.add('hidden'); | |
| }); | |
| // Analyze button | |
| document.getElementById('analyze-btn').addEventListener('click', function() { | |
| const sequence = document.getElementById('sequence-input').value.trim().toUpperCase(); | |
| if (!sequence) { | |
| alert('Please enter a protein sequence'); | |
| return; | |
| } | |
| if (!/^[ACDEFGHIKLMNPQRSTVWY]+$/i.test(sequence)) { | |
| alert('Invalid amino acid characters detected. Please enter a valid protein sequence.'); | |
| return; | |
| } | |
| // Show loading state | |
| document.getElementById('results-section').classList.add('hidden'); | |
| document.getElementById('loading-section').classList.remove('hidden'); | |
| // Simulate analysis progress | |
| simulateAnalysisProgress(); | |
| // After "analysis" is complete | |
| setTimeout(() => { | |
| document.getElementById('loading-section').classList.add('hidden'); | |
| document.getElementById('results-section').classList.remove('hidden'); | |
| analyzeSequence(sequence); | |
| }, 3000); | |
| }); | |
| // Sequence input listener | |
| document.getElementById('sequence-input').addEventListener('input', function() { | |
| const sequence = this.value.trim().toUpperCase(); | |
| updateSequenceStats(sequence); | |
| }); | |
| // Run mutagenesis button | |
| document.getElementById('run-mutagenesis-btn').addEventListener('click', function() { | |
| document.getElementById('mutagenesis-results').classList.remove('hidden'); | |
| // Scroll to results | |
| document.getElementById('mutagenesis-results').scrollIntoView({ behavior: 'smooth' }); | |
| }); | |
| // Run optimization button | |
| document.getElementById('run-optimization-btn').addEventListener('click', function() { | |
| document.getElementById('optimization-results').classList.remove('hidden'); | |
| // Scroll to results | |
| document.getElementById('optimization-results').scrollIntoView({ behavior: 'smooth' }); | |
| }); | |
| // Run model button | |
| document.getElementById('run-model-btn').addEventListener('click', function() { | |
| document.getElementById('model-results').classList.remove('hidden'); | |
| // Scroll to results | |
| document.getElementById('model-results').scrollIntoView({ behavior: 'smooth' }); | |
| // Create embedding visualization | |
| createEmbeddingChart(); | |
| }); | |
| // Function to update sequence statistics | |
| function updateSequenceStats(sequence) { | |
| if (!sequence) { | |
| document.getElementById('seq-length').textContent = '0'; | |
| document.getElementById('mol-weight').textContent = '0 Da'; | |
| document.getElementById('isoelectric-pt').textContent = '-'; | |
| document.getElementById('ext-coeff').textContent = '-'; | |
| document.getElementById('aa-composition').innerHTML = ''; | |
| return; | |
| } | |
| // Calculate length | |
| document.getElementById('seq-length').textContent = sequence.length; | |
| // Calculate molecular weight (simplified) | |
| const aaWeights = { | |
| 'A': 89.09, 'R': 174.20, 'N': 132.12, 'D': 133.10, 'C': 121.15, | |
| 'E': 147.13, 'Q': 146.15, 'G': 75.07, 'H': 155.16, 'I': 131.17, | |
| 'L': 131.17, 'K': 146.19, 'M': 149.21, 'F': 165.19, 'P': 115.13, | |
| 'S': 105.09, 'T': 119.12, 'W': 204.23, 'Y': 181.19, 'V': 117.15 | |
| }; | |
| let molWeight = 18.02; // Water | |
| for (let aa of sequence) { | |
| molWeight += aaWeights[aa] || 0; | |
| } | |
| document.getElementById('mol-weight').textContent = molWeight.toFixed(2) + ' Da'; | |
| // Calculate amino acid composition | |
| const aaCount = {}; | |
| for (let aa of sequence) { | |
| aaCount[aa] = (aaCount[aa] || 0) + 1; | |
| } | |
| let aaCompHTML = ''; | |
| for (let aa in aaCount) { | |
| const percentage = ((aaCount[aa] / sequence.length) * 100).toFixed(1); | |
| aaCompHTML += `<span class="amino-acid ${getAAClass(aa)}">${aa}: ${aaCount[aa]} (${percentage}%)</span>`; | |
| } | |
| document.getElementById('aa-composition').innerHTML = aaCompHTML; | |
| // Display sequence with coloring | |
| displaySequence(sequence); | |
| } | |
| // Function to display sequence with coloring | |
| function displaySequence(sequence) { | |
| let seqHTML = ''; | |
| for (let i = 0; i < sequence.length; i++) { | |
| const aa = sequence[i]; | |
| const aaClass = getAAClass(aa); | |
| seqHTML += `<span class="amino-acid ${aaClass} tooltip">${aa}<span class="tooltiptext">${getAAName(aa)} (Pos ${i+1})</span></span>`; | |
| } | |
| document.getElementById('sequence-display').innerHTML = seqHTML; | |
| } | |
| // Function to get amino acid class for styling | |
| function getAAClass(aa) { | |
| const hydrophobic = ['A', 'V', 'L', 'I', 'M', 'F', 'W', 'Y']; | |
| const hydrophilic = ['S', 'T', 'N', 'Q']; | |
| const acidic = ['D', 'E']; | |
| const basic = ['K', 'R', 'H']; | |
| if (aa === 'C') return 'cysteine'; | |
| if (aa === 'P') return 'proline'; | |
| if (hydrophobic.includes(aa)) return 'hydrophobic'; | |
| if (hydrophilic.includes(aa)) return 'hydrophilic'; | |
| if (acidic.includes(aa)) return 'acidic'; | |
| if (basic.includes(aa)) return 'basic'; | |
| return 'neutral'; | |
| } | |
| // Function to get amino acid name | |
| function getAAName(aa) { | |
| const aaNames = { | |
| 'A': 'Alanine', 'R': 'Arginine', 'N': 'Asparagine', 'D': 'Aspartic acid', | |
| 'C': 'Cysteine', 'E': 'Glutamic acid', 'Q': 'Glutamine', 'G': 'Glycine', | |
| 'H': 'Histidine', 'I': 'Isoleucine', 'L': 'Leucine', 'K': 'Lysine', | |
| 'M': 'Methionine', 'F': 'Phenylalanine', 'P': 'Proline', 'S': 'Serine', | |
| 'T': 'Threonine', 'W': 'Tryptophan', 'Y': 'Tyrosine', 'V': 'Valine' | |
| }; | |
| return aaNames[aa] || aa; | |
| } | |
| // Function to simulate analysis progress | |
| function simulateAnalysisProgress() { | |
| const progressStages = [ | |
| "Initializing models...", | |
| "Calculating physicochemical properties...", | |
| "Predicting secondary structure...", | |
| "Analyzing functional motifs...", | |
| "Running language model...", | |
| "Finalizing results..." | |
| ]; | |
| let progress = 0; | |
| const progressBar = document.getElementById('progress-bar'); | |
| const progressText = document.getElementById('progress-text'); | |
| const interval = setInterval(() => { | |
| progress += Math.random() * 10; | |
| if (progress > 100) progress = 100; | |
| progressBar.style.width = `${progress}%`; | |
| // Update progress text based on stage | |
| const stageIndex = Math.min(Math.floor(progress / (100 / progressStages.length)), progressStages.length - 1); | |
| progressText.textContent = progressStages[stageIndex]; | |
| if (progress >= 100) { | |
| clearInterval(interval); | |
| progressText.textContent = "Analysis complete!"; | |
| } | |
| }, 300); | |
| } | |
| // Function to analyze sequence (main analysis) | |
| function analyzeSequence(sequence) { | |
| // Update sequence stats | |
| updateSequenceStats(sequence); | |
| // Calculate isoelectric point (simplified) | |
| const pI = calculateIsoelectricPoint(sequence); | |
| document.getElementById('pI-value').textContent = pI.toFixed(2); | |
| document.getElementById('pI-bar').style.width = `${((pI - 3) / 8) * 100}%`; | |
| // Calculate extinction coefficient (simplified) | |
| const extCoeff = calculateExtinctionCoefficient(sequence); | |
| document.getElementById('ext-coeff-value').textContent = extCoeff.toLocaleString(); | |
| // Create charts | |
| createHydrophobicityChart(sequence); | |
| createSecondaryStructureChart(sequence); | |
| createDisorderChart(sequence); | |
| createAccessibilityChart(sequence); | |
| createTransmembraneChart(sequence); | |
| } | |
| // Function to calculate isoelectric point (simplified) | |
| function calculateIsoelectricPoint(sequence) { | |
| // Count charged residues | |
| let pos = (sequence.match(/[KRH]/g) || []).length; | |
| let neg = (sequence.match(/[DE]/g) || []).length; | |
| // Very simplified pI calculation | |
| if (pos > neg) return 9.0 + Math.random(); | |
| if (neg > pos) return 5.0 - Math.random(); | |
| return 7.0 + (Math.random() - 0.5); | |
| } | |
| // Function to calculate extinction coefficient (simplified) | |
| function calculateExtinctionCoefficient(sequence) { | |
| const trp = (sequence.match(/W/g) || []).length; | |
| const tyr = (sequence.match(/Y/g) || []).length; | |
| const cys = (sequence.match(/C/g) || []).length; | |
| // Extinction coefficient = (Trp*5500) + (Tyr*1490) + (Cys*125) | |
| return Math.round(trp * 5500 + tyr * 1490 + cys * 125); | |
| } | |
| // Function to create hydrophobicity chart | |
| function createHydrophobicityChart(sequence) { | |
| const ctx = document.getElementById('hydrophobicity-chart').getContext('2d'); | |
| // Kyte-Doolittle hydrophobicity scale | |
| const kdScale = { | |
| 'A': 1.8, 'R': -4.5, 'N': -3.5, 'D': -3.5, 'C': 2.5, | |
| 'Q': -3.5, 'E': -3.5, 'G': -0.4, 'H': -3.2, 'I': 4.5, | |
| 'L': 3.8, 'K': -3.9, 'M': 1.9, 'F': 2.8, 'P': -1.6, | |
| 'S': -0.8, 'T': -0.7, 'W': -0.9, 'Y': -1.3, 'V': 4.2 | |
| }; | |
| // Calculate hydrophobicity values with window averaging | |
| const windowSize = 7; | |
| const hydrophobicity = []; | |
| for (let i = 0; i < sequence.length; i++) { | |
| let sum = 0; | |
| let count = 0; | |
| for (let j = i - Math.floor(windowSize/2); j <= i + Math.floor(windowSize/2); j++) { | |
| if (j >= 0 && j < sequence.length) { | |
| sum += kdScale[sequence[j]] || 0; | |
| count++; | |
| } | |
| } | |
| hydrophobicity.push(sum / count); | |
| } | |
| // Create chart | |
| new Chart(ctx, { | |
| type: 'line', | |
| data: { | |
| labels: Array.from({length: sequence.length}, (_, i) => i+1), | |
| datasets: [{ | |
| label: 'Hydrophobicity', | |
| data: hydrophobicity, | |
| borderColor: 'rgb(59, 130, 246)', | |
| backgroundColor: 'rgba(59, 130, 246, 0.2)', | |
| borderWidth: 2, | |
| pointRadius: 0, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| title: { | |
| display: true, | |
| text: 'Residue Position' | |
| } | |
| }, | |
| y: { | |
| title: { | |
| display: true, | |
| text: 'Hydrophobicity (KD scale)' | |
| } | |
| } | |
| }, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const pos = context.dataIndex; | |
| return `Pos ${pos+1}: ${sequence[pos]} (${getAAName(sequence[pos])}) - ${context.parsed.y.toFixed(2)}`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Function to create secondary structure chart | |
| function createSecondaryStructureChart(sequence) { | |
| const ctx = document.getElementById('secondary-structure-chart').getContext('2d'); | |
| // Generate random secondary structure predictions for demo | |
| const helix = Array(sequence.length).fill(0).map(() => Math.random() * 0.8); | |
| const sheet = Array(sequence.length).fill(0).map(() => Math.random() * 0.6); | |
| const coil = Array(sequence.length).fill(0).map(() => Math.random() * 0.7); | |
| // Normalize to sum to 1 | |
| for (let i = 0; i < sequence.length; i++) { | |
| const total = helix[i] + sheet[i] + coil[i]; | |
| helix[i] = (helix[i] / total) * 100; | |
| sheet[i] = (sheet[i] / total) * 100; | |
| coil[i] = (coil[i] / total) * 100; | |
| } | |
| // Create chart | |
| new Chart(ctx, { | |
| type: 'bar', | |
| data: { | |
| labels: Array.from({length: sequence.length}, (_, i) => i+1), | |
| datasets: [ | |
| { | |
| label: 'Helix', | |
| data: helix, | |
| backgroundColor: 'rgba(239, 68, 68, 0.7)', | |
| stack: 'stack' | |
| }, | |
| { | |
| label: 'Sheet', | |
| data: sheet, | |
| backgroundColor: 'rgba(16, 185, 129, 0.7)', | |
| stack: 'stack' | |
| }, | |
| { | |
| label: 'Coil', | |
| data: coil, | |
| backgroundColor: 'rgba(156, 163, 175, 0.7)', | |
| stack: 'stack' | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| title: { | |
| display: true, | |
| text: 'Residue Position' | |
| }, | |
| stacked: true | |
| }, | |
| y: { | |
| title: { | |
| display: true, | |
| text: 'Probability (%)' | |
| }, | |
| min: 0, | |
| max: 100, | |
| stacked: true | |
| } | |
| }, | |
| plugins: { | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const pos = context.dataIndex; | |
| const datasetLabel = context.dataset.label || ''; | |
| const value = context.parsed.y; | |
| return `${datasetLabel}: ${value.toFixed(1)}% at pos ${pos+1} (${sequence[pos]})`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Function to create disorder chart | |
| function createDisorderChart(sequence) { | |
| const ctx = document.getElementById('disorder-chart').getContext('2d'); | |
| // Generate random disorder predictions for demo | |
| const disorder = Array(sequence.length).fill(0).map(() => Math.random()); | |
| // Create chart | |
| new Chart(ctx, { | |
| type: 'line', | |
| data: { | |
| labels: Array.from({length: sequence.length}, (_, i) => i+1), | |
| datasets: [{ | |
| label: 'Disorder', | |
| data: disorder, | |
| borderColor: 'rgb(139, 92, 246)', | |
| backgroundColor: 'rgba(139, 92, 246, 0.2)', | |
| borderWidth: 2, | |
| pointRadius: 0, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| title: { | |
| display: true, | |
| text: 'Residue Position' | |
| } | |
| }, | |
| y: { | |
| title: { | |
| display: true, | |
| text: 'Disorder Probability' | |
| }, | |
| min: 0, | |
| max: 1 | |
| } | |
| }, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const pos = context.dataIndex; | |
| return `Pos ${pos+1}: ${sequence[pos]} - ${context.parsed.y.toFixed(2)}`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Function to create accessibility chart | |
| function createAccessibilityChart(sequence) { | |
| const ctx = document.getElementById('accessibility-chart').getContext('2d'); | |
| // Generate random accessibility predictions for demo | |
| const accessibility = Array(sequence.length).fill(0).map(() => Math.random()); | |
| // Create chart | |
| new Chart(ctx, { | |
| type: 'line', | |
| data: { | |
| labels: Array.from({length: sequence.length}, (_, i) => i+1), | |
| datasets: [{ | |
| label: 'Relative Solvent Accessibility', | |
| data: accessibility, | |
| borderColor: 'rgb(20, 184, 166)', | |
| backgroundColor: 'rgba(20, 184, 166, 0.2)', | |
| borderWidth: 2, | |
| pointRadius: 0, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| title: { | |
| display: true, | |
| text: 'Residue Position' | |
| } | |
| }, | |
| y: { | |
| title: { | |
| display: true, | |
| text: 'Relative Accessibility' | |
| }, | |
| min: 0, | |
| max: 1 | |
| } | |
| }, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const pos = context.dataIndex; | |
| return `Pos ${pos+1}: ${sequence[pos]} - ${context.parsed.y.toFixed(2)}`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Function to create transmembrane chart | |
| function createTransmembraneChart(sequence) { | |
| const ctx = document.getElementById('transmembrane-chart').getContext('2d'); | |
| // Generate random transmembrane predictions for demo | |
| const tm = Array(sequence.length).fill(0).map(() => Math.random() > 0.9 ? Math.random() * 0.5 + 0.5 : Math.random() * 0.3); | |
| // Create chart | |
| new Chart(ctx, { | |
| type: 'line', | |
| data: { | |
| labels: Array.from({length: sequence.length}, (_, i) => i+1), | |
| datasets: [{ | |
| label: 'Transmembrane Probability', | |
| data: tm, | |
| borderColor: 'rgb(245, 158, 11)', | |
| backgroundColor: 'rgba(245, 158, 11, 0.2)', | |
| borderWidth: 2, | |
| pointRadius: 0, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| title: { | |
| display: true, | |
| text: 'Residue Position' | |
| } | |
| }, | |
| y: { | |
| title: { | |
| display: true, | |
| text: 'TM Probability' | |
| }, | |
| min: 0, | |
| max: 1 | |
| } | |
| }, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const pos = context.dataIndex; | |
| return `Pos ${pos+1}: ${sequence[pos]} - ${context.parsed.y.toFixed(2)}`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Function to create embedding visualization | |
| function createEmbeddingChart() { | |
| const ctx = document.getElementById('model-embedding-chart').getContext('2d'); | |
| // Generate random 2D embeddings for demo | |
| const embeddings = []; | |
| const colors = []; | |
| const aaClasses = []; | |
| const sequence = document.getElementById('sequence-input').value.trim().toUpperCase(); | |
| for (let i = 0; i < sequence.length; i++) { | |
| const aa = sequence[i]; | |
| embeddings.push({ | |
| x: (Math.random() - 0.5) * 10, | |
| y: (Math.random() - 0.5) * 10, | |
| aa: aa, | |
| pos: i+1 | |
| }); | |
| // Assign colors based on amino acid properties | |
| const aaClass = getAAClass(aa); | |
| aaClasses.push(aaClass); | |
| if (aaClass === 'hydrophobic') colors.push('rgba(30, 64, 175, 0.8)'); | |
| else if (aaClass === 'hydrophilic') colors.push('rgba(22, 101, 52, 0.8)'); | |
| else if (aaClass === 'acidic') colors.push('rgba(157, 23, 77, 0.8)'); | |
| else if (aaClass === 'basic') colors.push('rgba(109, 40, 217, 0.8)'); | |
| else if (aaClass === 'cysteine') colors.push('rgba(133, 77, 14, 0.8)'); | |
| else if (aaClass === 'proline') colors.push('rgba(14, 116, 144, 0.8)'); | |
| else colors.push('rgba(113, 63, 18, 0.8)'); | |
| } | |
| // Create chart | |
| new Chart(ctx, { | |
| type: 'scatter', | |
| data: { | |
| datasets: [{ | |
| label: 'Amino Acid Embeddings', | |
| data: embeddings, | |
| backgroundColor: colors, | |
| borderColor: 'rgba(0, 0, 0, 0.1)', | |
| borderWidth: 1, | |
| pointRadius: 5 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| title: { | |
| display: true, | |
| text: 'UMAP Dimension 1' | |
| } | |
| }, | |
| y: { | |
| title: { | |
| display: true, | |
| text: 'UMAP Dimension 2' | |
| } | |
| } | |
| }, | |
| plugins: { | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const data = context.raw; | |
| return `${data.aa} (${getAAName(data.aa)}) at position ${data.pos}`; | |
| } | |
| } | |
| }, | |
| legend: { | |
| display: false | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Initialize with example sequence | |
| document.getElementById('example-btn').click(); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=andersonhuang/plmtools" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |