<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://bootstrapbill.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bootstrapbill.github.io/" rel="alternate" type="text/html" /><updated>2026-03-13T13:25:28-07:00</updated><id>https://bootstrapbill.github.io/feed.xml</id><title type="html">William Turner</title><subtitle>Postdoctoral Researcher in Cognitive Neuroscience</subtitle><author><name>William Turner</name><email>wft@stanford.edu</email></author><entry><title type="html">Make your own motion illusion (in Python)</title><link href="https://bootstrapbill.github.io/posts/2024/01/blog-post-4/" rel="alternate" type="text/html" title="Make your own motion illusion (in Python)" /><published>2024-01-05T00:00:00-08:00</published><updated>2024-01-05T00:00:00-08:00</updated><id>https://bootstrapbill.github.io/posts/2024/01/blog-post-4</id><content type="html" xml:base="https://bootstrapbill.github.io/posts/2024/01/blog-post-4/"><![CDATA[<p>I’m going to show you how to make your own four-stroke apparent motion illusion!</p>

<p>“What on earth is four-stroke apparent motion?”, I hear you say.</p>

<p>It’s this mind-melting (and, after staring for a while, potentially stomach-churning!) effect:</p>

<p><img src="../../../../images/f1_headache.gif" width="500" height="500" /></p>

<p>What’s amazing is that this effect is generated by presenting just two (!) images again and again (so the illusion lasts more than a few milliseconds 😎) and inverting their luminance profiles with each repetition (hence four-stroke, since it’s essentially a four image sequence). Thats all it takes… kinda wild!</p>

<p>I won’t go into the specifics of why this gives rise to the perception of never-ending motion, but it relates to my <a href="https://bootstrapbill.github.io/posts/2022/07/blog-post-2/">previous post</a> on motion energy filtering and there are several <a href="https://www.sciencedirect.com/science/article/pii/S0042698998001916">interesting</a> <a href="https://journals.sagepub.com/doi/abs/10.1068/p150627">papers</a> on the topic (if you’re familiar with motion energy filtering then Figure 1 of the paper by Mather &amp; Murdoch should help your intuition!).</p>

<p>So, how can you make your own version of this effect? First you need to go find a gif that contains interesting motion! The one I used for the demo above looked like this:</p>

<p><img src="../../../../images/f1.png" alt="original gif" /></p>

<p>Then, it turns out that you can open gifs in preview (sorry non-mac users, I’m sure there is a very simple windows equivalent… but I’m not going to google it) and get at the individual frames. Having done so, all you need to do is pick two sequential (or there abouts…) frames from your gif, where there is interesting motion happening. Export the two frames as images (.tiff is fine), naming the first ‘img1’ and the second ‘img2’ (easiest way is to just drag and drop the relevant frame and then rename it).</p>

<p>(Note, I also desaturated the images in preview… you don’t strictly have to do this, but if you don’t then be warned that things will look kinda hectic when you invert the image colour profiles!)</p>

<p>Now here’s the code I used to actually generate the demo (which you can easily run too, so long as you have psychopy installed).</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">psychopy</span> <span class="kn">import</span> <span class="n">visual</span><span class="p">,</span> <span class="n">core</span>

