<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Quality Control on Gigabase or gigabyte</title><link>https://wdecoster.github.io/gigabaseorgigabyte/tags/quality-control/</link><description>Recent content in Quality Control on Gigabase or gigabyte</description><generator>Hugo -- 0.163.3</generator><language>en-us</language><copyright>© Wouter De Coster</copyright><lastBuildDate>Fri, 17 Jul 2026 12:00:00 +0200</lastBuildDate><atom:link href="https://wdecoster.github.io/gigabaseorgigabyte/tags/quality-control/index.xml" rel="self" type="application/rss+xml"/><item><title>NanoPlot, now in Rust</title><link>https://wdecoster.github.io/gigabaseorgigabyte/posts/2026-07-17-nanoplot-rust-port/</link><pubDate>Fri, 17 Jul 2026 12:00:00 +0200</pubDate><author>Wouter De Coster</author><guid>https://wdecoster.github.io/gigabaseorgigabyte/posts/2026-07-17-nanoplot-rust-port/</guid><description>&amp;lt;no value&amp;gt;</description><content type="text/html" mode="escaped"><![CDATA[<p><a href="https://github.com/wdecoster/NanoPlot">NanoPlot</a> is probably the most widely used of the tools I have written: a quick way to turn a run of long reads into the familiar set of plots and summary statistics — read-length and quality distributions, yield, and, for aligned data, percent identity. It has served people well for years, but it carries the weight of its Python stack: a pandas / plotly environment to install, and runtimes that start to drag on large datasets. So NanoPlot is now also available as <a href="https://github.com/wdecoster/nanoplotrs">a Rust tool</a>, a single self-contained binary that reads the same inputs and produces the same kind of report, faster and with nothing to install around it.</p>
<p>A note on how it was made: I did not port the code to Rust by hand, yet had <a href="https://claude.com/claude-code">Claude</a> working under my supervision. I directed the design, made the calls on what the tool should do and which features to implement, and reviewed the result, while Claude wrote and tested the code. I think it is worth being transparent about how this was done.</p>
<h2 id="what-you-get">What you get<a href="#what-you-get" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>Point it at a file and it works out the rest:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nanoplot -i reads.fastq.gz -o output/
</span></span></code></pre></div><p>The input format is auto-detected from the file content or from <code>stdin</code>. The output is familiar: a <code>NanoStats</code> table, a HTML report, and the expected plots regarding read-length, yields, qualities and percent-identity. Time-resolved views are available from a summary file or fastq rich format: cumulative yield, reads over time, active pores, and length and quality as violins across the run.</p>
<p>Here is the read-length-versus-percent-identity density plot from a real long-read human genome alignment:</p>
<p><img src="/gigabaseorgigabyte/images/2026-06_nanoplot_length_identity.png" alt="nanoplot read length versus percent identity density plot"></p>
<h2 id="how-fast">How fast<a href="#how-fast" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>That plot, and the rest of the report, came out of an 84 GB CRAM of a long-read human genome. On a chr20–22 slice of it (~300,000 reads, 5 Gbases of aligned data), nanoplotrs produced the full set of plots and statistics in <strong>51 seconds</strong>. The Python NanoPlot version took <strong>just over 7 minutes</strong> on the same data with the same number of threads, so the Rust version is at least <strong>8× faster</strong>, although an exact benchmark is out of scope for this post. On the full 84 GB alignment — 5.8 million reads, over 100 Gbases — nanoplotrs finishes in about three and a half minutes.</p>
<h2 id="a-few-nice-touches">A few nice touches<a href="#a-few-nice-touches" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>The statistics go a little further than a plain summary. Alongside the usual N50,
mean and median, the <code>NanoStats</code> table reports how many reads, what fraction, and
how many megabases fall above a set of quality and read-length cutoffs — the kind
of &ldquo;reads above Q10&rdquo; / &ldquo;reads above 50 kb&rdquo; numbers you usually end up computing by
hand. It stays a clean two-column table, with the same breakdown mirrored in JSON
and rendered in the HTML report.</p>
<p>A couple of details that matter for correctness on aligned data: each read is
counted exactly once — secondary alignments are always dropped, and supplementary
(split) alignments are excluded by default — so the length and yield numbers are
not inflated by chimeric records. And a handful of ultra-long reads no longer
flatten your histograms: by default the plots clip the longest 1% of reads for the
<em>display only</em>, while the statistics are always computed on every read.</p>
<p>The plots are rendered with <a href="https://psy-fer.github.io/kuva/">kuva</a>, the same Rust
scientific-plotting library behind my other recent tools, straight to SVG (or PNG
or PDF).</p>
<h2 id="getting-it">Getting it<a href="#getting-it" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>Pre-built binaries for Linux (including a static musl build) and macOS are attached
to each <a href="https://github.com/wdecoster/nanoplotrs/releases">release</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -L -o nanoplot https://github.com/wdecoster/nanoplotrs/releases/latest/download/nanoplot-linux
</span></span><span class="line"><span class="cl">chmod +x nanoplot
</span></span></code></pre></div><p>This is a fresh reimplementation rather than a line-for-line copy, so it covers the
core of what most people use NanoPlot for rather than every last flag. nanoplotrs
is open source and available on <a href="https://github.com/wdecoster/nanoplotrs">GitHub</a>,
where the <a href="https://github.com/wdecoster/nanoplotrs#readme">README</a> covers
installation and usage. Feedback and feature requests are welcome.</p>
]]></content></item></channel></rss>