1<!DOCTYPE html> 2<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> 3 4<meta charset="utf-8"> 5<meta name="generator" content="quarto-1.8.24"> 6 7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 8 9 10<title>Brady Johnston â Bradyâs Blog</title> 11<style> 12code{white-space: pre-wrap;} 13span.smallcaps{font-variant: small-caps;} 14div.columns{display: flex; gap: min(4vw, 1.5em);} 15div.column{flex: auto; overflow-x: auto;} 16div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} 17ul.task-list{list-style: none;} 18ul.task-list li input[type="checkbox"] { 19 width: 0.8em; 20 margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 21 vertical-align: middle; 22} 23</style> 24 25
26<script src="site_libs/quarto-nav/quarto-nav.js"></script>
vendor: 1 bytes, line 26
26
27<script src="site_libs/quarto-nav/headroom.min.js"></script>
vendor: 1 bytes, line 27
27
28<script src="site_libs/clipboard/clipboard.min.js"></script>
vendor: 1 bytes, line 28
28
29<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
vendor: 1 bytes, line 29
29
30<script src="site_libs/quarto-search/fuse.min.js"></script>
vendor: 1 bytes, line 30
30
31<script src="site_libs/quarto-search/quarto-search.js"></script>
31 32<meta name="quarto:offset" content="./">
33<script src="site_libs/quarto-listing/list.min.js"></script>
vendor: 1 bytes, line 33
33
34<script src="site_libs/quarto-listing/quarto-listing.js"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/quarto.js" type="module"></script>
vendor: 1 bytes, line 35
35
36<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
vendor: 1 bytes, line 36
36
37<script src="site_libs/quarto-html/axe/axe-check.js" type="module"></script>
vendor: 1 bytes, line 37
37
38<script src="site_libs/quarto-html/popper.min.js"></script>
vendor: 1 bytes, line 38
38
39<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
vendor: 1 bytes, line 39
39
40<script src="site_libs/quarto-html/anchor.min.js"></script>
40 41<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> 42<link href="site_libs/quarto-html/quarto-syntax-highlighting-dc55a5b9e770e841cd82e46aadbfb9b0.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-text-highlighting-styles"> 43<link href="site_libs/quarto-html/quarto-syntax-highlighting-dark-b651517ce65839d647a86e2780455cfb.css" rel="stylesheet" class="quarto-color-scheme quarto-color-alternate" id="quarto-text-highlighting-styles"> 44<link href="site_libs/quarto-html/quarto-syntax-highlighting-dc55a5b9e770e841cd82e46aadbfb9b0.css" rel="stylesheet" class="quarto-color-scheme-extra" id="quarto-text-highlighting-styles">
45<script src="site_libs/bootstrap/bootstrap.min.js"></script>
45 46<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> 47<link href="site_libs/bootstrap/bootstrap-a26f3680889bc016604be2101547878f.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme" id="quarto-bootstrap" data-mode="light"> 48<link href="site_libs/bootstrap/bootstrap-dark-0d4a9d19931feb4fee1ddab4b2489000.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme quarto-color-alternate" id="quarto-bootstrap" data-mode="dark"> 49<link href="site_libs/bootstrap/bootstrap-a26f3680889bc016604be2101547878f.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme-extra" id="quarto-bootstrap" data-mode="light">
50<script id="quarto-search-options" type="application/json">{ 51 "location": "navbar", 52 "copy-button": false, 53 "collapse-after": 3, 54 "panel-placement": "end", 55 "type": "overlay", 56 "limit": 50, 57 "keyboard-shortcut": [ 58 "f", 59 "/", 60 "s" 61 ], 62 "show-item-context": false, 63 "language": { 64 "search-no-results-text": "No results", 65 "search-matching-documents-text": "matching documents", 66 "search-copy-link-title": "Copy link to search", 67 "search-hide-matches-text": "Hide additional matches", 68 "search-more-match-text": "more match in this document", 69 "search-more-matches-text": "more matches in this document", 70 "search-clear-button-title": "Clear", 71 "search-text-placeholder": "", 72 "search-detached-cancel-button-title": "Cancel", 73 "search-submit-button-title": "Submit", 74 "search-label": "Search" 75 } 76}</script>
vendor: 1 bytes, line 76
76
77<script> 78 79 window.document.addEventListener("DOMContentLoaded", function (_event) { 80 const listingTargetEl = window.document.querySelector('#listing-posts .list'); 81 if (!listingTargetEl) { 82 // No listing discovered, do not attach. 83 return; 84 } 85 86 const options = { 87 valueNames: ['listing-title','listing-author','listing-date','listing-image','listing-description','listing-categories',{ data: ['index'] },{ data: ['categories'] },{ data: ['listing-date-sort'] },{ data: ['listing-file-modified-sort'] }], 88 89 searchColumns: ["listing-title","listing-author","listing-date","listing-image","listing-description","listing-categories"], 90 }; 91 92 window['quarto-listings'] = window['quarto-listings'] || {}; 93 window['quarto-listings']['listing-posts'] = new List('listing-posts', options); 94 95 if (window['quarto-listing-loaded']) { 96 window['quarto-listing-loaded'](); 97 } 98 }); 99 100 window.addEventListener('hashchange',() => { 101 if (window['quarto-listing-loaded']) { 102 window['quarto-listing-loaded'](); 103 } 104 }) 105 </script>
vendor: 67 bytes, lines 105-106
105 106<script async="" src="https://www.googletagmanager.com/gtag/js?id=
106G-T4ZHBLFMQF
vendor: 13 bytes, lines 106-107
106"></script> 107
108<script type="text/javascript"> 109
vendor: 127 bytes, lines 110-113
110window.dataLayer = window.dataLayer || []; 111function gtag(){dataLayer.push(arguments);} 112gtag('js', new Date()); 113gtag('config', '
113G-T4ZHBLFMQF
vendor: 29 bytes, line 113
113', { 'anonymize_ip': true});
114</script>
114 115 116
116<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
116 117
117<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
117 118
119<script type="text/javascript"> 120const typesetMath = (el) => { 121 if (window.MathJax) { 122 // MathJax Typeset 123 window.MathJax.typeset([el]); 124 } else if (window.katex) { 125 // KaTeX Render 126 var mathElements = el.getElementsByClassName("math"); 127 var macros = []; 128 for (var i = 0; i < mathElements.length; i++) { 129 var texText = mathElements[i].firstChild; 130 if (mathElements[i].tagName == "SPAN" && texText && texText.data) { 131 window.katex.render(texText.data, mathElements[i], { 132 displayMode: mathElements[i].classList.contains('display'), 133 throwOnError: false, 134 macros: macros, 135 fleqn: false 136 }); 137 } 138 } 139 } 140} 141window.Quarto = { 142 typesetMath 143}; 144</script>
144 145 146<link rel="stylesheet" href="styles.css"> 147</head> 148 149<body class="nav-fixed quarto-light">
149<script id="quarto-html-before-body" type="application/javascript"> 150 const toggleBodyColorMode = (bsSheetEl) => { 151 const mode = bsSheetEl.getAttribute("data-mode"); 152 const bodyEl = window.document.querySelector("body"); 153 if (mode === "dark") { 154 bodyEl.classList.add("quarto-dark"); 155 bodyEl.classList.remove("quarto-light"); 156 } else { 157 bodyEl.classList.add("quarto-light"); 158 bodyEl.classList.remove("quarto-dark"); 159 } 160 } 161 const toggleBodyColorPrimary = () => { 162 const bsSheetEl = window.document.querySelector("link#quarto-bootstrap:not([rel=disabled-stylesheet])"); 163 if (bsSheetEl) { 164 toggleBodyColorMode(bsSheetEl); 165 } 166 } 167 const setColorSchemeToggle = (alternate) => { 168 const toggles = window.document.querySelectorAll('.quarto-color-scheme-toggle'); 169 for (let i=0; i < toggles.length; i++) { 170 const toggle = toggles[i]; 171 if (toggle) { 172 if (alternate) { 173 toggle.classList.add("alternate"); 174 } else { 175 toggle.classList.remove("alternate"); 176 } 177 } 178 } 179 }; 180 const toggleColorMode = (alternate) => { 181 // Switch the stylesheets 182 const primaryStylesheets = window.document.querySelectorAll('link.quarto-color-scheme:not(.quarto-color-alternate)'); 183 const alternateStylesheets = window.document.querySelectorAll('link.quarto-color-scheme.quarto-color-alternate'); 184 manageTransitions('#quarto-margin-sidebar .nav-link', false); 185 if (alternate) { 186 // note: dark is layered on light, we don't disable primary! 187 enableStylesheet(alternateStylesheets); 188 for (const sheetNode of alternateStylesheets) { 189 if (sheetNode.id === "quarto-bootstrap") { 190 toggleBodyColorMode(sheetNode); 191 } 192 } 193 } else { 194 disableStylesheet(alternateStylesheets); 195 enableStylesheet(primaryStylesheets) 196 toggleBodyColorPrimary(); 197 } 198 manageTransitions('#quarto-margin-sidebar .nav-link', true); 199 // Switch the toggles 200 setColorSchemeToggle(alternate) 201 // Hack to workaround the fact that safari doesn't 202 // properly recolor the scrollbar when toggling (#1455) 203 if (navigator.userAgent.indexOf('Safari') > 0 && navigator.userAgent.indexOf('Chrome') == -1) { 204 manageTransitions("body", false); 205 window.scrollTo(0, 1); 206 setTimeout(() => { 207 window.scrollTo(0, 0); 208 manageTransitions("body", true); 209 }, 40); 210 } 211 } 212 const disableStylesheet = (stylesheets) => { 213 for (let i=0; i < stylesheets.length; i++) { 214 const stylesheet = stylesheets[i]; 215 stylesheet.rel = 'disabled-stylesheet'; 216 } 217 } 218 const enableStylesheet = (stylesheets) => { 219 for (let i=0; i < stylesheets.length; i++) { 220 const stylesheet = stylesheets[i]; 221 if(stylesheet.rel !== 'stylesheet') { // for Chrome, which will still FOUC without this check 222 stylesheet.rel = 'stylesheet'; 223 } 224 } 225 } 226 const manageTransitions = (selector, allowTransitions) => { 227 const els = window.document.querySelectorAll(selector); 228 for (let i=0; i < els.length; i++) { 229 const el = els[i]; 230 if (allowTransitions) { 231 el.classList.remove('notransition'); 232 } else { 233 el.classList.add('notransition'); 234 } 235 } 236 } 237 const isFileUrl = () => { 238 return window.location.protocol === 'file:'; 239 } 240 const hasAlternateSentinel = () => { 241 let styleSentinel = getColorSchemeSentinel(); 242 if (styleSentinel !== null) { 243 return styleSentinel === "alternate"; 244 } else { 245 return false; 246 } 247 } 248 const setStyleSentinel = (alternate) => { 249 const value = alternate ? "alternate" : "default"; 250 if (!isFileUrl()) { 251 window.localStorage.setItem("quarto-color-scheme", value); 252 } else { 253 localAlternateSentinel = value; 254 } 255 } 256 const getColorSchemeSentinel = () => { 257 if (!isFileUrl()) { 258 const storageValue = window.localStorage.getItem("quarto-color-scheme"); 259 return storageValue != null ? storageValue : localAlternateSentinel; 260 } else { 261 return localAlternateSentinel; 262 } 263 } 264 const toggleGiscusIfUsed = (isAlternate, darkModeDefault) => { 265 const baseTheme = document.querySelector('#giscus-base-theme')?.value ?? 'light'; 266 const alternateTheme = document.querySelector('#giscus-alt-theme')?.value ?? 'dark'; 267 let newTheme = ''; 268 if(authorPrefersDark) { 269 newTheme = isAlternate ? baseTheme : alternateTheme; 270 } else { 271 newTheme = isAlternate ? alternateTheme : baseTheme; 272 } 273 const changeGiscusTheme = () => { 274 // From: https://github.com/giscus/giscus/issues/336 275 const sendMessage = (message) => { 276 const iframe = document.querySelector('iframe.giscus-frame'); 277 if (!iframe) return; 278 iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); 279 } 280 sendMessage({ 281 setConfig: { 282 theme: newTheme 283 } 284 }); 285 } 286 const isGiscussLoaded = window.document.querySelector('iframe.giscus-frame') !== null; 287 if (isGiscussLoaded) { 288 changeGiscusTheme(); 289 } 290 }; 291 const authorPrefersDark = false;
292 const darkModeDefault = authorPrefersDark; 293 document.querySelector('link#quarto-text-highlighting-styles.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; 294 document.querySelector('link#quarto-bootstrap.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; 295 let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default'; 296 // Dark / light mode switch 297 window.quartoToggleColorScheme = () => { 298 // Read the current dark / light value 299 let toAlternate = !hasAlternateSentinel(); 300 toggleColorMode(toAlternate); 301 setStyleSentinel(toAlternate); 302 toggleGiscusIfUsed(toAlternate, darkModeDefault); 303 window.dispatchEvent(new Event('resize')); 304 }; 305 // Switch to dark mode if need be 306 if (hasAlternateSentinel()) { 307 toggleColorMode(true); 308 } else { 309 toggleColorMode(false); 310 } 311 </script>
311 312 313<div id="quarto-search-results"></div> 314 <header id="quarto-header" class="headroom fixed-top quarto-banner"> 315 <nav class="navbar navbar-expand-lg " data-bs-theme="dark"> 316 <div class="navbar-container container-fluid"> 317 <div class="navbar-brand-container mx-auto"> 318 <a href="./index.html" class="navbar-brand navbar-brand-logo"> 319 </a> 320 <a class="navbar-brand" href="./index.html"> 321 <span class="navbar-title">Bradyâs Blog</span> 322 </a> 323 </div> 324 <div id="quarto-search" class="" title="Search"></div> 325 <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> 326 <span class="navbar-toggler-icon"></span> 327</button> 328 <div class="collapse navbar-collapse" id="navbarCollapse"> 329 <ul class="navbar-nav navbar-nav-scroll me-auto"> 330 <li class="nav-item compact"> 331 <a class="nav-link" href="https://github.com/bradyajohnston"> <i class="bi bi-github" role="img"> 332</i> 333<span class="menu-text"></span></a> 334 </li> 335 <li class="nav-item compact"> 336 <a class="nav-link" href="https://youtube.com/c/bradyjohnston"> <i class="bi bi-youtube" role="img"> 337</i> 338<span class="menu-text"></span></a> 339 </li> 340 <li class="nav-item compact"> 341 <a class="nav-link" href="https://twitter.com/bradyajohnston"> <i class="bi bi-twitter" role="img"> 342</i> 343<span class="menu-text"></span></a> 344 </li> 345</ul> 346 <ul class="navbar-nav navbar-nav-scroll ms-auto"> 347 <li class="nav-item"> 348 <a class="nav-link" href="./about.html"> 349<span class="menu-text">About</span></a> 350 </li> 351 <li class="nav-item"> 352 <a class="nav-link active" href="./index.html" aria-current="page"> 353<span class="menu-text">Blog</span></a> 354 </li> 355 <li class="nav-item"> 356 <a class="nav-link" href="https://bradyajohnston.github.io/MolecularNodes"> <i class="bi bi-arrow-up-short" role="img"> 357</i> 358<span class="menu-text">Molecular Nodes</span></a> 359 </li> 360 <li class="nav-item"> 361 <a class="nav-link" href="./talks/index.html"> 362<span class="menu-text">Talks</span></a> 363 </li> 364</ul> 365 </div> <!-- /navcollapse --> 366 <div class="quarto-navbar-tools"> 367 <a href="" class="quarto-color-scheme-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleColorScheme(); return false;" title="Toggle dark mode"><i class="bi"></i></a> 368</div> 369 </div> <!-- /container-fluid --> 370 </nav> 371</header> 372<!-- content --> 373<header id="title-block-header" class="quarto-title-block default page-columns page-full"> 374 <div class="quarto-title-banner page-columns page-full"> 375 <div class="quarto-title column-page-left"> 376 <h1 class="title">Brady Johnston</h1> 377 </div> 378 </div> 379 380 381 <div class="quarto-title-meta column-page-left"> 382 383 384 385 386 </div> 387 388 389 </header><div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-full page-navbar"> 390<!-- sidebar --> 391<!-- margin-sidebar --> 392 <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> 393 394 <h5 class="quarto-listing-category-title">Categories</h5><div class="quarto-listing-category category-default"><div class="category" data-category="">All <span class="quarto-category-count">(8)</span></div><div class="category" data-category="QVI=">AR <span class="quarto-category-count">(1)</span></div><div class="category" data-category="YmFzaA==">bash <span class="quarto-category-count">(1)</span></div><div class="category" data-category="YmlvaW5mb3JtYXRpY3M=">bioinformatics <span class="quarto-category-count">(1)</span></div><div class="category" data-category="YmxlbmRlcg==">blender <span class="quarto-category-count">(3)</span></div><div class="category" data-category="Y29kaW5n">coding <span class="quarto-category-count">(1)</span></div><div class="category" data-category="ZGF0YSUyMHZpcw==">data vis <span class="quarto-category-count">(1)</span></div><div class="category" data-category="Zmx1b3Jlc2VuY2U=">fluoresence <span class="quarto-category-count">(1)</span></div><div class="category" data-category="Z2dwbG90Mg==">
394ggplot2 <span class="quarto-category-count">(1)</span></div><div class="category" data-category="bm9kZXM=">nodes <span class="quarto-category-count">(1)</span></div><div class="category" data-category="cHJvdGVpbg==">protein <span class="quarto-category-count">(2)</span></div><div class="category" data-category="cHl0aG9u">python <span class="quarto-category-count">(1)</span></div><div class="category" data-category="Ug==">R <span class="quarto-category-count">(4)</span></div><div class="category" data-category="c2NpYXJ0">sciart <span class="quarto-category-count">(1)</span></div><div class="category" data-category="c3RydWN0dXJhbCUyMGJpb2xvZ3k=">structural biology <span class="quarto-category-count">(2)</span></div><div class="category" data-category="dGlkeXR1ZXNkYXk=">tidytuesday <span class="quarto-category-count">(1)</span></div><div class="category" data-category="dHV0b3JpYWw=">tutorial <span class="quarto-category-count">(2)</span></div><div class="category" data-category="eW91dHViZQ==">youtube <span class="quarto-category-count">(1)</span></div></div></div> 395<!-- main --> 396<main class="content quarto-banner-title-block column-page-left" id="quarto-document-content"> 397 398 399 400 401 402 403<p>Havenât posted anything here in a whileâ¦</p> 404<div id="listing-posts" class="quarto-listing quarto-listing-container-grid"> 405<div class="list grid quarto-listing-cols-3"> 406<div class="g-col-1" data-index="0" data-categories="Z2dwbG90MiUyQ1IlMkNjb2RpbmclMkNmbHVvcmVzZW5jZQ==" data-listing-date-sort="1662163200000" data-listing-file-modified-sort="1758284183023" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="3" data-listing-word-count-sort="523"> 407<a href="./posts/2022-09-03-plotting-fluorescence/index.html" class="quarto-grid-link"> 408<div class="quarto-grid-item card h-100 card-left"> 409<p class="card-img-top"><img src="posts/2022-09-03-plotting-fluorescence/index_files/figure-html/unnamed-chunk-3-1.png" style="height: 150px;" class="thumbnail-image card-img"/></p> 410<div class="card-body post-contents"> 411<h5 class="no-anchor card-title listing-title"> 412Plotting Fluorescent Spectra 413</h5> 414<div class="listing-categories"> 415 416<div class="listing-category" onclick="window.quartoListingCategory('Z2dwbG90Mg=='); return false;">ggplot2</div> 417 418<div class="listing-category" onclick="window.quartoListingCategory('Ug=='); return false;">R</div> 419 420<div class="listing-category" onclick="window.quartoListingCategory('Y29kaW5n'); return false;">coding</div> 421 422<div class="listing-category" onclick="window.quartoListingCategory('Zmx1b3Jlc2VuY2U='); return false;">fluoresence</div> 423 424</div> 425<div class="card-text listing-description delink"> 426How do we go about plotting some spectral data from fluorophores, to get something like below? 427</div> 428<div class="card-attribution card-text-small justify"> 429<div class="listing-author"> 430Brady Johnston 431</div> 432<div class="listing-date"> 433Sep 3, 2022 434</div> 435</div> 436</div> 437</div></a> 438</div> 439<div class="g-col-1" data-index="1" data-categories="YmlvaW5mb3JtYXRpY3MlMkNSJTJDcHJvdGVpbg==" data-listing-date-sort="1613347200000" data-listing-file-modified-sort="1758284183023" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="2" data-listing-word-count-sort="241"> 440<a href="./posts/2021-02-15-r3dmol/index.html" class="quarto-grid-link"> 441<div class="quarto-grid-item card h-100 card-left"> 442<p class="card-img-top"> 443<img loading="lazy" src="https://swsoyee.github.io/r3dmol/reference/figures/spin_demo.gif" class="thumbnail-image card-img" style="height: 150px;"> 444</p> 445<div class="card-body post-contents"> 446<h5 class="no-anchor card-title listing-title"> 447Interactively Visualising Proteins 448</h5> 449<div class="listing-categories"> 450 451<div class="listing-category" onclick="window.quartoListingCategory('YmlvaW5mb3JtYXRpY3M='); return false;">bioinformatics</div> 452 453<div class="listing-category" onclick="window.quartoListingCategory('Ug=='); return false;">R</div> 454 455<div class="listing-category" onclick="window.quartoListingCategory('cHJvdGVpbg=='); return false;">protein</div> 456 457</div> 458<div class="card-text listing-description delink"> 459Recently Iâve been doing a lot of structural bioinformatics. To avoid having to export my results into PyMol of Chimerax, I wanted a better solution that could embed the⦠460</div> 461<div class="card-attribution card-text-small justify"> 462<div class="listing-author"> 463Brady Johnston 464</div> 465<div class="listing-date"> 466Feb 15, 2021 467</div> 468</div> 469</div> 470</div></a> 471</div> 472<div class="g-col-1" data-index="2" data-categories="UiUyQ3RpZHl0dWVzZGF5JTJDZGF0YSUyMHZpcw==" data-listing-date-sort="1612051200000" data-listing-file-modified-sort="1758284183023" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="6" data-listing-word-count-sort="1047"> 473<a href="./posts/2021-01-31-tt/index.html" class="quarto-grid-link"> 474<div class="quarto-grid-item card h-100 card-left"> 475<p class="card-img-top"> 476<img loading="lazy" src="./posts/2021-01-31-tt/images/paste-166E6C24.png" class="thumbnail-image card-img" style="height: 150px;"> 477</p> 478<div class="card-body post-contents"> 479<h5 class="no-anchor card-title listing-title"> 480Visualising Global Rubbish 481</h5> 482<div class="listing-categories"> 483 484<div class="listing-category" onclick="window.quartoListingCategory('Ug=='); return false;">R</div> 485 486<div class="listing-category" onclick="window.quartoListingCategory('dGlkeXR1ZXNkYXk='); return false;">tidytuesday</div> 487 488<div class="listing-category" onclick="window.quartoListingCategory('ZGF0YSUyMHZpcw=='); return false;">data vis</div> 489 490</div> 491<div class="card-text listing-description delink"> 492For this weekâs #tidytuesday, I visualise the vast dataset of rubbish collected on the beaches all over the world. 493</div> 494<div class="card-attribution card-text-small justify"> 495<div class="listing-author"> 496Brady Johnston 497</div> 498<div class="listing-date"> 499Jan 31, 2021 500</div> 501</div> 502</div> 503</div></a> 504</div> 505<div class="g-col-1" data-index="3" data-categories="UiUyQ3R1dG9yaWFs" data-listing-date-sort="1594080000000" data-listing-file-modified-sort="1758284183020" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="4" data-listing-word-count-sort="629"> 506<a href="./posts/2020-07-07-r-for-biologists/index.html" class="quarto-grid-link"> 507<div class="quarto-grid-item card h-100 card-left"> 508<div class="listing-item-img-placeholder card-img-top" style="height: 150px;"> </div> 509<div class="card-body post-contents"> 510<h5 class="no-anchor card-title listing-title"> 511R for Biologists 512</h5> 513<div class="listing-categories"> 514 515<div class="listing-category" onclick="window.quartoListingCategory('Ug=='); return false;">R</div> 516 517<div class="listing-category" onclick="window.quartoListingCategory('dHV0b3JpYWw='); return false;">tutorial</div> 518 519</div> 520<div class="card-text listing-description delink">
521A couple of months ago I ran (with lots of help for content) an R for biologists workshop. 522</div> 523<div class="card-attribution card-text-small justify"> 524<div class="listing-author"> 525Brady Johnston 526</div> 527<div class="listing-date"> 528Jul 7, 2020 529</div> 530</div> 531</div> 532</div></a> 533</div> 534<div class="g-col-1" data-index="4" data-categories="cHl0aG9uJTJDc3RydWN0dXJhbCUyMGJpb2xvZ3klMkNiYXNo" data-listing-date-sort="1591660800000" data-listing-file-modified-sort="1758284183020" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="3" data-listing-word-count-sort="519"> 535<a href="./posts/2020-06-09-pdb-tools/index.html" class="quarto-grid-link"> 536<div class="quarto-grid-item card h-100 card-left"> 537<p class="card-img-top"><img src="posts/2020-06-09-pdb-tools/images/pdb-tools.png" alt="Logo for the software package pdb-tools, showing a swiss-army-knife with molecular bonds instead of tools." style="height: 150px;" class="thumbnail-image card-img"/></p> 538<div class="card-body post-contents"> 539<h5 class="no-anchor card-title listing-title"> 540Praise for <code>pdb-tools</code> 541</h5> 542<div class="listing-categories"> 543 544<div class="listing-category" onclick="window.quartoListingCategory('cHl0aG9u'); return false;">python</div> 545 546<div class="listing-category" onclick="window.quartoListingCategory('c3RydWN0dXJhbCUyMGJpb2xvZ3k='); return false;">structural biology</div> 547 548<div class="listing-category" onclick="window.quartoListingCategory('YmFzaA=='); return false;">bash</div> 549 550</div> 551<div class="card-text listing-description delink"> 552An output from some MD work left me with a <code>.pdb</code> file with <code>0.00</code> <em>b-factors</em>. 553</div> 554<div class="card-attribution card-text-small justify"> 555<div class="listing-author"> 556Brady Johnston 557</div> 558<div class="listing-date"> 559Jun 9, 2020 560</div> 561</div> 562</div> 563</div></a> 564</div> 565<div class="g-col-1" data-index="5" data-categories="YmxlbmRlciUyQ3NjaWFydCUyQ3lvdXR1YmUlMkN0dXRvcmlhbA==" data-listing-date-sort="1588723200000" data-listing-file-modified-sort="1758284183020" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="1" data-listing-word-count-sort="114"> 566<a href="./posts/2020-05-06-blender-for-biochemists/index.html" class="quarto-grid-link"> 567<div class="quarto-grid-item card h-100 card-left"> 568<p class="card-img-top"> 569<img loading="lazy" src="./posts/2020-05-06-blender-for-biochemists/images/paste-6CB2B366.png" class="thumbnail-image card-img" style="height: 150px;"> 570</p> 571<div class="card-body post-contents"> 572<h5 class="no-anchor card-title listing-title"> 573Blender for Biochemists. 574</h5> 575<div class="listing-categories"> 576 577<div class="listing-category" onclick="window.quartoListingCategory('YmxlbmRlcg=='); return false;">blender</div> 578 579<div class="listing-category" onclick="window.quartoListingCategory('c2NpYXJ0'); return false;">sciart</div> 580 581<div class="listing-category" onclick="window.quartoListingCategory('eW91dHViZQ=='); return false;">youtube</div> 582 583<div class="listing-category" onclick="window.quartoListingCategory('dHV0b3JpYWw='); return false;">tutorial</div> 584 585</div> 586<div class="card-text listing-description delink"> 587Iâve started my journey into the realm of youtube. 588</div> 589<div class="card-attribution card-text-small justify"> 590<div class="listing-author"> 591Brady Johnston 592</div> 593<div class="listing-date"> 594May 6, 2020 595</div> 596</div> 597</div> 598</div></a> 599</div> 600<div class="g-col-1" data-index="6" data-categories="YmxlbmRlciUyQ3N0cnVjdHVyYWwlMjBiaW9sb2d5JTJDbm9kZXM=" data-listing-date-sort="1586044800000" data-listing-file-modified-sort="1758284183015" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="2" data-listing-word-count-sort="275"> 601<a href="./posts/2020-04-05-animation-nodes-crashing/index.html" class="quarto-grid-link"> 602<div class="quarto-grid-item card h-100 card-left"> 603<p class="card-img-top"><img src="posts/2020-04-05-animation-nodes-crashing/images/pixel_rna_pol.gif" style="height: 150px;" class="thumbnail-image card-img"/></p> 604<div class="card-body post-contents"> 605<h5 class="no-anchor card-title listing-title"> 606Rendering around crashes with Animation Nodes 607</h5> 608<div class="listing-categories"> 609 610<div class="listing-category" onclick="window.quartoListingCategory('YmxlbmRlcg=='); return false;">blender</div> 611 612<div class="listing-category" onclick="window.quartoListingCategory('c3RydWN0dXJhbCUyMGJpb2xvZ3k='); return false;">structural biology</div> 613 614<div class="listing-category" onclick="window.quartoListingCategory('bm9kZXM='); return false;">nodes</div> 615 616</div> 617<div class="card-text listing-description delink"> 618Can we make some pixelated protein art? 619</div> 620<div class="card-attribution card-text-small justify"> 621<div class="listing-author"> 622Brady Johnston 623</div> 624<div class="listing-date"> 625Apr 5, 2020 626</div> 627</div> 628</div> 629</div></a> 630</div> 631<div class="g-col-1" data-index="7" data-categories="YmxlbmRlciUyQ3Byb3RlaW4lMkNBUg==" data-listing-date-sort="1565913600000" data-listing-file-modified-sort="1758284182938" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="2" data-listing-word-count-sort="330"> 632<a href="./posts/2019-08-16-gfp-hat/index.html" class="quarto-grid-link"> 633<div class="quarto-grid-item card h-100 card-left"> 634<p class="card-img-top"> 635<img loading="lazy" src="./posts/2019-08-16-gfp-hat/images/paste-A96E3E60.png" class="thumbnail-image card-img" style="height: 150px;"> 636</p> 637<div class="card-body post-contents"> 638<h5 class="no-anchor card-title listing-title"> 639GFP as a Hat 640</h5> 641<div class="listing-categories"> 642 643<div class="listing-category" onclick="window.quartoListingCategory('YmxlbmRlcg=='); return false;">blender</div> 644 645<div class="listing-category" onclick="window.quartoListingCategory('cHJvdGVpbg=='); return false;">protein</div> 646 647<div class="listing-category" onclick="window.quartoListingCategory('QVI='); return false;">AR</div> 648 649</div> 650<div class="card-text listing-description delink"> 651As I was drifting off to sleep one night, the thought hit me: 652</div> 653<div class="card-attribution card-text-small justify"> 654<div class="listing-author"> 655Brady Johnston 656</div> 657<div class="listing-date"> 658Aug 16, 2019 659</div> 660</div> 661</div> 662</div></a> 663</div> 664</div> 665<div class="listing-no-matching d-none">No matching items</div> 666</div> 667 668 669 670 671</main> <!-- /main -->
672<script id="quarto-html-after-body" type="application/javascript"> 673 window.document.addEventListener("DOMContentLoaded", function (event) { 674 // Ensure there is a toggle, if there isn't float one in the top right 675 if (window.document.querySelector('.quarto-color-scheme-toggle') === null) { 676 const a = window.document.createElement('a'); 677 a.classList.add('top-right'); 678 a.classList.add('quarto-color-scheme-toggle'); 679 a.href = ""; 680 a.onclick = function() { try { window.quartoToggleColorScheme(); } catch {} return false; }; 681 const i = window.document.createElement("i"); 682 i.classList.add('bi'); 683 a.appendChild(i); 684 window.document.body.appendChild(a); 685 } 686 setColorSchemeToggle(hasAlternateSentinel()) 687 const icon = "î§"; 688 const anchorJS = new window.AnchorJS(); 689 anchorJS.options = { 690 placement: 'right', 691 icon: icon 692 }; 693 anchorJS.add('.anchored'); 694 const isCodeAnnotation = (el) => { 695 for (const clz of el.classList) { 696 if (clz.startsWith('code-annotation-')) { 697 return true; 698 } 699 } 700 return false; 701 } 702 const onCopySuccess = function(e) { 703 // button target 704 const button = e.trigger; 705 // don't keep focus 706 button.blur(); 707 // flash "checked" 708 button.classList.add('code-copy-button-checked'); 709 var currentTitle = button.getAttribute("title"); 710 button.setAttribute("title", "Copied!"); 711 let tooltip; 712 if (window.bootstrap) { 713 button.setAttribute("data-bs-toggle", "tooltip"); 714 button.setAttribute("data-bs-placement", "left"); 715 button.setAttribute("data-bs-title", "Copied!"); 716 tooltip = new bootstrap.Tooltip(button, 717 { trigger: "manual", 718 customClass: "code-copy-button-tooltip", 719 offset: [0, -8]}); 720 tooltip.show(); 721 } 722 setTimeout(function() { 723 if (tooltip) { 724 tooltip.hide(); 725 button.removeAttribute("data-bs-title"); 726 button.removeAttribute("data-bs-toggle"); 727 button.removeAttribute("data-bs-placement"); 728 } 729 button.setAttribute("title", currentTitle); 730 button.classList.remove('code-copy-button-checked'); 731 }, 1000); 732 // clear code selection 733 e.clearSelection(); 734 } 735 const getTextToCopy = function(trigger) { 736 const outerScaffold = trigger.parentElement.cloneNode(true); 737 const codeEl = outerScaffold.querySelector('code'); 738 for (const childEl of codeEl.children) { 739 if (isCodeAnnotation(childEl)) { 740 childEl.remove(); 741 } 742 } 743 return codeEl.innerText; 744 } 745 const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { 746 text: getTextToCopy 747 }); 748 clipboard.on('success', onCopySuccess); 749 if (window.document.getElementById('quarto-embedded-source-code-modal')) { 750 const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { 751 text: getTextToCopy, 752 container: window.document.getElementById('quarto-embedded-source-code-modal') 753 }); 754 clipboardModal.on('success', onCopySuccess); 755 } 756 var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); 757 var mailtoRegex = new RegExp(/^mailto:/); 758 var filterRegex = new RegExp("https:\/\/BradyAJohnston\.github\.io\/bradyajohnston\.github\.io\/"); 759 var isInternal = (href) => { 760 return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); 761 } 762 // Inspect non-navigation links and adorn them if external 763 var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)'); 764 for (var i=0; i<links.length; i++) { 765 const link = links[i]; 766 if (!isInternal(link.href)) { 767 // undo the damage that might have been done by quarto-nav.js in the case of 768 // links that we want to consider external 769 if (link.dataset.originalHref !== undefined) { 770 link.href = link.dataset.originalHref; 771 } 772 } 773 } 774 function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { 775 const config = { 776 allowHTML: true, 777 maxWidth: 500, 778 delay: 100,
779 arrow: false, 780 appendTo: function(el) { 781 return el.parentElement; 782 }, 783 interactive: true, 784 interactiveBorder: 10, 785 theme: 'quarto', 786 placement: 'bottom-start', 787 }; 788 if (contentFn) { 789 config.content = contentFn; 790 } 791 if (onTriggerFn) { 792 config.onTrigger = onTriggerFn; 793 } 794 if (onUntriggerFn) { 795 config.onUntrigger = onUntriggerFn; 796 } 797 window.tippy(el, config); 798 } 799 const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); 800 for (var i=0; i<noterefs.length; i++) { 801 const ref = noterefs[i]; 802 tippyHover(ref, function() { 803 // use id or data attribute instead here 804 let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); 805 try { href = new URL(href).hash; } catch {} 806 const id = href.replace(/^#\/?/, ""); 807 const note = window.document.getElementById(id); 808 if (note) { 809 return note.innerHTML; 810 } else { 811 return ""; 812 } 813 }); 814 } 815 const xrefs = window.document.querySelectorAll('a.quarto-xref'); 816 const processXRef = (id, note) => { 817 // Strip column container classes 818 const stripColumnClz = (el) => { 819 el.classList.remove("page-full", "page-columns"); 820 if (el.children) { 821 for (const child of el.children) { 822 stripColumnClz(child); 823 } 824 } 825 } 826 stripColumnClz(note) 827 if (id === null || id.startsWith('sec-')) { 828 // Special case sections, only their first couple elements 829 const container = document.createElement("div"); 830 if (note.children && note.children.length > 2) { 831 container.appendChild(note.children[0].cloneNode(true)); 832 for (let i = 1; i < note.children.length; i++) { 833 const child = note.children[i]; 834 if (child.tagName === "P" && child.innerText === "") { 835 continue; 836 } else { 837 container.appendChild(child.cloneNode(true)); 838 break; 839 } 840 } 841 if (window.Quarto?.typesetMath) { 842 window.Quarto.typesetMath(container); 843 } 844 return container.innerHTML 845 } else { 846 if (window.Quarto?.typesetMath) { 847 window.Quarto.typesetMath(note); 848 } 849 return note.innerHTML; 850 } 851 } else { 852 // Remove any anchor links if they are present 853 const anchorLink = note.querySelector('a.anchorjs-link'); 854 if (anchorLink) { 855 anchorLink.remove(); 856 } 857 if (window.Quarto?.typesetMath) { 858 window.Quarto.typesetMath(note); 859 } 860 if (note.classList.contains("callout")) { 861 return note.outerHTML; 862 } else { 863 return note.innerHTML; 864 } 865 } 866 } 867 for (var i=0; i<xrefs.length; i++) { 868 const xref = xrefs[i]; 869 tippyHover(xref, undefined, function(instance) { 870 instance.disable(); 871 let url = xref.getAttribute('href'); 872 let hash = undefined; 873 if (url.startsWith('#')) { 874 hash = url; 875 } else { 876 try { hash = new URL(url).hash; } catch {} 877 } 878 if (hash) { 879 const id = hash.replace(/^#\/?/, ""); 880 const note = window.document.getElementById(id); 881 if (note !== null) { 882 try { 883 const html = processXRef(id, note.cloneNode(true)); 884 instance.setContent(html); 885 } finally { 886 instance.enable(); 887 instance.show(); 888 } 889 } else { 890 // See if we can fetch this 891 fetch(url.split('#')[0]) 892 .then(res => res.text()) 893 .then(html => { 894 const parser = new DOMParser(); 895 const htmlDoc = parser.parseFromString(html, "text/html"); 896 const note = htmlDoc.getElementById(id); 897 if (note !== null) { 898 const html = processXRef(id, note); 899 instance.setContent(html); 900 } 901 }).finally(() => { 902 instance.enable(); 903 instance.show(); 904 }); 905 } 906 } else { 907 // See if we can fetch a full url (with no hash to target)
908 // This is a special case and we should probably do some content thinning / targeting 909 fetch(url) 910 .then(res => res.text()) 911 .then(html => { 912 const parser = new DOMParser(); 913 const htmlDoc = parser.parseFromString(html, "text/html"); 914 const note = htmlDoc.querySelector('main.content'); 915 if (note !== null) { 916 // This should only happen for chapter cross references 917 // (since there is no id in the URL) 918 // remove the first header 919 if (note.children.length > 0 && note.children[0].tagName === "HEADER") { 920 note.children[0].remove(); 921 } 922 const html = processXRef(null, note); 923 instance.setContent(html); 924 } 925 }).finally(() => { 926 instance.enable(); 927 instance.show(); 928 }); 929 } 930 }, function(instance) { 931 }); 932 } 933 let selectedAnnoteEl; 934 const selectorForAnnotation = ( cell, annotation) => { 935 let cellAttr = 'data-code-cell="' + cell + '"'; 936 let lineAttr = 'data-code-annotation="' + annotation + '"'; 937 const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; 938 return selector; 939 } 940 const selectCodeLines = (annoteEl) => { 941 const doc = window.document; 942 const targetCell = annoteEl.getAttribute("data-target-cell"); 943 const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); 944 const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); 945 const lines = annoteSpan.getAttribute("data-code-lines").split(","); 946 const lineIds = lines.map((line) => { 947 return targetCell + "-" + line; 948 }) 949 let top = null; 950 let height = null; 951 let parent = null; 952 if (lineIds.length > 0) { 953 //compute the position of the single el (top and bottom and make a div) 954 const el = window.document.getElementById(lineIds[0]); 955 top = el.offsetTop; 956 height = el.offsetHeight; 957 parent = el.parentElement.parentElement; 958 if (lineIds.length > 1) { 959 const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); 960 const bottom = lastEl.offsetTop + lastEl.offsetHeight; 961 height = bottom - top; 962 } 963 if (top !== null && height !== null && parent !== null) { 964 // cook up a div (if necessary) and position it 965 let div = window.document.getElementById("code-annotation-line-highlight"); 966 if (div === null) { 967 div = window.document.createElement("div"); 968 div.setAttribute("id", "code-annotation-line-highlight"); 969 div.style.position = 'absolute'; 970 parent.appendChild(div); 971 } 972 div.style.top = top - 2 + "px"; 973 div.style.height = height + 4 + "px"; 974 div.style.left = 0; 975 let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); 976 if (gutterDiv === null) { 977 gutterDiv = window.document.createElement("div"); 978 gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); 979 gutterDiv.style.position = 'absolute'; 980 const codeCell = window.document.getElementById(targetCell); 981 const gutter = codeCell.querySelector('.code-annotation-gutter'); 982 gutter.appendChild(gutterDiv); 983 } 984 gutterDiv.style.top = top - 2 + "px"; 985 gutterDiv.style.height = height + 4 + "px"; 986 } 987 selectedAnnoteEl = annoteEl; 988 } 989 }; 990 const unselectCodeLines = () => { 991 const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; 992 elementsIds.forEach((elId) => { 993 const div = window.document.getElementById(elId); 994 if (div) { 995 div.remove(); 996 } 997 }); 998 selectedAnnoteEl = undefined; 999 }; 1000 // Handle positioning of the toggle 1001 window.addEventListener( 1002 "resize", 1003 throttle(() => { 1004 elRect = undefined; 1005 if (selectedAnnoteEl) { 1006 selectCodeLines(selectedAnnoteEl); 1007 } 1008 }, 10) 1009 ); 1010 function throttle(fn, ms) { 1011 let throttle = false;
1012 let timer; 1013 return (...args) => { 1014 if(!throttle) { // first call gets through 1015 fn.apply(this, args); 1016 throttle = true; 1017 } else { // all the others get throttled 1018 if(timer) clearTimeout(timer); // cancel #2 1019 timer = setTimeout(() => { 1020 fn.apply(this, args); 1021 timer = throttle = false; 1022 }, ms); 1023 } 1024 }; 1025 } 1026 // Attach click handler to the DT 1027 const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); 1028 for (const annoteDlNode of annoteDls) { 1029 annoteDlNode.addEventListener('click', (event) => { 1030 const clickedEl = event.target; 1031 if (clickedEl !== selectedAnnoteEl) { 1032 unselectCodeLines(); 1033 const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); 1034 if (activeEl) { 1035 activeEl.classList.remove('code-annotation-active'); 1036 } 1037 selectCodeLines(clickedEl); 1038 clickedEl.classList.add('code-annotation-active'); 1039 } else { 1040 // Unselect the line 1041 unselectCodeLines(); 1042 clickedEl.classList.remove('code-annotation-active'); 1043 } 1044 }); 1045 } 1046 const findCites = (el) => { 1047 const parentEl = el.parentElement; 1048 if (parentEl) { 1049 const cites = parentEl.dataset.cites; 1050 if (cites) { 1051 return { 1052 el, 1053 cites: cites.split(' ') 1054 }; 1055 } else { 1056 return findCites(el.parentElement) 1057 } 1058 } else { 1059 return undefined; 1060 } 1061 }; 1062 var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); 1063 for (var i=0; i<bibliorefs.length; i++) { 1064 const ref = bibliorefs[i]; 1065 const citeInfo = findCites(ref); 1066 if (citeInfo) { 1067 tippyHover(citeInfo.el, function() { 1068 var popup = window.document.createElement('div'); 1069 citeInfo.cites.forEach(function(cite) { 1070 var citeDiv = window.document.createElement('div'); 1071 citeDiv.classList.add('hanging-indent'); 1072 citeDiv.classList.add('csl-entry'); 1073 var biblioDiv = window.document.getElementById('ref-' + cite); 1074 if (biblioDiv) { 1075 citeDiv.innerHTML = biblioDiv.innerHTML; 1076 } 1077 popup.appendChild(citeDiv); 1078 }); 1079 return popup.innerHTML; 1080 }); 1081 } 1082 } 1083 }); 1084 </script>
1084 1085</div> <!-- /content --> 1086 1087 1088 1089 1090</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.