<span class="c1">#create a window
</span><span class="n">win</span> <span class="o">=</span> <span class="n">visual</span><span class="p">.</span><span class="n">Window</span><span class="p">(</span><span class="n">fullscr</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">size</span> <span class="o">=</span> <span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="mi">800</span><span class="p">),</span> <span class="n">units</span> <span class="o">=</span> <span class="s">'pix'</span><span class="p">,</span> <span class="n">screen</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>

<span class="n">im1</span> <span class="o">=</span> <span class="n">visual</span><span class="p">.</span><span class="n">ImageStim</span><span class="p">(</span><span class="n">win</span><span class="p">,</span> <span class="n">image</span><span class="o">=</span><span class="s">'img1'</span><span class="p">,</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">800</span><span class="p">)</span>
<span class="n">im2</span> <span class="o">=</span> <span class="n">visual</span><span class="p">.</span><span class="n">ImageStim</span><span class="p">(</span><span class="n">win</span><span class="p">,</span> <span class="n">image</span><span class="o">=</span><span class="s">'img2'</span><span class="p">,</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">800</span><span class="p">)</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>

        <span class="n">im1</span><span class="p">.</span><span class="n">draw</span><span class="p">()</span>   
        <span class="n">win</span><span class="p">.</span><span class="n">flip</span><span class="p">()</span>
        <span class="n">win</span><span class="p">.</span><span class="n">getMovieFrame</span><span class="p">(</span><span class="nb">buffer</span><span class="o">=</span><span class="s">'front'</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>

        <span class="n">im2</span><span class="p">.</span><span class="n">draw</span><span class="p">()</span>   
        <span class="n">win</span><span class="p">.</span><span class="n">flip</span><span class="p">()</span>
        <span class="n">win</span><span class="p">.</span><span class="n">getMovieFrame</span><span class="p">(</span><span class="nb">buffer</span><span class="o">=</span><span class="s">'front'</span><span class="p">)</span>

    <span class="n">im1</span><span class="p">.</span><span class="n">color</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span>
    <span class="n">im2</span><span class="p">.</span><span class="n">color</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span>

<span class="n">win</span><span class="p">.</span><span class="n">saveMovieFrames</span><span class="p">(</span><span class="n">fileName</span><span class="o">=</span><span class="s">'f1_headache.gif'</span><span class="p">,</span> <span class="n">fps</span> <span class="o">=</span> <span class="mi">60</span><span class="p">)</span> <span class="c1"># save movie
</span>
<span class="n">win</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">core</span><span class="p">.</span><span class="n">quit</span><span class="p">()</span>
</code></pre></div></div>

<p>There are obviously myriad other ways to do this (e.g., with imageio), so here’s the essential logical steps: 1) You need to load the images, 2) present them for a few frames (I chose 3 arbitrarily, fewer frames give a more flicker-y vibe), 3) invert the luminance/colour profiles and present them again. Oh and you also need a way of saving the frame buffer with each screen refresh and then stitching the frames together at the end. That’s it!</p>

<p><img src="../../../../images/infinite_homer.gif" width="500" height="500" /></p>

<p>If you’ve actually bothered to follow these steps and make a demo then please feel free to send it my way - I’d love to see it!</p>

<p>There are also some interesting follow up ideas which you (or future me!?) might consider playing with. For example,  edge-detection filtering could be used to find salient edges (essentially as regions of interest) which can then be slightly offset and contrast reversed… like local four-stroke apparent motion sequences within an image. That might be a cool way of making stationary images appear to move in interesting ways? And may make the image look slightly less 🤮-inducing (since you might not have to contrast reverse everything?). Who knows…</p>

<p>If you’re reading this and have been bothered to implement that, then I guess you now know… so please enlighten me!</p>

<p><strong>Update (7/1/2024): Future me was actually bothered!</strong></p>

<p>I decided to quickly implement a rough version of the idea I had above, using a simple <a href="https://en.wikipedia.org/wiki/Sobel_operator">Sobel filter</a> for edge detection. I think the results are pretty cool! Here are two examples using William Turner’s (not me, nor the pirate… the other one) painting ‘The Shipwreck’ and Hokusai’s ‘The Great Wave off Kanagawa’ (then code below).</p>

<p><img src="../../../../images/turner.gif" width="800" height="800" /></p>

<p><img src="../../../../images/hokusai.gif" width="800" height="800" /></p>

<p>Pretty cool effects in my opinion! Here’s the code I whipped up:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">scipy.signal</span> <span class="kn">import</span> <span class="n">convolve2d</span>
<span class="kn">import</span> <span class="nn">cv2</span>
<span class="kn">import</span> <span class="nn">imageio</span>
<span class="kn">import</span> <span class="nn">os</span>

<span class="k">def</span> <span class="nf">edge_detection</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="nb">filter</span><span class="p">):</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">convolve2d</span><span class="p">(</span><span class="n">image</span><span class="p">[:,:,</span><span class="mi">0</span><span class="p">],</span> <span class="nb">filter</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">convolve2d</span><span class="p">(</span><span class="n">image</span><span class="p">[:,:,</span><span class="mi">0</span><span class="p">],</span> <span class="n">np</span><span class="p">.</span><span class="n">flip</span><span class="p">(</span><span class="nb">filter</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span>
    <span class="n">edges</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">square</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">square</span><span class="p">(</span><span class="n">y</span><span class="p">))</span>
    <span class="n">edges</span> <span class="o">*=</span> <span class="mf">255.0</span> <span class="o">/</span> <span class="n">edges</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>

    <span class="k">return</span> <span class="n">edges</span>

<span class="k">def</span> <span class="nf">mask_image</span><span class="p">(</span><span class="n">edge_image</span><span class="p">,</span> <span class="n">rep</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">direction</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span>

    <span class="k">if</span> <span class="n">offset</span><span class="p">:</span>
        <span class="n">edge_image</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">concatenate</span><span class="p">(</span>
            <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">offset</span><span class="p">,</span> <span class="n">edge_image</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])),</span> <span class="n">edge_image</span><span class="p">[</span><span class="n">offset</span><span class="p">:,</span> <span class="p">:]),</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span>
            <span class="p">)</span>
        <span class="n">edge_image</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">concatenate</span><span class="p">(</span>
            <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">edge_image</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">offset</span><span class="p">)),</span> <span class="n">edge_image</span><span class="p">[:,</span> <span class="p">:</span><span class="o">-</span><span class="n">offset</span><span class="p">]),</span><span class="n">axis</span><span class="o">=</span><span class="mi">1</span>
            <span class="p">)</span>

    <span class="n">mask_image</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">ma</span><span class="p">.</span><span class="n">masked_where</span><span class="p">(</span><span class="n">edge_image</span> <span class="o">&lt;</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">255</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">edge_image</span><span class="p">))</span>

    <span class="k">return</span> <span class="n">mask_image</span>

