<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Data-Visualization | Bas Nijholt</title><link>https://www.nijho.lt/tag/data-visualization/</link><atom:link href="https://www.nijho.lt/tag/data-visualization/index.xml" rel="self" type="application/rss+xml"/><description>Data-Visualization</description><generator>Hugo</generator><language>en-us</language><copyright>© 2026</copyright><lastBuildDate>Sun, 22 Dec 2024 00:00:00 +0000</lastBuildDate><image><url>https://www.nijho.lt/media/icon_hu_408a8f6cef43e327.png</url><title>Data-Visualization</title><link>https://www.nijho.lt/tag/data-visualization/</link></image><item><title>tiller-streamlit 💰</title><link>https://www.nijho.lt/post/advent-of-open-source/22-tiller-streamlit/</link><pubDate>Sun, 22 Dec 2024 00:00:00 +0000</pubDate><guid isPermaLink="false">/post/advent-of-open-source/22-tiller-streamlit/</guid><description>&lt;p&gt;(See my &lt;a href="../"&gt;intro post&lt;/a&gt;)&lt;/p&gt;&#10;&lt;p&gt;Tracking personal finances is crucial, especially when working towards financial independence (see my &lt;a href="../04-wenfire"&gt;WenFIRE post on Day 4&lt;/a&gt;). Today&amp;rsquo;s project is &lt;a href="https://github.com/basnijholt/tiller-streamlit" target="_blank" rel="noopener"&gt;&lt;code&gt;tiller-streamlit&lt;/code&gt;&lt;/a&gt;, a Streamlit app that visualizes your financial data from &lt;a href="https://www.tillerhq.com/" target="_blank" rel="noopener"&gt;Tiller&lt;/a&gt;. I host it on my local network under &lt;code&gt;money.local&lt;/code&gt; using Traefik for easy access.&lt;/p&gt;&#10;&lt;h2 id="-origin-story"&gt;📖 Origin Story &lt;a class="anchor" href="#-origin-story" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Used to use Intuit Mint, but when they shut down, I needed an alternative with full data control.&lt;/li&gt;&#10;&lt;li&gt;Tiller automatically populates your financial data into a Google Sheet that you own forever.&lt;/li&gt;&#10;&lt;li&gt;With 20+ accounts, manual updates are tedious – Tiller automates it.&lt;/li&gt;&#10;&lt;li&gt;Combined Tiller&amp;rsquo;s data with Streamlit&amp;rsquo;s ease of use, creating a personal finance dashboard.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-technical-highlights"&gt;🔧 Technical Highlights &lt;a class="anchor" href="#-technical-highlights" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Powered by Streamlit: Turns Python into a web app with minimal code.&lt;/li&gt;&#10;&lt;li&gt;Tiller Integration: Connects to Tiller&amp;rsquo;s Google Sheets for automated data retrieval.&lt;/li&gt;&#10;&lt;li&gt;Interactive Visualizations: Uses Plotly and Altair for dynamic charts.&lt;/li&gt;&#10;&lt;li&gt;Customizable Analysis: Filter by categories, time periods, and more.&lt;/li&gt;&#10;&lt;li&gt;Net Worth Tracking: Calculates and visualizes net worth over time.&lt;/li&gt;&#10;&lt;li&gt;Dockerized Deployment: Easy deployment with Docker, and served locally with Traefik.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-impact"&gt;📊 Impact &lt;a class="anchor" href="#-impact" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Primarily for personal use, it has significantly improved my understanding of my finances.&lt;/li&gt;&#10;&lt;li&gt;Great way to learn Streamlit and explore its capabilities.&lt;/li&gt;&#10;&lt;li&gt;Visualizing spending patterns helps identify areas to cut back and make informed financial decisions on the path to financial independence.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-challenges-and-solutions"&gt;🎯 Challenges and Solutions &lt;a class="anchor" href="#-challenges-and-solutions" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Learning Streamlit: Excellent documentation and community support made it a smooth process.&lt;/li&gt;&#10;&lt;li&gt;Data Wrangling: Transforming Tiller&amp;rsquo;s raw data into a format suitable for visualization.&lt;/li&gt;&#10;&lt;li&gt;Deployment: Docker and Traefik simplified local deployment, making it accessible on my home network.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-lessons-learned"&gt;💡 Lessons Learned &lt;a class="anchor" href="#-lessons-learned" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Data Ownership Matters: Owning your financial data gives you control and flexibility.&lt;/li&gt;&#10;&lt;li&gt;Visualization is Key: Seeing your finances visually makes a huge difference.&lt;/li&gt;&#10;&lt;li&gt;Streamlit is Powerful: Simplifies web app development.&lt;/li&gt;&#10;&lt;li&gt;Automation is Essential: Tiller&amp;rsquo;s automatic data population makes the whole process sustainable.&lt;/li&gt;&#10;&lt;li&gt;Docker and Traefik Simplify Local Deployment: Making it easy to access the app on my home network.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-future-plans"&gt;🔮 Future Plans &lt;a class="anchor" href="#-future-plans" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Budgeting Features: Integrate budget tracking and forecasting.&lt;/li&gt;&#10;&lt;li&gt;Goal Setting: Set financial goals and track progress.&lt;/li&gt;&#10;&lt;li&gt;Investment Tracking: Incorporate investment data for a complete picture.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Want to visualize your own finances with Tiller and Streamlit? Check out &lt;a href="https://github.com/basnijholt/tiller-streamlit" target="_blank" rel="noopener"&gt;&lt;code&gt;tiller-streamlit&lt;/code&gt; on GitHub&lt;/a&gt;!&lt;/p&gt;&#10;&lt;p&gt;#OpenSource #Python #Streamlit #PersonalFinance #DataVisualization #Tiller #Traefik #Docker&lt;/p&gt;&#10;</description></item><item><title>Interactive Graph Visualization 🕸️</title><link>https://www.nijho.lt/post/advent-of-open-source/21-interactive-graph-visualization/</link><pubDate>Sat, 21 Dec 2024 00:00:00 +0000</pubDate><guid isPermaLink="false">/post/advent-of-open-source/21-interactive-graph-visualization/</guid><description>&lt;p&gt;(See my &lt;a href="../"&gt;intro post&lt;/a&gt;)&lt;/p&gt;&#10;&lt;p&gt;After creating &lt;a href="../20-pipefunc"&gt;pipefunc (Day 20)&lt;/a&gt;, I wanted a way to visualize its (possibly large and complex) computational graphs interactively in Jupyter notebooks.&#10;What started as a simple visualization PR evolved into two standalone packages: &lt;a href="https://github.com/pipefunc/graphviz-anywidget" target="_blank" rel="noopener"&gt;graphviz-anywidget&lt;/a&gt; (Python) and &lt;a href="https://github.com/pipefunc/graphvizsvg" target="_blank" rel="noopener"&gt;graphvizsvg&lt;/a&gt; (JavaScript) - which unexpectedly introduced me to JavaScript development!&lt;/p&gt;&#10;&lt;h2 id="-origin-story"&gt;📖 Origin Story &lt;a class="anchor" href="#-origin-story" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;While working on pipefunc&amp;rsquo;s visualization features, I discovered that existing solutions didn&amp;rsquo;t quite meet my needs.&#10;However, I found several components that would solve my issue:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://anywidget.dev/" target="_blank" rel="noopener"&gt;AnyWidget&lt;/a&gt; (interactive GraphViz in Jupyter)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://github.com/hpcc-systems/hpcc-js-wasm" target="_blank" rel="noopener"&gt;@hpcc-js/wasm-graphviz&lt;/a&gt; (GraphViz in WASM)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://github.com/magjac/d3-graphviz" target="_blank" rel="noopener"&gt;d3-graphviz&lt;/a&gt; (interactive GraphViz in D3)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://github.com/mountainstorm/jquery.graphviz.svg/" target="_blank" rel="noopener"&gt;jquery.graphviz.svg&lt;/a&gt; (GraphViz SVG manipulation)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;AnyWidget would work with ESM modules, however, I had no clue what that even was.&#10;The &lt;code&gt;jquery.graphviz.svg&lt;/code&gt; package wasn&amp;rsquo;t one and hadn&amp;rsquo;t been maintained in 8 years.&lt;/p&gt;&#10;&lt;p&gt;With AI as my JavaScript mentor, I first rewrote &lt;code&gt;jquery.graphviz.svg&lt;/code&gt; into a modern ESM module (graphvizsvg), adding comprehensive tests that uncovered bugs in the original.&#10;Then, using AnyWidget, I created graphviz-anywidget to connect everything together - combining the WASM-powered d3-graphviz with the interactive features from graphvizsvg into a seamless Python package.&lt;/p&gt;&#10;&lt;p&gt;To my surprise, I found JavaScript&amp;rsquo;s development tooling remarkably sophisticated - especially npm, which handles everything from linting to testing to bundling to publishing.&#10;Something we&amp;rsquo;re still missing in Python!&lt;/p&gt;&#10;&lt;h2 id="-technical-highlights"&gt;🔧 Technical Highlights &lt;a class="anchor" href="#-technical-highlights" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="https://github.com/pipefunc/graphviz-anywidget" target="_blank" rel="noopener"&gt;graphviz-anywidget&lt;/a&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Interactive Graphviz visualization in Jupyter&lt;/li&gt;&#10;&lt;li&gt;WASM-powered graph rendering&lt;/li&gt;&#10;&lt;li&gt;Directional graph traversal&lt;/li&gt;&#10;&lt;li&gt;Node and edge highlighting&lt;/li&gt;&#10;&lt;li&gt;Works in JupyterLab, Notebook, and VS Code&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;a href="https://github.com/pipefunc/graphvizsvg" target="_blank" rel="noopener"&gt;graphvizsvg&lt;/a&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Modern ESM module for interactive SVG visualization&lt;/li&gt;&#10;&lt;li&gt;Automatic color transitions&lt;/li&gt;&#10;&lt;li&gt;Bi-directional graph traversal&lt;/li&gt;&#10;&lt;li&gt;Comprehensive test coverage&lt;/li&gt;&#10;&lt;li&gt;My first npm package!&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-impact"&gt;📊 Impact &lt;a class="anchor" href="#-impact" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Enhances &lt;a href="https://github.com/pipefunc/pipefunc" target="_blank" rel="noopener"&gt;pipefunc&lt;/a&gt;&amp;rsquo;s visualization capabilities&lt;/li&gt;&#10;&lt;li&gt;Modernizes legacy jQuery code for modern web development&lt;/li&gt;&#10;&lt;li&gt;Proves that diving into new technologies can yield useful tools&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-challenges-and-solutions"&gt;🎯 Challenges and Solutions &lt;a class="anchor" href="#-challenges-and-solutions" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Learning JavaScript/TypeScript from scratch&lt;/li&gt;&#10;&lt;li&gt;Making WASM work in Jupyter&lt;/li&gt;&#10;&lt;li&gt;Getting it to work in VS Code&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-lessons-learned"&gt;💡 Lessons Learned &lt;a class="anchor" href="#-lessons-learned" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Don&amp;rsquo;t let preconceptions limit your tech choices&lt;/li&gt;&#10;&lt;li&gt;Modern JavaScript development is actually enjoyable&lt;/li&gt;&#10;&lt;li&gt;AI can be an excellent programming mentor&lt;/li&gt;&#10;&lt;li&gt;Good visualization makes complex data accessible&lt;/li&gt;&#10;&lt;li&gt;Breaking features into separate packages increases reusability&lt;/li&gt;&#10;&lt;li&gt;Test coverage helps find bugs in even well-used code&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;Want to visualize graphs interactively? Check out &lt;a href="https://github.com/pipefunc/graphviz-anywidget" target="_blank" rel="noopener"&gt;graphviz-anywidget&lt;/a&gt; and &lt;a href="https://github.com/pipefunc/graphvizsvg" target="_blank" rel="noopener"&gt;graphvizsvg&lt;/a&gt;!&lt;/p&gt;&#10;&lt;p&gt;#OpenSource #JavaScript #Python #DataVisualization #WebDev&lt;/p&gt;&#10;</description></item><item><title>PhD Thesis Cover Design 🎨</title><link>https://www.nijho.lt/post/advent-of-open-source/14-phd-thesis-cover-design/</link><pubDate>Sat, 14 Dec 2024 00:00:00 +0000</pubDate><guid isPermaLink="false">/post/advent-of-open-source/14-phd-thesis-cover-design/</guid><description>&lt;p&gt;(See my &lt;a href="../"&gt;intro post&lt;/a&gt;)&lt;/p&gt;&#10;&lt;p&gt;When most people think of open source, they think of software. But what about open-sourcing your PhD thesis and creating a generative art system for its cover?&lt;/p&gt;&#10;&lt;h2 id="-origin-story"&gt;📖 Origin Story &lt;a class="anchor" href="#-origin-story" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;With my PhD defense approaching and needing around 100 copies of my thesis, I faced a design challenge. As someone more comfortable with Python than Photoshop, I turned what started as a simple visualization idea into a full-blown generative art project with machine learning-based clustering.&lt;/p&gt;&#10;&lt;figure id="figure-multiple-printed-copies-of-the-thesis"&gt;&lt;img src="https://www.nijho.lt/post/advent-of-open-source/14-phd-thesis-cover-design/image_2_hu_8cd2dfb49d0239e5.webp" srcset="https://www.nijho.lt/post/advent-of-open-source/14-phd-thesis-cover-design/image_2_hu_91ed23b7c6d41771.webp 400w, https://www.nijho.lt/post/advent-of-open-source/14-phd-thesis-cover-design/image_2_hu_8cd2dfb49d0239e5.webp 760w, https://www.nijho.lt/post/advent-of-open-source/14-phd-thesis-cover-design/image_2_hu_1ad1cec7a7457f36.webp 1200w" sizes="auto, (max-width: 760px) 100vw, 720px" width="760" height="616" alt="A photograph of multiple printed copies of Bas&amp;#39;s PhD thesis laid out on a table outdoors. Each copy has a unique, colorful, generated cover design. Potted plants are visible in the background." loading="lazy" data-zoomable&gt;&lt;figcaption&gt;Multiple printed copies of the thesis&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h2 id="-technical-highlights"&gt;🔧 Technical Highlights &lt;a class="anchor" href="#-technical-highlights" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Generated 3,671 unique covers from quantum physics simulation data&lt;/li&gt;&#10;&lt;li&gt;Used VGG16 neural network to extract features from covers&lt;/li&gt;&#10;&lt;li&gt;Implemented K-means clustering to group similar designs&lt;/li&gt;&#10;&lt;li&gt;Created interactive IPywidgets for design selection&lt;/li&gt;&#10;&lt;li&gt;Built a Binder app for real-time color scheme adjustment&lt;/li&gt;&#10;&lt;li&gt;Added unique edition numbers (1/120, 2/120, etc.)&lt;/li&gt;&#10;&lt;li&gt;Made both thesis and cover design code fully open source&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;The project combines:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Adaptive sampling for physics simulations&lt;/li&gt;&#10;&lt;li&gt;Neural networks for image feature extraction&lt;/li&gt;&#10;&lt;li&gt;Interactive visualization tools&lt;/li&gt;&#10;&lt;li&gt;Parallel processing for batch generation&lt;/li&gt;&#10;&lt;li&gt;Version control for scientific writing&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-impact"&gt;📊 Impact &lt;a class="anchor" href="#-impact" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Thesis repository: 14 GitHub stars&lt;/li&gt;&#10;&lt;li&gt;Cover design repository: 36 GitHub stars&lt;/li&gt;&#10;&lt;li&gt;Real-world adoption: &lt;a href="https://repository.tudelft.nl/record/uuid:e88a1897-0033-47e3-8b4f-84fd9cd5eec0" target="_blank" rel="noopener"&gt;Dr. Tomas Pippia from TU Delft&lt;/a&gt; used the code to create his own thesis cover&lt;/li&gt;&#10;&lt;li&gt;~100 unique printed copies, each with its own generated cover and edition number&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-challenges-and-solutions"&gt;🎯 Challenges and Solutions &lt;a class="anchor" href="#-challenges-and-solutions" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Managing 3,671 unique PDF files and their conversions&lt;/li&gt;&#10;&lt;li&gt;Creating a clustering system for visually similar designs&lt;/li&gt;&#10;&lt;li&gt;Building interactive tools for non-technical collaborators&lt;/li&gt;&#10;&lt;li&gt;Ensuring consistent print quality across designs&lt;/li&gt;&#10;&lt;li&gt;Balancing artistic appeal with scientific relevance&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-lessons-learned"&gt;💡 Lessons Learned &lt;a class="anchor" href="#-lessons-learned" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Open source isn&amp;rsquo;t just about code - it&amp;rsquo;s about sharing knowledge&lt;/li&gt;&#10;&lt;li&gt;Python can be a powerful tool for creative projects&lt;/li&gt;&#10;&lt;li&gt;Machine learning can help solve unexpected problems&lt;/li&gt;&#10;&lt;li&gt;Good visualization requires both technical skill and artistic sense&lt;/li&gt;&#10;&lt;li&gt;Interactive tools make collaboration with non-programmers easier&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="-fun-fact"&gt;📚 Fun Fact &lt;a class="anchor" href="#-fun-fact" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Due to COVID restrictions, I defended my thesis without any guests present. The silver lining? I still have about 100 beautifully unique copies at home, each with a different generated cover and edition number. If you&amp;rsquo;d like a physical copy of this piece of quantum physics meets generative art, just let me know!&lt;/p&gt;&#10;&lt;p&gt;Want to create your own thesis cover or see how I wrote mine? Check out the &lt;a href="https://github.com/basnijholt/thesis-cover" target="_blank" rel="noopener"&gt;thesis cover project&lt;/a&gt; and &lt;a href="https://github.com/basnijholt/thesis" target="_blank" rel="noopener"&gt;thesis source&lt;/a&gt;!&lt;/p&gt;&#10;&lt;p&gt;#OpenSource #PhD #Python #MachineLearning #DataVisualization&lt;/p&gt;&#10;</description></item><item><title>Calendar of Life 📅</title><link>https://www.nijho.lt/post/advent-of-open-source/01-calendar-of-life/</link><pubDate>Sun, 01 Dec 2024 00:00:00 +0000</pubDate><guid isPermaLink="false">/post/advent-of-open-source/01-calendar-of-life/</guid><description>&lt;p&gt;(See my &lt;a href="../"&gt;intro post&lt;/a&gt;.)&lt;/p&gt;&#10;&lt;p&gt;Visualizing the finite weeks of our lives, because apparently, I needed another reminder of my mortality!&lt;/p&gt;&#10;&lt;h2 id="-origin-story"&gt;📖 Origin Story &lt;a class="anchor" href="#-origin-story" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;You know how sometimes you&amp;rsquo;re just casually browsing the internet, not looking to have an existential crisis? Well, that&amp;rsquo;s exactly what happened when I stumbled upon Tim Urban&amp;rsquo;s Wait But Why post &amp;ldquo;Your Life in Weeks&amp;rdquo; and saw Kurzgesagt&amp;rsquo;s &amp;ldquo;Calendar of Your Life&amp;rdquo; poster. Instead of just feeling mildly anxious about the finite nature of existence like a normal person, I decided to cope by writing some Python code. Because that&amp;rsquo;s what we do, right?&lt;/p&gt;&#10;&lt;h2 id="-technical-highlights"&gt;🔧 Technical Highlights &lt;a class="anchor" href="#-technical-highlights" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The project uses matplotlib to create a grid where:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Each row represents one year (up to 80 years, optimistically speaking!)&lt;/li&gt;&#10;&lt;li&gt;Each column represents one week (52 weeks per year)&lt;/li&gt;&#10;&lt;li&gt;Different colors show different life stages (early childhood, school, university, etc.)&lt;/li&gt;&#10;&lt;li&gt;The current week blinks in the animated version, just in case you needed a more urgent reminder of time passing&lt;/li&gt;&#10;&lt;li&gt;Supports both dark and light modes, because existential dread comes in all themes&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;One interesting technical detail is handling the fact that 52 weeks isn&amp;rsquo;t exactly one year. The code uses a small correction factor (&lt;code&gt;days_per_week = 365.25 / 52&lt;/code&gt;) to ensure the visualization stays accurate over many years. Yes, I made sure your existential crisis would be mathematically precise.&lt;/p&gt;&#10;&lt;h2 id="-impact"&gt;📊 Impact &lt;a class="anchor" href="#-impact" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;With its whopping 5 GitHub stars, this project clearly hasn&amp;rsquo;t taken the world by storm. But hey, sometimes the best tools are the ones we make for ourselves, right?&lt;/p&gt;&#10;&lt;h2 id="-challenges-and-solutions"&gt;🎯 Challenges and Solutions &lt;a class="anchor" href="#-challenges-and-solutions" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The main challenges were (this was actually a very simple one):&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Accurately mapping life events to week numbers (turns out life doesn&amp;rsquo;t fit neatly into boxes)&lt;/li&gt;&#10;&lt;li&gt;Creating smooth animations for the current week indicator (because a blinking dot really drives home the whole &amp;ldquo;time is passing&amp;rdquo; thing)&lt;/li&gt;&#10;&lt;li&gt;Handling the 52 vs 52.18 weeks per year discrepancy (thanks, Earth&amp;rsquo;s orbit)&lt;/li&gt;&#10;&lt;li&gt;Making the visualization work well in both dark and light modes (for viewing your life calendar at any time of day)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="-lessons-learned"&gt;💡 Lessons Learned &lt;a class="anchor" href="#-lessons-learned" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;This project taught me that sometimes the most impactful tools are the simplest ones. Sure, it&amp;rsquo;s just a bunch of dots on a grid, but each dot represents a week of life - past, present, or future. It&amp;rsquo;s a humbling reminder that while we can&amp;rsquo;t add more dots to our grid, we can try to make each one count.&lt;/p&gt;&#10;&lt;p&gt;Want to contemplate your own mortality in a more organized way? Check out the &lt;a href="https://github.com/basnijholt/calendar-of-life" target="_blank" rel="noopener"&gt;project on GitHub&lt;/a&gt;!&lt;/p&gt;&#10;&lt;p&gt;#OpenSource #Python #DataVisualization #Programming&lt;/p&gt;&#10;</description></item><item><title>Crafting unique Ph.D. thesis covers with Python 🎨</title><link>https://www.nijho.lt/post/thesis-cover/</link><pubDate>Sat, 04 Apr 2020 13:40:00 +0000</pubDate><guid isPermaLink="false">/post/thesis-cover/</guid><description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://quantumtinkerer.tudelft.nl/blog/thesis-cover/" target="_blank" rel="noopener"&gt;quantumtinkerer.tudelft.nl/blog/thesis-cover&lt;/a&gt; on 2020-04-04 13:40.&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;I will hand out around a hundred copies of my thesis to my defense committee, colleagues, and my family and friends.&#10;Let&amp;rsquo;s be honest, most people will probably not get further than attempting to read the summary and appreciating the cover.&#10;Four years of work has gone into generating the content of the thesis, so I figured, at least some thought has to go into the design of its cover.&#10;Unfortunately, I am by no means an expert on a graphical design or even competent enough to attempt to use any kind of graphic design software.&#10;But luckily for me, I do consider myself an expert in Python &lt;i class="fab fa-python"&gt;&lt;/i&gt;, and why not make the thesis design a fun process?&lt;/p&gt;&#10;&lt;h2 id="initial-design-adaptive-sampling-and-data-visualization"&gt;Initial Design: Adaptive Sampling and Data Visualization &lt;a class="anchor" href="#initial-design-adaptive-sampling-and-data-visualization" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;My vague plan was to somehow incorporate a plot resulting from a simulation run with &lt;a href="https://adaptive.readthedocs.io/" target="_blank" rel="noopener"&gt;Adaptive&lt;/a&gt; [&lt;a href="https://github.com/python-adaptive/adaptive" target="_blank" rel="noopener"&gt;source&lt;/a&gt; &lt;i class="fab fa-github"&gt;&lt;/i&gt;], the software I wrote during my Ph.D. to adaptively sample functions in parallel and my proudest work.&#10;I even had a potential simulation result in mind that I would use for it, specifically, one that has been on the background of my good friend’s phone for some years and one that has earned me quite some internet points on &lt;a href="https://www.reddit.com/r/dataisbeautiful/comments/eaap3p/python_quantum_research_art_saving_1000s_hours_of/" target="_blank" rel="noopener"&gt;Reddit&lt;/a&gt;.&#10;This plot (below) is one of the results of Chapter 4 of &lt;a href="http://files.nijho.lt/thesis.pdf" target="_blank" rel="noopener"&gt;my thesis&lt;/a&gt; [&lt;a href="https://github.com/basnijholt/thesis" target="_blank" rel="noopener"&gt;source&lt;/a&gt; &lt;i class="fab fa-github"&gt;&lt;/i&gt;] and &lt;a href="https://arxiv.org/abs/1807.01940%ef%bf%bc" target="_blank" rel="noopener"&gt;this paper&lt;/a&gt;.&lt;/p&gt;&#10;&lt;video style="width: 100%;max-width: 500px;" controls&gt;&#10; &lt;source src="https://user-images.githubusercontent.com/6897215/233811442-ce9bc475-af15-4b89-9578-67925419b769.mp4" type="video/mp4"&gt;&#10; Your browser does not support the video tag.&#10;&lt;/video&gt;&#10;&lt;p&gt;I went back to the code that generates the plot and started hacking away in Matplotlib.&#10;Quickly, I realized that not only the plot above was going to look cool, but that many other data sets that I had also resulted in beautiful patterns.&#10;I hit the paradox of choice: I had a total of &lt;em&gt;3671&lt;/em&gt; unique data sets (all for Majorana devices with either different parameter sweeps or different physical effects that were included in the model) and no idea how I was going to make a selection.&lt;/p&gt;&#10;&lt;p&gt;This is an early attempt (and rather ugly in hindsight)&lt;/p&gt;&#10;&lt;figure&gt;&lt;img src="https://user-images.githubusercontent.com/6897215/233811538-dc3b5b86-6f6f-4bd6-840c-e466918ce151.jpeg" alt="early-attempt" loading="lazy" data-zoomable&gt;&lt;/figure&gt;&lt;p&gt;I decided to postpone the choice of which data to use and just focus on how to plot the data first.&#10;I experimented with different colormaps, fading colormaps that gradually reveal the underlying triangulation better, and more.&#10;On a weekend night, after telling &lt;a href="https://github.com/sbalk" target="_blank" rel="noopener"&gt;a friend&lt;/a&gt; I was with about my plans, we (as usually happens) started to program some of the ideas we came up with.&#10;We settled on a design where the triangulation would slowly fade from the top to bottom and where each triangle simultaneously transitioned from a solid color (the average of the values at its vertices) to densely interpolated values.&#10;See &lt;a href="https://github.com/basnijholt/thesis-cover/blob/master/generate-covers.ipynb" target="_blank" rel="noopener"&gt;this Jupyter notebook&lt;/a&gt; which generated the final version of the cover.&#10;After we also chose a nice colormap (by simply creating the cover for each possible colormap,) the following was suggested: “You know what would be even cooler?! To make every cover unique.”&#10;Ten minutes later, I had started 3671 jobs on our computational cluster.&#10;When the files slowly started to appear on my computer (I have my local files synced with the cluster), we could not have been more excited.&#10;There were simply so many cool looking alternatives.&#10;Too many to manually select now, to be honest&amp;mdash;a problem for later I thought.&lt;/p&gt;&#10;&lt;h2 id="overcoming-the-paradox-of-choice-clustering-and-neural-networks"&gt;Overcoming the Paradox of Choice: Clustering and Neural Networks &lt;a class="anchor" href="#overcoming-the-paradox-of-choice-clustering-and-neural-networks" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Four months later, with the rest of my thesis completely done and about a day left on the deadline to submit my thesis, I found myself facing the selection problem I had successfully ignored for so long.&#10;There must be a smarter way to select the covers, I thought.&#10;Many of them look roughly similar (and some of them are even quite boring or not ecstatically pleasing), so it does not make sense to scroll through all of them.&#10;I could cluster them by similarity and then I would just have to choose the nicely looking clusters while being able to instantly discard many.&lt;/p&gt;&#10;&lt;p&gt;Finally, a good application to use neural networks!&lt;/p&gt;&#10;&lt;p&gt;I still had the 3671 covers in pdf format in some folder, so using the wonderful &lt;a href="https://www.gnu.org/software/parallel/" target="_blank" rel="noopener"&gt;GNU Parallel&lt;/a&gt;, I converted and rasterized all of them to jpeg with&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -iname &lt;span class="se"&gt;\*&lt;/span&gt;pdf -print0 &lt;span class="p"&gt;|&lt;/span&gt; parallel -0 sips -s format jpeg &lt;span class="o"&gt;{}&lt;/span&gt; --out &lt;span class="o"&gt;{&lt;/span&gt;.&lt;span class="o"&gt;}&lt;/span&gt;.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I used a pre-trained convolutional neural network model (&lt;a href="https://keras.io/applications/#vgg16" target="_blank" rel="noopener"&gt;VGG16&lt;/a&gt;) to extract features in a lower-dimensional representation.&#10;I fed the feature arrays to a &lt;a href="https://en.wikipedia.org/wiki/K-means_clustering" target="_blank" rel="noopener"&gt;K-Means clustering algorithm&lt;/a&gt; that sorted them in 80 clusters.&#10;To procrastinate a little more, I created an interactive widget using &lt;a href="https://ipywidgets.readthedocs.io/" target="_blank" rel="noopener"&gt;&lt;code&gt;ipywidgets&lt;/code&gt;&lt;/a&gt; (see video below) to facilitate the selection process.&lt;/p&gt;&#10;&lt;video style="width: 100%;max-width: 800px;" controls&gt;&#10; &lt;source src="https://user-images.githubusercontent.com/6897215/233811575-98ea0be2-33f4-47f4-b3ee-f8e7bdf3c475.mp4" type="video/mp4"&gt;&#10; Your browser does not support the video tag.&#10;&lt;/video&gt;&#10;&lt;p&gt;These are the clusters that I selected in a grid&lt;/p&gt;&#10;&lt;figure&gt;&lt;img src="https://user-images.githubusercontent.com/6897215/233811546-36be2cec-eb8c-437a-88d1-595a8602a7ba.jpeg" alt="chosen-clusters-front-and-back" loading="lazy" data-zoomable&gt;&lt;/figure&gt;&lt;p&gt;The selection process was done using &lt;a href="https://github.com/basnijholt/thesis-cover/blob/master/thesis-cover-selection.ipynb" target="_blank" rel="noopener"&gt;this Jupyter notebook&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Finally, I copied the selected clusters into different folders and used the OS&amp;rsquo;s file explorer to manually select a few covers from each cluster.&lt;/p&gt;&#10;&lt;h2 id="final-touches-fine-tuning-colors-and-adding-edition-numbers"&gt;Final Touches: Fine-Tuning Colors and Adding Edition Numbers &lt;a class="anchor" href="#final-touches-fine-tuning-colors-and-adding-edition-numbers" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Then I printed an initial version of my thesis, however, I wasn&amp;rsquo;t really happy with the colors.&lt;/p&gt;&#10;&lt;p&gt;To choose the right color scheme I got help from a non-tech savvy friend who went to art school.&#10;Due to the COVID-19 crisis, we couldn&amp;rsquo;t sit side by side, so I created &lt;a href="https://mybinder.org/v2/gh/basnijholt/thesis-cover/master?filepath=color-picker.ipynb" target="_blank" rel="noopener"&gt;this Binder &amp;ldquo;app&amp;rdquo;&lt;/a&gt; with sliders.&lt;/p&gt;&#10;&lt;video style="width: 100%;max-width: 800px;" controls&gt;&#10; &lt;source src="https://user-images.githubusercontent.com/6897215/233811609-8fa74955-0c51-443e-9a87-115921530b7d.mp4" type="video/mp4"&gt;&#10; Your browser does not support the video tag.&#10;&lt;/video&gt;&#10;&lt;p&gt;Additionally, since all of them were different anyway, I gave them an identifier and added&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;edition n of 120&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;to the back.&lt;/p&gt;&#10;&lt;p&gt;These are a few examples of the final result (click on one of the images to open gallery view)&lt;/p&gt;&#10;&lt;div class="gallery"&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0061.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0061.pickle_hu_8e2f6288e2299f4b.webp" width="350" height="242" alt="Image 1 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0087.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0087.pickle_hu_cfe0a7647b8b4d1a.webp" width="350" height="242" alt="Image 2 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0094.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0094.pickle_hu_4767f3839b1f22bc.webp" width="350" height="242" alt="Image 3 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0119.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0119.pickle_hu_9a20ab2d5318b96f.webp" width="350" height="242" alt="Image 4 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0254.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha__data_learner_0254.pickle_hu_e670a31aca40cc2e.webp" width="350" height="242" alt="Image 5 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha2__data_learner_0175.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-alpha2__data_learner_0175.pickle_hu_236481dab96c15b5.webp" width="350" height="242" alt="Image 6 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-rotation-0-90-move-so-slowly__data_learner_0457.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-rotation-0-90-move-SO-slowly__data_learner_0457.pickle_hu_cc81d6c6a833f7ce.webp" width="350" height="242" alt="Image 7 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-rotation-0-90-move-so-slowly__data_learner_0699.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-rotation-0-90-move-SO-slowly__data_learner_0699.pickle_hu_4744ce916ab208d2.webp" width="350" height="242" alt="Image 8 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-rotation-0-90-move-so-slowly__data_learner_0811.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__gradient-sweep-rotation-0-90-move-SO-slowly__data_learner_0811.pickle_hu_5f6e91d59b7c978e.webp" width="350" height="242" alt="Image 9 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__mu-sweep2__data_learner_0179.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__mu-sweep2__data_learner_0179.pickle_hu_ad9a40d0f92c3c0f.webp" width="350" height="242" alt="Image 10 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__mu-sweep2__data_learner_0254.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__mu-sweep2__data_learner_0254.pickle_hu_2e0e64805618b36d.webp" width="350" height="242" alt="Image 11 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10; &lt;a href="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__mu-sweep2__data_learner_0255.pickle.jpg"&gt;&lt;img src="https://www.nijho.lt/media/albums/basnijholt-thesis-cover/data__mu-sweep2__data_learner_0255.pickle_hu_e7bc31a50788a8cd.webp" width="350" height="242" alt="Image 12 of 12" loading="lazy" data-zoomable&gt;&lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;A few days later, this was delivered to my doorstep&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/6897215/233811518-bd5426d6-05bc-4c7a-854a-4c373aa21fcf.jpg" alt="theses-everywhere" loading="lazy" data-zoomable&gt;&#10;&lt;img src="https://user-images.githubusercontent.com/6897215/233811525-645b67a4-a9ea-48ba-a391-4639ed92c19d.jpg" alt="printed" loading="lazy" data-zoomable&gt;&lt;/p&gt;&#10;&lt;p&gt;And finally I mailed them to my Ph.D. committee&lt;/p&gt;&#10;&lt;figure&gt;&lt;img src="https://user-images.githubusercontent.com/6897215/233811533-3b85ff8d-8359-453b-8aa1-ef653629a0f4.jpg" alt="mail" loading="lazy" data-zoomable&gt;&lt;/figure&gt;&lt;p&gt;Now it&amp;rsquo;s time to start preparing for my defense at May 11, 2020 at 15:00!&lt;/p&gt;&#10;&lt;h3 id="notes"&gt;Notes &lt;a class="anchor" href="#notes" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;The data and code to generate all printed covers is available at &lt;a href="https://github.com/basnijholt/thesis-cover" target="_blank" rel="noopener"&gt;basnijholt/thesis-cover&lt;/a&gt; &lt;i class="fab fa-github"&gt;&lt;/i&gt;&lt;/li&gt;&#10;&lt;li&gt;The simulation code that generates the data is available at &lt;a href="https://github.com/basnijholt/spin-orbit-nanowires" target="_blank" rel="noopener"&gt;basnijholt/spin-orbit-nanowires&lt;/a&gt; &lt;i class="fab fa-github"&gt;&lt;/i&gt;&lt;/li&gt;&#10;&lt;li&gt;The video of the Reddit post is generated using &lt;a href="https://gist.github.com/basnijholt/7aaeb7b9c506f830e6791d264a6cf467" target="_blank" rel="noopener"&gt;this code&lt;/a&gt; &lt;i class="fab fa-github"&gt;&lt;/i&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>