PageSourceSearch

https://bradyajohnston.github.io/index.html

html bradyajohnston.github.io collected 2026-10-03 08:43:52 UTC 46,010 bytes, 1,090 lines download raw bytes

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;">&nbsp;</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.