<span class="k">def</span> <span class="nf">plot_image</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">mask</span><span class="p">,</span> <span class="n">color_map</span><span class="p">,</span> <span class="n">saving</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">filenames</span><span class="p">):</span>
    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">30</span><span class="p">))</span>

    <span class="n">ax</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">image</span><span class="p">[...,::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
    <span class="c1"># ax.imshow(image[:, :, 0], cmap=color_map, alpha=0.2)
</span>    <span class="n">ax</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">mask</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="n">color_map</span><span class="p">,</span> <span class="n">interpolation</span><span class="o">=</span><span class="s">'none'</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="mi">255</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">saving</span><span class="p">:</span>
        <span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s">'</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s">.png'</span>
        <span class="n">filenames</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
        <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="k">return</span> <span class="n">i</span><span class="p">,</span> <span class="n">filename</span>    

<span class="k">def</span> <span class="nf">build_gif</span><span class="p">(</span><span class="n">filenames</span><span class="p">):</span>
    <span class="k">with</span> <span class="n">imageio</span><span class="p">.</span><span class="n">get_writer</span><span class="p">(</span><span class="s">'hokusai.gif'</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'I'</span><span class="p">,</span> <span class="n">duration</span><span class="o">=</span><span class="mf">0.09</span><span class="p">)</span> <span class="k">as</span> <span class="n">writer</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">filenames</span><span class="p">:</span>
            <span class="n">image</span> <span class="o">=</span> <span class="n">imageio</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
            <span class="n">writer</span><span class="p">.</span><span class="n">append_data</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="n">filenames</span><span class="p">):</span>
        <span class="n">os</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

<span class="nb">filter</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]])</span> <span class="c1"># simple sobel filter
</span>
<span class="n">image</span> <span class="o">=</span> <span class="n">cv2</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="s">"hokusai.jpeg"</span><span class="p">)</span>
<span class="n">edges</span> <span class="o">=</span> <span class="n">edge_detection</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="nb">filter</span><span class="p">)</span>

