<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  
  <title>Enigmeta</title>
  <subtitle>Writing by Frederik De Bleser, designer, researcher and teacher at Sint Lucas Antwerpen.</subtitle>
  <link href="https://enigmeta.com/atom.xml" rel="self" />
  <link href="https://enigmeta.com/" />
  <updated>2026-02-19T00:00:00Z</updated>
  <id>https://enigmeta.com/</id>
  <author>
    <name>Frederik De Bleser</name>
  </author>
  <entry>
    <title>Fighting Cognitive Debt in Agentic Code with Video Overviews</title>
    <link href="https://enigmeta.com/posts/2026-02-19-video-overviews-for-agentic-code/" />
    <updated>2026-02-19T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2026-02-19-video-overviews-for-agentic-code/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;AI writes code faster than I can understand it — so now the system generates narrated videos of itself.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I used &lt;a href=&quot;https://claude.ai/code&quot;&gt;Claude Code&lt;/a&gt; to build &lt;a href=&quot;https://github.com/fdb/vamos&quot;&gt;Vamos&lt;/a&gt;, a polyphonic synthesizer plugin in C++20, based on Ableton&#39;s Drift. A working synth in a few hours — but since I didn&#39;t write any of the code, I&#39;m missing the crucial part: understanding what was actually implemented.&lt;/p&gt;
&lt;p&gt;Margaret-Anne Storey &lt;a href=&quot;https://margaretstorey.com/blog/2026/02/09/cognitive-debt/&quot;&gt;calls this &amp;quot;cognitive debt&amp;quot;&lt;/a&gt;: gaps in human comprehension that widen even when the code itself is perfectly fine. Agentic coding amplifies this — the code arrives faster than your ability to absorb it. So I tried something different: &lt;strong&gt;what if the synth code also generates narrated video walkthroughs that explain it?&lt;/strong&gt; Using &lt;a href=&quot;https://www.remotion.dev/&quot;&gt;Remotion&lt;/a&gt; for programmatic video and &lt;a href=&quot;https://elevenlabs.io/&quot;&gt;ElevenLabs&lt;/a&gt; for voice-over, the whole thing feels like a natural YouTube series.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/video-overviews-for-agentic-code/vamos-ui.png&quot; alt=&quot;The Vamos synthesizer UI — dark synthwave theme with signal flow, knobs, and modulation controls&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/video-overviews-for-agentic-code/ep01-signal-flow.png&quot; alt=&quot;Signal flow diagram from the video: Osc1 + Osc2 + Noise → Mixer → Filter → Amp Envelope → Output&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s the first episode — an 8-minute walkthrough of Phase 1, from an empty project to a working eight-voice polyphonic synth:&lt;/p&gt;
&lt;div class=&quot;embed-responsive embed-responsive-16by9&quot;&gt;
  &lt;iframe class=&quot;embed-responsive-item&quot; src=&quot;https://www.youtube.com/embed/B-rts5qSmZY&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;The video pipeline&lt;/h2&gt;
&lt;p&gt;The videos are built with Remotion — each visual element (code blocks, waveform visualizers, architecture diagrams) is a React component that animates based on frame count. Because these are code, you can create domain-specific visualizations. Here&#39;s an ADSR envelope, color-coded by phase, with the overshoot line clearly marked:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/video-overviews-for-agentic-code/ep01-adsr.png&quot; alt=&quot;Color-coded ADSR envelope with overshoot line at 1.2&quot;&gt;&lt;/p&gt;
&lt;p&gt;The production workflow has two passes:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pass 1: Structure and mute review.&lt;/strong&gt; Claude Code outlines the episode, writes the narration transcript, and builds the Remotion scenes — but doesn&#39;t generate audio yet. Instead, it renders a mute video with burned-in captions. I review, give feedback, Claude Code adjusts and re-renders. This is where most of the iteration happens, without spending TTS credits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pass 2: Voiceover and retiming.&lt;/strong&gt; Once the mute video looks right, Claude Code generates voiceover through ElevenLabs. The audio durations then dictate final timing: each segment&#39;s length gets converted to frames, and scene durations are recalculated to match.&lt;/p&gt;
&lt;p&gt;A useful ElevenLabs detail: since each narration segment is a separate API call, voice quality can drift between segments. The generation script passes adjacent segment text as context (&lt;code&gt;previous_text&lt;/code&gt; / &lt;code&gt;next_text&lt;/code&gt;) and chains request IDs, so each segment is conditioned on the actual audio of the one before it.&lt;/p&gt;
&lt;p&gt;The result is that code and visuals work together in ways that comments never can. When SmoothedValue code appears alongside a before/after waveform comparison — the click artifact versus the smooth ramp — you &lt;em&gt;see&lt;/em&gt; why it matters:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/video-overviews-for-agentic-code/ep01-smoothed-value.png&quot; alt=&quot;SmoothedValue: code plus before/after waveform comparison showing click versus smooth ramp&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Where this could go&lt;/h2&gt;
&lt;p&gt;Three levels of video overview worth exploring:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;In the weeds&amp;quot;&lt;/strong&gt; — You open a PR, and a two-minute narrated video walks the reviewer through the changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Diving back in&amp;quot;&lt;/strong&gt; — You return from vacation, hit a button, and a video catches you up on what changed while you were away.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Archaeology&amp;quot;&lt;/strong&gt; — Historical deep dives that capture the &lt;em&gt;reasoning&lt;/em&gt; behind decisions, the part that&#39;s hardest to recover from code alone.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/video-overviews-for-agentic-code/ep02-waveforms.png&quot; alt=&quot;Waveform shape visualizer from Episode 2 — saw, rectangle, sharktooth, and saturated waveforms responding to a shape parameter&quot;&gt;&lt;/p&gt;
&lt;p&gt;Video isn&#39;t necessarily the final form — Simon Willison has been exploring &lt;a href=&quot;https://simonwillison.net/2026/Feb/17/release-notes-webcomic/&quot;&gt;web comics&lt;/a&gt; for the same purpose. But the pattern of narration-driven explanation (structure → transcript → mute review → TTS + retiming) works well and isn&#39;t specific to any particular type of code.&lt;/p&gt;
&lt;p&gt;The code has become easy. Understanding is the hard part.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>NodeBox: Data Visualisation Made in Belgium</title>
    <link href="https://enigmeta.com/posts/2019-09-26-nodebox-data-visualisation-made-in-belgium/" />
    <updated>2019-09-26T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2019-09-26-nodebox-data-visualisation-made-in-belgium/</id>
    <content type="html">&lt;p&gt;On 26 September 2019 I gave a talk at Dataviz BXL, a data visualisation meetup organised by Digityser in Brussels, on an evening themed &amp;quot;data visualisation made in Belgium&amp;quot;. I talked about &lt;a href=&quot;https://www.nodebox.net/&quot;&gt;NodeBox&lt;/a&gt;, the tool we build at &lt;a href=&quot;https://www.sintlucasantwerpen.be/&quot;&gt;Sint Lucas Antwerpen&lt;/a&gt;: where it comes from, how it works, and what people have made with it. This is a cleaned-up version of that talk, with the slides on the left.&lt;/p&gt;
&lt;div class=&quot;talk&quot;&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-02.jpg&quot; alt=&quot;The glass and wood façade of the Sint Lucas Antwerpen building&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;I work at Sint Lucas Antwerpen, an art college where we teach painting, sculpture, photography, graphic design, advertising and illustration. Because it is an academic institution it also does research, and that is where I work, in a research group called EMRG. We develop NodeBox.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;NodeBox 1&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-05.jpg&quot; alt=&quot;Pages from Design by Numbers by John Maeda (1999), with small programs and their output&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-06.jpg&quot; alt=&quot;The Processing editor next to a sketch by Casey Reas and Ben Fry (2001)&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;NodeBox started from software like John Maeda&#39;s &lt;em&gt;Design by Numbers&lt;/em&gt; (1999), made to teach programming to designers. You write very small programs that draw into a square of 100 by 100 pixels. It is an imperative way of programming: each line is a command that does something.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://processing.org/&quot;&gt;Processing&lt;/a&gt;, by Casey Reas and Ben Fry, grew out of the same ideas, and we started NodeBox around the same time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-07.jpg&quot; alt=&quot;NodeBox 1 (2004): a window with a generated composition of circles on the left and Python code on the right&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;NodeBox 1 (2004) works much like Processing. It was built on DrawBot by LettError, which is still active today. The visuals are on one side, the code on the other, and the errors at the bottom, which is where you look most of the time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/painters-model.gif&quot; alt=&quot;Animation of the painter&#39;s model: fill, rect, ellipse and fill commands are executed one by one and drawn on top of each other&quot; width=&quot;1920&quot; height=&quot;1080&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;You type a command and it gets painted. This is called the painter&#39;s model, and you know it if you have worked with Canvas or OpenGL. A command sets some state, such as the fill colour, and the drawing commands after it use that state.&lt;/p&gt;
&lt;p&gt;It works well, but you have to keep the state of the program in your head at every point. If you copy a few lines to another place and forget the &lt;code&gt;fill&lt;/code&gt; line, the result changes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-10.jpg&quot; alt=&quot;Organic Dots by Veronika Schmidt (2008): dense, hairy circular forms built from small drawn shapes&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;We run a lot of workshops with this software, and none of the students are programmers. They draw basic shapes in Illustrator or elsewhere, bring them into NodeBox and start manipulating them. &lt;em&gt;Organic Dots&lt;/em&gt; by Veronika Schmidt is an example. These are generative designs rather than data visualisations, and the only data in them is random.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides grid-2&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-12.jpg&quot; alt=&quot;The Evil Font parameter panel with a text field and an Evilness slider set to 0&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-14.jpg&quot; alt=&quot;The word EVIL with a few blood spatters&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-17.jpg&quot; alt=&quot;The word EVIL overgrown with thorns, eyes and pentagrams&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-20.jpg&quot; alt=&quot;The word EVIL at full evilness, buried under scribbles, swords and red splatter&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Some of these programs do take input. The &lt;em&gt;Evil Font&lt;/em&gt; by Valtteri Vitakoski is a generative typeface with one parameter, evilness. At zero it is a plain sans serif. Add some evil and the letters start sprouting thorns, eyes and swords, until at full evilness the word disappears under them.&lt;/p&gt;
&lt;p&gt;What I like about it is that this slider is not one you will find in Illustrator. Students invent their own parameters, make a slider for them, and connect it to whatever they want. People who work in data visualisation know this idea well, but it is still good to see students discover it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-21.jpg&quot; alt=&quot;Spamghetto by TODO: rooms wallpapered with flowing ribbons of text&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-22.jpg&quot; alt=&quot;Close-up of Spamghetto wallpaper with lines of spam text inside curving ribbons&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;&lt;em&gt;Spamghetto&lt;/em&gt;, by the Italian design studio TODO, takes the spam in your mail folder and turns it into wallpaper. You can send them your own spam and they run their NodeBox script on it to make a personal pattern. In the close-up you can read a mail &amp;quot;from the desk of the president of Trump University&amp;quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;NodeBox 3&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-24.jpg&quot; alt=&quot;The NodeBox Live interface: a list of nodes, a network of connected nodes, and a colour wheel made of thousands of points&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;The biggest problem with NodeBox 1 turned out to be the programming. Many of the people we teach are graphic designers and illustrators who have no background in programming and are not much interested in it. We tried teaching them, and it works for some people but not for everybody.&lt;/p&gt;
&lt;p&gt;So we tried to turn the model around, and that became NodeBox 3. It is a visual application that requires no programming. You build a visualisation from small building blocks, which we call nodes, and each node does one part of the work. (This screenshot is of NodeBox Live, the later web version, which I come back to below.)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-25.jpg&quot; alt=&quot;A Volkswagen Beetle assembly line&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-26.jpg&quot; alt=&quot;A diagram of a path from &#39;data&#39; to &#39;visuals&#39; with four intermediate steps&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Think of a factory assembly line. The cars move down the line and every station does one part of the job.&lt;/p&gt;
&lt;p&gt;We are going from data to visuals instead of building cars, and there are intermediate steps on the way. We process the data until it has the right shape. At some point we turn a value into a visual property: the width of a bar in a bar chart, the radius of a circle, a position on a map after a projection.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-27.jpg&quot; alt=&quot;A NodeBox network: import CSV, three lookups, convert and multiply, textpath, rect and line angle, colorize and align, merge&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Here is a simple network. We import a CSV file, and lookup nodes extract the columns we need. The data is rarely in the form we want, so we convert it: we change the range from millions to pixels, or simply multiply. Then we generate shapes from the data, such as text on a path, rectangles or lines, and modify them further by aligning or colouring them. A merge node combines everything into the finished visualisation.&lt;/p&gt;
&lt;p&gt;The whole application uses this one consistent system, which makes it easy to learn.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-28.jpg&quot; alt=&quot;A grid of eight black and white geometric patterns&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;You don&#39;t need to understand the whole process to use it. You can take an existing NodeBox file and start changing its parameters without touching its structure. All of these designs come from the same network; only the parameter values differ.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-29.jpg&quot; alt=&quot;Screenshots of NodeBox 2, NodeBox 3 and NodeBox Live side by side&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;There have been several versions. NodeBox 2 worked quite differently and is no longer supported. NodeBox 3 and NodeBox Live share the same evaluation model. NodeBox 3 is an open source desktop application, and NodeBox Live runs in the browser.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Examples&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-30.jpg&quot; alt=&quot;Shipwrecks of California by Jan Aulbach (2012): a vertical timeline of shipwrecks, each bar sized by tonnage&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Jan Aulbach made &lt;em&gt;Shipwrecks of California&lt;/em&gt; in a data visualisation workshop we gave in The Hague. It is a timeline of the ships that wrecked off the Californian coast, each sized by its tonnage. In the early years there are many wrecks as maritime traffic grows. Later, safety improves and wrecks become rare, but when one happens it is a much bigger ship.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-31.jpg&quot; alt=&quot;North Sea Fish by Katju Aro: curved bands for each species of fish, all declining from left to right&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Katju Aro visualised the declining stock of fish in the North Sea, with a colour for each species. It is a dramatic picture: nearly every band goes down.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-32.jpg&quot; alt=&quot;The poster Fifty Years of Film Speech by Jonas Lekevicius and Juste Ziliute&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;&lt;em&gt;Fifty Years of Film Speech&lt;/em&gt; by Jonas Lekevicius and Juste Ziliute is one of my favourites because it brings everything together. They took the subtitles of the fifty most popular films of each year, over fifty years, and kept the fifty most frequent words. For every word they drew a sound wave that shows how often it is spoken over time.&lt;/p&gt;
&lt;p&gt;A lot of data preparation happened before the data reached NodeBox. Not everything can be done inside it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides grid-2&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-33.jpg&quot; alt=&quot;Raw JSON data with word frequencies per year&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-34.jpg&quot; alt=&quot;An Excel line chart with all fifty words plotted on top of each other&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-35.jpg&quot; alt=&quot;NodeBox with the sound-wave shapes for oh, yeah, look, time and gonna, and the network next to it&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-36.jpg&quot; alt=&quot;Close-up of the poster with sound waves for hell, baby, child, dad, mom, wife, gun and other words&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;If you put the raw data into Excel with every word on top of each other, you get the chart on the top right. That is a bit unfair to Excel; you would use small multiples instead.&lt;/p&gt;
&lt;p&gt;NodeBox let them build their own visualisation, a sound-wave shape, which suits a project about speech. Like the evilness slider, the sound wave is a custom node: a small network packaged as a single node. You attach data to it and the shape comes out. The last image is a close-up of the words changing over time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-37.jpg&quot; alt=&quot;Off the Staff by Nicholas Rougeux (2016): a circular burst of coloured dots representing a musical score&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-38.jpg&quot; alt=&quot;Ten Off the Staff visualisations of pieces by Tchaikovsky, Schubert, Mozart, Beethoven, Vivaldi and Bach&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Nicholas Rougeux visualises musical scores in a series called &lt;em&gt;Off the Staff&lt;/em&gt;. Each image is a whole piece: Tchaikovsky&#39;s &lt;em&gt;1812 Overture&lt;/em&gt;, Vivaldi&#39;s &lt;em&gt;Autumn&lt;/em&gt;, a Brandenburg Concerto. He uses NodeBox among other tools, and he writes about his process, which shows that NodeBox gets used outside the classroom too.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides grid-2&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-39.jpg&quot; alt=&quot;Nicholas Rougeux&#39;s blog post Making of Off the Staff, with the tools of the process&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-40.jpg&quot; alt=&quot;Bach&#39;s Toccata and Fugue in D minor in MuseScore&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-41.jpg&quot; alt=&quot;An online XML to CSV converter&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-42.jpg&quot; alt=&quot;The note data in Google Sheets, with columns for duration, octave, note and order&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;His &lt;a href=&quot;https://www.c82.net/blog/?id=72&quot;&gt;making-of post&lt;/a&gt; explains every step. He opens the score in MuseScore, exports it from MIDI to MusicXML, converts the XML to CSV, and cleans it up in Google Sheets, because no data visualisation project is finished without a spreadsheet. Then it goes into NodeBox.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-43.jpg&quot; alt=&quot;NodeBox with an Off the Staff visualisation in the viewer and the network below&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-44.jpg&quot; alt=&quot;The Off the Staff network, with groups of nodes numbered 1 to 11&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;He numbered the parts of his network, which makes it a good illustration of the model I described. It starts by importing the CSV. The blue nodes process the data. They compute the current time from the frame number (NodeBox renders video at 30 frames per second and the data is in seconds), a colour per instrument, an angle starting at twelve o&#39;clock, a circle size from the note&#39;s duration, and a distance from the centre from its pitch and octave.&lt;/p&gt;
&lt;p&gt;From step 10 the nodes turn dark. Those are visual nodes, where numbers become shapes. A &lt;code&gt;rect&lt;/code&gt; node, for example, has four input ports for x, y, width and height, and what it draws depends on what you connect to each.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-45.jpg&quot; alt=&quot;Literary Constellations by Nicholas Rougeux (2017): four circular star charts made from books&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;There is much more on his site, &lt;a href=&quot;https://www.c82.net/&quot;&gt;c82.net&lt;/a&gt;, such as &lt;em&gt;Literary Constellations&lt;/em&gt; (2017).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;List matching&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-47.jpg&quot; alt=&quot;A translate node with a list of numbers 0 to 9 and a list of ten dots as input, producing ten numbers&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-48.jpg&quot; alt=&quot;A translate node with one triangle and ten dots as input, producing ten triangles&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-49.jpg&quot; alt=&quot;A translate node with a triangle and a square and ten dots as input, producing alternating triangles and squares&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;All these examples work on many data points, so where are the loops? NodeBox behaves like a functional programming language. There are no explicit loops; NodeBox loops over everything implicitly, using a system we call list matching.&lt;/p&gt;
&lt;p&gt;When a node gets two lists, it pairs them element by element. Say the dots are positions and the numbers are data: the first number goes to the first dot, the second to the second, and so on.&lt;/p&gt;
&lt;p&gt;If one list has a single element and the other has many, the single element is repeated. With other lengths, such as two shapes and ten positions, the shorter list wraps around and the shapes alternate. The output is as long as the longest list.&lt;/p&gt;
&lt;p&gt;This works well in practice, and it makes it easy to see what every node is doing.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Visual debugging&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/demo-broken.jpg&quot; alt=&quot;Photo of the projected demo: NodeBox with a circle of word labels and no lines inside, and the network on the right&quot; width=&quot;1280&quot; height=&quot;720&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/demo-fixed.jpg&quot; alt=&quot;Photo of the projected demo after the fix: the circle is filled with coloured lines connecting the words&quot; width=&quot;1280&quot; height=&quot;720&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Because every node does something concrete, you can always check where things go wrong. We use this when teaching: once students know a bit of NodeBox, we ask them to swap computers with the person next to them and break their network. Then everyone has to find the bug in their own.&lt;/p&gt;
&lt;p&gt;In the demo I opened a network that visualises the words used across all Metallica albums. I expected lines inside the circle and saw none. The viewer shows the output of the node at the bottom, a combine node that merges everything. I clicked my way up through the network. The text around the circle was fine, but the coloured lines were missing. Further up, a lookup node that should have returned the list of albums returned nothing, because of a mistake in its settings. After fixing it, I stepped back down node by node, checked the lines, the colours and the combine, and the visualisation appeared.&lt;/p&gt;
&lt;p&gt;In an imperative program with loops, a mistake somewhere in the middle is hard to locate. In NodeBox you go up the network one node at a time, compare the data you see with the data you expect, and find the node where they differ.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;NodeBox Live&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;video src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/dashboard.mp4&quot; poster=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-53.jpg&quot; width=&quot;1280&quot; height=&quot;814&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; preload=&quot;none&quot;&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;NodeBox 3 works well, but it cannot do anything interactive. About two years before the talk we made NodeBox Live, which brings the same model to the web.&lt;/p&gt;
&lt;p&gt;This demo builds a dashboard widget from tweets about telecom operators. Here they are imported from a file, but NodeBox Live also supports real-time data streams. A scale node maps the earliest and latest dates to pixels, those become points, and the port you connect them to decides whether they drive x or y. A sentiment analysis library splits the tweets into positive and negative. We turn them into ellipses, colour them, add a legend and combine everything.&lt;/p&gt;
&lt;p&gt;To put it on a dashboard, we make it smaller, copy a snippet of iframe code and paste it into the dashboard page. The embed stays live, so you can keep adjusting it afterwards. Because the network is a procedure, you can point it at the data of another operator. The other charts on the dashboard, such as the word cloud, are NodeBox Live networks too.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;video src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/revolving-door.mp4&quot; poster=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-54.jpg&quot; width=&quot;1100&quot; height=&quot;1376&quot; style=&quot;max-width: 26rem&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;On the web you get everything the web offers, including interactivity, and I like to mix the serious work with less serious student projects. Quinten De Meester was fascinated by how slow the revolving doors in shopping centres are, and wondered what would happen if you could change their parameters.&lt;/p&gt;
&lt;p&gt;His &lt;em&gt;Raging Revolving Door&lt;/em&gt; (2015) lets you set the motor speed, how fast people walk, and how many of them there are, like a busy shopping season versus a normal day. Then you can turn everything up and watch.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;De Standaard&lt;/h2&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-56.jpg&quot; alt=&quot;Cover of the report Jouw gemeente in cijfers, edition 2018, with a municipality sign in tall grass&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-57.jpg&quot; alt=&quot;A page from the report: a dense table of demographic figures with a green header&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Because we work in an academic context, we have to think about how NodeBox can sustain itself, and a commercial version is one option. So we worked with De Standaard on &lt;em&gt;Jouw gemeente in cijfers&lt;/em&gt; (&amp;quot;your municipality in numbers&amp;quot;), a large dataset the Flemish government publishes about every municipality.&lt;/p&gt;
&lt;p&gt;We knew the format in advance but not the data, so we prepared everything and had only a few days once it came out. We worried the report would be so beautiful that we would be out of a job. This is what came out: about 150 pages of tables like this one for every municipality.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides grid-2&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-58.jpg&quot; alt=&quot;Welkom in Edegem: a page with a dark blue skyline of Edegem under a large moon&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-59.jpg&quot; alt=&quot;Welkom in De Panne, with a skyline of the coast and a boat&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-60.jpg&quot; alt=&quot;Welkom in Brugge, with the belfry of Bruges in the skyline&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-61.jpg&quot; alt=&quot;A grid of hundreds of thumbnails, one welcome page per municipality&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;We made a day in the life of someone living in each municipality, from Edegem and De Panne to Bruges and every other one, and the illustrated skyline changes with the place.&lt;/p&gt;
&lt;p&gt;NodeBox generated everything, including the HTML and the text. It has nodes for working with text, so a sentence like &amp;quot;as for the 21,834 other inhabitants of Edegem, your day begins&amp;quot; comes straight out of the network.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides grid-2&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-62.jpg&quot; alt=&quot;Wakker worden, 7.00: an illustrated kitchen with a coffee machine under a lamp&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-63.jpg&quot; alt=&quot;Allez, en route, 7.30, for Zoersel: a long queue of cars next to a cyclist&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-64.jpg&quot; alt=&quot;Allez, en route, 7.30, for Antwerp: only a few cars next to a cyclist&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-65.jpg&quot; alt=&quot;Rows of person icons, a few highlighted, showing that 19.2% of Edegem&#39;s inhabitants are of foreign origin&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Each part of the day has its own visualisations. On the commute, the number of cars on the road follows the data: 75% of people in Zoersel drive to work or school almost every day, against 43% in Antwerp. A row of people shows the share of inhabitants of foreign origin, 19.2% in Edegem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-row&quot;&gt;
&lt;div class=&quot;slides&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-66.jpg&quot; alt=&quot;NodeBox Live with the network for the foreign-origin section next to its output&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-data-visualisation-made-in-belgium/slide-67.jpg&quot; alt=&quot;Ontspannen, 20.30: two illustrated faces, a young man and an older woman, under text about cultural facilities&quot; width=&quot;1200&quot; height=&quot;675&quot; loading=&quot;lazy&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;slide-text&quot;&gt;
&lt;p&gt;Every segment is a NodeBox Live network, and the networks are grouped together. It was a fun project, because illustrators, people working on the data and people building the visualisations all worked on the same thing.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;The future of NodeBox&lt;/h2&gt;
&lt;p&gt;At the time of the talk there were two applications, NodeBox 3 and NodeBox Live. Our plan was to bring them together, with the web version as the standard and something like Electron, which Slack, GitHub Desktop and Spotify use, to run it on the desktop.&lt;/p&gt;
&lt;p&gt;We think it matters to have a tool that is open source, freely available and supported by its community. The speaker before me argued that these tools have to last over time, and I agree. Open source means you can keep using them for as long as you need.&lt;/p&gt;
&lt;p&gt;You can find NodeBox at &lt;a href=&quot;https://www.nodebox.net/&quot;&gt;nodebox.net&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Counting Words with Python 3</title>
    <link href="https://enigmeta.com/posts/2018-03-07-counting-words-with-python-3/" />
    <updated>2018-03-07T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2018-03-07-counting-words-with-python-3/</id>
    <content type="html">&lt;p&gt;This post will get you set up to start processing datasets with Python 3. We will learn how to use the terminal, install Python if you don&#39;t have it already, and write a simple word-counting script that returns the result in CSV.&lt;/p&gt;
