For those that know biology and just want to do the thing, see: Section "Protocols used".
The PuntSeq team uses an Oxford Nanopore MinION DNA sequencer made by Oxford Nanopore Technologies to sequence the 16S region of bacterial DNA, which is about 1500 nucleotides long.
This kind of "decode everything from the sample to see what species are present approach" is called "metagenomics".
This is how the MinION looks like: Figure 1. "Oxford Nanopore MinION top".
The 16S region codes for one of the RNA pieces that makes the bacterial ribosome.
Before sequencing the DNA, we will do a PCR with primers that fit just before and just after the 16S DNA, in well conserved regions expected to be present in all bacteria.
The PCR replicates only the DNA region between our two selected primers a gazillion times so that only those regions will actually get picked up by the sequencing step in practice.
Eukaryotes also have an analogous ribosome part, the 18S region, but the PCR primers are selected for targets around the 16S region which are only present in prokaryotes.
This way, we amplify only the 16S region of bacteria, excluding other parts of bacterial genome, and excluding eukaryotes entirely.
Despite coding such a fundamental piece of RNA, there is still surprisingly variability in the 16S region across different bacteria, and it is those differences will allow us to identify which bacteria are present in the river.
The variability exists because certain base pairs are not fundamental for the function of the 16S region. This variability happens mostly on RNA loops as opposed to stems, i.e. parts of the RNA that don't base pair with other RNA in the RNA secondary structure as shown at: Code 1. "RNA stem-loop structure".
                A-U
               /   \
A-U-C-G-A-U-C-G     C
| | | | | | | |     |
U-A-G-C-U-A-G-C     G
               \   /
                U-A
|             ||    |
+-------------++----+
    stem        loop
Code 1.
RNA stem-loop structure
.
This is how the 16S RNA secondary structure looks like in its full glory: Figure 5. "16S RNA secondary structure".
Since loops don't base pair, they are less crucial in the determination of the secondary structure of the RNA.
The variability is such that it is possible to identify individual species apart if full sequences are known with certainty.
With the experimental limitations of experiment however, we would only be able to obtain family or genus level breakdowns.
As you would expect, not much secret here, we just dumped a 1 liter glass bottle with a rope attached around the neck in a few different locations of the river, and pulled it out with the rope.
And, in the name of science, we even wore gloves to not contaminate the samples!
Figure 1.
Swans swimming in the river when during sample collection
. Source. Swam poo bacteria?
Figure 2.
Tying rope to bootle for river water sample collection
. Source.
Figure 3.
Dumping the bottle into the river to collect the water sample
. Source.
Figure 5.
Measuring the river water sample pH with a pH strip
. Source. The strip is compared with the color of a mobile app that gives the pH for a given strip color.
Figure 6.
Noting sample collection location on the water bottle
. Source.
Video 1.
Dumping the bottle into the river to collect the water sample
. Source. That was fun.
The first thing we had to do with the sample was to extract the DNA present in the water in a pure form for the PCR.
As you would expect, this consists of a purification procedure with several steps.
In each step we take a physical or chemical action on the sample, which splits it into two parts: the one with the DNA and the one without.
We then take the part with the DNA, and throw away the one without the DNA.
The first steps are coarser, and finer and finer splits are done as we move forward.
Because it is considered the less interesting step, and because it takes quite some time, this step was done by the event organizers between the two event days, so participants did not get to take many photos.
PCR protocols are very standard it seems, all that biologists need to know to reproduce is the time and temperature of each step.
We did 35 cycles of:
Figure 1.
Marshal Scientific MJ Research PTC-200 Thermal Cycler.
Source.
We added PCR primers for regions that surround the 16S DNA. The primers are just bought from a vendor, and we used well known regions are called 27F and 1492R. Here is a paper that analyzes other choices: academic.oup.com/femsle/article/221/2/299/630719 (archive) "Evaluation of primers and PCR conditions for the analysis of 16S rRNA genes from a natural environment" by Yuichi Hongoh, Hiroe Yuzawa, Moriya Ohkuma, Toshiaki Kudo (2003)
One cool thing about the PCR is that we can also add a known barcode at the end of each primer as shown at Code 1. "PCR diagram".
This means that we bought a few different versions of our 27F/1492R primers, each with a different small DNA tag attached directly to them in addition to the matching sequence.
This way, we were able to:
  • use a different barcode for samples collected from different locations. This means we
    • did PCR separately for each one of them
    • for each PCR run, used a different set of primers, each with a different tag
    • the primer is still able to attach, and then the tag just gets amplified with the rest of everything!
  • sequence them all in one go
  • then just from the sequencing output the barcode to determine where each sequence came from!