<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">filenames</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">rep</span><span class="p">,</span> <span class="n">color</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">([</span><span class="s">'Greys'</span><span class="p">,</span> <span class="s">'Greys_r'</span><span class="p">]):</span>
        <span class="n">mask</span> <span class="o">=</span> <span class="n">mask_image</span><span class="p">(</span><span class="n">edges</span><span class="p">,</span> <span class="n">rep</span><span class="p">)</span>
        <span class="n">i</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">plot_image</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">mask</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">filenames</span><span class="p">)</span>

        <span class="n">mask</span> <span class="o">=</span> <span class="n">mask_image</span><span class="p">(</span><span class="n">edges</span><span class="p">,</span> <span class="n">rep</span><span class="p">,</span> <span class="n">offset</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
        <span class="n">i</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">plot_image</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">mask</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">filenames</span><span class="p">)</span>

<span class="n">build_gif</span><span class="p">(</span><span class="n">filenames</span><span class="p">)</span>
</code></pre></div></div>

<p>There are lots of parameters to be played with, and no doubt many improvements to be made, but here’s the essential logic. Basically: 1) I use <a href="https://en.wikipedia.org/wiki/Sobel_operator">Sobel filter</a> to find the salient edges within the image, 2) I create a mask of those edges, 3) I plot the mask over the original image four times following the typical four-stroke apparent motion logic (having a sequential offset of the mask, which is then repeated with a luminance inversion). You can also toggle on and off having an additional partially transparent greyscale overlay of the image which switches luminance… this seems to make the motion effect stronger, but also adds even more annoying flicker, so I commented it out for the demos above.</p>]]></content><author><name>William Turner</name><email>wft@stanford.edu</email></author><category term="Visual Illusion" /><category term="Apparent Motion" /><category term="Python" /><summary type="html"><![CDATA[I’m going to show you how to make your own four-stroke apparent motion illusion!]]></summary></entry><entry><title type="html">Moving data between university HPCs</title><link href="https://bootstrapbill.github.io/posts/2023/05/blog-post-3/" rel="alternate" type="text/html" title="Moving data between university HPCs" /><published>2023-05-15T00:00:00-07:00</published><updated>2023-05-15T00:00:00-07:00</updated><id>https://bootstrapbill.github.io/posts/2023/05/blog-post-3</id><content type="html" xml:base="https://bootstrapbill.github.io/posts/2023/05/blog-post-3/"><![CDATA[<p>Here I outline a process for moving large amounts of data between two uni HPCs.</p>

<p>Recently I moved to a new university and found myself banging my head against the problem of transferring large files from my old uni’s High Performance Computing (HPC) system (‘SPARTAN’) and my new uni’s HPC (‘Lyra’). I found this somewhat tricky because you are dealing with two remote hosts that can’t directly communicate with one another. I wanted to come up with a solution that avoided the need for manually downloading everything from the old HPC onto a local computer before re-uploading to the new HPC.</p>

<p>Below is the process that worked for me. <strong>Note, this is mac specific (OS Catalina 10.15.7)</strong></p>

<ol>
  <li>
    <p>Install macFuse and sshfs from <a href="https://osxfuse.github.io/">here</a>.</p>
  </li>
  <li>
    <p>Go to System Preferences -&gt; Users &amp; Groups -&gt; Click the ‘+’ sign at the bottom left of the window -&gt; Set the New Account dropdown to ‘Group’ -&gt; Full Name = ‘fuse’ -&gt; Click on group and user check box to mark yourself as a member</p>
  </li>
  <li>
    <p>Make a folder where you will ‘mount’ the old HPC:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mkdir ~/sshfs_mount
</code></pre></div>    </div>
  </li>
  <li>
    <p>Mount the relevant folder from your old HPC (enter old HPC password when prompted)</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sshfs -o idmap=user OLD_USERNAME@OLD-HPC-ADDRESS://OLD_PATH-TO-FOLDER ~/sshfs_mount
</code></pre></div>    </div>
  </li>
  <li>
    <p>Navigate to the mounted folder on your local computer (you don’t need to ssh into the old HPC).</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> cd ~/sshfs_mount 
</code></pre></div>    </div>
  </li>
  <li>
    <p>Use rsync to transfer files from mounted folder to new HPC (in the example below I am transferring all files ending in ‘.bdf’ from the old HPC to the new HPC).</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> rsync -rv --ignore-existing --progress *.bdf NEW_USERNAME@NEW_HPC_ADDRESS:NEW_PATH_TO_FOLDER
</code></pre></div>    </div>
  </li>
</ol>

<p><strong>Troubleshooting</strong></p>

<p>To get macFUSE to work I had to go to: Security &amp; Privacy System Preferences -&gt; General preferences, and allow loading system software from developer “Benjamin Fleischer”.</p>