&lt;p&gt;A big focus will be on getting you to &amp;quot;Google level experience&amp;quot;, meaning that you will know the right things to search for if you want to do something not mentioned in this article, or if you get stuck. Knowing &lt;em&gt;what&lt;/em&gt; to search for is important to tackle your own data processing jobs.&lt;/p&gt;
&lt;p&gt;During the many NodeBox workshops I&#39;ve given I noticed that students would eventually be able to figure out the visualization on their own, but they had trouble getting the data in the correct shape. Being able to acquire the data (e.g. from an external API), converting it to a format you can use is key to making good visualizations. But first, we need to talk about the terminal.&lt;/p&gt;
&lt;p&gt;Full source code of this project is available here: &lt;a href=&quot;https://gist.github.com/fdb/1c7234fb49757df588c1302f44f0f125&quot;&gt;https://gist.github.com/fdb/1c7234fb49757df588c1302f44f0f125&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Terminal is Your Friend&lt;/h2&gt;
&lt;p&gt;You probably already heard this a number of times, but the Terminal, also known as the command line, is an immensely powerful tool that we&#39;re going to use.&lt;/p&gt;
&lt;p&gt;The command line has been around since the dawn of the computers. Even with all graphical interfaces, people keep coming back to it. The reason is simple: it gives you access to the raw power of your computer. If you want to do something that no one else has done, the terminal is the place to be.&lt;/p&gt;
&lt;p&gt;A good way to look at the terminal is as having a chat conversation with your computer. When you start it up it will be waiting for your command. You give it an instruction and press enter, and the terminal will execute it. It&#39;s a silent partner: often if the command succeeds it will be silent. It doesn&#39;t ask you to brag about the fact you just created a directory to your friends on Facebook.&lt;/p&gt;
&lt;p&gt;Fully understanding the command line can take years. Luckily we just need a few very basic commands: how to switch to the right directory, how to install some software, and how to start and stop our scripts.&lt;/p&gt;
&lt;p&gt;First we need to &lt;em&gt;find&lt;/em&gt; the Terminal. On a Mac, the program is called &amp;quot;Terminal&amp;quot; and can be found using Spotlight, or in the Utilities subfolder under the Applications folder. On Windows, you need to install the Bash terminal. Instructions are here.&lt;/p&gt;
&lt;p&gt;Once you open the Terminal you will get a blank screen with some text. Again, think of it as a chat conversation, not a text editor. You can&#39;t move the cursor to a random position on the screen. Instead you just type a command, press enter, and new text will appear below.&lt;/p&gt;
&lt;p&gt;The place where the terminal is waiting for your input is called the &lt;em&gt;prompt&lt;/em&gt;. After you&#39;ve executed a command, the terminal will show a new prompt, informing you it&#39;s ready for the next command. You don&#39;t always have to wait for the previous command to complete though. Often with long-running jobs (like downloading some images) you can just open another terminal tab or window and continue working there.&lt;/p&gt;
&lt;p&gt;Let&#39;s try our first command. Open the terminal if it&#39;s not open already. Then, type &lt;code&gt;pwd&lt;/code&gt; and press ENTER.&lt;/p&gt;
&lt;p&gt;The terminal will print out your &lt;em&gt;current working directory&lt;/em&gt;. In my case it&#39;s &lt;code&gt;/Users/fdb&lt;/code&gt;. &amp;quot;fdb&amp;quot; is my user name, so yours will probably be somewhat different.&lt;/p&gt;
&lt;p&gt;Already there are two important concepts we need to discuss. One, what&#39;s a &amp;quot;working directory&amp;quot;? And two, what is &lt;em&gt;our&lt;/em&gt; working directory (in other words, where are we?)&lt;/p&gt;
&lt;h2&gt;Working Directory&lt;/h2&gt;
&lt;p&gt;Whenever we type a command in the terminal it executed in the &lt;em&gt;current working directory&lt;/em&gt;. Compare it to a builder constructing a house. If you enter a certain room in the house and execute an operation - say, paint a wall, then that will happen in the room you&#39;re currently in. It&#39;s the same with the terminal. Instead of being in a room, you&#39;re in a certain directory on your file system.&lt;/p&gt;
&lt;h2&gt;Finding your way&lt;/h2&gt;
&lt;p&gt;Modern operating systems try to obscure the directory structure from you but it&#39;s actually quite important. Knowing where your files &lt;em&gt;are&lt;/em&gt; is essential when working in the terminal.&lt;/p&gt;
&lt;p&gt;When the terminal starts up it&#39;ll be in your &lt;em&gt;home directory&lt;/em&gt; (the builder analogy is not that far fetched!). In your home directory you Will have subdirectories - rooms - that contain even more subdirectories (ehm, cupboards, in our analogy). The main subdirectories in your home directory will sound familiar: the desktop, your documents, downloads, movies, pictures.&lt;/p&gt;
&lt;p&gt;The home directory itself is in a folder called &amp;quot;Users&amp;quot;. If you share your computer with other people, they will have &lt;em&gt;their&lt;/em&gt; home folder under a different user name in the &amp;quot;Users&amp;quot; folder.&lt;/p&gt;
&lt;p&gt;The Users folder itself is in the &lt;em&gt;root&lt;/em&gt; of your computer. In addition to a &amp;quot;Users&amp;quot; folder there is also the &amp;quot;Applications&amp;quot; folders. Applications are shared between all users of the computer: if you install a new app it will be available to everybody using the same computer.&lt;/p&gt;
&lt;p&gt;We used the &lt;code&gt;pwd&lt;/code&gt; command to print the current working directory. Hopefully it&#39;s now clear what this prints out:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/Users/fdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The root folder contains a directory called &amp;quot;Users&amp;quot;. In that directory is a folder called &amp;quot;fdb&amp;quot; (or whatever your user name is). The different directories are separated by slashes (&amp;quot;/&amp;quot;).&lt;/p&gt;
&lt;h2&gt;Listing a directory&lt;/h2&gt;
&lt;p&gt;To see which files are in a directory use the &lt;code&gt;ls&lt;/code&gt; command. Type &lt;code&gt;ls&lt;/code&gt; and press enter. This will show you a list of files inside of the current (home) folder. Here are mine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Desktop
Documents
Downloads
Dropbox
Experiments
Google Drive
Library
Movies
Music
Pictures
Public
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You probably recognize some: your desktop, your documents, downloads and so on. All of these are inside our home folder. Note that the desktop is &lt;em&gt;also&lt;/em&gt; a directory, just like your downloads directory.&lt;/p&gt;
&lt;p&gt;The Finder provides a different, somewhat more user-friendly, view on the same information. If we go to the &amp;quot;Go&amp;quot; menu in the finder and choose &amp;quot;Home&amp;quot;, it opens up a window with the same files. It&#39;s important to realize that what the Finder shows and what the terminal views are two views on the same information: the files stored in a directory on your hard drive.&lt;/p&gt;
&lt;h2&gt;Changing Directories&lt;/h2&gt;
&lt;p&gt;Your projects are probably saved in the Documents folder, or the desktop, or maybe the Dropbox folder. Whatever the place we need to switch to that directory before we start executing commands. We&#39;ll use the &lt;code&gt;cd&lt;/code&gt; command, short for &lt;em&gt;change directory&lt;/em&gt;, for that.&lt;/p&gt;
&lt;p&gt;To get to your desktop type the following command and press enter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd Desktop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we type &lt;code&gt;pwd&lt;/code&gt; now (don&#39;t forget to press enter!) we&#39;ll see that the working directory has changed to &lt;code&gt;/Users/fdb/Desktop&lt;/code&gt;. That means we&#39;re in the desktop directory.&lt;/p&gt;
&lt;p&gt;Type &lt;code&gt;ls&lt;/code&gt; to see the files on your desktop:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Screen Shot 2018-03-06 at 23.38.57.png
Screen Shot 2018-03-06 at 23.39.13.png
Screen Shot 2018-03-06 at 23.41.43.png
Screen Shot 2018-03-06 at 23.45.14.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My listing will have very different files from yours. The Desktop starts out empty, and in my case fills up quickly as the deadline approaches!&lt;/p&gt;
&lt;h2&gt;Installing Packages with Homebrew&lt;/h2&gt;
&lt;p&gt;Installing software in the Terminal is done through &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt;. The package we&#39;ll need right now is Python 3, which is not installed by default on the Mac.&lt;/p&gt;
&lt;p&gt;First, let&#39;s install Homebrew. Copy and paste the following line of code in your Terminal and press enter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/ruby -e &amp;quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First this will ask to confirm the directories, just press enter. Then it will ask for your password and show a small key cursor. Type your password here. &lt;em&gt;You will not see any letters appear, that&#39;s okay.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If all goes well we should have a working Homebrew install. Type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and press enter to see a list of options. You&#39;ll type options after the &lt;code&gt;brew&lt;/code&gt; command, separated by a space. The most important ones are &lt;code&gt;brew install&lt;/code&gt; and &lt;code&gt;brew search&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Installing Python 3 using Homebrew&lt;/h2&gt;
&lt;p&gt;Python 3 is not installed by default on your macOS. But maybe you have it through a different installer. Try typing &lt;code&gt;python3&lt;/code&gt;. If the command line responds with &amp;quot;command not found&amp;quot; you don&#39;t have Python installed.&lt;/p&gt;
&lt;p&gt;If you &lt;em&gt;have&lt;/em&gt; Python installed, it will show some text and then the Python &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; prompt. Here, type Ctrl-D (not Command) to exit Python.&lt;/p&gt;
&lt;p&gt;To install Python 3, type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install python
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, you should be able to type &lt;code&gt;python3&lt;/code&gt; (and enter) to start Python in what&#39;s called &lt;em&gt;&amp;quot;interactive mode&amp;quot;&lt;/em&gt;. It will show the version number, and then the Python prompt, indicating it&#39;s listening to your commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you&#39;re having a chat conversation with Python. Try typing &lt;code&gt;3 + 5&lt;/code&gt; (and enter) to let Python calculate something and return a response.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Press Ctrl-D (not Command) to exit Python.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The interactive mode is useful for trying out quick things. In general though, we&#39;ll run Python by executing a scripts. This is a text file with a &lt;code&gt;.py&lt;/code&gt; extension that contains a list of commands we want Python to do, like open a file, download a web page, and so on.&lt;/p&gt;
&lt;h2&gt;Text Editors and Project Folders&lt;/h2&gt;
&lt;p&gt;To edit files we need a plain text editor. This is not Word or LibreOffice, but a program like Sublime Text, Atom or &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;. I prefer the latter since it has an integrated terminal, which will automatically change the directory to the current project path.&lt;/p&gt;
&lt;p&gt;Whenever we work on a data processing folder we should create a &lt;em&gt;project folder&lt;/em&gt;. It&#39;s generally a bad idea just to create files randomly on the desktop, but especially for data processing jobs since they can produce many intermediate folders. Also, our editor works at the folder level, automatically helping us find files in the project folder.&lt;/p&gt;
&lt;p&gt;Create a project folder on the desktop called &amp;quot;dataproc&amp;quot;. You can use the Finder, or you can type the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd
cd Desktop
mkdir dataproc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first &lt;code&gt;cd&lt;/code&gt; here has no directory path and conveniently changes the directory to the home directory no matter where we are.&lt;/p&gt;
&lt;h2&gt;Our First Python Script&lt;/h2&gt;
&lt;p&gt;We&#39;re going to write a small script that will load a file, count the unique words in the file and save the word count as a CSV file.&lt;/p&gt;
&lt;p&gt;First we need to have some content. I&#39;m going to use the American declaration of dependence since it&#39;s freely available. You can download it here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/fdb/1c7234fb49757df588c1302f44f0f125&quot;&gt;https://gist.github.com/fdb/1c7234fb49757df588c1302f44f0f125&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But wait! Since we can now use the command line, we can also download it by using &lt;code&gt;curl&lt;/code&gt;, a program that can fetch web pages and files from the web.&lt;/p&gt;
&lt;p&gt;Make sure we&#39;re in the &amp;quot;dataproc&amp;quot; folder (if not use &lt;code&gt;cd Desktop/dataproc&lt;/code&gt; to navigate to it) then type the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -O https://gist.githubusercontent.com/fdb/1c7234fb49757df588c1302f44f0f125/raw/bf6e32adb152fada6d08e54447f7d2e9370ea883/declaration.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &amp;quot;&lt;code&gt;-O&lt;/code&gt;&amp;quot; part is important. It&#39;s a &lt;em&gt;flag&lt;/em&gt;: an extra option that indicates to the program we want to do something different from its default operation. By default, curl will &lt;em&gt;show&lt;/em&gt; the file. By using the -O option, we can instruct curl to download the file. In this case, it will be saved as &lt;code&gt;declaration.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Open the project folder in your favorite editor. Make sure to open the whole folder (and not just the declaration.txt file) by clicking the folder and choosing &amp;quot;Open&amp;quot;. You will see the list of files in the sidebar.&lt;/p&gt;
&lt;p&gt;Let&#39;s make a Python script called &lt;code&gt;count_words.py&lt;/code&gt;. We can create our Python script in this same folder by clicking the &amp;quot;new file&amp;quot; icon in Visual Studio Code, or we can do it from the command line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch count_words.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;touch&lt;/code&gt; command is meant to change the date and time the file was last accessed. A side effect of the command is that it will create a new file if it doesn&#39;t already exist, which is what we use it for.&lt;/p&gt;
&lt;p&gt;We&#39;re going to write some very basic Python code to open the file, read it in, then show us the first 10 words of the file. Here&#39;s the code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;declaration.txt&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
words &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;split&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;words&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code demonstrates why I like Python: it&#39;s terse, and contains just the information we need without being &amp;quot;magic&amp;quot;.&lt;/p&gt;
&lt;p&gt;The first line opens the file and reads the contents. It stores this in a variable we define called &amp;quot;text&amp;quot;. Note that we can call it anything we like, as long as we use the same name to refer to it later.&lt;/p&gt;
&lt;p&gt;We didn&#39;t specify what &lt;em&gt;type&lt;/em&gt; the variable has. In Python each variable will have a type when the script is running. Here it&#39;s going to be a string: a container that holds text. It also supports Unicode, so we can store complex strings and Emoji&#39;s.&lt;/p&gt;
&lt;p&gt;The second line takes the text we read in and splits it. Since we didn&#39;t tell it on &lt;em&gt;what&lt;/em&gt; to split, the string will be split on whitespace. The result will be stored in the &lt;code&gt;words&lt;/code&gt; variable (again, we choose that name ourselves).&lt;/p&gt;
&lt;p&gt;The type of the &lt;code&gt;words&lt;/code&gt; variable is a &lt;code&gt;list&lt;/code&gt;. It&#39;s &lt;em&gt;the&lt;/em&gt; most useful type in Python: lists are the core of any data processing job. Complex jobs will require us to iterate over lists of directories, which might contain lists of files, where each file is a list of lines each containing lists of words, which consist of a list of characters... Even images can be regarded as a list of numbers defining the red, green and blue values making up the pixels of the image.&lt;/p&gt;
&lt;p&gt;We can do a lot with lists. The last line in our script just prints out the first 10 words of the list, using the &lt;code&gt;[:10]&lt;/code&gt; syntax. This means print from the beginning of the list, until (but not including) the 10th element.&lt;/p&gt;
&lt;p&gt;Save the script, then run it by &lt;code&gt;cd&lt;/code&gt;-ing to the correct directory if you&#39;re not there already and typing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 count_words.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see the following output:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;When&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;in&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;the&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Course&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;of&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;human&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;events,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;it&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;becomes&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;necessary&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If not, check every letter of the script carefully. If you get a &lt;code&gt;FileNotFoundError&lt;/code&gt; it means that Python can&#39;t find the file. Make sure it is in the same directory and has the same name as written in the script.&lt;/p&gt;
&lt;p&gt;To actually &lt;em&gt;count&lt;/em&gt; the words we need another data structure. We need a way to &lt;em&gt;map&lt;/em&gt; each word to a value: the number of times we encounter that word in the text. In other words, we want to have something that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;of     78
the    76
to     64
and    55
our    25
their  20
has    20
for    19
in     18
He     18
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Python we can use a &lt;em&gt;dictionary&lt;/em&gt; to contain this mapping. It stores a &lt;em&gt;key&lt;/em&gt; and an associated &lt;em&gt;value&lt;/em&gt;. In our case, the key is going to be the word, and the value is going to be our count.&lt;/p&gt;
&lt;p&gt;Here&#39;s the full code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;declaration.txt&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
words &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;split&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
word_count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; word &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; words&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; word_count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    word_count&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; count
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word_count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The initial two lines are the same as before. The third line creates a new variable called &lt;code&gt;word_count&lt;/code&gt; that is an empty dictionary.&lt;/p&gt;
&lt;p&gt;Then we encounter our main loop. This block iterates over each word and increases the count for it. In Python, a block is &lt;em&gt;indented&lt;/em&gt; (has extra spaces). It&#39;s recommended to use 4 spaces. All indented lines are executed in the loop. Note that the print statement at the bottom is not indented. We don&#39;t want it to happen after every word, but instead after all words have been counted.&lt;/p&gt;
&lt;p&gt;Let&#39;s look at the lines in our loop:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; word_count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line looks up the word in the &lt;code&gt;word_count&lt;/code&gt; dictionary. To get a value from a dictionary in Python we can also use square brackets (e.g. &lt;code&gt;word_count[word]&lt;/code&gt;). However, this will fail if the word is not available. That&#39;s why we use &lt;code&gt;get&lt;/code&gt; to provide a default value of 0 if the word can not be found. So after this line, the count is either the number of times we encountered the word, or 0 if we haven&#39;t seen it yet.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line increases the count by 1. It&#39;s shorthand for &lt;code&gt;count = count + 1&lt;/code&gt;. It takes the count, adds one to it, then stores it back into the count variable.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;word_count&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; count&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally we&#39;ll store the updated count back into the &lt;code&gt;word_count&lt;/code&gt; dictionary, under the key contained in the word.&lt;/p&gt;
&lt;p&gt;After the loop is done we print out the list of words. However, you&#39;ll see that this format is not really useful:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;When&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;in&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;the&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;76&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Course&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;of&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;human&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;events,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;it&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;becomes&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;necessary&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;for&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;one&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;people&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;to&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dissolve&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;political&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;bands&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;which&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;have&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;connected&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;them&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;with&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;another,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;and&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;assume,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;among&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Powers&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;earth,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;separate&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;equal&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;station&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Laws&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Nature&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Nature&#39;s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;God&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;entitle&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;them,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;a&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;decent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The words are ordered not by the count, but by the order in which we encounter them. We&#39;d like to see them in a more useful format, so let&#39;s &lt;em&gt;sort&lt;/em&gt; the dictionary.&lt;/p&gt;
&lt;p&gt;Actually, we can&#39;t really sort a dictionary. Instead, we can get a representation of the dictionary with the keys, sorted.&lt;/p&gt;
&lt;p&gt;Remove the last print statement and replace it with the following code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;word_count_list &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word_count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;word_count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reverse&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; word &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; word_count_list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; word_count&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line here is a bit tricky. &lt;code&gt;sorted&lt;/code&gt; is a built-in Python operation that sorts the input and returns a list. By default, if we give it a dictionary it will sort the keys alphabetically. Instead, we provide a &lt;code&gt;key&lt;/code&gt; argument to indicate on what to sort. Here, that is the value of each item, which we can write by asking it to &lt;code&gt;get&lt;/code&gt; the value for each item.&lt;/p&gt;
&lt;p&gt;This would start with the smallest values, so we use &lt;code&gt;reverse=True&lt;/code&gt; to tell Python to reverse the ordering.&lt;/p&gt;
&lt;p&gt;Once we have this list, we print the first 20 words of it. We loop over them, then call print with both the word, and the word count, retrieved by calling &lt;code&gt;word_count[word]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is what the output looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;of 78
the 76
to 64
and 55
our 25
their 20
has 20
for 19
in 18
He 18
a 15
these 13
by 13
have 11
them 11
which 10
that 10
all 10
is 10
with 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Obviously English stop words will be the most frequent words appearing in the top of the list. We can filter those out if we want (if we have a list of stop words), or we can just print more of the list (e.g. 50 items) to see more interesting words.&lt;/p&gt;
&lt;p&gt;Another issue is that commas and periods will be regarded as part of the word, messing up the count. We want to remove all special characters and only worry about the words. In addition we should consider the &lt;em&gt;casing&lt;/em&gt;: Python considers the word &amp;quot;People&amp;quot; and &amp;quot;people&amp;quot; as two distinct words. We&#39;ll turn everything into lower case so words are countly correctly.&lt;/p&gt;
&lt;p&gt;At the top of our file, add the following code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; string

translator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maketrans&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;punctuation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This imports an external module called &amp;quot;string&amp;quot; that contains a list of punctuation. The next line creates a &lt;em&gt;translator&lt;/em&gt; which is a Python construct allowing us to remove all punctuation.&lt;/p&gt;
&lt;p&gt;To use this, add the following code right before the &lt;code&gt;count = word.get&lt;/code&gt; line:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;word &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; word&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;translate&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;translator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lower&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Give it the same indentation (4 spaces) as the lines below it. This takes the word and removes all special characters.&lt;/p&gt;
&lt;p&gt;Run the script again. We&#39;ll see that the word &amp;quot;people&amp;quot; is now the most frequent word after all common stop words.&lt;/p&gt;
&lt;p&gt;To save this information in a useful format we&#39;ll use the &lt;code&gt;csv.writer&lt;/code&gt; to write out the data as comma-separated values: basically a simple text-based format that we can open in Excel, Google Docs, NodeBox, Processing or D3.&lt;/p&gt;
&lt;p&gt;We&#39;ll add an import at the top of the file:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; csv&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, add the very end of the file, add the following code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;output_file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;words.csv&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;w&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
writer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; csv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output_file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
writer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writerow&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;word&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;count&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; word &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; word_count_list&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    writer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writerow&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; word_count&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This opens a new file, called &lt;code&gt;words.csv&lt;/code&gt;. Note the extra argument with the &lt;code&gt;&#39;w&#39;&lt;/code&gt;. This is necessary to tell Python to open the file for writing. This makes sure we have the correct permissions to write to a file.
The next line takes this file (often called the &lt;em&gt;file handle&lt;/em&gt;) and turns it into a &lt;em&gt;CSV writer&lt;/em&gt;. This is a special object that has a method called &lt;code&gt;writerow&lt;/code&gt; allowing us to write CSV data.&lt;/p&gt;
&lt;p&gt;CSV files look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;word,count
of,78
the,77
to,65
and,56
for,28
our,26
their,20
has,20
in,19
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The CSV writer can output data in this format, making sure that the system doesn&#39;t mess up if our actual word contains a comma.&lt;/p&gt;
&lt;p&gt;Run the script again. You should now see a &lt;code&gt;words.csv&lt;/code&gt; file appear. Open it up in your editor and check that it contains the list of words and counts.&lt;/p&gt;
&lt;p&gt;Congratulations! You created your first Python data processing job. Here&#39;s the &lt;a href=&quot;https://gist.github.com/fdb/1c7234fb49757df588c1302f44f0f125&quot;&gt;finished Python code&lt;/a&gt;, for reference.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Google Cloud OnBoard Eindhoven</title>
    <link href="https://enigmeta.com/posts/2017-09-22-google-cloud-onboard-eindhoven/" />
    <updated>2017-09-22T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2017-09-22-google-cloud-onboard-eindhoven/</id>
    <content type="html">&lt;style&gt;
.post p img { border: none; box-shadow: none; }
&lt;/style&gt;
&lt;p&gt;On Wednesday September 20th I participated in the Google Cloud OnBoard event at the High Tech Campus in Eindhoven.&lt;/p&gt;
&lt;p&gt;The event was an introduction in the features of the Google Cloud infrastructure: everything from hosting your own apps, storage and databases to working with big data and machine learning.&lt;/p&gt;
&lt;p&gt;The event was organized by Google and presented by &lt;a href=&quot;https://twitter.com/mattfgl&quot;&gt;Matthew Feigal&lt;/a&gt; from Google and &lt;a href=&quot;https://twitter.com/crumpyscloud&quot;&gt;Mark Crump&lt;/a&gt; from &lt;a href=&quot;https://www.qa.com&quot;&gt;QA&lt;/a&gt;, a Google training partner.&lt;/p&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/google-cloud-onboard-eindhoven/gcp.png&quot; alt=&quot;Google Cloud Platform&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Google Cloud platform is big, but can be broken down in four sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Compute&lt;/strong&gt;: managing the machines that run your applications. Ranging from Compute Engine, which is a VPS, to App Engine, which is a Platform as a Service (PaaS).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage&lt;/strong&gt;: managing how you store and access data. This covers file storage (Cloud Storage), Cloud SQL and Bigtable for big projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Big Data&lt;/strong&gt;: asking questions about large datasets. Use BigQuery to perform SQL-like queries on terabyte-size datasets, Pub/Sub for messaging, Datalab for an IPython Notebook in the cloud.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Machine Learning&lt;/strong&gt;: access to Google&#39;s infrastructure for your own machine learning jobs using TensorFlow, or pre-built machine learning apps like Cloud Vision, the Natural Language API or the Speech API.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Monitoring all of that data happens through &lt;a href=&quot;https://cloud.google.com/stackdriver/&quot;&gt;StackDriver&lt;/a&gt;, an application to monitor, log and debug applications.&lt;/p&gt;
&lt;h2&gt;Infrastructure&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Google&#39;s physical network is impressive. They essentially built their own internet, including undersea cables and dark fiber, so that once you get on the Google network everything is super-fast.&lt;/li&gt;
&lt;li&gt;The primary Europe data center (europe-west1) is located in Belgium, at &lt;a href=&quot;https://www.google.com/about/datacenters/inside/locations/st-ghislain/&quot;&gt;St. Ghislain&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can &lt;a href=&quot;http://www.gcping.com/&quot;&gt;ping the Google data centers&lt;/a&gt; to get an idea for latency.&lt;/li&gt;
&lt;li&gt;For large customers, they offer to &lt;a href=&quot;https://peering.google.com/#/infrastructure&quot;&gt;peer&lt;/a&gt; so you can connect directly to their network. In Amsterdam, you can use &lt;a href=&quot;http://www.equinix.com/&quot;&gt;Equinix&lt;/a&gt; to peer.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=zDAYZU4A3w0&quot;&gt;360° video tour of the Google Data Center&lt;/a&gt;. Spot the security guard in every shot.&lt;/li&gt;
&lt;li&gt;There is a &lt;a href=&quot;https://landing.google.com/sre/&quot;&gt;book about how Google runs production systems&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Projects and Access&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Everything in Google Cloud Platform is managed by &lt;a href=&quot;https://cloud.google.com/storage/docs/projects&quot;&gt;&lt;strong&gt;project&lt;/strong&gt;&lt;/a&gt;. A project contains all infrastructure you want to set up: server, storage, logging, ... . It also unifies billing. A project has a visible name and an internal ID that needs to be globally unique.&lt;/li&gt;
&lt;li&gt;You can use &lt;a href=&quot;https://cloud.google.com/iam/&quot;&gt;IAM (Identity and Access Management)&lt;/a&gt; to control who has access to what. This can be really granular.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Privacy / GDPR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Google &lt;a href=&quot;https://cloud.google.com/security/compliance&quot;&gt;complies with available ISO and HIPAA standards&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Google intends to fully comply with the &lt;a href=&quot;http://www.eugdpr.org&quot;&gt;European General Data Protection Regulation (GDPR)&lt;/a&gt;, once they become available.&lt;/li&gt;
&lt;li&gt;You can choose in which &lt;a href=&quot;https://cloud.google.com/compute/docs/regions-zones/regions-zones&quot;&gt;region&lt;/a&gt; your data is stored (North America, South America, Europe, Asia, Australia).&lt;/li&gt;
&lt;li&gt;All data is encrypted at rest. If you don&#39;t trust Google, you can also provide your own custom encryption keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Interacting with Google Cloud Platform&lt;/h2&gt;
&lt;p&gt;You can access GCP (Google Cloud Platform) using different methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://console.cloud.google.com/&quot;&gt;&lt;strong&gt;Cloud Console&lt;/strong&gt;&lt;/a&gt;: a web interface to Google Cloud.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/sdk/&quot;&gt;&lt;strong&gt;Cloud SDK&lt;/strong&gt;&lt;/a&gt;: terminal-based tools for accessing services and deploying apps.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/shell/&quot;&gt;&lt;strong&gt;Cloud Shell&lt;/strong&gt;&lt;/a&gt;: from the web interface, you get free access to a Linux machine that contains all tools pre-installed. Super-useful.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/apis/docs/overview&quot;&gt;&lt;strong&gt;REST-based APIs&lt;/strong&gt;&lt;/a&gt;: so you can create services on-demand. Use &lt;a href=&quot;https://developers.google.com/apis-explorer/#p/&quot;&gt;API Explorer&lt;/a&gt; to get an overview and try out all accessible APIs. Libraries are available for Java, Python, JavaScript, PHP, .NET, Go, Node.js, Ruby, Objective-C, Dart.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/console-app/&quot;&gt;&lt;strong&gt;Mobile App&lt;/strong&gt;&lt;/a&gt;: for managing services from iOS or Android.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Compute&lt;/h1&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/appengine/&quot;&gt;App Engine&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Easiest way to build an application that doesn&#39;t require maintenance and works online.&lt;/li&gt;
&lt;li&gt;Similar to &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Two types of environments:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Standard&lt;/strong&gt;: autoscaling, free daily quota, limited language support (Java, Python, Go). Has some restrictions to enable scaling: no writing to local file system, for example. Automatic shutdown if the app is not used, saving cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flex&lt;/strong&gt;: works with containers, which you can inspect and log in to. Supports every possible language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Provides extra services like cron jobs, task queues for rendering or batch processing, search, logs.&lt;/li&gt;
&lt;li&gt;Example: &lt;a href=&quot;https://www.crowdsite.com/&quot;&gt;Crowdsite&lt;/a&gt;, dutch marketplace for design &amp;amp; creatives.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/compute/&quot;&gt;Compute Engine&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;VPS, like &lt;a href=&quot;https://www.linode.com/&quot;&gt;Linode&lt;/a&gt; or &lt;a href=&quot;https://www.digitalocean.com/&quot;&gt;Digital Ocean&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Different variants: high CPU, high memory, even GPU machines.&lt;/li&gt;
&lt;li&gt;Running a single 512MB server is free!&lt;/li&gt;
&lt;li&gt;Fast to spin up, per-minute billing.&lt;/li&gt;
&lt;li&gt;Use load balancer to distribute load between multiple machines.&lt;/li&gt;
&lt;li&gt;Supports &lt;a href=&quot;https://cloud.google.com/compute/docs/instances/live-migration&quot;&gt;live migration&lt;/a&gt;, so the server keeps running as it is migrated to a different host.&lt;/li&gt;
&lt;li&gt;You can &lt;a href=&quot;https://cloud.google.com/compute/docs/storing-retrieving-metadata&quot;&gt;set and access metadata&lt;/a&gt; for bootstrapping a server. The server has access to &lt;code&gt;http://metadata.google.internal/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/container-engine/&quot;&gt;Container Engine&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Used for virtualization at the operating system layer. Separates operating system from &lt;em&gt;application code and dependencies&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Containers are used &lt;em&gt;everywhere&lt;/em&gt; in Google. Any application runs in a container: Search, Mail, Maps, ... It&#39;s the best way to keep dependencies of different applications from messing with each other.&lt;/p&gt;
&lt;p&gt;Consistent environment for development, testing, and production. Simple to migrate and move around.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.docker.com&quot;&gt;Docker&lt;/a&gt; and &lt;a href=&quot;https://coreos.com/rkt/&quot;&gt;rkt&lt;/a&gt; are the most popular container implementations.&lt;/p&gt;
&lt;h3&gt;Kubernetes&lt;/h3&gt;
&lt;p&gt;If you have multiple containers, you might want to orchestrate (manage) them. You can use &lt;a href=&quot;https://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt; for that. It automates deployment and scaling.&lt;/p&gt;
&lt;p&gt;Kubernetes specifies a configuration file that contains the requirements of your app: project folder, RAM, disk, CPU and how many replicas you want to have running. The system then makes sure you have that many containers always available. In Google this system is called &lt;strong&gt;Borg&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Containers lie between directly using a VPS, and the Platform-as-a-Service. You can run everything you want, but Google manages scaling and failover.&lt;/p&gt;
&lt;p&gt;Example: &lt;a href=&quot;https://cloud.google.com/customers/philips/&quot;&gt;Philips Hue&lt;/a&gt; uses containers for scaling the infrastructure controlling the lights in your home. They use &lt;a href=&quot;http://docs.apigee.com/api-services/content/what-apigee-edge&quot;&gt;Apigee Edge&lt;/a&gt; for managing access to their API, and &lt;a href=&quot;https://redis.io&quot;&gt;Redis&lt;/a&gt; for storage.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.google.com/container-engine/&quot;&gt;Container Engine&lt;/a&gt; is the hosted version of Kubernetes, running on Google Cloud Platform.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/functions/&quot;&gt;Cloud Functions&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Run a single function in the cloud, using JavaScript.&lt;/li&gt;
&lt;li&gt;No servers to manage, billing in 100ms intervals.&lt;/li&gt;
&lt;li&gt;Functions that respond to events (e.g. subscribe button, IoT event).&lt;/li&gt;
&lt;li&gt;Works with &lt;a href=&quot;https://firebase.google.com&quot;&gt;Firebase&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Perfect for microservices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/products/networking/&quot;&gt;Cloud Networking&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Once you have many systems, you can connect them in a virtual network (VPC). You can set this up using custom routing, DNS, load balancing.&lt;/li&gt;
&lt;li&gt;All nodes in the network (e.g. &lt;code&gt;192.168.20.0/24&lt;/code&gt;) can be in different regions of the world.&lt;/li&gt;
&lt;li&gt;Google also provides &lt;a href=&quot;https://cloud.google.com/cdn/&quot;&gt;Cloud CDN&lt;/a&gt;, a content delivery network.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://domains.google/&quot;&gt;Google Domains&lt;/a&gt; is a domain name registrar for buying and managing domain names. Not available in Belgium / The Netherlands yet.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/endpoints/&quot;&gt;Cloud Endpoints&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Proxy for your APIs.&lt;/li&gt;
&lt;li&gt;Supports access control, caching, monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/deployment-manager/&quot;&gt;Cloud Deployment Manager&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Create templates to deploy your resources in a repeatable manner.&lt;/li&gt;
&lt;li&gt;Like &lt;a href=&quot;https://puppet.com&quot;&gt;Puppet&lt;/a&gt; or &lt;a href=&quot;https://www.chef.io/chef/&quot;&gt;Chef&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Storage&lt;/h1&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/storage/&quot;&gt;Cloud Storage&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Like Amazon S3, but cheaper. Similar structure: files are stored in Buckets.&lt;/li&gt;
&lt;li&gt;Access the data from the command line using &lt;code&gt;gsutil&lt;/code&gt; or through the web interface. You can also transfer data from S3 directly into Cloud Storage.&lt;/li&gt;
&lt;li&gt;You can choose where the data is located: Europe, Asia, America, or multi-regional.&lt;/li&gt;
&lt;li&gt;Supports &amp;quot;nearline&amp;quot; and &amp;quot;coldline&amp;quot;, for archival data that is infrequently accessed. Much cheaper, but more expensive to access. Unlike Amazon Glacier, access to the nearline and coldline data is immediate.&lt;/li&gt;
&lt;li&gt;Often used as a first step to store data that can be processed by machine learning jobs, for example tables for BigQuery or images for Cloud Vision.&lt;/li&gt;
&lt;li&gt;Can also serve HTTP/HTTPS traffic. If you have a static site, this might be all you need.&lt;/li&gt;
&lt;li&gt;Good for storing images, media files, backups.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/datastore/&quot;&gt;Cloud Datastore&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;NoSQL database supporting billions of rows.&lt;/li&gt;
&lt;li&gt;Schemaless access.&lt;/li&gt;
&lt;li&gt;View and edit the data in the web console interface.&lt;/li&gt;
&lt;li&gt;Useful for simple applications but you often need some sort of schema for more complex operations.&lt;/li&gt;
&lt;li&gt;Good for product catalogs, user profiles.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codelabs.developers.google.com/codelabs/cp100-app-engine/&quot;&gt;Tutorial application with App Engine and Cloud Datastore&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/bigtable/&quot;&gt;Cloud Bigtable&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Wide-column NoSQL store for terabyte to petabyte-scale applications.&lt;/li&gt;
&lt;li&gt;Used in Gmail, Google Analytics.&lt;/li&gt;
&lt;li&gt;Similar to Cassandra. Accessed using the HBase API (Hadoop).&lt;/li&gt;
&lt;li&gt;Good for &amp;quot;flat data&amp;quot;: time series, AdTech, financial data, IoT sensor data, computer logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/sql/&quot;&gt;Cloud SQL&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Managed MySQL and PostgreSQL database as a service.&lt;/li&gt;
&lt;li&gt;Automatic replication, backups, scaling.&lt;/li&gt;
&lt;li&gt;Easy to integrate with App Engine or Compute Engine instances.&lt;/li&gt;
&lt;li&gt;Good for typical SQL workloads: relational data, customer orders.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloud.google.com/spanner/&quot;&gt;Cloud Spanner&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Horizontally-scalable, strongly consistent relational database.&lt;/li&gt;
&lt;li&gt;Based on the &lt;a href=&quot;https://research.google.com/archive/spanner.html&quot;&gt;Spanner paper&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Global consistency: very hard to do! Uses atomic clocks in all servers.&lt;/li&gt;
&lt;li&gt;Good for large-scale database applications (&amp;gt; 2 TB).&lt;/li&gt;
&lt;li&gt;Used in GMail for storing metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/source-repositories/&quot;&gt;Cloud Source Repositories&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Managed private Git hosting, like GitHub enterprise.&lt;/li&gt;
&lt;li&gt;Can mirror other Git repositories, like from GitHub for example.&lt;/li&gt;
&lt;li&gt;Supports webhooks so that actions happen when a commit is pushed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/stackdriver/&quot;&gt;StackDriver&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Used for monitoring, logging, debugging, error reporting on your infrastructure.&lt;/li&gt;
&lt;li&gt;Nice visualizations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Big Data and Machine Learning&lt;/h1&gt;
&lt;p&gt;Running big data operations on Google Cloud means you just need to focus on the application. You don&#39;t have to manage servers or acquire costly GPUs.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/bigquery/&quot;&gt;Cloud BigQuery&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An analytics database that provides near real-time interactive analysis of massive datasets (hundreds of TBs).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You throw your data at it (CSV, JSON, realtime streams), write a SQL query, and get a result back.&lt;/li&gt;
&lt;li&gt;Based on the &lt;a href=&quot;https://research.google.com/pubs/pub36632.html&quot;&gt;Dremel paper&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;During the presentation, we saw queries on the full Wikipedia data set (100 billion rows) in a few seconds.&lt;/li&gt;
&lt;li&gt;Can query custom datasets, or &lt;a href=&quot;https://cloud.google.com/bigquery/public-data/&quot;&gt;public datasets&lt;/a&gt; such as GitHub, Open Images, World Bank.&lt;/li&gt;
&lt;li&gt;Good for medical data, analytics, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/pubsub/&quot;&gt;Cloud Pub/Sub&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Managed messaging queue, like &lt;a href=&quot;http://www.rabbitmq.com&quot;&gt;RabbitMQ&lt;/a&gt; or &lt;a href=&quot;https://kafka.apache.org&quot;&gt;Kafka&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Includes support for offline consumers.&lt;/li&gt;
&lt;li&gt;Good for Internet of Things (IoT), marketing analytics, connecting different parts of your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/dataflow/&quot;&gt;Cloud Dataflow&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Create data pipelines for ETL and run them on a scalable, managed infrastructure.&lt;/li&gt;
&lt;li&gt;A managed installation of &lt;a href=&quot;https://beam.apache.org/&quot;&gt;Apache Beam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Integrates with all other cloud services. BigQuery, Cloud Storage, Pub/Sub.&lt;/li&gt;
&lt;li&gt;Write dataflows in Java and Python.&lt;/li&gt;
&lt;li&gt;Example use case: find the top watched videos at the moment, in 5 minute windows.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/dataproc/&quot;&gt;Cloud Dataproc&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Managed Hadoop&lt;/li&gt;
&lt;li&gt;Fast to create your own clusters (90 seconds).&lt;/li&gt;
&lt;li&gt;Good for analyzing large data sets (e.g. logging data) stored in Cloud Storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/datalab/&quot;&gt;Cloud Datalab&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://jupyter.org&quot;&gt;Jupyter&lt;/a&gt; (IPython notebook) in the cloud.&lt;/li&gt;
&lt;li&gt;Run and manage data tasks and machine learning in a cloud environment, with fast access to Cloud Storage, machine learning APIs, etc.&lt;/li&gt;
&lt;li&gt;Free (but you pay the costs of accessing other cloud services).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/dataprep/&quot;&gt;Cloud Dataprep&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Service for exploring, visualizing and cleaning up your data.&lt;/li&gt;
&lt;li&gt;Similar to Google Refine / &lt;a href=&quot;http://openrefine.org&quot;&gt;OpenRefine&lt;/a&gt;, but running in the cloud.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://cloud.google.com/products/machine-learning/&quot;&gt;Machine Learning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Google open-source &lt;a href=&quot;https://www.tensorflow.org&quot;&gt;TensorFlow&lt;/a&gt;, a widely-used tool for machine learning. They now provide tools to run TensorFlow jobs in the cloud, as well as pre-trained models for computer vision, language analysis and translation, and text-to-speech.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/rjankie&quot;&gt;Rokesh Jankie&lt;/a&gt;, a Google engineer, gave the best one-line introduction to AI I&#39;ve ever heard: &amp;quot;You create a function, only we don&#39;t know yet the formula of the function.&amp;quot; Instead of linear functions, we use neural networks, which can handle complex transformations and noise better. He demonstrated this using the &lt;a href=&quot;http://playground.tensorflow.org/&quot;&gt;TensorFlow Playground&lt;/a&gt;. He also showed the &lt;a href=&quot;http://vision-explorer.reactive.ai/&quot;&gt;Cloud Vision Explorer&lt;/a&gt;, showing an interactive demonstration of the capabilities of the Cloud Vision API. He also showed &lt;a href=&quot;https://deepmind.com/blog/wavenet-generative-model-raw-audio/&quot;&gt;WaveNet&lt;/a&gt;, a generative model for the generation of text-to-speech. He demonstrated how computer vision can be used to find disease patterns in images of eyes.&lt;/p&gt;
&lt;p&gt;A few use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Classification / Regression&lt;/strong&gt;: forecasting, customer churn analysis (&amp;quot;why are my customers leaving?&amp;quot;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recommendations&lt;/strong&gt;: content personalization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anomaly detection&lt;/strong&gt;: detect fraud, log anomalies in metrics or sensors&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image analytics&lt;/strong&gt;: identify damaged shipments, detect explicit (adult/violent) images.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text analytics&lt;/strong&gt;: call center log analysis, language identification, sentiment extraction.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloud.google.com/ml-engine/&quot;&gt;Cloud Machine Learning Engine&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;For custom machine learning jobs.&lt;/li&gt;
&lt;li&gt;Google provides infrastructure for training your model.&lt;/li&gt;
&lt;li&gt;Once trained, your model can run on user&#39;s computer or smartphones.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloud.google.com/vision/&quot;&gt;Cloud Vision API&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Analyze images with a REST api.&lt;/li&gt;
&lt;li&gt;Supports face detection, label detection, sentiment analysis, text extraction (OCR).&lt;/li&gt;
&lt;li&gt;Returns bounding boxes of faces (and facial features), objects in JSON.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cocodataset.org/&quot;&gt;COCO&lt;/a&gt; is an image dataset that has labelled and segmented images for use in image recognition. It is available under a &lt;a href=&quot;http://cocodataset.org/#termsofuse&quot;&gt;Creative Commons license&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloud.google.com/speech/&quot;&gt;Cloud Speech API&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Recognizes over 80 languages.&lt;/li&gt;
&lt;li&gt;Can return text in real-time (streaming).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloud.google.com/natural-language/&quot;&gt;Cloud Natural Language API&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Extract information about people, places, events mentioned in text: news articles, papers, blog posts.&lt;/li&gt;
&lt;li&gt;Sentiment extraction.&lt;/li&gt;
&lt;li&gt;Can be used for Chatbots.&lt;/li&gt;
&lt;li&gt;Ocado, an online grocery store in the UK, used it to triage customer requests into urgent delivery-related messages and other messages.&lt;/li&gt;
&lt;li&gt;Dealing with sarcasm is still difficult. You can tune the parameters of the network.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloud.google.com/translate/&quot;&gt;Cloud Translation API&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Translate strings between different languages.&lt;/li&gt;
&lt;li&gt;Detect language of input text.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;AutoML&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Selecting machine learning architectures is a difficult and time-consuming task.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sites.google.com/site/automl2017icml/&quot;&gt;AutoML&lt;/a&gt; is an area of research that tries to automate this process, by having machine learning algorithms figure out the best machine learning algorithms.&lt;/li&gt;
&lt;li&gt;One way to do this is to have neural networks compete with each other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Next Steps&lt;/h1&gt;
&lt;h2&gt;Learning Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/docs/&quot;&gt;Official Google Cloud Platform documentation site&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://googlecloudplatform.github.io&quot;&gt;GitHub page with tutorials&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qwiklabs.com&quot;&gt;Qwiklabs: self-paced training labs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Google also offers &lt;a href=&quot;https://cloud.google.com/training/&quot;&gt;training and certification&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Community&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In the Netherlands there is the &lt;a href=&quot;https://www.gdgnetherlands.org&quot;&gt;Google Developers Group&lt;/a&gt;. There is also a &lt;a href=&quot;https://www.meetup.com/Google-Developer-Group-Netherlands/&quot;&gt;Meetup Group&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In Belgium there is the &lt;a href=&quot;http://gdg.brussels/&quot;&gt;Brussels GDG&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/google-cloud-onboard-eindhoven/outro.jpg&quot; alt=&quot;High Tech Campus Eindhoven&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Making of my PhD Thesis Generator</title>
    <link href="https://enigmeta.com/posts/2016-06-29-phd-thesis-generator/" />
    <updated>2016-06-29T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2016-06-29-phd-thesis-generator/</id>
    <content type="html">&lt;p&gt;On June 15, I received my PhD in the Arts from the University of Antwerp / ARIA. My research was about the impact of generative design tools. I researched how generative design tools (specifically &lt;a href=&quot;https://www.nodebox.net/&quot;&gt;NodeBox&lt;/a&gt;) affect the quality and creativity of designers, and whether they were more efficient and self-reliant.&lt;/p&gt;
&lt;p&gt;A PhD in the arts lies somewhere between scientific research and artistic practice. It is at times both, and at other times neither.
One day you&#39;ll be performing A/B tests on users, the other days you&#39;re knee-deep in artistic projects. I wanted to represent this battle between two sides in the thesis as well. In line with the message of the PhD I didn&#39;t simply want to create a thesis, but a thesis &lt;em&gt;generator&lt;/em&gt;: a system that could generate endless variations of the thesis (keeping the content intact but dynamically generating the design).&lt;/p&gt;
&lt;p&gt;I&#39;ve opted to created &lt;strong&gt;&amp;quot;the slider&amp;quot;&lt;/strong&gt;: an interactive element that allows you to choose for yourself whether you want an artistic or scientific thesis. The design is adapted to match, and every design will be unique.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://enigmeta.com/thesis/&quot;&gt;Go generate your own thesis&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/phd-thesis-generator/screenshot.png&quot; alt=&quot;PhD thesis generator screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;Some designs evolve over multiple pages, gradually changing background elements from page to page. Flipping through the thesis results in interesting animations:&lt;/p&gt;
&lt;div class=&quot;embed-responsive embed-responsive-16by9&quot;&gt;
  &lt;iframe class=&quot;embed-responsive-item&quot; src=&quot;https://www.youtube.com/embed/VZCYH8Fy2sk&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I had a selection of these theses printed. Each design used different font sizes and margins, meaning layouts had to be recalculated, taking typesetting issues like &lt;a href=&quot;https://en.wikipedia.org/wiki/Widows_and_orphans&quot;&gt;widows and orphans&lt;/a&gt; into account. The total number of pages varied between 140 and 180, meaning that the thickness of the book varied as well. I added routines to calculate the width of the spine and generate different-sized book covers based on those calculations.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/phd-thesis-generator/variations.jpg&quot; alt=&quot;A number of printed variations&quot;&gt;&lt;/p&gt;
&lt;p&gt;The text of the thesis was written in &lt;a href=&quot;https://workflowy.com/&quot;&gt;Workflowy&lt;/a&gt;. It was imported automatically and converted to &lt;a href=&quot;https://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt;. The thesis generator was built in &lt;a href=&quot;https://golang.org/&quot;&gt;Go&lt;/a&gt;. It doesn&#39;t use any additional packages apart from the Go standard library. This means that every single byte of the PDF is generated by my own software. Here are some of the aspects that were implemented, from high-level to low-level:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web Server&lt;/li&gt;
&lt;li&gt;Style interpolation&lt;/li&gt;
&lt;li&gt;Workflowy import&lt;/li&gt;
&lt;li&gt;Automatic figure generation (from inline NB1-style Python code)&lt;/li&gt;
&lt;li&gt;Markdown parsing&lt;/li&gt;
&lt;li&gt;Text layout (justification)&lt;/li&gt;
&lt;li&gt;Layout calculation&lt;/li&gt;
&lt;li&gt;Dynamic background generation&lt;/li&gt;
&lt;li&gt;Automatic TOC and bibliography generation&lt;/li&gt;
&lt;li&gt;Separate cover / body generation&lt;/li&gt;
&lt;li&gt;Font parsing (to determine widths, taking kerning into account)&lt;/li&gt;
&lt;li&gt;Color handling (HSL / RGB calculations)&lt;/li&gt;
&lt;li&gt;PDF object generation (pages, outlines, font and image embedding)&lt;/li&gt;
&lt;li&gt;PDF primitives (dictionaries, arrays, xrefs, ...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The low-level PDF handling and layout and typesetting calculations might be interesting as a library to release in the future. In addition, higher-level concepts like style interpolation might be interesting as well; currently they are connected to the thesis.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.enigmeta.com/thesis/&quot;&gt;Go generate your own thesis&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Random Compositions using Overtone</title>
    <link href="https://enigmeta.com/posts/2013-10-11-random-compositions-overtone/" />
    <updated>2013-10-11T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2013-10-11-random-compositions-overtone/</id>
    <content type="html">&lt;p&gt;While learning &lt;a href=&quot;http://overtone.github.io/&quot;&gt;Overtone&lt;/a&gt; I&#39;ve created a composition that randomly downloads sounds from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesounds.org&lt;/a&gt; and makes beat-like soundscapes with them. (First composition starts at 1&amp;quot;20.)&lt;/p&gt;
&lt;p&gt;If you want to try this yourself, start by downloading Leiningen from &lt;a href=&quot;http://leiningen.org/&quot;&gt;leiningen.org&lt;/a&gt;.&lt;/p&gt;
&lt;iframe width=&quot;777&quot; height=&quot;583&quot; src=&quot;https://www.youtube.com/embed/n0_fJBpFkbA&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;
</content>
  </entry>
  <entry>
    <title>Deconstructing Nature - Day 5</title>
    <link href="https://enigmeta.com/posts/2012-09-08-deconstructing-nature-day5/" />
    <updated>2012-09-08T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-09-08-deconstructing-nature-day5/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;My colleague Werner and I are holding a challenge this week to produce one visual work each day. I&#39;m working around the theme of &amp;quot;Deconstructing Nature&amp;quot;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day1&quot;&gt;Day 1&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day2&quot;&gt;Day 2&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day3&quot;&gt;Day 3&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day4&quot;&gt;Day 4&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day5&quot;&gt;Day 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the last day I wanted to do something with &lt;em&gt;human&lt;/em&gt; nature. And there is no better place on the internet to watch human nature decompose than &lt;a href=&quot;http://www.4chan.org/&quot;&gt;4chan&lt;/a&gt; (Warning: Not Safe For Work!). The website is a huge image board on a large number of topics ranging from Anime to Politics.&lt;/p&gt;
&lt;p&gt;And then there&#39;s the &amp;quot;random&amp;quot; image board, also known as /b/, also known as the cesspool of the internet. I wanted to visualize the streams of data coming out of there, and with 4chan recently providing an API to their data, this might actually be feasible.&lt;/p&gt;
&lt;p&gt;I use a veritable &lt;em&gt;potpourri&lt;/em&gt; of Python libraries to bring everything together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.python-requests.org/en/latest/index.html&quot;&gt;requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.crummy.com/software/BeautifulSoup/&quot;&gt;BeautifulSoup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.pythonware.com/products/pil/&quot;&gt;Python Imaging Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://api.mongodb.org/python/current/&quot;&gt;pymongo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.virtualenv.org/en/latest/index.html&quot;&gt;virtualenv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.pip-installer.org/en/latest/index.html&quot;&gt;pip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nodebox.net/code/index.php/Home&quot;&gt;NodeBox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end, it was very hard to do something with images that are often gross, sometimes shocking and mostly bizarre. So I decided to abstract the representation:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day5/final.jpg&quot; alt=&quot;Deconstructing Nature: Final Work Day #5&quot;&gt;&lt;/p&gt;
&lt;p&gt;Again, this is a visualization of the random image board. It would be interesting to see visualizations of the other thematic boars to see if they show different patterns.&lt;/p&gt;
&lt;p&gt;Other sketches:
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day5/experiment1.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day5/experiment2.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day5/experiment3.jpg&quot; alt=&quot;Other experiment&quot;&gt;&lt;/p&gt;
&lt;p&gt;The source is available in the &lt;a href=&quot;https://github.com/fdb/deconstructing-nature&quot;&gt;Deconstructing Nature GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Deconstructing Nature - Day 3</title>
    <link href="https://enigmeta.com/posts/2012-09-06-deconstructing-nature-day3/" />
    <updated>2012-09-06T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-09-06-deconstructing-nature-day3/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;My colleague Werner and I are holding a challenge this week to produce one visual work each day. I&#39;m working around the theme of &amp;quot;Deconstructing Nature&amp;quot;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day1&quot;&gt;Day 1&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day2&quot;&gt;Day 2&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day3&quot;&gt;Day 3&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day4&quot;&gt;Day 4&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day5&quot;&gt;Day 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Inspired by Werner&#39;s work I wanted to do something with swarms. For another project we&#39;re talking about creating a &lt;em&gt;living wallpaper&lt;/em&gt; which I also wanted to integrate here. And I wanted to make something that was animated and a little bit interactive.&lt;/p&gt;
&lt;p&gt;I decided to create an animated swarm in a browser, using trails to create a wallpaper. I used the excellent &lt;a href=&quot;http://mrdoob.github.com/three.js/&quot;&gt;three.js&lt;/a&gt; library to access WebGL.&lt;/p&gt;
&lt;p&gt;Here&#39;s the result from day 3. &lt;strong&gt;Click the image to view it live (Chrome / Firefox)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keys&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Hold Spacebar&lt;/em&gt;: Direct the swarm to the center.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;C&lt;/em&gt;: Clear the screen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://enigmeta.com/doodles/metaspace/&quot;&gt; &lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day3/final.png&quot; alt=&quot;Deconstructing Nature: Final Work Day #3&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The source is available in the &lt;a href=&quot;https://github.com/fdb/deconstructing-nature&quot;&gt;Deconstructing Nature GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Deconstructing Nature - Day 2</title>
    <link href="https://enigmeta.com/posts/2012-09-05-deconstructing-nature-day2/" />
    <updated>2012-09-05T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-09-05-deconstructing-nature-day2/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;My colleague Werner and I are holding a challenge this week to produce one visual work each day. I&#39;m working around the theme of &amp;quot;Deconstructing Nature&amp;quot;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day1&quot;&gt;Day 1&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day2&quot;&gt;Day 2&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day3&quot;&gt;Day 3&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day4&quot;&gt;Day 4&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day5&quot;&gt;Day 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the second day I wanted to do something &lt;em&gt;physical&lt;/em&gt;. I was thinking about the act of deconstructing – breaking something down to its simplest components. &amp;quot;Simpling&amp;quot;.&lt;/p&gt;
&lt;p&gt;This brought me to the idea of microscopy. I discovered that you can do extreme macro-photography by installing the lens &lt;em&gt;backwards&lt;/em&gt; on a camera.&lt;/p&gt;
&lt;p&gt;I did some experiments with my aging DSLR, but results were not as sharp as I hoped. However, I discovered that I can &amp;quot;attach&amp;quot; a regular lens to my smartphone, producing very detailed images. I used this technique to create the final image.&lt;/p&gt;
&lt;p&gt;Here&#39;s the result from day 2:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/final.jpg&quot; alt=&quot;Deconstructing Nature: Final Work Day #2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here are some other images from this session:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/experiment1.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/experiment2.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/experiment3.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/experiment4.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/experiment5.jpg&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day2/experiment6.jpg&quot; alt=&quot;Other experiment&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Deconstructing Nature - Day 1</title>
    <link href="https://enigmeta.com/posts/2012-09-04-deconstructing-nature-day1/" />
    <updated>2012-09-04T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-09-04-deconstructing-nature-day1/</id>
    <content type="html">&lt;p&gt;My colleague Werner and I are holding a challenge this week to produce &lt;strong&gt;one visual work each day&lt;/strong&gt;. I&#39;ve given myself the theme of &lt;strong&gt;&amp;quot;Deconstructing Nature&amp;quot;&lt;/strong&gt;, which you can interpret as wide as you want.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day1&quot;&gt;Day 1&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day2&quot;&gt;Day 2&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day3&quot;&gt;Day 3&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day4&quot;&gt;Day 4&lt;/a&gt; — &lt;a href=&quot;https://enigmeta.com/blog/deconstructing-nature-day5&quot;&gt;Day 5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the first day I wanted to design the layout of a space – specifically a &lt;em&gt;garden&lt;/em&gt; – according to patterns occurring in nature. I thought about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The spread of forest fires&lt;/li&gt;
&lt;li&gt;The intricate nerve pattern of plants&lt;/li&gt;
&lt;li&gt;Patterns of underground movement: worms, ants, tree roots, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I liked the idea of constructing something above ground that followed movement patterns below ground. I stumbled a lot trying to model the movement of worms, but in the end used a tweaked boids algorithm to produce strange natural/artifical hybrids.&lt;/p&gt;
&lt;p&gt;Here&#39;s the result from day 1:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/final.png&quot; alt=&quot;Deconstructing Nature: Final Work Day #1&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here are some details of the work:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/detail1.png&quot; alt=&quot;Detail of the work&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/detail2.png&quot; alt=&quot;Detail of the work&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/detail3.png&quot; alt=&quot;Detail of the work&quot;&gt;&lt;/p&gt;
&lt;p&gt;The work is made in &lt;a href=&quot;http://nodebox.net/&quot;&gt;NodeBox 1&lt;/a&gt; using a tweaked &lt;a href=&quot;http://nodebox.net/code/index.php/Boids&quot;&gt;Boids algorithm&lt;/a&gt; (created by Tom De Smedt).&lt;/p&gt;
&lt;p&gt;Here are some other sketches I made:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment1.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment2.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment3.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment4.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment5.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment6.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment7.png&quot; alt=&quot;Other experiment&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/blog/deconstructing-nature-day1/experiment8.png&quot; alt=&quot;Other experiment&quot;&gt;&lt;/p&gt;
&lt;p&gt;The source is available in the &lt;a href=&quot;https://github.com/fdb/deconstructing-nature&quot;&gt;Deconstructing Nature GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And finally, you can watch a &lt;a href=&quot;http://youtu.be/X4qqghkyIJI&quot;&gt;timelapse of the construction&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Starting web projects using Flask, virtualenv, pip</title>
    <link href="https://enigmeta.com/posts/2012-08-16-starting-flask/" />
    <updated>2012-08-16T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-08-16-starting-flask/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://flask.pocoo.org&quot;&gt;Flask&lt;/a&gt; is an awesome framework for building lightweight Python web-apps using a minimal amount of boilerplate. This tutorial discusses how to start a new Flask project and how to deploy it on a server.&lt;/p&gt;
&lt;p&gt;These instructions are tested on Mac OS X 10.8. All code is available under the &lt;a href=&quot;https://github.com/fdb/helloflask&quot;&gt;GitHub helloflask project&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Bootstrapping your project&lt;/h1&gt;
&lt;p&gt;One server can host multiple running web applications, and they probably all use different versions of the underlying frameworks. To manage these dependencies, we&#39;ll create a &lt;em&gt;virtual environment&lt;/em&gt; where we install the dependencies locally, together with the project instead of globally. In Python, we&#39;ll do this using virtualenv and pip. These tools provide a clean way to manage the dependencies of different Python projects.&lt;/p&gt;
&lt;h2&gt;Install virtualenv&lt;/h2&gt;
&lt;p&gt;Virtualenv creates the virtual environment. Initializing a virtual environment automatically installs pip as well, which does the Python package installs. We&#39;ll install virtualenv locally, and again on the server. But first, let&#39;s install it on your machine:&lt;/p&gt;
&lt;p&gt;sudo easy_install virtualenv&lt;/p&gt;
&lt;h2&gt;Setup a new project using virtualenv.&lt;/h2&gt;
&lt;p&gt;To start our new project, we&#39;re going to use virtualenv to setup the directory for us:&lt;/p&gt;
&lt;p&gt;virtualenv helloflask&lt;/p&gt;
&lt;p&gt;This creates a folder &amp;quot;helloflask&amp;quot; that includes an isolated Python install. This project will not look at global site-packages, and packages installed there don&#39;t affect the global Python install. Hence the &amp;quot;isolated&amp;quot;.&lt;/p&gt;
&lt;h2&gt;Start working on your project&lt;/h2&gt;
&lt;p&gt;Each time you work on this project, you need to &lt;em&gt;activate&lt;/em&gt; the virtual environment. From a new Terminal window:&lt;/p&gt;
&lt;p&gt;cd helloflask
source bin/activate&lt;/p&gt;
&lt;p&gt;You can check that your environment is active because virtualenv puts the name of the app before the&lt;/p&gt;
&lt;p&gt;Any packages you install now using pip or easy_install get installed into helloflask/lib/python2.7/site-packages.&lt;/p&gt;
&lt;h2&gt;Install Flask&lt;/h2&gt;
&lt;p&gt;We&#39;ve activated our virtual environment. This environment is devoid of any installed packages, so let&#39;s install Flask:&lt;/p&gt;
&lt;p&gt;# Make sure you&#39;ve done &amp;quot;source bin/activate&amp;quot; first
pip install flask&lt;/p&gt;
&lt;p&gt;This installs Flask, Werkzeug (a utility library) and Jinja (a templating framework).&lt;/p&gt;
&lt;h2&gt;Write some code&lt;/h2&gt;
&lt;p&gt;Create a file helloflask.py that contains the following application:&lt;/p&gt;
&lt;p&gt;from flask import Flask
app = Flask(&lt;strong&gt;name&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;@app.route(&amp;quot;/&amp;quot;)
def hello():
return &amp;quot;Hello World!&amp;quot;&lt;/p&gt;
&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == &amp;quot;&lt;strong&gt;main&lt;/strong&gt;&amp;quot;:
app.run()&lt;/p&gt;
&lt;p&gt;Run the application:&lt;/p&gt;
&lt;p&gt;python helloflask.py&lt;/p&gt;
&lt;p&gt;You should be able to surf to &lt;a href=&quot;http://127.0.0.1:5000&quot;&gt;http://127.0.0.1:5000&lt;/a&gt; and see a cheery &amp;quot;Hello World!&amp;quot; message.&lt;/p&gt;
&lt;p&gt;To stop the server process, press control-C.&lt;/p&gt;
&lt;h2&gt;Learn Flask&lt;/h2&gt;
&lt;p&gt;Browse through the excellent &lt;a href=&quot;http://flask.pocoo.org/docs/&quot;&gt;Flask documentation&lt;/a&gt; for more information on how to build the actual application. This is not covered here.&lt;/p&gt;
&lt;h2&gt;List your requirements&lt;/h2&gt;
&lt;p&gt;When deploying to a webserver it is important to register which requirements we need. To do this we &lt;em&gt;freeze&lt;/em&gt; the installed packages and store this setup in a &lt;code&gt;requirements.txt&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;pip freeze &amp;gt; requirements.txt&lt;/p&gt;
&lt;p&gt;This writes a plain text file that contains the names of the required Python packages and their versions, for example &lt;code&gt;Flask==0.9&lt;/code&gt;. We&#39;ll use this file later when we&#39;re setting up our server.&lt;/p&gt;
&lt;h2&gt;The WSGI script&lt;/h2&gt;
&lt;p&gt;When we&#39;re running our application on a browser, we&#39;ll need a &amp;quot;run script&amp;quot; that tells the server how to setup your application. In other words, the webserver doesn&#39;t run your application directly like we did from the terminal, but uses WSGI to load the application into a separate process. In this WSGI script we can tell the server to use virtualenv to load our setup.&lt;/p&gt;
&lt;p&gt;Create a new file called &lt;code&gt;application.wsgi&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;p&gt;import os, sys&lt;/p&gt;
&lt;p&gt;PROJECT_DIR = &#39;/www/helloflask.enigmeta.com/helloflask&#39;&lt;/p&gt;
&lt;p&gt;activate_this = os.path.join(PROJECT_DIR, &#39;bin&#39;, &#39;activate_this.py&#39;)
execfile(activate_this, dict(&lt;strong&gt;file&lt;/strong&gt;=activate_this))
sys.path.append(PROJECT_DIR)&lt;/p&gt;
&lt;p&gt;from helloflask import app as application&lt;/p&gt;
&lt;p&gt;Note that this file refers to a (non-existent) &lt;code&gt;/www/helloflask.enigmeta.com&lt;/code&gt; directory. We&#39;ll create this directory on the server in a minute.&lt;/p&gt;
&lt;h2&gt;Version your files&lt;/h2&gt;
&lt;p&gt;To make development and deployment easier we should really use version control. Here, we&#39;ll use &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; to manage our files. You should already have a working Git install. At the very least, make sure you&#39;ve configured your full name and email address:&lt;/p&gt;
&lt;p&gt;git config --global user.name &amp;quot;Your Name&amp;quot;
git config --global user.email &amp;quot;your.email@example.org&amp;quot;&lt;/p&gt;
&lt;p&gt;Initialize Git in our project directory:&lt;/p&gt;
&lt;p&gt;git init&lt;/p&gt;
&lt;p&gt;Because virtualenv installs a lot of unneeded files, we should ignore them. We need .gitignore to do this for us. Because .gitignore is a hidden file, we could use an editor like nano to change it:&lt;/p&gt;
&lt;p&gt;nano .gitignore&lt;/p&gt;
&lt;p&gt;An initial .gitignore file should look like this:&lt;/p&gt;
&lt;p&gt;# Virtualenv
.Python
bin
lib
include
*.py[cod]&lt;/p&gt;
&lt;p&gt;# Mac OS X custom attribute files
.DS_Store&lt;/p&gt;
&lt;p&gt;Now add everything to your initial commit:&lt;/p&gt;
&lt;p&gt;git add .
git status&lt;/p&gt;
&lt;p&gt;Git status should list all files. This should be &lt;code&gt;helloflask.py&lt;/code&gt;, &lt;code&gt;application.wsgi&lt;/code&gt;, &lt;code&gt;.gitignore&lt;/code&gt; and &lt;code&gt;requirements.txt&lt;/code&gt;. With those three files added to the Git index, let&#39;s commit them:&lt;/p&gt;
&lt;p&gt;git commit -m &amp;quot;Initial commit.&amp;quot;&lt;/p&gt;
&lt;h2&gt;Store the project in a central repository&lt;/h2&gt;
&lt;p&gt;In this example we&#39;ll use &lt;a href=&quot;http://github.com&quot;&gt;GitHub&lt;/a&gt; to store our project. This gives us a central place where we can push files to (our machine → GitHub) and pull files from (GitHub → webserver). You can use &lt;a href=&quot;http://bitbucket.com&quot;&gt;BitBucket&lt;/a&gt; which provides unlimited private repositories, or a custom setup using the webserver itself.&lt;/p&gt;
&lt;p&gt;Create a GitHub account if you don&#39;t have one yet. Then &lt;a href=&quot;https://github.com/new&quot;&gt;create a new project&lt;/a&gt;. Call it &amp;quot;helloflask&amp;quot;. Then, to push to this application, setup GitHub as the origin:&lt;/p&gt;
&lt;p&gt;git remote add origin https://github.com/USERNAME/helloflask.git
git push -u origin master&lt;/p&gt;
&lt;p&gt;This is all we need to do on the client side. Let&#39;s look at the server for now.&lt;/p&gt;
&lt;h2&gt;Setup the server&lt;/h2&gt;
&lt;p&gt;In this example we&#39;re using Apache 2 as the web server.&lt;/p&gt;
&lt;p&gt;We&#39;re going to assume we&#39;re running our app on its own domain or subdomain. This means we&#39;ll use a virtual host with its own configuration.&lt;/p&gt;
&lt;p&gt;This is on a virtual private server (VPS), such as from &lt;a href=&quot;http://www.linode.com/?r=4be4bc35d12677cff12e393c9f4dd167d9eb6dfb&quot;&gt;Linode&lt;/a&gt; (referral link).&lt;/p&gt;
&lt;p&gt;Let&#39;s set up the directory structure first. It will look like this:&lt;/p&gt;
&lt;p&gt;/www                         # Root of all sites on this machine
helloflask.example.org   # Your full domain and subdomain
helloflask           # Python project folder
logs                 # Server access and error logs&lt;/p&gt;
&lt;p&gt;To set up this directory structure:&lt;/p&gt;
&lt;p&gt;# Install virtualenv
sudo su # You probably need to be root to do this.
apt-get install python-virtualenv&lt;/p&gt;
&lt;p&gt;# Create the directory structure
mkdir -p /www/helloflask.example.org
cd /www/helloflask.example.org
mkdir logs&lt;/p&gt;
&lt;p&gt;# Clone the project
git clone https://github.com/USERNAME/helloflask.git&lt;/p&gt;
&lt;p&gt;# Initialize virtualenv and install dependencies
virtualenv helloflask
cd helloflask
pip install -r requirements.txt&lt;/p&gt;
&lt;p&gt;Here&#39;s a complete template Apache site configuration that can go in /etc/apache2/sites-available/helloflask.example.org (change the last part to reflect your domain):&lt;/p&gt;
&lt;p&gt;&amp;lt;VirtualHost *:80&amp;gt;
ServerName helloflask.enigmeta.com&lt;/p&gt;
&lt;p&gt;WSGIDaemonProcess helloflask user=www-data group=www-data threads=5
WSGIScriptAlias / /www/helloflask.enigmeta.com/helloflask/application.wsgi&lt;/p&gt;
&lt;p&gt;&amp;lt;Directory /www/helloflask.enigmeta.com/helloflask&amp;gt;
WSGIProcessGroup helloflask
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all

LogLevel warn
ErrorLog /www/helloflask.enigmeta.com/log/error.log
CustomLog /www/helloflask.enigmeta.com/log/access.log combined
&lt;/p&gt;
&lt;p&gt;Activate the virtual host:&lt;/p&gt;
&lt;p&gt;a2ensite helloflask.example.org
service apache2 reload&lt;/p&gt;
&lt;p&gt;You should now have the site running under helloflask.example.org (replace this with your domain).&lt;/p&gt;
&lt;h2&gt;Automate deployments using Fabric&lt;/h2&gt;
&lt;p&gt;Manually re-uploading the code and restarting the server gets tedious after a while. Instead, we can automate this by using Fabric.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.fabfile.org/&quot;&gt;Fabric&lt;/a&gt; is a command-line utility that runs a &lt;code&gt;fabfile&lt;/code&gt; containing instructions on how to deploy to a server. It can automate &lt;em&gt;any&lt;/em&gt; server task, not just deployment.&lt;/p&gt;
&lt;p&gt;Install Fabric using:&lt;/p&gt;
&lt;p&gt;pip install Fabric&lt;/p&gt;
&lt;p&gt;Here&#39;s an example Fabric script (change the relevant variables at the top of the script):&lt;/p&gt;
&lt;p&gt;from fabric.api import env, run, cd&lt;/p&gt;
&lt;p&gt;USERNAME = &#39;root&#39;
SERVER = &#39;helloflask.example.org&#39;
APP_NAME = &#39;helloflask&#39;
PROJECT_DIR = &#39;/www/%s/%s&#39; % (SERVER, APP_NAME)
WSGI_SCRIPT = &#39;application.wsgi&#39;&lt;/p&gt;
&lt;p&gt;env.hosts = [&amp;quot;%s@%s&amp;quot; % (USERNAME, SERVER)]&lt;/p&gt;
&lt;p&gt;def deploy():
with cd(PROJECT_DIR):
run(&#39;git pull&#39;)
run(&#39;source bin/activate; pip install -r requirements.txt&#39;)
run(&#39;touch %s&#39; % WSGI_SCRIPT)&lt;/p&gt;
&lt;p&gt;Let&#39;s go over the commands we&#39;re running:&lt;/p&gt;
&lt;p&gt;git pull # Get the new source code from GitHub
bin source/activate # Activate the virtual environment (needed for the next step)
pip install -r requirements.txt # Check if there are new required packages and install them.
touch helloflask.py # Let Apache reload your application.&lt;/p&gt;
&lt;p&gt;Save this in a file called &lt;code&gt;fabfile.py&lt;/code&gt; in the root of your project and add it to version control:&lt;/p&gt;
&lt;p&gt;git add fabfile.py
git commit -m &amp;quot;Add deployment automation script.&amp;quot;&lt;/p&gt;
&lt;p&gt;Subsequent deployments can be done using:&lt;/p&gt;
&lt;p&gt;fab deploy&lt;/p&gt;
&lt;p&gt;Fabric shows the output of the server so you can check when things go wrong.&lt;/p&gt;
&lt;h2&gt;Update workflow&lt;/h2&gt;
&lt;p&gt;Now that you have a fully working install, you can keep updating the application with a minimum of effort:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run the server locally.&lt;/li&gt;
&lt;li&gt;Change helloflask.py locally and go to http://localhost:5000 to see the results.&lt;/li&gt;
&lt;li&gt;If you&#39;re happy with the results you can commit the changes and push them to GitHub.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;fab deploy&lt;/code&gt; to update the application on the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- In a next post, I&#39;ll discuss creating REST API&#39;s using Flask. --&gt;
&lt;!-- I&#39;ll get to it eventually I promise :-)  --&gt;
</content>
  </entry>
  <entry>
    <title>Teaching lists to designers</title>
    <link href="https://enigmeta.com/posts/2012-05-04-teaching-lists-to-designers/" />
    <updated>2012-05-04T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-05-04-teaching-lists-to-designers/</id>
    <content type="html">&lt;p&gt;I&#39;ve been teaching generative design using &lt;a href=&quot;http://nodebox.net/&quot;&gt;NodeBox 1&lt;/a&gt; since 2004. NodeBox 1 is a &lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt; IDE for making generative graphics. With my team at &lt;a href=&quot;http://www.emrg.be/&quot;&gt;EMRG&lt;/a&gt; I&#39;ve been teaching one- or two-week workshops for graphic designers, resulting in a poster or animation at the end. You can see some of the process / results at the &lt;a href=&quot;http://workshops.nodebox.net/&quot;&gt;Workshop Blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The most important insight I&#39;ve discovered during the workshops is to &lt;strong&gt;teach people data structures as soon as possible&lt;/strong&gt;. Often I teach this before learning about conditions or loops. Data structures are absolutely essential to let students progress from the &amp;quot;beginner&amp;quot; stage to the &amp;quot;competent&amp;quot; stage.&lt;/p&gt;
&lt;p&gt;Before, I learned the &amp;quot;building blocks of programming&amp;quot;: variables, loops, conditions, functions. But without a way to store and manipulate data, &lt;em&gt;none of these constructs are useful&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;One week is too short to learn about all data structures so we only teach lists. &lt;strong&gt;Lists can be used for everything:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the keywords of a web page&lt;/li&gt;
&lt;li&gt;the points of a path&lt;/li&gt;
&lt;li&gt;the installed fonts&lt;/li&gt;
&lt;li&gt;the images in a folder&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these require lists. Once we have a list what can we do with it? We can:&lt;/p&gt;
&lt;h2&gt;Iterate a list&lt;/h2&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; pt &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;points&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    ellipse&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; random&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; random&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Sort a list&lt;/h2&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; glob
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ImageStat

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image_brightness&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fname&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
   img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Image&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fname&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;convert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;L&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   stat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ImageStat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; stat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

icon_files &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; glob&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;glob&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;icons/*.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
sorted_icons &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;icon_files&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;image_brightness&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Choose elements from the list&lt;/h2&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; random &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; choice
    all_words &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/usr/share/dict/web2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readlines&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    old_word &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; choice&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;all_words&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;strip&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    new_word &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; choice&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;all_words&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;strip&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%s is the new %s.&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;old_word&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;capitalize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; new_word&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For some students we also teach dictionaries (maps) if they need it to do lookups. But lists are absolutely essential.&lt;/p&gt;
&lt;p&gt;Before teaching data structures students were struggling in going from their idea to a solution. By teaching lists we&#39;ve seen a huge increase in self-reliance. They can now express their ideas in terms of a programming construct. Have a set of Wikipedia articles you want to visualize? Use a list to store them and iterate through them. Have an idea for a font where the points are randomly wiggled? Get the list of points from a glyph shape and add a random value.&lt;/p&gt;
&lt;p&gt;I think most designers never learn to program because all the teaching material is about variables, conditions and loops. As programmers we know that programming is fundamentally about manipulating data. But designers don&#39;t know this! By teaching data structures as soon as possible they understand why knowing coding can be useful for them as well.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Alternate Universe of the Mac App Store</title>
    <link href="https://enigmeta.com/posts/2012-03-18-alternate-universe-mac-app-store/" />
    <updated>2012-03-18T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-03-18-alternate-universe-mac-app-store/</id>
    <content type="html">&lt;p&gt;When trying to reinstall my MacBook Air, I tried going through the Mac App Store to download my applications. It seems like the store operates in an alternate universe:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/dropbox.png&quot; alt=&quot;Dropbox&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/skype.png&quot; alt=&quot;Skype&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/firefox.png&quot; alt=&quot;Firefox&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/chrome.png&quot; alt=&quot;Chrome&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/vlc.png&quot; alt=&quot;VLC&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/parallels.png&quot; alt=&quot;Parallels&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/photoshop.png&quot; alt=&quot;Photoshop&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/illustrator.png&quot; alt=&quot;Illustrator&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/textmate.png&quot; alt=&quot;TextMate&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/macvim.png&quot; alt=&quot;MacVIM&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/alternate-universe-mac-app-store/minecraft.png&quot; alt=&quot;Minecraft&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Profilitics</title>
    <link href="https://enigmeta.com/posts/2012-02-24-profilitics/" />
    <updated>2012-02-24T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2012-02-24-profilitics/</id>
    <content type="html">&lt;p&gt;The 2012 American elections promise to be exciting. Candidates throwing mud at eachother, and attacks becoming increasingly more personal. But how different are the candidates really?&lt;/p&gt;
&lt;p&gt;As part of the &lt;a href=&quot;http://www.imal.org/en/activity/generatorx3&quot;&gt;Generator.x 3.0 workshop&lt;/a&gt; by &lt;a href=&quot;http://mariuswatz.com/&quot;&gt;Marius Watz&lt;/a&gt;, I worked together with Lieven Menschaert to produce three-dimensional lasercut heads detailing what really goes through the minds of the republican and democratic candidates.&lt;/p&gt;
&lt;p&gt;Using generative software, we map the democratic and republican candidate on a variety of layers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keywords layers: containing keywords from quotes of political candidates on important issues.&lt;/li&gt;
&lt;li&gt;Campaign contributions: amount of contributions from various sectors.&lt;/li&gt;
&lt;li&gt;Regional popularity: a map of the states linked to a certain party.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The project uses an alpha version of &lt;a href=&quot;http://alpha.nodebox.net/&quot;&gt;NodeBox 3&lt;/a&gt;, developed simultaneously with the project.&lt;/p&gt;
&lt;img src=&quot;https://enigmeta.com/media/profilitics/head-overlays.png&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/profilitics/keywords-laser-cut.jpg&quot;&gt;
</content>
  </entry>
  <entry>
    <title>City in a Bottle</title>
    <link href="https://enigmeta.com/posts/2011-11-01-city-in-a-bottle/" />
    <updated>2011-11-01T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2011-11-01-city-in-a-bottle/</id>
    <content type="html">&lt;p&gt;&amp;quot;City in a Bottle&amp;quot; is an interactive, generative forest with computer-generated trees, plants and animals.&lt;/p&gt;
&lt;p&gt;Together with artists, musicians and programmers, we created a project bordering between art, science and gaming, funded by the Flemish Audiovisual Fund.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.cityinabottle.org/&quot;&gt;http://www.cityinabottle.org/&lt;/a&gt;&lt;/p&gt;
&lt;img src=&quot;https://enigmeta.com/media/city-in-a-bottle/promo.jpg&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/city-in-a-bottle/shot1.jpg&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/city-in-a-bottle/shot2.jpg&quot;&gt;
</content>
  </entry>
  <entry>
    <title>Word Maze</title>
    <link href="https://enigmeta.com/posts/2011-06-01-word-maze/" />
    <updated>2011-06-01T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2011-06-01-word-maze/</id>
    <content type="html">&lt;p&gt;Made for the &amp;quot;Travelling Letters exhibition&amp;quot; in 2011 Vilnius, Lithuania, I developed a set of words around the concept of &amp;quot;transit&amp;quot;, disguised as generative mazes.&lt;/p&gt;
&lt;img src=&quot;https://enigmeta.com/media/word-maze/transit.jpg&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/word-maze/motion.jpg&quot;&gt;
&lt;img src=&quot;https://enigmeta.com/media/word-maze/wander.jpg&quot;&gt;
</content>
  </entry>
  <entry>
    <title>NodeBox 2 is a Graph</title>
    <link href="https://enigmeta.com/posts/2011-05-01-nodebox-2-is-a-graph/" />
    <updated>2011-05-01T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2011-05-01-nodebox-2-is-a-graph/</id>
    <content type="html">&lt;p&gt;In this post, I&#39;ll explain how NodeBox 2 is build as a big graph evaluator and describe how the program arrives at its visual output. I will detail the difficulties in marrying the functional aspects of NodeBox 2 with Processing&#39;s imperative nature.&lt;/p&gt;
&lt;h2&gt;NodeBox 2 as a functional language&lt;/h2&gt;
&lt;p&gt;NodeBox 2 is a program where operations are presented as a graph of nodes. Each node fetches data from its inputs, calculates a new result and sends it off to its outputs. In the end, the output of one node gets displayed (this node is marked in the screenshot with a yellow rim).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/cooking-example-screenshot.png&quot; alt=&quot;Cooking Example&quot;&gt;&lt;/p&gt;
&lt;p&gt;The underlying data structure is a &lt;a href=&quot;http://en.wikipedia.org/wiki/Directed_acyclic_graph&quot;&gt;directed acyclic graph&lt;/a&gt;. This is a graph where all nodes have a direction, and where cycles between nodes &lt;em&gt;verboten&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Each node contains a &amp;quot;cook&amp;quot; function. The output of the node (which is stored in its output port) is the return value of this function. We mark one of the nodes as the &lt;em&gt;rendered node&lt;/em&gt;. This node is the one we want to cook.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From the rendered node, find its &lt;strong&gt;dependencies&lt;/strong&gt;. These are the nodes connected to input ports of this node.&lt;/li&gt;
&lt;li&gt;For each dependency:
&lt;ul&gt;
&lt;li&gt;Find &lt;em&gt;its&lt;/em&gt; dependencies and update them, recursively.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cook&lt;/em&gt; the node. This executes the cook function and puts the return value in the output port, ready for the dependent nodes to pick it up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cook the rendered node.&lt;/li&gt;
&lt;li&gt;Draw the result of the rendered node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach has a number of benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is &lt;strong&gt;one clear endpoint&lt;/strong&gt;, the rendered node. By changing the rendered node, users can look at the output of a node anywhere in the graph.&lt;/li&gt;
&lt;li&gt;The graph is &lt;strong&gt;determinate&lt;/strong&gt;. Cooking the network always gives the same result.&lt;/li&gt;
&lt;li&gt;Unchanged parts of the graph can be &lt;strong&gt;cached&lt;/strong&gt;. We can determine which nodes we need to recalculate whenever something changes by looking at its dependencies. We try to be as lazy as possible. Doing the least amount of work needed is good for speed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, NodeBox 2 takes some aspects from functional programming, such as &amp;quot;pure&amp;quot; functions and function composition, and makes them visual. Now that I think about it, this explains my fascination for &lt;a href=&quot;http://clojure.org/&quot;&gt;Clojure&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Processing is a state machine&lt;/h2&gt;
&lt;p&gt;We&#39;d like to integrate &lt;a href=&quot;http://processing.org/&quot;&gt;Processing&lt;/a&gt; into the network. Processing provides an API for drawing, interactivity and animation.&lt;/p&gt;
&lt;p&gt;The design of Processing is quite different. Processing is designed as a &lt;strong&gt;state machine&lt;/strong&gt;. This has a number of effects:&lt;/p&gt;
&lt;p&gt;Here is a simple Processing example that demonstrates its stateful nature.&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mousePressed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ellipse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mouseX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mouseY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&#39;s what it looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/processing-example.png&quot; alt=&quot;Processing Example&quot;&gt;&lt;/p&gt;
&lt;p&gt;Note that we don&#39;t specify the fill color in the ellipse. Instead, we &lt;em&gt;set&lt;/em&gt; the fill color. All commands that draw something, from that point on, will use this new fill color.
Also note that the ellipse command &lt;em&gt;immediately&lt;/em&gt; draws something on the screen.&lt;/p&gt;
&lt;p&gt;In other words, all Processing commands have &lt;em&gt;side effects&lt;/em&gt;. We don&#39;t care about their return value, but we call them because they change something in the world. Processing is an &lt;strong&gt;imperative language&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Compare this to the typical code of a node:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    p &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Path&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fill &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fill
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code doesn&#39;t draw anything! All it does is create a Path object with the right geometry and color and return it. It is free of side effects. You could call this code many times, or not at all if you already have the cached result.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;basic problem&lt;/strong&gt; is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can no longer be sure that a node has no side effects. Quite the contrary! Processing is all about managing state.&lt;/li&gt;
&lt;li&gt;There is no clear endpoint or &amp;quot;rendered node&amp;quot;. Instead, the render is a result of calling the commands.&lt;/li&gt;
&lt;li&gt;The order in which nodes are cooked is important.&lt;/li&gt;
&lt;li&gt;Caching doesn&#39;t work since the functions have to be called for them to have an effect.&lt;/li&gt;
&lt;li&gt;There is no data involved! In the Processing example, nothing gets passed on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Processing → Graph&lt;/h2&gt;
&lt;p&gt;Let&#39;s try converting our simple Processing example into a node network.&lt;/p&gt;
&lt;p&gt;We&#39;ll start simple by drawing a rectangle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/01-net-rect.png&quot; alt=&quot;Graph of a Simple Rectangle&quot;&gt;&lt;/p&gt;
&lt;p&gt;This node has a number of connection points, or &lt;em&gt;ports&lt;/em&gt; that can be connected. As in the example, we&#39;ll connect the X and Y coordinates to the mouse.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/02-net-rect-mouse.png&quot; alt=&quot;02 Net Rect Mouse&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, the rendered node comes into play. Since we have more than one node, we need to know which one to render. Here, we want to see the result of drawing the rectangle. The mouse node is a dependency.&lt;/p&gt;
&lt;p&gt;We haven&#39;t set a color though. Let&#39;s do that now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/03-net-fill.png&quot; alt=&quot;03 Net Fill&quot;&gt;&lt;/p&gt;
&lt;p&gt;Uh-oh. We&#39;ve run into a problem. As said before, we now have &lt;em&gt;two&lt;/em&gt; rendered nodes. One that sets the fill color, and one that draws the rectangle. In which order do we execute them? How do we specify this order?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/04-net-rect-with-fill.png&quot; alt=&quot;04 Net Rect With Fill&quot;&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s work around the problem. We&#39;ll give the draw rectangle node a &amp;quot;fill&amp;quot; attribute. Then, inside of the node, we call the Processing &amp;quot;fill&amp;quot; command first, and than the &amp;quot;rect&amp;quot; command.&lt;/p&gt;
&lt;p&gt;We know set only one fill color. Remember, from our code, that the fill color changes depending on if the mouse was pressed or not. This means we&#39;ll need &lt;em&gt;two&lt;/em&gt; colors, and some way to choose between the two.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/05-net-rect-with-fill-condition.png&quot; alt=&quot;05 Net Rect With Fill Condition&quot;&gt;&lt;/p&gt;
&lt;p&gt;The choice node does the trick. It checks a boolean value, &amp;quot;condition&amp;quot;, which is connected to the mouse pressed port. If the condition is true, its output is set to input A. Otherwise, if the condition is false, we&#39;ll set the output to input B.&lt;/p&gt;
&lt;p&gt;By having the choice determine the color, we can now use this color as the fill for our rectangle node.&lt;/p&gt;
&lt;p&gt;This whole &amp;quot;fill&amp;quot; port feels like cheating though. What if there is more state we need to set? Will we need a huge list for each node that draws something? Imagine that the state itself is order-dependent: setting a rotation before a translation has a different effect than the other way around. In which order do we set the state inside of the node itself?&lt;/p&gt;
&lt;p&gt;Clearly, if we want to fully support the stateful nature of Processing, we need a different solution.&lt;/p&gt;
&lt;p&gt;Quartz Composer does this by tagging each node with an order number. Instead of one rendered node, we now have a list of nodes that needs to be executed in the specified order. Without the &amp;quot;mouse pressed&amp;quot; condition, the graph can look as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/06-net-fill-with-order.png&quot; alt=&quot;06 Net Fill With Order&quot;&gt;&lt;/p&gt;
&lt;p&gt;By specifying the order, we make state ordering explicit. In this graph, the fill node is executed first, setting the global state fill color. After that, the &amp;quot;draw rectangle&amp;quot; node is evaluated, which processes its dependencies (the mouse) first after drawing something itself.&lt;/p&gt;
&lt;p&gt;This seems like a good solution! By tagging the nodes with an order, we can choose the ordering.&lt;/p&gt;
&lt;p&gt;How does this look when we add a condition? I don&#39;t know:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/07-net-fill-with-order-condition.png&quot; alt=&quot;07 Net Fill With Order Condition&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can&#39;t execute both the black and white nodes, because they would set state and the last one would win. Also, we can&#39;t use a condition node since none of them have an output. They just set state.&lt;/p&gt;
&lt;p&gt;One solution is to pass data around until the very end. In this example, we would choose between two color objects (that don&#39;t set state), then finally set state after we&#39;ve chosen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://enigmeta.com/media/blog/nodebox-2-is-a-graph/08-net-fill-with-fill-condition.png&quot; alt=&quot;08 Net Fill With Fill Condition&quot;&gt;&lt;/p&gt;
&lt;p&gt;This works for this case. However, it is not sustainable for every kind of state.&lt;/p&gt;
&lt;p&gt;The semantics of the network need to change to adapt this imperative way of handling code. In a way, it becomes a wrapper around the constructs we use in programming: conditions, loops, functions, etc. Figuring out these semantics will be part of my research project.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>PyCon 2009 report</title>
    <link href="https://enigmeta.com/posts/2009-04-15-pycon-2009-report/" />
    <updated>2009-04-15T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2009-04-15-pycon-2009-report/</id>
    <content type="html">&lt;p&gt;This year was my first visit to &lt;a href=&quot;http://www.pycon.org/&quot;&gt;PyCon&lt;/a&gt; in the United
States. Here&#39;s the &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/&quot;&gt;full schedule for the
conference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I will give some notes and remarks about the sessions that I
followed. For each session I included a link to the session details. Most of
them have videos and slides of the talks.&lt;/p&gt;
&lt;h2&gt;How to Give a Python talk&lt;/h2&gt;
&lt;p&gt;A lot of talk about presentations using slides. I don&#39;t like slides. The
author didn&#39;t like live coding because you could make a lot of typos, which
would frustrate an audience. Later on, somebody gave a lightning talk about
&lt;a href=&quot;http://code.google.com/p/playerpiano/&quot;&gt;player piano&lt;/a&gt;, a project that types
automatically for you and is very useful for presentations.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/6/&quot;&gt;How to Give a Python
talk&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Introduction to CherryPy&lt;/h2&gt;
&lt;p&gt;CherryPy is a lightweight HTTP framework. It is very much unlike Django: it
doesn&#39;t have an ORM or administrative interface, but just provides the perfect
balance for creating web applications that are different from the standard
&lt;a href=&quot;http://en.wikipedia.org/wiki/Create,_read,_update_and_delete&quot;&gt;CRUD&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can install &amp;quot;tools&amp;quot; that can, for example, automatically encode/decode JSON. CherryPy-guy gave a nice example that I can&#39;t find, but here&#39;s &lt;a href=&quot;http://www.cherrypy.org/wiki/CustomTools&quot;&gt;the webpage&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can use &lt;a href=&quot;http://www.cherrypy.org/wiki/PageHandlers&quot;&gt;other dispatchers&lt;/a&gt; than the default. MethodDispatcher looks interesting, because it allows you to do REST-style systems.&lt;/li&gt;
&lt;li&gt;There&#39;s a tool to &lt;a href=&quot;http://www.cherrypy.org/wiki/StaticContent&quot;&gt;serve static content&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/11/&quot;&gt;Introduction to
CherryPy&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Introduction to Python Profiling&lt;/h2&gt;
&lt;p&gt;Tools for how to write fast Python code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need to profile your code to find out where it spends its time. This is really important: you really don&#39;t know where your code is slow.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;http://docs.python.org/library/profile.html&quot;&gt;cProfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://kcachegrind.sourceforge.net/html/Home.html&quot;&gt;KCacheGrind&lt;/a&gt; can help you with interpreting Python profiles.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vrplumber.com/programming/runsnakerun/&quot;&gt;RunSnakeRun&lt;/a&gt; allows you to view cProfile dumps in a GUI. This tool was created by the guy giving the talk.&lt;/li&gt;
&lt;li&gt;Caching function references can speed up deeply nested code. But profile first.&lt;/li&gt;
&lt;li&gt;Property lookups look just like an attribute lookup, but can be much slower.&lt;/li&gt;
&lt;li&gt;Another interesting tool is &lt;a href=&quot;http://packages.python.org/line_profiler/&quot;&gt;line profiler&lt;/a&gt;, by Robert Kern of Enthought.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/15/&quot;&gt;Introduction to Python
Profiling&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Panel: Python VMs&lt;/h2&gt;
&lt;p&gt;A discussion about the different implementations of Python:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPython, the &amp;quot;official&amp;quot; Python implementation. This gets confused with Python, because a few years ago there was only one Python language and implementation. Now there are many implementations of the same language.&lt;/li&gt;
&lt;li&gt;Jython, Python on the JVM.&lt;/li&gt;
&lt;li&gt;IronPython, Python on .NET and Mono.&lt;/li&gt;
&lt;li&gt;PyPy, Python in Python. This is actually more useful than it sounds.&lt;/li&gt;
&lt;li&gt;Unladen swallow, an effort by Google to make Python 10x faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I found interesting in the discussion was that the &amp;quot;official&amp;quot; Python guys
really welcome and support the other implementations. I had a chance to have
lunch together with all the different VM guys, and they are really sincere
about this.&lt;/p&gt;
&lt;p&gt;Just as with JavaScript implementations, there is a lot of buzz and activity
around making Python run faster. Python and JavaScript are very different
languages however, and optimization techniques used in JavaScript cannot be
used in Python. Still, everybody has their own idea of how to make Python
faster (check out &amp;quot;PyPy status&amp;quot;).&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/21/&quot;&gt;Panel: Python VMs&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Python in a sandbox&lt;/h2&gt;
&lt;p&gt;A talk by the makers of PyPy about the use of PyPy as a virtualization tool.
PyPy has a secure sandbox for running untrusted Python code, where you can
bound IO calls, CPU and RAM resources. Really interesting for running other
peoples&#39; Python code on your own server. PyPy is &amp;quot;only&amp;quot; 2-3 times slower than
regular Python.&lt;/p&gt;
&lt;p&gt;There is no official release, but here are the steps for running it yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Download the &lt;a href=&quot;http://codespeak.net/svn/user/getxsick/django-sandbox/&quot;&gt;sandbox&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Translate pypy with --sandbox flag (this takes a while).&lt;/li&gt;
&lt;li&gt;Run the script using pypy interact.py&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/27/&quot;&gt;Python in a
sandbox&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;A better Python for the JVM&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;very&lt;/strong&gt; technical talk about the Jython compiler. A bit over my head.
However the conclusions were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Currently Jython is a bit slower than Python.&lt;/li&gt;
&lt;li&gt;The new Jython compiler should make things a bit faster.&lt;/li&gt;
&lt;li&gt;However, currently the new compiler isn&#39;t faster.&lt;/li&gt;
&lt;li&gt;But it provides better opportunities for optimization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/32/&quot;&gt;A better Python for the
JVM&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Behind the scenes of EveryBlock.com&lt;/h2&gt;
&lt;p&gt;Adrian Holovaty, maker of Django, talked about Everyblock, his project to
catalog everything that&#39;s happening at the hyper-local level (in your
neighborhood).&lt;/p&gt;
&lt;p&gt;They have a lot of different data-types, and wanted to store all of them in
the same table. This meant that date types had to be opaque, since the columns
would be different for the various datatypes. The main table has columns named
varchar1, varchar2, int1, int2, etc. A schema table defines what these various
columns means for a given schema.&lt;/p&gt;
&lt;p&gt;This really looked like a hack, which was surprising coming from Adrian,
someone who has written such a clean web framework. It seems like an other
database system (such as key-value stores or even a graph database, such as
&lt;a href=&quot;http://neo4j.org/&quot;&gt;neo4j&lt;/a&gt;) would fit the job better.&lt;/p&gt;
&lt;p&gt;One remark also struck me as odd: Adrian stated that he wrote everything from
scratch, basically because &amp;quot;I don&#39;t trust other people&#39;s code&amp;quot;. It was unclear
whether he was entirely serious or not, but the fact remains that no external
code was used in his website.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/36/&quot;&gt;Behind the scenes of
EveryBlock.com&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Jython Progress&lt;/h2&gt;
&lt;p&gt;The reason for coming to PyCon: a very interesting talk by &lt;a href=&quot;http://fwierzbicki.blogspot.com/&quot;&gt;Frank
Wierzbicki&lt;/a&gt;, who works at Sun on Jython.&lt;/p&gt;
&lt;p&gt;The focus for the Jython 2.5 release was on compatibility. Through our use
with Jython we found that a lot of stuff that worked in Python really worked
in Jython as well, which was nice.&lt;/p&gt;
&lt;p&gt;The focus for Jython 2.6 will be on performance and integration with Java. It
should show up quicker than the 2.2 &amp;gt; 2.5 release, which took years to
complete.&lt;/p&gt;
&lt;p&gt;At the end he also showed &lt;a href=&quot;http://www.openendedgroup.com/field&quot;&gt;Field&lt;/a&gt;, which
is a Processing/NodeBox-like environment in Java using Jython. It has only
very recently been open-sourced. It only runs on Mac OS X 10.5.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/46/&quot;&gt;Jython Progress&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Pinax: a platform for rapidly developing websites&lt;/h2&gt;
&lt;p&gt;Pinax has been getting some exposure lately because it provides ready-made
components for Django. I had some troubles getting it to work, and was hoping
this talk would provide some answers.&lt;/p&gt;
&lt;p&gt;There seemed to be some problems with how to distribute this, and how to
version all of it. They make a lot of use of svn:externals, which isn&#39;t bad
per se. It really requires a lot of commitment to get started with the
framework, but once you have it installed, it provides a lot of the
boilerplate functionality of sites, and more specifically, social networks:
user-to-user messaging, twitter clone, tagging, photo management, interest
groups, … .&lt;/p&gt;
&lt;p&gt;After the talk, I&#39;m still not sure if it&#39;s worth the trouble, or if I&#39;d rather
be writing a lot of that from scratch. I feel the framework is still a bit too
young to be used without to much configuration hassle. Also, the remark of
Adrian during his EveryBlock talk about writing everything himself rings true
here.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/49/&quot;&gt;Pinax: a platform for rapidly developing
websites&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Class Decorators: Radically Simple&lt;/h2&gt;
&lt;p&gt;A nice introduction to &amp;quot;better metaclasses&amp;quot;. The functionality is only
available in Python 2.6, but the talk is interesting (and short) enough to
watch in its entirety.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/55/&quot;&gt;Class Decorators: Radically
Simple&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;PyPy status talk&lt;/h2&gt;
&lt;p&gt;After the talk about Python sandboxing using PyPy, I was interested in what
the status of PyPy was as a project. PyPy was started to be able to generate
Python interpreters with more flexibility than a fixed C implementation. By
defining a Python Interpreter on a higher level, you can experiment with
different VM features quickly.&lt;/p&gt;
&lt;p&gt;The PyPy interpreter is slower but consumes a lot less memory: some objects
are 50% the size of CPython. They don&#39;t support libraries written in C, but
they do support CTypes as the official way to have bindings for PyPy.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/59/&quot;&gt;PyPy status talk&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Drop ACID and think about data&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://bob.pythonmac.org/&quot;&gt;Bob Ippolito&lt;/a&gt; talked about the various alternative
data storage implementations that have come up recently. He covered both
closed- and open-source implementations. Most of the talk was about
alternative key-value stores and other non-relational models, but he didn&#39;t
cover graph databases.&lt;/p&gt;
&lt;p&gt;There are a lot of different kinds of databases out there, but none of them
seemed particularly stable or usable for my purposes. Afterwards, I checked
out the open space about Cassandra, which seemed like the most stable one.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/64/&quot;&gt;Drop ACID and think about
data&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Concurrency and Distributed Computing with Python Today&lt;/h2&gt;
&lt;p&gt;This talk was not so much about the multiprocessing module in Python 2.6, but
more about the tools available today.&lt;/p&gt;
&lt;p&gt;He covered Jython as a solution for the global interpreter lock (GIL), because
Jython uses Java threading which does not have the GIL. Also, the usage of
java.util.concurrent solves a lot of problems. Actually, this seemed the most
interesting approach for my projects.&lt;/p&gt;
&lt;p&gt;He also talked about &lt;a href=&quot;http://www.stackless.com/&quot;&gt;Stackless Python&lt;/a&gt;, which
offers lightweight threads and cooperative multitasking.&lt;/p&gt;
&lt;p&gt;There are different approaches to multitasking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real threads: hard to use because concurrency requires a lot of thinking ahead. They are hampered by the GIL in CPython.&lt;/li&gt;
&lt;li&gt;Coroutines: light-weight threads are not truly parallel, but simplify the threading problem.&lt;/li&gt;
&lt;li&gt;Actors: isolated, self reliant components that communicate via messages. They are truly parallel, and are a good model to overcome the threading fallacies. &lt;a href=&quot;http://erlang.org/&quot;&gt;Erlang&lt;/a&gt; and &lt;a href=&quot;http://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt; are two programming languages that use the actors idiom for concurrency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these approaches have libraries implementing them in Python. There are
a &lt;strong&gt;lot&lt;/strong&gt; of them, and most are alpha quality. The two good ones are
&lt;a href=&quot;http://twistedmatrix.com/trac/&quot;&gt;Twisted&lt;/a&gt; and
&lt;a href=&quot;http://www.kamaelia.org/Home&quot;&gt;Kamaelia&lt;/a&gt;. The rest is a mish-mash of
technologies. (&amp;quot;Concurrency is hard, let’s go shopping!&amp;quot;)&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/69/&quot;&gt;Concurrency and Distributed Computing with Python
Today&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Abstraction as Leverage&lt;/h2&gt;
&lt;p&gt;An abstract talk about the tower of abstractions we use every as programmers,
and how to produce and consume abstraction layers.&lt;/p&gt;
&lt;p&gt;The starting point for the talk was that abstractions &amp;quot;leak&amp;quot;. This is
something &lt;a href=&quot;http://www.joelonsoftware.com/articles/LeakyAbstractions.html&quot;&gt;Joe
Spolsky&lt;/a&gt; has
written about, and an interesting read. He also pointed out a quote from Jason
Fried of 37 signals: &amp;quot;Prefer action over abstr-action&amp;quot;.&lt;/p&gt;
&lt;p&gt;It&#39;s hard to sum up the talk without paraphrasing it (badly), so I suggest you
go see it.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/75/&quot;&gt;Abstraction as
Leverage&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Paver: easy build and deployment automation for Python projects&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver&lt;/a&gt; is sort of like
&lt;a href=&quot;http://ant.apache.org/&quot;&gt;Ant&lt;/a&gt; for Python projects, but instead of using a
bizarre XML&lt;/p&gt;
&lt;p&gt;syntax, just using Python. It is also very similar to Ruby&#39;s
&lt;a href=&quot;http://rake.rubyforge.org/&quot;&gt;Rake&lt;/a&gt;. It is really&lt;/p&gt;
&lt;p&gt;interesting and looks mature. It requires you to make a pavement.py file in
your project&lt;/p&gt;
&lt;p&gt;directory that gets picked up and executed by Paver.&lt;/p&gt;
&lt;p&gt;The basic building blocks in Paver are tasks. Tasks can be given command
options (using &lt;a href=&quot;http://docs.python.org/library/optparse.html&quot;&gt;optparse&lt;/a&gt; -like
syntax).&lt;/p&gt;
&lt;p&gt;Paver can be used for deploying servers, generating documentation, building a
distribution&lt;/p&gt;
&lt;p&gt;(using distutils/setuptools), working with files, etc. Paver doesn&#39;t replace
distutils, but&lt;/p&gt;
&lt;p&gt;embraces and extends it in a non-evil way.&lt;/p&gt;
&lt;p&gt;A good introduction is &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/getting_started.html&quot;&gt;Getting Starting with
Paver&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/82/&quot;&gt;Paver: easy build and deployment automation for Python
projects&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Making games in Python - Tools and techniques at CCP&lt;/h2&gt;
&lt;p&gt;I wanted to see this talk to see how a gaming company used Python almost
everywhere in a high-profile MMORPG. They use Python for networking, the web
server, content authoring tools (using wxPython) and game logic. Some
performance-critical parts were they use C++. They did not talk about how they
wrapped C++ code, only that they didn&#39;t use Boost.Python.&lt;/p&gt;
&lt;p&gt;They use embedded &lt;a href=&quot;http://www.stackless.com/&quot;&gt;stackless Python&lt;/a&gt;, which they
actively maintain. It allows them to do micro-threading (every object in the
world runs in its own light-weight thread).&lt;/p&gt;
&lt;p&gt;They use their own code-reloading system called
&lt;a href=&quot;http://code.google.com/p/livecoding/&quot;&gt;livecoding&lt;/a&gt; because the reload built-in
was deemed unsuitable. Their custom code reloading system allows them to
reload game code while server and client are running. They also integrated
unit testing so that the tests run before the code is reloaded to see if it
passes.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/87/&quot;&gt;Making games in Python - Tools and techniques at
CCP&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Stackless python in EVE, pt. 2&lt;/h2&gt;
&lt;p&gt;This talk went more in depth about how they used Stackless Python in EVE. It
covered&lt;/p&gt;
&lt;p&gt;StacklessIO, a unified framework for blocking operations in Stackless Python.
He also talked&lt;/p&gt;
&lt;p&gt;about how they deployed StacklessIO at CCP, using &amp;quot;Cowboy mode&amp;quot;, which short-
circuited normal&lt;/p&gt;
&lt;p&gt;QA procedures. Although interesting, I could not see myself using any of the
technologies or&lt;/p&gt;
&lt;p&gt;working methods introduced.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/91/&quot;&gt;Stackless python in EVE, pt.
2&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Designing a web framework: Django&#39;s design decisions&lt;/h2&gt;
&lt;p&gt;I love to see Jacob Kaplan-Moss give a talk, and this one was no exception.
This talk was high-level overview of some of the design decisions they made in
the framework, and how to keep ego out of the equation.&lt;/p&gt;
&lt;p&gt;He talked about the difference between academic frameworks (&amp;quot;architecture
astronauts&amp;quot;) and the real world.&lt;/p&gt;
&lt;p&gt;What I found interesting was the decision in Django to make a full stack
framework instead of glueing together existing components. Part of the reason
for this was that there were not much existing components available, but also
that they could provide one consistent API&lt;/p&gt;
&lt;p&gt;dialect that felt they same, whether you were working in the templating
language, the database API or some other part of the stack.&lt;/p&gt;
&lt;p&gt;He also pointed that out that having users pick from existing components
because it would allow for full flexibility only makes sense for expert users,
and not for beginners that are just starting out with your framework. Having
them pick from a list of components that they have no knowledge over is silly.&lt;/p&gt;
&lt;p&gt;He also pointed out the talk by Cal Henderson of Flickr, &lt;a href=&quot;http://www.youtube.com/watch?v=i6Fr65PFqfk&quot;&gt;Why I Hate
Django&lt;/a&gt; which is really
interesting and funny.&lt;/p&gt;
&lt;p&gt;» &lt;a href=&quot;http://us.pycon.org/2009/conference/schedule/event/95/&quot;&gt;Designing a web framework: Django&#39;s design
decisions&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Open Space: Cassandra&lt;/h2&gt;
&lt;p&gt;I followed an open space talk by Jonathan Ellis of Rackspace Managed Hosting,
one of the maintainers of Cassandra. [Cassandra](http://code.google.com/p/the-
cassandra-project/) is a distributed database somewhere between
&lt;a href=&quot;http://en.wikipedia.org/wiki/BigTable&quot;&gt;BigTable&lt;/a&gt; and
&lt;a href=&quot;http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html&quot;&gt;Dynamo&lt;/a&gt;,
which are both closed source. The project was started by two ex-Googlers at
Facebook, and has now been open-sourced. The talk went into depth about the
implementation of Cassandra.&lt;/p&gt;
&lt;p&gt;The system looks interesting but way too big for my needs. As long as we don&#39;t
really need high-performance distributed databases, I&#39;d prefer my ACID using
MySQL or Postgresql (or Neo4j).&lt;/p&gt;
&lt;h2&gt;Neo4j&lt;/h2&gt;
&lt;p&gt;Turns out the maker of the new Jython compiler also works on an open-source
graph database called &lt;a href=&quot;http://neo4j.org/&quot;&gt;neo4j&lt;/a&gt;. His name is &lt;a href=&quot;http://twitter.com/thobe&quot;&gt;Tobias
Ivarsson&lt;/a&gt;. I talked to him and showed him
&lt;a href=&quot;http://nodebox.net/code/index.php/Perception&quot;&gt;Perception&lt;/a&gt;. He was convinced
that neo4j would be perfect for this: super-fast, O(1) lookups, lightweight,
&lt;a href=&quot;http://components.neo4j.org/neo4j.py/&quot;&gt;Python bindings&lt;/a&gt;. It is a mature graph
database that runs in production for over 5 years.&lt;/p&gt;
&lt;p&gt;There are &lt;a href=&quot;http://components.neo4j.org/&quot;&gt;components&lt;/a&gt; available for indexing,
graph algorithms and much more.&lt;/p&gt;
&lt;h2&gt;Answered questions&lt;/h2&gt;
&lt;p&gt;I came to the conference to hear talks about the progress and future of
Jython. I am now convinced that Jython is an excellent choice for Python
development, given that there are some very motivated people working on it,
and they have the full support of the CPython guys.&lt;/p&gt;
&lt;h2&gt;Unanswered questions&lt;/h2&gt;
&lt;p&gt;One thing I&#39;ve been struggling with in NodeBox is how to do proper packaging
of NodeBox packages. I need a system that can version packages, do dependency
management, can run several version of the same package at the same time, and
do live loading/unloading of packages. I recently discovered
&lt;a href=&quot;http://www.osgi.org/Main/HomePage&quot;&gt;OSGi&lt;/a&gt; recently, which seems to solve this
problem for Java. However, Python doesn&#39;t seem to have a system like that
available. There was a lot of talk about
&lt;a href=&quot;http://pypi.python.org/pypi/virtualenv&quot;&gt;virtualenv&lt;/a&gt;,
&lt;a href=&quot;http://pypi.python.org/pypi/pip&quot;&gt;pip&lt;/a&gt; and even
&lt;a href=&quot;http://pypi.python.org/pypi/zc.buildout&quot;&gt;zc.buildout&lt;/a&gt;, but none of those
seems to provide a complete answer. (By the way, Jacob&#39;s recent &lt;a href=&quot;http://jacobian.org/writing/django-apps-with-buildout/&quot;&gt;blog post
about zc.buildout&lt;/a&gt; is
very interesting.) The whole environment seems very much in flux, and I think
we&#39;ll have to wait for the next PyCon to have an answer available.&lt;/p&gt;
&lt;p&gt;Personally, I would love to see integration between the VM&#39;s native package
management system and the Python implementation (for Jython, that would be
OSGi). However, even OSGi seems to come under attack, as Sun is [rolling its
own solution](http://www.osgi.org/blog/2007/07/can-someone-tell-sun-about-
osgi.html).&lt;/p&gt;
&lt;p&gt;Overall, package management is a hairy business, and one that needs some
serious thought. As for now, I think I&#39;m better off taking a good hard look at
OSGi and then rolling my own solution.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>My Favourite Python hack</title>
    <link href="https://enigmeta.com/posts/2009-03-27-my-favourite-python-hack/" />
    <updated>2009-03-27T00:00:00Z</updated>
    <id>https://enigmeta.com/posts/2009-03-27-my-favourite-python-hack/</id>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;https://nodebox.net/code/&quot;&gt;NodeBox 1&lt;/a&gt; we have this cool feature that we call &amp;quot;the throttle&amp;quot;. It allows you to interactively drag any number in the (Python) script and see the results immediately. Whether it&#39;s and X/Y coordinate, the number in &amp;quot;for i in range(10)&amp;quot;, or a number in a complicated formula, just dragging the number helps you visualize the effect of it on the overall composition. Here&#39;s a movie that demonstrates how this works:&lt;/p&gt;
&lt;div class=&quot;embed-responsive embed-responsive-16by9&quot;&gt;
  &lt;iframe class=&quot;embed-responsive-item&quot; src=&quot;https://www.youtube.com/embed/sCPjlnTcopg&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Today I&#39;d like to talk about the implementation, which works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find the character under the cursor.&lt;/li&gt;
&lt;li&gt;Expand until you get the full number (include digits, periods and minus signs)&lt;/li&gt;
&lt;li&gt;Replace it with &lt;code&gt;&lt;strong&gt;magic_var&lt;/strong&gt;&lt;/code&gt; and add this variable to the locals dictionary&lt;/li&gt;
&lt;li&gt;When the user &amp;quot;drags&amp;quot; the number, replace the value of &lt;code&gt;&lt;strong&gt;magic_var&lt;/strong&gt;&lt;/code&gt; with an updated value and run the script again.&lt;/li&gt;
&lt;li&gt;When the user releases the mouse, replace the old number in the source file with the new number.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sounds simple, right? While this approach worked well in 90% of the cases, it broke down when the signs of the number changes from positive to negative or vice versa. Here are the three use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If an addition goes from positive to negative the sign should change:&lt;pre&gt;random(alpha+8) -&gt; random(alpha-8)&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;If a subtraction goes from negative to positive the sign should change as well:&lt;pre&gt;random(alpha-8) -&gt; random(alpha+8)&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;But&lt;/em&gt; if a negative number turns positive, the sign should disappear:&lt;pre&gt;random(-8) -&gt; random(8)&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The difficulty was in finding the difference between the first case and the third case. After a lot of dabbling around with regular expressions, I suddenly had an insight. There is actually a Python module that handles this problem: the Python parser itself.&lt;/p&gt;
&lt;p&gt;When Python parses the code, it builds an abstract syntax tree (AST), a tree-like representation of the code. Different nodes are represented by classes in the compiler.ast module. The use cases above are represented by instance of Sub (a two-part subtraction), UnarySub (a negative number), and Addition (a two-part addition).&lt;/p&gt;
&lt;p&gt;Note that we replaced the original number with the name &lt;code&gt;&lt;strong&gt;magic_var&lt;/strong&gt;&lt;/code&gt; in our original source code, and compiled that. After compilation succeeds and returns an AST, a function called &lt;code&gt;checkSigns&lt;/code&gt; recursively checks the AST for special sign cases. First, it tries to find the magic variable. Once it has found that, it checks the parent node to see if it encounters any of the special cases, and basically prepares the object for string replacement afterwards.&lt;/p&gt;
&lt;p&gt;What I like about this hack is that if it works correctly, you don&#39;t even notice it&#39;s there.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to view the code, it&#39;s in the NodeBox source as &lt;a href=&quot;https://github.com/nodebox/nodebox-pyobjc/blob/master/nodebox/gui/mac/ValueLadder.py&quot;&gt;ValueLadder.py&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
</feed>