Input: Bacterial DNA (a little bit)
... --- 27S --- 16S --- 1492R --- ...

|||
|||
vvv

Output: PCR output (a lot of)
Barcode --- 27S --- 16S --- 1492R
Code 1.
PCR diagram
.
Finally, after purification, we used the Qiagen QIAquick PCR Purification Kit protocol to purify the generated from unwanted PCR byproducts.
Because Ciro's a software engineer, and he's done enough staring in computers for a lifetime already, and he believes in the power of Git, he didn't pay much attention to this part ;-)
According to the eLife paper, the code appears to have been uploaded to: github.com/d-j-k/puntseq. TODO at least mention the key algorithms used more precisely.
Ciro can however see that it does present interesting problems!
Because it was necessary to wait for 2 days to get our data, the workshop first reused sample data from previous collections done earlier in the year to illustrate the software.
First there is some signal processing/machine learning required to do the base calling, which is not trivial in the Oxford Nanopore, since neighbouring bases can affect the signal of each other. This is mostly handled by Oxford Nanopore itself, or by hardcore programmers in the field however.
After the base calling was done, the data was analyzed using computer programs that match the sequenced 16S sequences to a database of known sequenced species.
This is of course not just a simple direct string matching problem, since like any in experiment, the DNA reads have some errors, so the program has to find the best match even though it is not exact.
The PuntSeq team would later upload the data to well known open databases so that it will be preserved forever! When ready, a link to the data would be uploaded to: www.puntseq.co.uk/data
Protocols are the biologist term for "recipe".
I found that a lot of biology comes down to this: get the right recipe, follow it well even though you don't understand all the proprietary details, and pray.
sqlite3 Node.js package Updated 2025-07-16
Includes its own copy of sqlite3, you don't use the system one, which is good to ensure compatibility. The version is shown at: github.com/mapbox/node-sqlite3/blob/918052b538b0effe6c4a44c74a16b2749c08a0d2/deps/common-sqlite.gypi#L3 SQLite source is tracked compressed in-tree: github.com/mapbox/node-sqlite3/blob/918052b538b0effe6c4a44c74a16b2749c08a0d2/deps/sqlite-autoconf-3360000.tar.gz horrendous. This explains why it takes forever to clone that repository. People who don't believe in git submodules, there's even an official Git mirror at: github.com/sqlite/sqlite
It appears to spawn its own threads via its C extension (since JavaScript is single threaded and and SQLite is not server-based), which allows for parallel queries using multiple threads: github.com/mapbox/node-sqlite3/blob/v5.0.2/src/threading.h
As of 2021, this had slumped back a bit, as maintainers got tired. Unmerged pull requests started piling more, and better-sqlite3 Node.js package started pulling ahead a little.
better-sqlite3 Node.js package Updated 2025-07-16
As claimed on their README, their operation truly appears to be 10x faster than the node-sqlite package!! It is insane!! How can that other package still exist at all?
The only big problem was the lack of ORM, but people are looking into that by adding it to Sequelize:
Isomer Updated 2025-07-16
Isomers were quite confusing for early chemists, before atomic theory was widely accepted, and people where thinking mostly in terms of proportions of equations, related: Section "Isomers suggest that atoms exist".
Microwave source Updated 2025-07-16
Microwave only found applications into the 1940s and 1950s, much later than radio, because good enough sources were harder to develop.
One notable development was the cavity magnetron in 1940, which was the basis for the original radar systems of World War II.
Microwave oven Updated 2025-07-16
Video 1.
How Microwaves Work by National MagLab (2017)
Source. A bit meh. Does not mention the word cavity magnetron!
Video 2. . Source. Cool demonstration of the standing waves in the cavity with cheese!

There are unlisted articles, also show them or only show them.