<p>When I first tried mounting the remote folder I got this error message: <code class="language-plaintext highlighter-rouge">'remote host has disconnected'</code>… this was because I’d mis-typed my old HPC address 🤦</p>

<p>Then when I tried remounting the remote I got this message: <code class="language-plaintext highlighter-rouge">'mount_macfuse: mount point /Users/willturner/sshfs_mount is itself on a macFUSE volume'</code></p>

<p>To fix that I simply had to run: <code class="language-plaintext highlighter-rouge">diskutil umount force ~/sshfs_mount</code></p>

<p>If you’ve stumbled across this, I hope it was helpful. Please feel free to reach out and let me know if you’ve come across a better method for solving this task.</p>

<p><strong>UPDATE (3/8/23)</strong></p>

<p>The above method, whilst technically functional, is in practise agonisingly slow (with transfer speeds of Kb/s 🤦). To speed things up this is what I’ve been doing (if you have better ideas please let me know!):</p>

<p>1) I use a virtual machine (provided by my uni) as the intermediate ‘bridge’ between the two remotes, instead of my laptop.</p>

<p>2) On that computer (a windows machine) I mounted my old HPC (following these <a href="https://phoenixnap.com/kb/sshfs">instructions</a>).</p>

<p>3) Then I used <a href="https://cyberduck.io/download/">cyberduck</a>, connected to the new HPC, to upload the files off the mounted folder on the virtual machine. This massively increased the upload speed (although it does still take ages to transfer 250Gb of data… but luckily that can all chug away on the virtual machine in the background!).</p>]]></content><author><name>William Turner</name><email>wft@stanford.edu</email></author><category term="Uni HPCs" /><category term="remote to remote" /><category term="transfer files" /><summary type="html"><![CDATA[Here I outline a process for moving large amounts of data between two uni HPCs.]]></summary></entry><entry><title type="html">Motion energy filtering in Python</title><link href="https://bootstrapbill.github.io/posts/2022/07/blog-post-2/" rel="alternate" type="text/html" title="Motion energy filtering in Python" /><published>2022-07-19T00:00:00-07:00</published><updated>2022-07-19T00:00:00-07:00</updated><id>https://bootstrapbill.github.io/posts/2022/07/blog-post-2</id><content type="html" xml:base="https://bootstrapbill.github.io/posts/2022/07/blog-post-2/"><![CDATA[<p>As a fun exercise I translated George Mather’s <a href="http://www.georgemather.com/Model.html">motion energy filtering demo</a> from MATLAB into Python.</p>

<p>The GitHub repo with Python code and stimulus files can be found <a href="https://github.com/bootstrapbill/motion-energy-python-translation">here</a>.</p>

<h3 id="what-is-motion-energy-filtering">What is motion energy filtering?</h3>
<p>Motion energy filtering revolves around a surprisingly powerful observation: that motion manifests as oriented structure in space-time. If you’re reading about this for the first time and find that idea completely incomprehensible (it certainly was for me!) I’d recommend checking out this <a href="https://jake.vision/blog/motion-illusions/">blog</a> by Jacob Yates, which does a far better job of explaining things than I ever could. Seriously, go check it out, it’s entertaining AND informative. If, however, you want to just soldier on, really all you need to know is that motion = orientation in space-time.</p>

<p>Motion energy filtering involves building detectors (‘filters’) which are sensitive to orientation in space-time, providing an elegantly simple means of detecting motion. To make things extra interesting, its generally thought that this is (part of) what the visual system does to sense motion!</p>

<p>Below I’ve plotted the filters generated in the demo. Notice how they contain diagonally oriented streaks… that’s essentially what enables them to look for oriented structure in space-time (i.e., motion)! In fact, if you cycle through each time-slice of the filters you will see what looks like ‘pulses’ of leftwards and rightwards motion, giving a hint at what they are trying to detect. Jacob’s <a href="https://jake.vision/blog/motion-illusions/">blog</a> has a really nice demo of this.</p>

<p><img src="../../../../images/motion_energy_filters.jpg" alt="" /></p>

<h3 id="additional-resources">Additional resources</h3>

<p>The original paper on motion energy filtering by Adelson and Bergen can be found <a href="https://opg.optica.org/josaa/fulltext.cfm?uri=josaa-2-2-284&amp;id=1945">here</a>. It’s somewhat dense, but is a beautiful paper once you wrap your head around things. I’d recommend reading it after going through Jacob’s blog, before diving into the code.</p>

<p>George Mather’s <a href="http://www.georgemather.com/Model.html">website</a> contains detailed descriptions of the steps involved in the demo code. I’d recommend having this open as you go through the Python translation.</p>

<p>The current demo only considers 1D motion (e.g., motion along a single axis). For more complex (2D motion) implementations see <a href="https://github.com/anne-urai/motion_energy_filtering">this nice MATLAB toolbox</a> by Anne Urai and Klaus Wimmer, which contains links to additional resources.</p>]]></content><author><name>William Turner</name><email>wft@stanford.edu</email></author><category term="motion energy filtering" /><category term="python" /><summary type="html"><![CDATA[As a fun exercise I translated George Mather’s motion energy filtering demo from MATLAB into Python.]]></summary></entry><entry><title type="html">Making an academic website (like this one)</title><link href="https://bootstrapbill.github.io/posts/2022/06/blog-post-1/" rel="alternate" type="text/html" title="Making an academic website (like this one)" /><published>2022-06-07T00:00:00-07:00</published><updated>2022-06-07T00:00:00-07:00</updated><id>https://bootstrapbill.github.io/posts/2022/06/blog-post-1</id><content type="html" xml:base="https://bootstrapbill.github.io/posts/2022/06/blog-post-1/"><![CDATA[<p>This is a guide to how I made this website (to help you make one too!).</p>

<h3 id="what-kind-of-website-is-this">What kind of website is this?</h3>

<p>This is a static website (really just a collection of files) built using <a href="https://jekyllrb.com/">Jekyll</a> and the <a href="https://github.com/academicpages/academicpages.github.io">academicpages</a> template. It’s hosted for free (!) on <a href="https://pages.github.com/">GitHub Pages</a> hence the funky (some might say cool?!) ‘github.io’ address.</p>

<h3 id="what-does-is-cost">What does is cost?</h3>

<p>Zero dollars… 🤯 	🎉</p>

<p>All you need is a bit of time up your sleeve, it took me ~1-2 hrs to get a basic site up and running.</p>

<h3 id="what-coding-knowledge-is-required">What coding knowledge is required?</h3>

<p>All that’s required is some familiarity with using a git client (I used <a href="https://www.sourcetreeapp.com/">SourceTree</a>) and a willingness to google <a href="https://www.markdownguide.org/getting-started/">Markdown</a> formatting issues until you get what you want. If you have no idea what Markdown and git are then don’t fear… learning the basics of both is actually super simple. So building a website like this even with zero experience is still very doable (it might just take you a wee bit longer!).</p>

<p>To ease you into things, I’ll briefly sketch out the steps that lie between you and being a website owner. First, you will use a git client (a bit like dropbox for code) to transfer all the template website files onto your computer. Then you will edit and personalise some of these newly acquired files, using the Markdown language to specify text formatting (e.g., specifying whether things should be <strong>bolded</strong>, <em>italicised</em>, <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ">hyperlinked</a> etc). After you are done editing things, you will use your trusty git client to ‘push’ the files back onto the web for people to look at (in the form of your new website). That’s pretty much it! All the fancy website formatting is taken care of by the academicpages template, so you really only have to edit text files and move them around (easy!).</p>

<h3 id="are-you-ready-to-roll">Are you ready to roll?</h3>
<details>
  <summary>
    Yes!
  </summary>

  Heck yeah!!! Read on...
</details>
<details>
  <summary>
    No!
  </summary>

  Believe in yourself!
</details>
<p><br /></p>
<h3 id="heres-what-you-need-to-do">Here’s what you need to do:</h3>

<ol>
  <li>
    <p>Make sure you have a <a href="https://github.com/">GitHub</a> account. If you don’t have one then… make one! Also bear in mind that your username becomes the initial part of your website address, so you probably want to pick a professional looking username (or end up with one like mine 😬). If you really don’t want a funky ‘github.io’ address you also have the option of 💸 buying 💸 your own domain name (e.g., bestpostdoc.com… actually I just checked and it’s taken but postdoc.best is available and will only set you back AU$42.78).</p>
  </li>
  <li>
    <p>Make sure you have a git client installed (or do everything through terminal, if you’re into that!). If you want to follow in my footsteps exactly then use <a href="https://www.sourcetreeapp.com/">SourceTree</a>. Download the app, make an account and link it to your GitHub. Remember, we will use SourceTree to move files from GitHub onto your computer so we can then edit them and then upload the freshly edited files back onto the web!</p>
  </li>
  <li>
    <p>For the initial website building process I’d recommend you just follow <a href="https://jayrobwilliams.com/posts/2020/06/academic-website/">this excellent guide</a> by Rob Williams. Its very clear and beautiful. Note, however, that I deviated from this guide slightly. I opted to just push my edited files onto the web immediately (using SourceTree) and fix bugs that I saw in the online version with subsequent pushes, rather than testing my website ‘locally’ (i.e. behind closed doors). I found this much easier, but in doing so you do run the risk of someone catching a glimpse of your mangled half-built website, so beware!</p>
  </li>
  <li>
    <p>If you have ignored my advice to go follow Rob’s guide, here’s a sketch of the steps involved… in Rob’s guide:</p>
    <ol>
      <li><a href="https://docs.github.com/en/get-started/quickstart/fork-a-repo">‘Fork’</a> the <a href="https://github.com/academicpages/academicpages.github.io">academicpages repository</a> into your GitHub (this just means we make our own copy of the original bunch of files, to do whatever we want with).</li>
      <li><a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository">‘Clone’</a> the newly forked repository from your GitHub onto your computer (this just means we create a local copy of the repository on our own computer… kind of like downloading everything). We do this so we can then edit the files. I did all of this with… you guessed it, SourceTree!</li>
      <li>Edit the relevant files. I used <a href="https://macdown.uranusjr.com/">MacDown</a> to edit all files. I started by editing the ‘_config.yml’ file, following Rob’s guide. Then I edited the ‘about.md’ file (in the ‘pages’ folder) to add in a blurb about myself. Finally I added my profile photo into the ‘images’ folder to replace the original ‘profile.png’ file.</li>
      <li>For the initial version of my website I decided to just have an ‘about me’ page with links to my twitter, email, google scholar, and github accounts on the left-hand side and nothing else. So I went to the ‘data’ folder and edited the ‘navigation.yml’ file to remove all the default links to other pages at the top of the website. To do this you just have to put a hash (‘#’) in front of the lines you don’t want. For example, to remove the publications link you do this:</li>
    </ol>
  </li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># main links links
main:
  #- title: "Publications"
  #  url: /publications/
</code></pre></div></div>

<h3 id="customising-your-site">Customising your site</h3>

<h3 id="icon-links">Icon links</h3>

<p>I later came back to my initial husk of a website and decided to add in my publications at the bottom of the ‘about me’ page.</p>

<p>Here’s a snapshot of the code I added in to the ‘about.md’ file to achieve this (this snippet adds in the first two publications I have listed).</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>### Publications

1. Ko, Feuerriegel, **Turner**, Overhoff, Niessen, Stahl, Hester, Fink, Weiss, <span class="err">&amp;</span> Bode (2022). Divergent effects of absolute evidence magnitude on decision accuracy and confidence in perceptual judgements. *Cognition*. <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"../files/Ko_et_al_2022.pdf"</span><span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-file-pdf"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a&gt;</span> <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://www.sciencedirect.com/science/article/pii/S0010027722001135?dgcid=coauthor"</span><span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-link"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a&gt;</span> <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://osf.io/r8vfx/"</span><span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-code"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a&gt;</span>

2. **Turner** (2022). Unravelling the neural mechanisms which encode rapid streams of visual input. *The Journal of Neuroscience*. <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"../files/Turner_2022.pdf"</span><span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-file-pdf"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a&gt;</span> <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://www.jneurosci.org/content/42/7/1170"</span><span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-link"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a&gt;</span>
</code></pre></div></div>

<p>With a bit of googling I worked out how to use some simple HTML to add in fancy icons like this <i class="fas fa-file-pdf"></i> which I use to link to a pdf copy of my papers. I put these pdfs in the ‘files’ folder and then pushed them onto GitHub with… SourceTree. Happily, you don’t need to install anything extra to use icons like this. You can search to see what other icons are available on the <a href="https://fontawesome.com/">Font Awesome</a> website.</p>

<p>To make things a bit more digestable, I’ll focus in on the code snippet that goes into making just one of these links:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"../files/Turner_2022.pdf"</span><span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-file-pdf"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a&gt;</span>
</code></pre></div></div>

<p>The first bit <code class="language-plaintext highlighter-rouge">&lt;a href="../files/Turner_2022.pdf"&gt;</code> specifies the link to the pdf document which I put in the files folder. The second bit <code class="language-plaintext highlighter-rouge">&lt;i class="fas fa-file-pdf"&gt;&lt;/i&gt;&lt;/a&gt;</code> says that the link should be an icon from the Font Awesome Solid (‘fas’) class, specifically the pdf doc one (‘fa-file-pdf’). How did I work out that I needed to write <code class="language-plaintext highlighter-rouge">fas fa-file-pdf</code> to get that? Well I went on the Font Awesome website and searched for ‘pdf’. I then clicked on the icon I liked and looked at the html snippet provided. If you’re particularly sharp eyed you’ll notice that this html snippet <code class="language-plaintext highlighter-rouge">&lt;i class="fa-solid fa-file"&gt;&lt;/i&gt;</code> is actually different to the one I used, and so it didn’t work when I first copied it in 😱! It turns out that this is because the academicpages template uses version 5 of Font Awesome. After some googling I found <a href="https://fontawesome.com/v5/icons/file-pdf?s=solid">this page</a> which showed me the old syntax for referencing icons in version 5 <code class="language-plaintext highlighter-rouge">&lt;i class="fas fa-file-pdf"&gt;&lt;/i&gt;</code> which fixed the issue! Note, for all of this to work you might need to make the small edit suggested <a href="https://jayrobwilliams.com/posts/2020/07/customizing-website/">here</a> under the heading <strong>‘Fixing fancy icons’</strong>.</p>

<h3 id="code-chunks-and-wrapping-to-avoid-long-scroll-bars">Code chunks (and wrapping to avoid long scroll bars)</h3>

<p>To add in a code chunk you simply add three back ticks ` before and after the code (and to get syntax highlighting you just add the language (e.g., python) straight after the first lot of back ticks). To write code inline (i.e. in the middle of a sentence) you just add one back tick either side of the code.</p>

<p>One issue I ran into when using this default code chunk quoting is that for long lines of code, the text wont ‘wrap’, so you can end up with a ridiculously long horizontal scroll bar. If you want to avoid that, all you need to do is open the ‘_base.scss’ file in the ‘_sass’ folder, search for the word ‘pre’ and change the following chunk:</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">pre</span> <span class="p">{</span>
  <span class="nl">overflow-x</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span> <span class="c">/* add scrollbars to wide code blocks*/</span>
<span class="p">}</span>
</code></pre></div></div>

<p>to this:</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">pre</span> <span class="p">{</span>
  <span class="nl">overflow-x</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span> <span class="c">/* add scrollbars to wide code blocks*/</span>
  <span class="nl">white-space</span><span class="p">:</span> <span class="n">pre-line</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>After you save and push that change it should fix the issue (at least when viewing on google chrome… I haven’t tested other browsers).</p>

<p><strong>Update 5/1/2024:</strong> to get wrapping but still respect indentation within code blocks you actually want to set white space to ‘pre-wrap’ rather than ‘pre-line’ (this is what I have now done).</p>

<h3 id="emojis">Emojis</h3>

<p>To add emojis to your text all you need to do is find out the ‘hexadecimal HTML code’ for the emoji you want. So for example, if I wanted to add in a cowboy hat emoji I would google ‘cowboy hat emoji hexadecimal HTML’ and copy in the relevant code <code class="language-plaintext highlighter-rouge">&amp;#x1F920;</code> … 🤠</p>]]></content><author><name>William Turner</name><email>wft@stanford.edu</email></author><category term="academic website" /><category term="github pages" /><category term="academicpages" /><summary type="html"><![CDATA[This is a guide to how I made this website (to help you make one too!).]]></summary></entry></feed>