<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>CanvasXpress Recipes</title>
<link>https://neuhausi.github.io/canvasxpress-blog/python.html</link>
<atom:link href="https://neuhausi.github.io/canvasxpress-blog/python.xml" rel="self" type="application/rss+xml"/>
<description>Interactive, reproducible scientific visualization with canvasXpress — in R, Python and JavaScript.</description>
<generator>quarto-1.6.39</generator>
<lastBuildDate>Fri, 30 Oct 2026 04:00:00 GMT</lastBuildDate>
<item>
  <title>Interactive network graphs in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/network-graphs-in-python/</link>
  <description><![CDATA[ 




<p>A network graph shows <strong>relationships</strong>: nodes connected by edges, laid out so connected things sit near each other. The usual Python reach is <code>networkx</code> + matplotlib (static) or <code>pyvis</code>. Here we build one with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — draggable, hover-labelled, force-directed, and reproducible from a single portable spec.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-data-shape" class="level2">
<h2 class="anchored" data-anchor-id="the-data-shape">The data shape</h2>
<p>canvasXpress builds a network from two lists: <strong>nodes</strong> (<code>id</code>, <code>name</code>, <code>group</code>) and <strong>edges</strong> (<code>id1</code>, <code>id2</code>, <code>value</code>). Swap this simulated three-community graph for your own.</p>
<div id="d93a4a56" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> random</span>
<span id="cb2-2">random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-3"></span>
<span id="cb2-4">groups <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Alpha"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Beta"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Gamma"</span>]</span>
<span id="cb2-5">nodes, by_group <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], {g: [] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> groups}</span>
<span id="cb2-6">k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb2-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> groups:</span>
<span id="cb2-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>):</span>
<span id="cb2-9">        nid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"n</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> nodes.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span>: nid, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"group"</span>: g})</span>
<span id="cb2-10">        by_group[g].append(nid)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb2-11"></span>
<span id="cb2-12">edges <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb2-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> groups:                                   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dense within a community</span></span>
<span id="cb2-14">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> by_group[g]</span>
<span id="cb2-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(m)):</span>
<span id="cb2-16">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(m)):</span>
<span id="cb2-17">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> random.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>:</span>
<span id="cb2-18">                edges.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id1"</span>: m[i], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id2"</span>: m[j], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>: random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)})</span>
<span id="cb2-19"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>):                                 <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a few cross-community links</span></span>
<span id="cb2-20">    g1, g2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> random.sample(groups, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb2-21">    edges.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id1"</span>: random.choice(by_group[g1]), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id2"</span>: random.choice(by_group[g2]), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>})</span></code></pre></div>
</div>
</section>
<section id="the-plot" class="level2">
<h2 class="anchored" data-anchor-id="the-plot">The plot</h2>
<div id="499d16e7" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"nodes"</span>: nodes, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"edges"</span>: edges}</span>
<span id="cb3-6">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Network"</span>,</span>
<span id="cb3-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"networkLayoutType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"forceDirected"</span>,</span>
<span id="cb3-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorNodeBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"group"</span>,</span>
<span id="cb3-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"nodeSize"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>,</span>
<span id="cb3-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showAnimation"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb3-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A small community network"</span>,</span>
<span id="cb3-13">}</span>
<span id="cb3-14"></span>
<span id="cb3-15">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"network"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">650</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb3-16"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-17">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="network" width="650" height="500"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("network");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart network removed for re-rendering.");
  } else {
    console.log("Chart network ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart network could not be cleaned for re-rendering:", error);
}

var chart_network = new CanvasXpress({"renderTo": "network", "data": {"nodes": [{"id": "n0", "name": "Alpha1", "group": "Alpha"}, {"id": "n1", "name": "Alpha2", "group": "Alpha"}, {"id": "n2", "name": "Alpha3", "group": "Alpha"}, {"id": "n3", "name": "Alpha4", "group": "Alpha"}, {"id": "n4", "name": "Alpha5", "group": "Alpha"}, {"id": "n5", "name": "Alpha6", "group": "Alpha"}, {"id": "n6", "name": "Alpha7", "group": "Alpha"}, {"id": "n7", "name": "Beta1", "group": "Beta"}, {"id": "n8", "name": "Beta2", "group": "Beta"}, {"id": "n9", "name": "Beta3", "group": "Beta"}, {"id": "n10", "name": "Beta4", "group": "Beta"}, {"id": "n11", "name": "Beta5", "group": "Beta"}, {"id": "n12", "name": "Beta6", "group": "Beta"}, {"id": "n13", "name": "Beta7", "group": "Beta"}, {"id": "n14", "name": "Gamma1", "group": "Gamma"}, {"id": "n15", "name": "Gamma2", "group": "Gamma"}, {"id": "n16", "name": "Gamma3", "group": "Gamma"}, {"id": "n17", "name": "Gamma4", "group": "Gamma"}, {"id": "n18", "name": "Gamma5", "group": "Gamma"}, {"id": "n19", "name": "Gamma6", "group": "Gamma"}, {"id": "n20", "name": "Gamma7", "group": "Gamma"}], "edges": [{"id1": "n0", "id2": "n1", "value": 1}, {"id1": "n0", "id2": "n2", "value": 4}, {"id1": "n0", "id2": "n4", "value": 4}, {"id1": "n0", "id2": "n6", "value": 1}, {"id1": "n1", "id2": "n3", "value": 5}, {"id1": "n1", "id2": "n5", "value": 4}, {"id1": "n1", "id2": "n6", "value": 2}, {"id1": "n2", "id2": "n4", "value": 3}, {"id1": "n2", "id2": "n5", "value": 1}, {"id1": "n3", "id2": "n4", "value": 4}, {"id1": "n7", "id2": "n10", "value": 2}, {"id1": "n8", "id2": "n9", "value": 5}, {"id1": "n8", "id2": "n11", "value": 3}, {"id1": "n8", "id2": "n12", "value": 3}, {"id1": "n10", "id2": "n12", "value": 3}, {"id1": "n14", "id2": "n16", "value": 2}, {"id1": "n14", "id2": "n18", "value": 2}, {"id1": "n14", "id2": "n19", "value": 3}, {"id1": "n14", "id2": "n20", "value": 5}, {"id1": "n15", "id2": "n16", "value": 2}, {"id1": "n15", "id2": "n18", "value": 4}, {"id1": "n15", "id2": "n20", "value": 3}, {"id1": "n16", "id2": "n20", "value": 2}, {"id1": "n17", "id2": "n18", "value": 2}, {"id1": "n19", "id2": "n20", "value": 5}, {"id1": "n10", "id2": "n16", "value": 1}, {"id1": "n17", "id2": "n6", "value": 1}, {"id1": "n18", "id2": "n6", "value": 1}, {"id1": "n17", "id2": "n0", "value": 1}, {"id1": "n11", "id2": "n18", "value": 1}, {"id1": "n3", "id2": "n13", "value": 1}], "x": null, "z": null}, "config": {"graphType": "Network", "networkLayoutType": "forceDirected", "colorNodeBy": "group", "nodeSize": 25, "showAnimation": true, "title": "A small community network"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Drag any node and the layout settles around it; hover to read the label. The three communities separate on their own because within-group edges outnumber the cross-group ones.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>The nodes, edges and <code>config</code> <strong>are</strong> the figure — one portable JSON spec that renders the identical network from R or JavaScript, and can be validated and re-rendered later.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../sankey-diagrams-in-python/">Sankey / alluvial diagrams in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>network</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/network-graphs-in-python/</guid>
  <pubDate>Fri, 30 Oct 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/network-graphs-in-python/thumbnail.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>An interactive NGS sequencing-QC dashboard in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/linked-dashboards-in-python/</link>
  <description><![CDATA[ 




<p>After a sequencing run you get a QC table — one row per sample, a dozen metrics — and you need to answer three questions fast: <strong>which samples fail, is a whole batch off, and are the failures correlated?</strong> A single scatter can’t do it; you want several views that <strong>talk to each other</strong> — select a suspicious sample in one and see it light up in the rest. In Python that usually means Dash or Streamlit (a server, callbacks). canvasXpress does it client-side: give every panel the same <strong>broadcast group</strong> and a selection broadcasts to all of them. Here we build a real QC dashboard for 96 RNA/exome samples.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-qc-table" class="level2">
<h2 class="anchored" data-anchor-id="the-qc-table">The QC table</h2>
<p>96 samples with mapping rate, duplication, Q30, GC, insert size and contamination (VerifyBamID <code>freemix</code>), plus lane / batch / library annotations. (Download: <a href="ngs-qc.csv"><code>ngs-qc.csv</code></a>.)</p>
<div id="1697589b" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> csv, statistics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> st</span>
<span id="cb2-2"></span>
<span id="cb2-3">rows <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(csv.DictReader(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">open</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ngs-qc.csv"</span>)))</span>
<span id="cb2-4">metrics <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total_reads"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_mapped"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_duplication"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_q30"</span>,</span>
<span id="cb2-5">           <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gc_content"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"insert_size"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"contamination_freemix"</span>]</span>
<span id="cb2-6"></span>
<span id="cb2-7">samples <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [r[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sample"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> rows]</span>
<span id="cb2-8">annot   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lane"</span>: [r[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lane"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> rows], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Batch"</span>: [r[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"batch"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> rows],</span>
<span id="cb2-9">           <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Library"</span>: [r[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"library"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> rows]}</span>
<span id="cb2-10">raw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {m: [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(r[m]) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> rows] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> m <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> metrics}</span>
<span id="cb2-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(samples), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"samples,"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(metrics), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"metrics"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>96 samples, 7 metrics</code></pre>
</div>
</div>
</section>
<section id="overview-a-clustered-qc-heatmap" class="level2">
<h2 class="anchored" data-anchor-id="overview-a-clustered-qc-heatmap">Overview — a clustered QC heatmap</h2>
<p>Z-score each metric and cluster: outlier samples and any batch/library structure jump out at a glance. This is the “is anything wrong, and where” view. Here the matrix is metrics × samples.</p>
<div id="54355646" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb4-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb4-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb4-4"></span>
<span id="cb4-5">z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {m: [(v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> st.mean(raw[m])) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (st.pstdev(raw[m]) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> v <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> raw[m]] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> m <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> metrics}</span>
<span id="cb4-6">hm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: metrics, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: samples, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> z[m]] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> m <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> metrics]},</span>
<span id="cb4-7">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Batch"</span>: annot[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Batch"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Library"</span>: annot[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Library"</span>]}}</span>
<span id="cb4-8"></span>
<span id="cb4-9">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"qcHeat"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>hm, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">820</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">420</span>, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb4-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Heatmap"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"samplesClustered"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"variablesClustered"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb4-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorSpectrum"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"navy"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"firebrick3"</span>],</span>
<span id="cb4-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"QC metrics (z-scored) — 96 samples clustered"</span>})</span>
<span id="cb4-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb4-14">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="qcHeat" width="820" height="420"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("qcHeat");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart qcHeat removed for re-rendering.");
  } else {
    console.log("Chart qcHeat ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart qcHeat could not be cleaned for re-rendering:", error);
}

var chart_qcHeat = new CanvasXpress({"renderTo": "qcHeat", "data": {"y": {"vars": ["total_reads", "pct_mapped", "pct_duplication", "pct_q30", "gc_content", "insert_size", "contamination_freemix"], "smps": ["S001", "S002", "S003", "S004", "S005", "S006", "S007", "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", "S096"], "data": [[-0.3, -0.23, -1.09, 1.27, 0.25, -0.64, 0.4, 0.61, -0.67, 0.94, -0.97, 0.69, 0.77, 0.52, 0.49, -0.09, 1.83, 0.19, 0.58, -0.63, -1.06, 1.84, 0.21, 0.88, -1.63, 1.39, 0.57, -1.77, 0.22, -1.3, 0.2, -0.56, 1.05, -0.72, 0.16, -1.95, -0.76, 1.02, -0.24, 2.18, -2.13, 0.63, -0.71, 1.05, -0.33, -0.96, 0.35, -0.35, 0.13, -1.78, 0.93, -0.18, 0.54, 0.1, -0.26, -2.22, -0.85, 1.01, 0.09, -0.92, 0.18, -1.14, -1.39, 0.51, -1.41, 0.58, -1.04, 0.91, -0.6, 0.67, -0.03, 0.66, 0.18, -1.29, -0.84, -1.34, -0.81, -0.41, 1.04, 0.72, 1.2, 0.82, 0.43, 3.01, 1.03, -1.17, -0.45, -0.6, 1.3, -0.57, 0.22, 0.95, -1.35, 0.73, 1.21, 0.25], [0.29, -1.51, 1.73, 1.18, 0.14, 0.28, 1.02, 0.65, 0.96, 1.41, -0.68, -0.6, -0.03, -0.66, 1.11, -1.68, 0.04, 0.96, -0.78, -0.75, -3.5, 1.25, -1.01, -0.54, -1.1, 0.04, 0.77, 0.69, 1.74, 0.52, -1.1, -0.35, 0.32, -0.83, -0.6, 0.34, -0.71, -0.77, 0.03, 0.37, -1.03, 0.17, 0.8, 1.18, -0.96, 0.18, 0.95, -0.29, 1.62, -1.18, 0.88, 0.42, 0.91, 0.74, 1.74, 0.66, -0.09, 0.39, 0.97, 0.07, -2.43, -0.31, 0.77, -2.7, -1.87, 1.74, 0.23, -0.06, -0.12, 0.02, -1.08, 0.19, 0.26, 0.69, -0.15, -2.81, 1.06, 0.32, -0.25, -0.22, 0.2, 0.98, -0.52, 0.5, -0.19, -0.54, 0.26, 0.03, -0.26, 0.12, 0.11, 0.36, -1.05, 0.88, -1.13, 0.19], [-0.38, -0.15, -1.0, -0.07, -0.51, -0.07, 0.81, 0.68, -0.17, 2.25, 0.09, 1.54, -0.4, -0.61, -1.37, 1.31, 0.51, -1.47, -1.68, 0.32, 1.73, -0.37, 1.4, -1.11, -1.76, -1.28, -0.63, 0.67, -1.25, 0.31, -0.58, 1.07, -0.85, 1.47, -1.55, -0.06, -0.84, -0.4, -0.51, 0.7, 0.38, 1.94, -0.83, 0.41, -0.57, -1.34, -0.44, -0.45, -0.6, 0.85, -0.38, 1.21, -0.64, 0.21, -1.21, -0.92, -1.26, 1.01, -0.42, -1.5, 1.3, 0.59, -0.31, 2.58, 2.62, -0.88, 0.13, 0.16, -1.03, 1.26, -0.27, -1.14, -0.55, 0.94, -0.33, 1.08, -0.54, -0.34, 0.91, 0.11, -0.97, 0.05, -0.07, 0.19, -1.58, 0.77, -1.29, 0.84, -0.37, 0.72, 0.9, 1.8, 1.16, 0.1, 0.13, 0.09], [-1.13, 1.28, -0.58, 0.56, -0.09, -0.2, -0.17, 0.23, 0.13, -0.82, -1.96, 0.35, -0.07, -0.24, -0.77, 1.11, 0.88, -0.97, -0.66, 0.21, 1.13, 1.73, -1.63, -0.64, 0.46, -0.17, 0.61, 1.91, -2.8, 0.54, -0.17, 0.25, 0.73, 0.18, -0.09, -0.27, 0.11, -0.8, -0.36, 0.32, 0.29, 0.23, 0.52, 2.04, -0.44, 1.3, -0.22, -0.71, -1.53, 1.33, -1.61, -0.19, -1.27, -0.67, -0.2, -2.11, -0.85, -1.34, 0.33, -1.66, 1.72, -0.45, 0.42, -1.24, 1.9, 0.61, 0.01, -2.49, 0.19, -0.67, -1.19, 0.62, 1.21, -0.66, 0.84, -0.95, -0.37, 0.01, 0.56, 0.62, 0.85, 0.91, 0.09, -0.25, 1.87, 0.32, 0.8, 2.06, -0.25, 1.25, -0.56, 1.21, 0.0, -0.33, 0.79, -0.79], [-1.07, -0.46, 0.6, -1.11, -0.77, -0.48, -0.04, 0.14, 1.66, -0.92, -0.92, -0.0, -1.24, -0.1, -1.69, 1.2, -2.4, -0.33, -1.8, 1.05, -0.09, 1.26, 0.11, -0.23, -0.69, 1.2, -0.16, 0.65, -1.65, -0.04, 0.44, -0.98, 0.42, -2.2, 1.14, 1.75, -0.92, -0.49, 2.42, 0.06, -0.13, 0.11, -0.5, -2.34, 0.55, 0.01, -0.01, 0.4, -1.65, 0.89, -0.05, -0.56, 0.14, 2.22, -0.84, -0.23, 1.48, -1.33, -0.42, 1.01, -0.4, 0.27, 0.89, -0.37, 0.49, 0.27, -2.35, -0.48, 1.45, -0.74, 1.56, 1.35, 0.26, 0.01, 0.43, 0.63, 1.18, -0.44, -0.12, -1.43, 0.23, 0.68, 0.28, 0.92, 0.36, 0.21, 0.02, 1.02, 0.54, 1.35, -0.89, 0.46, 0.81, 0.32, -1.2, 0.34], [0.51, 0.11, 0.27, 0.54, 2.06, 0.83, -2.03, -0.61, 0.0, 0.96, 0.83, 0.32, 0.86, -0.96, -0.8, -2.17, 0.08, -0.67, 1.04, 0.19, -0.19, -1.04, 0.72, -0.16, 1.1, 0.75, -0.29, -0.69, -0.56, 0.94, 1.02, 1.23, -0.94, -1.39, -0.61, -0.35, 0.46, 0.78, 2.09, -1.47, -1.28, -3.4, -0.51, -1.12, 0.86, -0.59, 0.78, -0.29, -0.29, -0.75, -1.34, 1.82, 1.39, -0.37, -0.83, -0.24, -0.29, -0.11, 1.26, 0.11, -0.61, 1.23, 0.48, -0.48, -0.11, -1.1, 0.99, -0.35, 0.72, -1.04, -0.32, 0.67, -0.11, 1.1, 0.24, -2.09, 1.2, 0.8, 0.86, 2.41, -0.05, 0.96, -0.35, -1.26, -1.1, 0.38, 0.16, -0.21, -0.05, -0.48, -0.03, -0.11, -0.24, 0.32, 1.58, -1.58], [-0.15, -1.46, 0.2, 0.88, 1.41, 0.61, 1.7, 0.8, -1.27, 1.57, 0.27, 0.9, -0.68, 0.02, -1.15, 1.03, -1.2, -0.94, 0.21, 1.7, -0.65, 1.2, -1.0, -1.11, 1.49, -1.58, -1.23, 1.76, 0.95, -1.26, 1.8, -0.88, 1.81, -0.03, -0.07, -0.77, 0.8, -1.13, -0.64, -1.38, 1.56, 0.02, -0.2, -1.37, -0.83, -1.1, 0.06, -0.04, -0.86, -1.55, -1.2, -0.34, -1.04, -0.1, -0.82, -0.29, 1.13, 1.09, 0.77, -0.94, 0.41, -0.47, -1.48, 1.0, 1.61, -1.48, 1.01, 0.05, 0.75, 0.36, -0.7, 1.52, -0.92, -0.74, -0.47, -1.01, 0.8, 0.58, -0.09, -0.76, 0.37, 0.9, -0.41, 1.39, 0.53, 1.24, -1.55, 0.9, 1.24, -0.67, -1.05, -0.14, 0.12, 0.95, 0.18, -0.4]]}, "x": {"Batch": ["RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunB", "RunB", "RunB", "RunC", "RunC", "RunC", "RunB", "RunA", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunB", "RunC", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunC", "RunA", "RunB", "RunA", "RunC", "RunB", "RunB", "RunC", "RunA", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunC", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunC", "RunA", "RunB", "RunA", "RunB", "RunC", "RunB", "RunB", "RunB", "RunB", "RunC", "RunB", "RunB", "RunA", "RunA", "RunC", "RunB", "RunA", "RunB", "RunA", "RunB", "RunC", "RunC", "RunA", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunA", "RunB", "RunC", "RunA", "RunC", "RunC"], "Library": ["PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "PolyA", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "RiboZero", "Exome", "RiboZero", "RiboZero", "RiboZero", "Exome", "RiboZero", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "RiboZero", "Exome", "PolyA", "Exome", "PolyA", "PolyA", "PolyA", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "RiboZero", "PolyA", "Exome", "Exome", "PolyA", "RiboZero", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "RiboZero", "PolyA", "Exome", "Exome", "Exome", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "PolyA", "PolyA", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "Exome"]}, "z": null}, "config": {"graphType": "Heatmap", "samplesClustered": true, "variablesClustered": true, "colorSpectrum": ["navy", "white", "firebrick3"], "title": "QC metrics (z-scored) \u2014 96 samples clustered"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
</section>
<section id="the-linked-triage-dashboard" class="level2">
<h2 class="anchored" data-anchor-id="the-linked-triage-dashboard">The linked triage dashboard</h2>
<p>Four panels over the <strong>same samples</strong>, all sharing <code>broadcastGroup: "qc"</code>. The sample is the unit, so each sample is a point and its lane/batch/library live in the per-sample annotation <code>z</code>. Select points in any panel and the same samples re-mark everywhere.</p>
<div id="b56999fe" class="cell" data-execution_count="3">
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sample-centric: vars = samples (points), smps = metrics (axes), z = per-sample annotations.</span></span>
<span id="cb5-2">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: samples, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: metrics, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [[raw[m][i] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> m <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> metrics] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(samples))]},</span>
<span id="cb5-3">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z"</span>: annot}</span>
<span id="cb5-4"></span>
<span id="cb5-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> panel(cfg, cid, w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">640</span>, h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">360</span>):</span>
<span id="cb5-6">    cfg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>cfg, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"broadcast"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"broadcastGroup"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"qc"</span>}</span>
<span id="cb5-7">    cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>cid, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>cfg, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>w, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>h)</span>
<span id="cb5-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb5-9">        display(part)</span></code></pre></div>
</div>
<section id="mapping-rate-vs-duplication-the-triage-plot" class="level3">
<h3 class="anchored" data-anchor-id="mapping-rate-vs-duplication-the-triage-plot">1 — Mapping rate vs duplication (the triage plot)</h3>
<p>Bubble size is depth; failing libraries fall to the <strong>bottom-right</strong>. Lasso them here.</p>
<div id="8a232ed8" class="cell" data-execution_count="4">
<div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">panel({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scatter2D"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_duplication"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_mapped"</span>],</span>
<span id="cb6-2">       <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Batch"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sizeBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total_reads"</span>,</span>
<span id="cb6-3">       <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mapping rate vs duplication — select the bottom-right"</span>}, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"qcMap"</span>)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="qcMap" width="640" height="360"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("qcMap");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart qcMap removed for re-rendering.");
  } else {
    console.log("Chart qcMap ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart qcMap could not be cleaned for re-rendering:", error);
}

var chart_qcMap = new CanvasXpress({"renderTo": "qcMap", "data": {"y": {"vars": ["S001", "S002", "S003", "S004", "S005", "S006", "S007", "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", "S096"], "smps": ["total_reads", "pct_mapped", "pct_duplication", "pct_q30", "gc_content", "insert_size", "contamination_freemix"], "data": [[39731273.0, 93.85, 11.9, 89.58, 44.63, 295.0, 0.0165], [40380961.0, 86.82, 13.41, 94.49, 46.71, 280.0, 0.0015], [32582992.0, 99.47, 7.88, 90.7, 50.27, 286.0, 0.0205], [53943211.0, 97.33, 13.95, 93.02, 44.51, 296.0, 0.0283], [44716872.0, 93.27, 11.08, 91.7, 45.65, 353.0, 0.0344], [36599101.0, 93.81, 13.99, 91.47, 46.64, 307.0, 0.0252], [46095164.0, 96.7, 19.76, 91.54, 48.13, 200.0, 0.0377], [48000008.0, 95.26, 18.89, 92.35, 48.73, 253.0, 0.0274], [36369073.0, 96.45, 13.29, 92.15, 53.85, 276.0, 0.0037], [50969240.0, 98.24, 29.2, 90.22, 45.15, 312.0, 0.0363], [33599116.0, 90.06, 14.99, 87.9, 45.15, 307.0, 0.0214], [48655822.0, 90.39, 24.5, 92.59, 48.25, 288.0, 0.0286], [49427201.0, 92.61, 11.81, 91.74, 44.08, 308.0, 0.0104], [47119993.0, 90.14, 10.41, 91.39, 47.9, 240.0, 0.0185], [46853194.0, 97.07, 5.44, 90.31, 42.56, 246.0, 0.005], [41603968.0, 86.13, 23.03, 94.13, 52.31, 195.0, 0.0301], [59046428.0, 92.89, 17.75, 93.67, 40.16, 279.0, 0.0045], [44160518.0, 96.46, 4.81, 89.9, 47.14, 251.0, 0.0074], [47727667.0, 89.67, 3.39, 90.54, 42.19, 315.0, 0.0206], [36724246.0, 89.8, 16.5, 92.31, 51.81, 283.0, 0.0378], [32834123.0, 79.02, 25.79, 94.17, 47.94, 269.0, 0.0108], [59130932.0, 97.62, 11.99, 95.4, 52.51, 237.0, 0.032], [44365467.0, 88.78, 23.6, 88.56, 48.62, 303.0, 0.0068], [50373280.0, 90.6, 7.17, 90.58, 47.49, 270.0, 0.0055], [27634567.0, 88.41, 2.91, 92.81, 45.91, 317.0, 0.0353], [55067555.0, 92.88, 6.01, 91.54, 52.3, 304.0, 0.0001], [47573074.0, 95.73, 10.26, 93.11, 47.71, 265.0, 0.0041], [26419904.0, 95.42, 18.8, 95.77, 50.43, 250.0, 0.0384], [44382069.0, 99.5, 6.25, 86.2, 42.67, 255.0, 0.0291], [30681013.0, 94.75, 16.45, 92.97, 48.13, 311.0, 0.0038], [44211734.0, 88.42, 10.6, 91.53, 49.74, 314.0, 0.0389], [37321516.0, 91.33, 21.43, 92.38, 44.94, 322.0, 0.0081], [51980437.0, 93.95, 8.86, 93.36, 49.68, 241.0, 0.039], [35908215.0, 89.48, 24.07, 92.25, 40.83, 224.0, 0.0179], [43841593.0, 90.38, 4.28, 91.69, 52.09, 253.0, 0.0174], [24751211.0, 94.05, 14.02, 91.33, 54.14, 263.0, 0.0094], [35531985.0, 89.94, 8.89, 92.11, 45.14, 293.0, 0.0274], [51665363.0, 89.7, 11.8, 90.25, 46.59, 305.0, 0.0053], [40270860.0, 92.83, 11.11, 91.15, 56.42, 354.0, 0.0109], [62194964.0, 94.15, 18.98, 92.54, 48.46, 221.0, 0.0024], [23130329.0, 88.7, 16.89, 92.46, 47.81, 228.0, 0.0362], [48105118.0, 93.37, 27.16, 92.35, 48.63, 149.0, 0.0185], [36035403.0, 95.84, 8.99, 92.94, 46.56, 257.0, 0.016], [51977734.0, 97.33, 17.13, 96.02, 40.34, 234.0, 0.0025], [39437507.0, 88.95, 10.68, 90.99, 50.1, 308.0, 0.0087], [33750550.0, 93.43, 5.63, 94.53, 48.28, 254.0, 0.0056], [45625993.0, 96.44, 11.56, 91.44, 48.23, 305.0, 0.0189], [39267219.0, 91.57, 11.44, 90.43, 49.61, 265.0, 0.0178], [43603870.0, 99.05, 10.52, 88.77, 42.68, 265.0, 0.0084], [26322443.0, 88.1, 20.0, 94.59, 51.26, 248.0, 0.0005], [50827140.0, 96.17, 11.95, 88.6, 48.08, 226.0, 0.0045], [40761784.0, 94.36, 22.35, 91.5, 46.36, 344.0, 0.0143], [47320485.0, 96.26, 10.22, 89.31, 48.72, 328.0, 0.0063], [43369554.0, 95.62, 15.79, 90.51, 55.74, 262.0, 0.0171], [40114772.0, 99.5, 6.46, 91.48, 45.43, 245.0, 0.0088], [22339638.0, 95.3, 8.38, 87.6, 47.46, 267.0, 0.0149], [34758883.0, 92.38, 6.17, 90.16, 53.23, 265.0, 0.0312], [51604859.0, 94.24, 21.01, 89.15, 43.77, 272.0, 0.0307], [43270147.0, 96.49, 11.69, 92.55, 46.85, 323.0, 0.0271], [34107245.0, 92.97, 4.57, 88.51, 51.67, 280.0, 0.0074], [44048770.0, 83.22, 22.92, 95.37, 46.89, 253.0, 0.0229], [32112102.0, 91.49, 18.3, 90.97, 49.17, 322.0, 0.0128], [29809698.0, 95.74, 12.41, 92.73, 51.25, 294.0, 0.0013], [47040642.0, 82.17, 31.35, 89.37, 46.99, 258.0, 0.0297], [29626002.0, 85.39, 31.62, 95.75, 49.92, 272.0, 0.0367], [47661306.0, 99.5, 8.65, 93.12, 49.15, 235.0, 0.0013], [33024620.0, 93.63, 15.27, 91.9, 40.33, 313.0, 0.0298], [50703414.0, 92.5, 15.47, 86.82, 46.62, 263.0, 0.0188], [37015975.0, 92.23, 7.66, 92.26, 53.15, 303.0, 0.0268], [48527426.0, 92.78, 22.69, 90.51, 45.75, 237.0, 0.0224], [42127399.0, 88.49, 12.67, 89.46, 53.53, 264.0, 0.0102], [48366188.0, 93.46, 6.95, 93.15, 52.82, 301.0, 0.0357], [44082084.0, 93.74, 10.84, 94.33, 49.12, 272.0, 0.0077], [30703825.0, 95.42, 20.6, 90.54, 48.28, 317.0, 0.0098], [34817148.0, 92.11, 12.25, 93.58, 49.7, 285.0, 0.0129], [30327242.0, 81.72, 21.48, 89.96, 50.38, 198.0, 0.0066], [35056118.0, 96.86, 10.9, 91.12, 52.24, 321.0, 0.0274], [38741227.0, 93.97, 12.2, 91.9, 46.75, 306.0, 0.0249], [51892586.0, 91.75, 20.37, 93.02, 47.86, 308.0, 0.0172], [48967691.0, 91.86, 15.16, 93.14, 43.43, 366.0, 0.0095], [53294644.0, 93.5, 8.04, 93.6, 49.02, 274.0, 0.0225], [49837358.0, 96.54, 14.74, 93.72, 50.56, 312.0, 0.0286], [46298909.0, 90.68, 13.94, 92.06, 49.18, 263.0, 0.0135], [69724382.0, 94.67, 15.69, 91.37, 51.37, 229.0, 0.0342], [51769934.0, 91.97, 4.04, 95.67, 49.45, 235.0, 0.0243], [31818466.0, 90.59, 19.49, 92.53, 48.97, 290.0, 0.0325], [38365238.0, 93.75, 5.95, 93.5, 48.33, 282.0, 0.0005], [37024697.0, 92.84, 19.93, 96.06, 51.7, 268.0, 0.0286], [54204131.0, 91.71, 11.97, 91.38, 50.06, 274.0, 0.0325], [37236193.0, 93.17, 19.11, 94.41, 52.82, 258.0, 0.0106], [44443845.0, 93.16, 20.34, 90.74, 45.25, 275.0, 0.0062], [51079846.0, 94.13, 26.21, 94.33, 49.79, 272.0, 0.0166], [30167587.0, 88.6, 22.03, 91.89, 50.98, 267.0, 0.0196], [49060567.0, 96.15, 15.06, 91.21, 49.33, 288.0, 0.0292], [53415711.0, 88.31, 15.27, 93.49, 44.19, 335.0, 0.0203], [44717772.0, 93.47, 15.0, 90.28, 49.4, 217.0, 0.0136]]}, "z": {"Lane": ["L4", "L5", "L4", "L1", "L4", "L7", "L7", "L4", "L5", "L7", "L3", "L1", "L2", "L1", "L1", "L3", "L8", "L2", "L6", "L8", "L3", "L5", "L6", "L8", "L6", "L2", "L2", "L4", "L6", "L8", "L2", "L1", "L4", "L1", "L4", "L4", "L5", "L7", "L8", "L8", "L7", "L6", "L5", "L8", "L6", "L5", "L4", "L1", "L5", "L5", "L8", "L7", "L5", "L5", "L6", "L8", "L4", "L1", "L7", "L7", "L3", "L7", "L5", "L3", "L3", "L8", "L1", "L7", "L6", "L4", "L1", "L8", "L6", "L5", "L5", "L3", "L4", "L7", "L7", "L2", "L7", "L1", "L7", "L8", "L2", "L2", "L4", "L5", "L6", "L2", "L1", "L8", "L3", "L2", "L4", "L8"], "Batch": ["RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunB", "RunB", "RunB", "RunC", "RunC", "RunC", "RunB", "RunA", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunB", "RunC", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunC", "RunA", "RunB", "RunA", "RunC", "RunB", "RunB", "RunC", "RunA", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunC", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunC", "RunA", "RunB", "RunA", "RunB", "RunC", "RunB", "RunB", "RunB", "RunB", "RunC", "RunB", "RunB", "RunA", "RunA", "RunC", "RunB", "RunA", "RunB", "RunA", "RunB", "RunC", "RunC", "RunA", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunA", "RunB", "RunC", "RunA", "RunC", "RunC"], "Library": ["PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "PolyA", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "RiboZero", "Exome", "RiboZero", "RiboZero", "RiboZero", "Exome", "RiboZero", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "RiboZero", "Exome", "PolyA", "Exome", "PolyA", "PolyA", "PolyA", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "RiboZero", "PolyA", "Exome", "Exome", "PolyA", "RiboZero", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "RiboZero", "PolyA", "Exome", "Exome", "Exome", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "PolyA", "PolyA", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "Exome"]}, "x": null}, "config": {"graphType": "Scatter2D", "xAxis": ["pct_duplication"], "yAxis": ["pct_mapped"], "colorBy": "Batch", "sizeBy": "total_reads", "title": "Mapping rate vs duplication \u2014 select the bottom-right", "broadcast": true, "broadcastGroup": "qc"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
</section>
<section id="contamination-vs-mapping" class="level3">
<h3 class="anchored" data-anchor-id="contamination-vs-mapping">2 — Contamination vs mapping</h3>
<div id="4bdf91e5" class="cell" data-execution_count="5">
<div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">panel({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scatter2D"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_mapped"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"contamination_freemix"</span>],</span>
<span id="cb7-2">       <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Batch"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Contamination (freemix) vs mapping rate"</span>}, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"qcContam"</span>)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="qcContam" width="640" height="360"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("qcContam");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart qcContam removed for re-rendering.");
  } else {
    console.log("Chart qcContam ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart qcContam could not be cleaned for re-rendering:", error);
}

var chart_qcContam = new CanvasXpress({"renderTo": "qcContam", "data": {"y": {"vars": ["S001", "S002", "S003", "S004", "S005", "S006", "S007", "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", "S096"], "smps": ["total_reads", "pct_mapped", "pct_duplication", "pct_q30", "gc_content", "insert_size", "contamination_freemix"], "data": [[39731273.0, 93.85, 11.9, 89.58, 44.63, 295.0, 0.0165], [40380961.0, 86.82, 13.41, 94.49, 46.71, 280.0, 0.0015], [32582992.0, 99.47, 7.88, 90.7, 50.27, 286.0, 0.0205], [53943211.0, 97.33, 13.95, 93.02, 44.51, 296.0, 0.0283], [44716872.0, 93.27, 11.08, 91.7, 45.65, 353.0, 0.0344], [36599101.0, 93.81, 13.99, 91.47, 46.64, 307.0, 0.0252], [46095164.0, 96.7, 19.76, 91.54, 48.13, 200.0, 0.0377], [48000008.0, 95.26, 18.89, 92.35, 48.73, 253.0, 0.0274], [36369073.0, 96.45, 13.29, 92.15, 53.85, 276.0, 0.0037], [50969240.0, 98.24, 29.2, 90.22, 45.15, 312.0, 0.0363], [33599116.0, 90.06, 14.99, 87.9, 45.15, 307.0, 0.0214], [48655822.0, 90.39, 24.5, 92.59, 48.25, 288.0, 0.0286], [49427201.0, 92.61, 11.81, 91.74, 44.08, 308.0, 0.0104], [47119993.0, 90.14, 10.41, 91.39, 47.9, 240.0, 0.0185], [46853194.0, 97.07, 5.44, 90.31, 42.56, 246.0, 0.005], [41603968.0, 86.13, 23.03, 94.13, 52.31, 195.0, 0.0301], [59046428.0, 92.89, 17.75, 93.67, 40.16, 279.0, 0.0045], [44160518.0, 96.46, 4.81, 89.9, 47.14, 251.0, 0.0074], [47727667.0, 89.67, 3.39, 90.54, 42.19, 315.0, 0.0206], [36724246.0, 89.8, 16.5, 92.31, 51.81, 283.0, 0.0378], [32834123.0, 79.02, 25.79, 94.17, 47.94, 269.0, 0.0108], [59130932.0, 97.62, 11.99, 95.4, 52.51, 237.0, 0.032], [44365467.0, 88.78, 23.6, 88.56, 48.62, 303.0, 0.0068], [50373280.0, 90.6, 7.17, 90.58, 47.49, 270.0, 0.0055], [27634567.0, 88.41, 2.91, 92.81, 45.91, 317.0, 0.0353], [55067555.0, 92.88, 6.01, 91.54, 52.3, 304.0, 0.0001], [47573074.0, 95.73, 10.26, 93.11, 47.71, 265.0, 0.0041], [26419904.0, 95.42, 18.8, 95.77, 50.43, 250.0, 0.0384], [44382069.0, 99.5, 6.25, 86.2, 42.67, 255.0, 0.0291], [30681013.0, 94.75, 16.45, 92.97, 48.13, 311.0, 0.0038], [44211734.0, 88.42, 10.6, 91.53, 49.74, 314.0, 0.0389], [37321516.0, 91.33, 21.43, 92.38, 44.94, 322.0, 0.0081], [51980437.0, 93.95, 8.86, 93.36, 49.68, 241.0, 0.039], [35908215.0, 89.48, 24.07, 92.25, 40.83, 224.0, 0.0179], [43841593.0, 90.38, 4.28, 91.69, 52.09, 253.0, 0.0174], [24751211.0, 94.05, 14.02, 91.33, 54.14, 263.0, 0.0094], [35531985.0, 89.94, 8.89, 92.11, 45.14, 293.0, 0.0274], [51665363.0, 89.7, 11.8, 90.25, 46.59, 305.0, 0.0053], [40270860.0, 92.83, 11.11, 91.15, 56.42, 354.0, 0.0109], [62194964.0, 94.15, 18.98, 92.54, 48.46, 221.0, 0.0024], [23130329.0, 88.7, 16.89, 92.46, 47.81, 228.0, 0.0362], [48105118.0, 93.37, 27.16, 92.35, 48.63, 149.0, 0.0185], [36035403.0, 95.84, 8.99, 92.94, 46.56, 257.0, 0.016], [51977734.0, 97.33, 17.13, 96.02, 40.34, 234.0, 0.0025], [39437507.0, 88.95, 10.68, 90.99, 50.1, 308.0, 0.0087], [33750550.0, 93.43, 5.63, 94.53, 48.28, 254.0, 0.0056], [45625993.0, 96.44, 11.56, 91.44, 48.23, 305.0, 0.0189], [39267219.0, 91.57, 11.44, 90.43, 49.61, 265.0, 0.0178], [43603870.0, 99.05, 10.52, 88.77, 42.68, 265.0, 0.0084], [26322443.0, 88.1, 20.0, 94.59, 51.26, 248.0, 0.0005], [50827140.0, 96.17, 11.95, 88.6, 48.08, 226.0, 0.0045], [40761784.0, 94.36, 22.35, 91.5, 46.36, 344.0, 0.0143], [47320485.0, 96.26, 10.22, 89.31, 48.72, 328.0, 0.0063], [43369554.0, 95.62, 15.79, 90.51, 55.74, 262.0, 0.0171], [40114772.0, 99.5, 6.46, 91.48, 45.43, 245.0, 0.0088], [22339638.0, 95.3, 8.38, 87.6, 47.46, 267.0, 0.0149], [34758883.0, 92.38, 6.17, 90.16, 53.23, 265.0, 0.0312], [51604859.0, 94.24, 21.01, 89.15, 43.77, 272.0, 0.0307], [43270147.0, 96.49, 11.69, 92.55, 46.85, 323.0, 0.0271], [34107245.0, 92.97, 4.57, 88.51, 51.67, 280.0, 0.0074], [44048770.0, 83.22, 22.92, 95.37, 46.89, 253.0, 0.0229], [32112102.0, 91.49, 18.3, 90.97, 49.17, 322.0, 0.0128], [29809698.0, 95.74, 12.41, 92.73, 51.25, 294.0, 0.0013], [47040642.0, 82.17, 31.35, 89.37, 46.99, 258.0, 0.0297], [29626002.0, 85.39, 31.62, 95.75, 49.92, 272.0, 0.0367], [47661306.0, 99.5, 8.65, 93.12, 49.15, 235.0, 0.0013], [33024620.0, 93.63, 15.27, 91.9, 40.33, 313.0, 0.0298], [50703414.0, 92.5, 15.47, 86.82, 46.62, 263.0, 0.0188], [37015975.0, 92.23, 7.66, 92.26, 53.15, 303.0, 0.0268], [48527426.0, 92.78, 22.69, 90.51, 45.75, 237.0, 0.0224], [42127399.0, 88.49, 12.67, 89.46, 53.53, 264.0, 0.0102], [48366188.0, 93.46, 6.95, 93.15, 52.82, 301.0, 0.0357], [44082084.0, 93.74, 10.84, 94.33, 49.12, 272.0, 0.0077], [30703825.0, 95.42, 20.6, 90.54, 48.28, 317.0, 0.0098], [34817148.0, 92.11, 12.25, 93.58, 49.7, 285.0, 0.0129], [30327242.0, 81.72, 21.48, 89.96, 50.38, 198.0, 0.0066], [35056118.0, 96.86, 10.9, 91.12, 52.24, 321.0, 0.0274], [38741227.0, 93.97, 12.2, 91.9, 46.75, 306.0, 0.0249], [51892586.0, 91.75, 20.37, 93.02, 47.86, 308.0, 0.0172], [48967691.0, 91.86, 15.16, 93.14, 43.43, 366.0, 0.0095], [53294644.0, 93.5, 8.04, 93.6, 49.02, 274.0, 0.0225], [49837358.0, 96.54, 14.74, 93.72, 50.56, 312.0, 0.0286], [46298909.0, 90.68, 13.94, 92.06, 49.18, 263.0, 0.0135], [69724382.0, 94.67, 15.69, 91.37, 51.37, 229.0, 0.0342], [51769934.0, 91.97, 4.04, 95.67, 49.45, 235.0, 0.0243], [31818466.0, 90.59, 19.49, 92.53, 48.97, 290.0, 0.0325], [38365238.0, 93.75, 5.95, 93.5, 48.33, 282.0, 0.0005], [37024697.0, 92.84, 19.93, 96.06, 51.7, 268.0, 0.0286], [54204131.0, 91.71, 11.97, 91.38, 50.06, 274.0, 0.0325], [37236193.0, 93.17, 19.11, 94.41, 52.82, 258.0, 0.0106], [44443845.0, 93.16, 20.34, 90.74, 45.25, 275.0, 0.0062], [51079846.0, 94.13, 26.21, 94.33, 49.79, 272.0, 0.0166], [30167587.0, 88.6, 22.03, 91.89, 50.98, 267.0, 0.0196], [49060567.0, 96.15, 15.06, 91.21, 49.33, 288.0, 0.0292], [53415711.0, 88.31, 15.27, 93.49, 44.19, 335.0, 0.0203], [44717772.0, 93.47, 15.0, 90.28, 49.4, 217.0, 0.0136]]}, "z": {"Lane": ["L4", "L5", "L4", "L1", "L4", "L7", "L7", "L4", "L5", "L7", "L3", "L1", "L2", "L1", "L1", "L3", "L8", "L2", "L6", "L8", "L3", "L5", "L6", "L8", "L6", "L2", "L2", "L4", "L6", "L8", "L2", "L1", "L4", "L1", "L4", "L4", "L5", "L7", "L8", "L8", "L7", "L6", "L5", "L8", "L6", "L5", "L4", "L1", "L5", "L5", "L8", "L7", "L5", "L5", "L6", "L8", "L4", "L1", "L7", "L7", "L3", "L7", "L5", "L3", "L3", "L8", "L1", "L7", "L6", "L4", "L1", "L8", "L6", "L5", "L5", "L3", "L4", "L7", "L7", "L2", "L7", "L1", "L7", "L8", "L2", "L2", "L4", "L5", "L6", "L2", "L1", "L8", "L3", "L2", "L4", "L8"], "Batch": ["RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunB", "RunB", "RunB", "RunC", "RunC", "RunC", "RunB", "RunA", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunB", "RunC", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunC", "RunA", "RunB", "RunA", "RunC", "RunB", "RunB", "RunC", "RunA", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunC", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunC", "RunA", "RunB", "RunA", "RunB", "RunC", "RunB", "RunB", "RunB", "RunB", "RunC", "RunB", "RunB", "RunA", "RunA", "RunC", "RunB", "RunA", "RunB", "RunA", "RunB", "RunC", "RunC", "RunA", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunA", "RunB", "RunC", "RunA", "RunC", "RunC"], "Library": ["PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "PolyA", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "RiboZero", "Exome", "RiboZero", "RiboZero", "RiboZero", "Exome", "RiboZero", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "RiboZero", "Exome", "PolyA", "Exome", "PolyA", "PolyA", "PolyA", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "RiboZero", "PolyA", "Exome", "Exome", "PolyA", "RiboZero", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "RiboZero", "PolyA", "Exome", "Exome", "Exome", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "PolyA", "PolyA", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "Exome"]}, "x": null}, "config": {"graphType": "Scatter2D", "xAxis": ["pct_mapped"], "yAxis": ["contamination_freemix"], "colorBy": "Batch", "title": "Contamination (freemix) vs mapping rate", "broadcast": true, "broadcastGroup": "qc"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
</section>
<section id="q30-vs-gc-by-library-prep" class="level3">
<h3 class="anchored" data-anchor-id="q30-vs-gc-by-library-prep">3 — Q30 vs GC, by library prep</h3>
<div id="66a1edee" class="cell" data-execution_count="6">
<div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">panel({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scatter2D"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gc_content"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct_q30"</span>],</span>
<span id="cb8-2">       <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Library"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Q30 vs GC content, coloured by library"</span>}, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"qcQ30"</span>)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="qcQ30" width="640" height="360"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("qcQ30");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart qcQ30 removed for re-rendering.");
  } else {
    console.log("Chart qcQ30 ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart qcQ30 could not be cleaned for re-rendering:", error);
}

var chart_qcQ30 = new CanvasXpress({"renderTo": "qcQ30", "data": {"y": {"vars": ["S001", "S002", "S003", "S004", "S005", "S006", "S007", "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", "S096"], "smps": ["total_reads", "pct_mapped", "pct_duplication", "pct_q30", "gc_content", "insert_size", "contamination_freemix"], "data": [[39731273.0, 93.85, 11.9, 89.58, 44.63, 295.0, 0.0165], [40380961.0, 86.82, 13.41, 94.49, 46.71, 280.0, 0.0015], [32582992.0, 99.47, 7.88, 90.7, 50.27, 286.0, 0.0205], [53943211.0, 97.33, 13.95, 93.02, 44.51, 296.0, 0.0283], [44716872.0, 93.27, 11.08, 91.7, 45.65, 353.0, 0.0344], [36599101.0, 93.81, 13.99, 91.47, 46.64, 307.0, 0.0252], [46095164.0, 96.7, 19.76, 91.54, 48.13, 200.0, 0.0377], [48000008.0, 95.26, 18.89, 92.35, 48.73, 253.0, 0.0274], [36369073.0, 96.45, 13.29, 92.15, 53.85, 276.0, 0.0037], [50969240.0, 98.24, 29.2, 90.22, 45.15, 312.0, 0.0363], [33599116.0, 90.06, 14.99, 87.9, 45.15, 307.0, 0.0214], [48655822.0, 90.39, 24.5, 92.59, 48.25, 288.0, 0.0286], [49427201.0, 92.61, 11.81, 91.74, 44.08, 308.0, 0.0104], [47119993.0, 90.14, 10.41, 91.39, 47.9, 240.0, 0.0185], [46853194.0, 97.07, 5.44, 90.31, 42.56, 246.0, 0.005], [41603968.0, 86.13, 23.03, 94.13, 52.31, 195.0, 0.0301], [59046428.0, 92.89, 17.75, 93.67, 40.16, 279.0, 0.0045], [44160518.0, 96.46, 4.81, 89.9, 47.14, 251.0, 0.0074], [47727667.0, 89.67, 3.39, 90.54, 42.19, 315.0, 0.0206], [36724246.0, 89.8, 16.5, 92.31, 51.81, 283.0, 0.0378], [32834123.0, 79.02, 25.79, 94.17, 47.94, 269.0, 0.0108], [59130932.0, 97.62, 11.99, 95.4, 52.51, 237.0, 0.032], [44365467.0, 88.78, 23.6, 88.56, 48.62, 303.0, 0.0068], [50373280.0, 90.6, 7.17, 90.58, 47.49, 270.0, 0.0055], [27634567.0, 88.41, 2.91, 92.81, 45.91, 317.0, 0.0353], [55067555.0, 92.88, 6.01, 91.54, 52.3, 304.0, 0.0001], [47573074.0, 95.73, 10.26, 93.11, 47.71, 265.0, 0.0041], [26419904.0, 95.42, 18.8, 95.77, 50.43, 250.0, 0.0384], [44382069.0, 99.5, 6.25, 86.2, 42.67, 255.0, 0.0291], [30681013.0, 94.75, 16.45, 92.97, 48.13, 311.0, 0.0038], [44211734.0, 88.42, 10.6, 91.53, 49.74, 314.0, 0.0389], [37321516.0, 91.33, 21.43, 92.38, 44.94, 322.0, 0.0081], [51980437.0, 93.95, 8.86, 93.36, 49.68, 241.0, 0.039], [35908215.0, 89.48, 24.07, 92.25, 40.83, 224.0, 0.0179], [43841593.0, 90.38, 4.28, 91.69, 52.09, 253.0, 0.0174], [24751211.0, 94.05, 14.02, 91.33, 54.14, 263.0, 0.0094], [35531985.0, 89.94, 8.89, 92.11, 45.14, 293.0, 0.0274], [51665363.0, 89.7, 11.8, 90.25, 46.59, 305.0, 0.0053], [40270860.0, 92.83, 11.11, 91.15, 56.42, 354.0, 0.0109], [62194964.0, 94.15, 18.98, 92.54, 48.46, 221.0, 0.0024], [23130329.0, 88.7, 16.89, 92.46, 47.81, 228.0, 0.0362], [48105118.0, 93.37, 27.16, 92.35, 48.63, 149.0, 0.0185], [36035403.0, 95.84, 8.99, 92.94, 46.56, 257.0, 0.016], [51977734.0, 97.33, 17.13, 96.02, 40.34, 234.0, 0.0025], [39437507.0, 88.95, 10.68, 90.99, 50.1, 308.0, 0.0087], [33750550.0, 93.43, 5.63, 94.53, 48.28, 254.0, 0.0056], [45625993.0, 96.44, 11.56, 91.44, 48.23, 305.0, 0.0189], [39267219.0, 91.57, 11.44, 90.43, 49.61, 265.0, 0.0178], [43603870.0, 99.05, 10.52, 88.77, 42.68, 265.0, 0.0084], [26322443.0, 88.1, 20.0, 94.59, 51.26, 248.0, 0.0005], [50827140.0, 96.17, 11.95, 88.6, 48.08, 226.0, 0.0045], [40761784.0, 94.36, 22.35, 91.5, 46.36, 344.0, 0.0143], [47320485.0, 96.26, 10.22, 89.31, 48.72, 328.0, 0.0063], [43369554.0, 95.62, 15.79, 90.51, 55.74, 262.0, 0.0171], [40114772.0, 99.5, 6.46, 91.48, 45.43, 245.0, 0.0088], [22339638.0, 95.3, 8.38, 87.6, 47.46, 267.0, 0.0149], [34758883.0, 92.38, 6.17, 90.16, 53.23, 265.0, 0.0312], [51604859.0, 94.24, 21.01, 89.15, 43.77, 272.0, 0.0307], [43270147.0, 96.49, 11.69, 92.55, 46.85, 323.0, 0.0271], [34107245.0, 92.97, 4.57, 88.51, 51.67, 280.0, 0.0074], [44048770.0, 83.22, 22.92, 95.37, 46.89, 253.0, 0.0229], [32112102.0, 91.49, 18.3, 90.97, 49.17, 322.0, 0.0128], [29809698.0, 95.74, 12.41, 92.73, 51.25, 294.0, 0.0013], [47040642.0, 82.17, 31.35, 89.37, 46.99, 258.0, 0.0297], [29626002.0, 85.39, 31.62, 95.75, 49.92, 272.0, 0.0367], [47661306.0, 99.5, 8.65, 93.12, 49.15, 235.0, 0.0013], [33024620.0, 93.63, 15.27, 91.9, 40.33, 313.0, 0.0298], [50703414.0, 92.5, 15.47, 86.82, 46.62, 263.0, 0.0188], [37015975.0, 92.23, 7.66, 92.26, 53.15, 303.0, 0.0268], [48527426.0, 92.78, 22.69, 90.51, 45.75, 237.0, 0.0224], [42127399.0, 88.49, 12.67, 89.46, 53.53, 264.0, 0.0102], [48366188.0, 93.46, 6.95, 93.15, 52.82, 301.0, 0.0357], [44082084.0, 93.74, 10.84, 94.33, 49.12, 272.0, 0.0077], [30703825.0, 95.42, 20.6, 90.54, 48.28, 317.0, 0.0098], [34817148.0, 92.11, 12.25, 93.58, 49.7, 285.0, 0.0129], [30327242.0, 81.72, 21.48, 89.96, 50.38, 198.0, 0.0066], [35056118.0, 96.86, 10.9, 91.12, 52.24, 321.0, 0.0274], [38741227.0, 93.97, 12.2, 91.9, 46.75, 306.0, 0.0249], [51892586.0, 91.75, 20.37, 93.02, 47.86, 308.0, 0.0172], [48967691.0, 91.86, 15.16, 93.14, 43.43, 366.0, 0.0095], [53294644.0, 93.5, 8.04, 93.6, 49.02, 274.0, 0.0225], [49837358.0, 96.54, 14.74, 93.72, 50.56, 312.0, 0.0286], [46298909.0, 90.68, 13.94, 92.06, 49.18, 263.0, 0.0135], [69724382.0, 94.67, 15.69, 91.37, 51.37, 229.0, 0.0342], [51769934.0, 91.97, 4.04, 95.67, 49.45, 235.0, 0.0243], [31818466.0, 90.59, 19.49, 92.53, 48.97, 290.0, 0.0325], [38365238.0, 93.75, 5.95, 93.5, 48.33, 282.0, 0.0005], [37024697.0, 92.84, 19.93, 96.06, 51.7, 268.0, 0.0286], [54204131.0, 91.71, 11.97, 91.38, 50.06, 274.0, 0.0325], [37236193.0, 93.17, 19.11, 94.41, 52.82, 258.0, 0.0106], [44443845.0, 93.16, 20.34, 90.74, 45.25, 275.0, 0.0062], [51079846.0, 94.13, 26.21, 94.33, 49.79, 272.0, 0.0166], [30167587.0, 88.6, 22.03, 91.89, 50.98, 267.0, 0.0196], [49060567.0, 96.15, 15.06, 91.21, 49.33, 288.0, 0.0292], [53415711.0, 88.31, 15.27, 93.49, 44.19, 335.0, 0.0203], [44717772.0, 93.47, 15.0, 90.28, 49.4, 217.0, 0.0136]]}, "z": {"Lane": ["L4", "L5", "L4", "L1", "L4", "L7", "L7", "L4", "L5", "L7", "L3", "L1", "L2", "L1", "L1", "L3", "L8", "L2", "L6", "L8", "L3", "L5", "L6", "L8", "L6", "L2", "L2", "L4", "L6", "L8", "L2", "L1", "L4", "L1", "L4", "L4", "L5", "L7", "L8", "L8", "L7", "L6", "L5", "L8", "L6", "L5", "L4", "L1", "L5", "L5", "L8", "L7", "L5", "L5", "L6", "L8", "L4", "L1", "L7", "L7", "L3", "L7", "L5", "L3", "L3", "L8", "L1", "L7", "L6", "L4", "L1", "L8", "L6", "L5", "L5", "L3", "L4", "L7", "L7", "L2", "L7", "L1", "L7", "L8", "L2", "L2", "L4", "L5", "L6", "L2", "L1", "L8", "L3", "L2", "L4", "L8"], "Batch": ["RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunB", "RunB", "RunB", "RunC", "RunC", "RunC", "RunB", "RunA", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunB", "RunC", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunC", "RunA", "RunB", "RunA", "RunC", "RunB", "RunB", "RunC", "RunA", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunC", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunC", "RunA", "RunB", "RunA", "RunB", "RunC", "RunB", "RunB", "RunB", "RunB", "RunC", "RunB", "RunB", "RunA", "RunA", "RunC", "RunB", "RunA", "RunB", "RunA", "RunB", "RunC", "RunC", "RunA", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunA", "RunB", "RunC", "RunA", "RunC", "RunC"], "Library": ["PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "PolyA", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "RiboZero", "Exome", "RiboZero", "RiboZero", "RiboZero", "Exome", "RiboZero", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "RiboZero", "Exome", "PolyA", "Exome", "PolyA", "PolyA", "PolyA", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "RiboZero", "PolyA", "Exome", "Exome", "PolyA", "RiboZero", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "RiboZero", "PolyA", "Exome", "Exome", "Exome", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "PolyA", "PolyA", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "Exome"]}, "x": null}, "config": {"graphType": "Scatter2D", "xAxis": ["gc_content"], "yAxis": ["pct_q30"], "colorBy": "Library", "title": "Q30 vs GC content, coloured by library", "broadcast": true, "broadcastGroup": "qc"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
</section>
<section id="sequencing-depth-per-sample" class="level3">
<h3 class="anchored" data-anchor-id="sequencing-depth-per-sample">4 — Sequencing depth per sample</h3>
<div id="4d91e972" class="cell" data-execution_count="7">
<div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">panel({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bar"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphOrientation"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vertical"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total_reads"</span>],</span>
<span id="cb9-2">       <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Batch"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total reads per sample (flag the short ones)"</span>}, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"qcReads"</span>, w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">820</span>, h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="qcReads" width="820" height="300"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("qcReads");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart qcReads removed for re-rendering.");
  } else {
    console.log("Chart qcReads ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart qcReads could not be cleaned for re-rendering:", error);
}

var chart_qcReads = new CanvasXpress({"renderTo": "qcReads", "data": {"y": {"vars": ["S001", "S002", "S003", "S004", "S005", "S006", "S007", "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", "S096"], "smps": ["total_reads", "pct_mapped", "pct_duplication", "pct_q30", "gc_content", "insert_size", "contamination_freemix"], "data": [[39731273.0, 93.85, 11.9, 89.58, 44.63, 295.0, 0.0165], [40380961.0, 86.82, 13.41, 94.49, 46.71, 280.0, 0.0015], [32582992.0, 99.47, 7.88, 90.7, 50.27, 286.0, 0.0205], [53943211.0, 97.33, 13.95, 93.02, 44.51, 296.0, 0.0283], [44716872.0, 93.27, 11.08, 91.7, 45.65, 353.0, 0.0344], [36599101.0, 93.81, 13.99, 91.47, 46.64, 307.0, 0.0252], [46095164.0, 96.7, 19.76, 91.54, 48.13, 200.0, 0.0377], [48000008.0, 95.26, 18.89, 92.35, 48.73, 253.0, 0.0274], [36369073.0, 96.45, 13.29, 92.15, 53.85, 276.0, 0.0037], [50969240.0, 98.24, 29.2, 90.22, 45.15, 312.0, 0.0363], [33599116.0, 90.06, 14.99, 87.9, 45.15, 307.0, 0.0214], [48655822.0, 90.39, 24.5, 92.59, 48.25, 288.0, 0.0286], [49427201.0, 92.61, 11.81, 91.74, 44.08, 308.0, 0.0104], [47119993.0, 90.14, 10.41, 91.39, 47.9, 240.0, 0.0185], [46853194.0, 97.07, 5.44, 90.31, 42.56, 246.0, 0.005], [41603968.0, 86.13, 23.03, 94.13, 52.31, 195.0, 0.0301], [59046428.0, 92.89, 17.75, 93.67, 40.16, 279.0, 0.0045], [44160518.0, 96.46, 4.81, 89.9, 47.14, 251.0, 0.0074], [47727667.0, 89.67, 3.39, 90.54, 42.19, 315.0, 0.0206], [36724246.0, 89.8, 16.5, 92.31, 51.81, 283.0, 0.0378], [32834123.0, 79.02, 25.79, 94.17, 47.94, 269.0, 0.0108], [59130932.0, 97.62, 11.99, 95.4, 52.51, 237.0, 0.032], [44365467.0, 88.78, 23.6, 88.56, 48.62, 303.0, 0.0068], [50373280.0, 90.6, 7.17, 90.58, 47.49, 270.0, 0.0055], [27634567.0, 88.41, 2.91, 92.81, 45.91, 317.0, 0.0353], [55067555.0, 92.88, 6.01, 91.54, 52.3, 304.0, 0.0001], [47573074.0, 95.73, 10.26, 93.11, 47.71, 265.0, 0.0041], [26419904.0, 95.42, 18.8, 95.77, 50.43, 250.0, 0.0384], [44382069.0, 99.5, 6.25, 86.2, 42.67, 255.0, 0.0291], [30681013.0, 94.75, 16.45, 92.97, 48.13, 311.0, 0.0038], [44211734.0, 88.42, 10.6, 91.53, 49.74, 314.0, 0.0389], [37321516.0, 91.33, 21.43, 92.38, 44.94, 322.0, 0.0081], [51980437.0, 93.95, 8.86, 93.36, 49.68, 241.0, 0.039], [35908215.0, 89.48, 24.07, 92.25, 40.83, 224.0, 0.0179], [43841593.0, 90.38, 4.28, 91.69, 52.09, 253.0, 0.0174], [24751211.0, 94.05, 14.02, 91.33, 54.14, 263.0, 0.0094], [35531985.0, 89.94, 8.89, 92.11, 45.14, 293.0, 0.0274], [51665363.0, 89.7, 11.8, 90.25, 46.59, 305.0, 0.0053], [40270860.0, 92.83, 11.11, 91.15, 56.42, 354.0, 0.0109], [62194964.0, 94.15, 18.98, 92.54, 48.46, 221.0, 0.0024], [23130329.0, 88.7, 16.89, 92.46, 47.81, 228.0, 0.0362], [48105118.0, 93.37, 27.16, 92.35, 48.63, 149.0, 0.0185], [36035403.0, 95.84, 8.99, 92.94, 46.56, 257.0, 0.016], [51977734.0, 97.33, 17.13, 96.02, 40.34, 234.0, 0.0025], [39437507.0, 88.95, 10.68, 90.99, 50.1, 308.0, 0.0087], [33750550.0, 93.43, 5.63, 94.53, 48.28, 254.0, 0.0056], [45625993.0, 96.44, 11.56, 91.44, 48.23, 305.0, 0.0189], [39267219.0, 91.57, 11.44, 90.43, 49.61, 265.0, 0.0178], [43603870.0, 99.05, 10.52, 88.77, 42.68, 265.0, 0.0084], [26322443.0, 88.1, 20.0, 94.59, 51.26, 248.0, 0.0005], [50827140.0, 96.17, 11.95, 88.6, 48.08, 226.0, 0.0045], [40761784.0, 94.36, 22.35, 91.5, 46.36, 344.0, 0.0143], [47320485.0, 96.26, 10.22, 89.31, 48.72, 328.0, 0.0063], [43369554.0, 95.62, 15.79, 90.51, 55.74, 262.0, 0.0171], [40114772.0, 99.5, 6.46, 91.48, 45.43, 245.0, 0.0088], [22339638.0, 95.3, 8.38, 87.6, 47.46, 267.0, 0.0149], [34758883.0, 92.38, 6.17, 90.16, 53.23, 265.0, 0.0312], [51604859.0, 94.24, 21.01, 89.15, 43.77, 272.0, 0.0307], [43270147.0, 96.49, 11.69, 92.55, 46.85, 323.0, 0.0271], [34107245.0, 92.97, 4.57, 88.51, 51.67, 280.0, 0.0074], [44048770.0, 83.22, 22.92, 95.37, 46.89, 253.0, 0.0229], [32112102.0, 91.49, 18.3, 90.97, 49.17, 322.0, 0.0128], [29809698.0, 95.74, 12.41, 92.73, 51.25, 294.0, 0.0013], [47040642.0, 82.17, 31.35, 89.37, 46.99, 258.0, 0.0297], [29626002.0, 85.39, 31.62, 95.75, 49.92, 272.0, 0.0367], [47661306.0, 99.5, 8.65, 93.12, 49.15, 235.0, 0.0013], [33024620.0, 93.63, 15.27, 91.9, 40.33, 313.0, 0.0298], [50703414.0, 92.5, 15.47, 86.82, 46.62, 263.0, 0.0188], [37015975.0, 92.23, 7.66, 92.26, 53.15, 303.0, 0.0268], [48527426.0, 92.78, 22.69, 90.51, 45.75, 237.0, 0.0224], [42127399.0, 88.49, 12.67, 89.46, 53.53, 264.0, 0.0102], [48366188.0, 93.46, 6.95, 93.15, 52.82, 301.0, 0.0357], [44082084.0, 93.74, 10.84, 94.33, 49.12, 272.0, 0.0077], [30703825.0, 95.42, 20.6, 90.54, 48.28, 317.0, 0.0098], [34817148.0, 92.11, 12.25, 93.58, 49.7, 285.0, 0.0129], [30327242.0, 81.72, 21.48, 89.96, 50.38, 198.0, 0.0066], [35056118.0, 96.86, 10.9, 91.12, 52.24, 321.0, 0.0274], [38741227.0, 93.97, 12.2, 91.9, 46.75, 306.0, 0.0249], [51892586.0, 91.75, 20.37, 93.02, 47.86, 308.0, 0.0172], [48967691.0, 91.86, 15.16, 93.14, 43.43, 366.0, 0.0095], [53294644.0, 93.5, 8.04, 93.6, 49.02, 274.0, 0.0225], [49837358.0, 96.54, 14.74, 93.72, 50.56, 312.0, 0.0286], [46298909.0, 90.68, 13.94, 92.06, 49.18, 263.0, 0.0135], [69724382.0, 94.67, 15.69, 91.37, 51.37, 229.0, 0.0342], [51769934.0, 91.97, 4.04, 95.67, 49.45, 235.0, 0.0243], [31818466.0, 90.59, 19.49, 92.53, 48.97, 290.0, 0.0325], [38365238.0, 93.75, 5.95, 93.5, 48.33, 282.0, 0.0005], [37024697.0, 92.84, 19.93, 96.06, 51.7, 268.0, 0.0286], [54204131.0, 91.71, 11.97, 91.38, 50.06, 274.0, 0.0325], [37236193.0, 93.17, 19.11, 94.41, 52.82, 258.0, 0.0106], [44443845.0, 93.16, 20.34, 90.74, 45.25, 275.0, 0.0062], [51079846.0, 94.13, 26.21, 94.33, 49.79, 272.0, 0.0166], [30167587.0, 88.6, 22.03, 91.89, 50.98, 267.0, 0.0196], [49060567.0, 96.15, 15.06, 91.21, 49.33, 288.0, 0.0292], [53415711.0, 88.31, 15.27, 93.49, 44.19, 335.0, 0.0203], [44717772.0, 93.47, 15.0, 90.28, 49.4, 217.0, 0.0136]]}, "z": {"Lane": ["L4", "L5", "L4", "L1", "L4", "L7", "L7", "L4", "L5", "L7", "L3", "L1", "L2", "L1", "L1", "L3", "L8", "L2", "L6", "L8", "L3", "L5", "L6", "L8", "L6", "L2", "L2", "L4", "L6", "L8", "L2", "L1", "L4", "L1", "L4", "L4", "L5", "L7", "L8", "L8", "L7", "L6", "L5", "L8", "L6", "L5", "L4", "L1", "L5", "L5", "L8", "L7", "L5", "L5", "L6", "L8", "L4", "L1", "L7", "L7", "L3", "L7", "L5", "L3", "L3", "L8", "L1", "L7", "L6", "L4", "L1", "L8", "L6", "L5", "L5", "L3", "L4", "L7", "L7", "L2", "L7", "L1", "L7", "L8", "L2", "L2", "L4", "L5", "L6", "L2", "L1", "L8", "L3", "L2", "L4", "L8"], "Batch": ["RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunB", "RunB", "RunB", "RunC", "RunC", "RunC", "RunB", "RunA", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunC", "RunB", "RunC", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunC", "RunA", "RunB", "RunA", "RunC", "RunB", "RunB", "RunC", "RunA", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunA", "RunB", "RunA", "RunC", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunC", "RunA", "RunB", "RunA", "RunB", "RunC", "RunB", "RunB", "RunB", "RunB", "RunC", "RunB", "RunB", "RunA", "RunA", "RunC", "RunB", "RunA", "RunB", "RunA", "RunB", "RunC", "RunC", "RunA", "RunA", "RunA", "RunC", "RunA", "RunC", "RunC", "RunA", "RunA", "RunA", "RunB", "RunC", "RunA", "RunC", "RunC"], "Library": ["PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "PolyA", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "RiboZero", "Exome", "RiboZero", "RiboZero", "RiboZero", "Exome", "RiboZero", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "RiboZero", "Exome", "PolyA", "Exome", "PolyA", "PolyA", "PolyA", "RiboZero", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "RiboZero", "PolyA", "Exome", "Exome", "PolyA", "RiboZero", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "RiboZero", "PolyA", "Exome", "Exome", "Exome", "RiboZero", "RiboZero", "PolyA", "RiboZero", "Exome", "Exome", "RiboZero", "PolyA", "PolyA", "PolyA", "PolyA", "PolyA", "Exome", "RiboZero", "RiboZero", "PolyA", "Exome", "PolyA", "RiboZero", "RiboZero", "PolyA", "RiboZero", "RiboZero", "RiboZero", "Exome", "PolyA", "PolyA", "Exome", "Exome"]}, "x": null}, "config": {"graphType": "Bar", "graphOrientation": "vertical", "xAxis": ["total_reads"], "colorBy": "Batch", "title": "Total reads per sample (flag the short ones)", "broadcast": true, "broadcastGroup": "qc"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Lasso the bad cluster in panel 1 and panels 2–4 immediately restrict to those samples — you can read their contamination, library and depth without a single callback. The “wiring” is one shared group id.</p>
</section>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>Each panel is a portable <code>data</code> + <code>config</code> spec; the cross-filter is just a shared <code>broadcastGroup</code>. The same specs reproduce the dashboard from R or JavaScript, against the same <code>ngs-qc.csv</code>.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../network-graphs-in-python/">Interactive network graphs in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>dashboard</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/linked-dashboards-in-python/</guid>
  <pubDate>Fri, 30 Oct 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/linked-dashboards-in-python/thumbnail.png" medium="image" type="image/png" height="110" width="144"/>
</item>
<item>
  <title>Genome browser tracks in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/genome-tracks-in-python/</link>
  <description><![CDATA[ 




<p>A genome browser view stacks <strong>tracks</strong> that share one coordinate axis: coverage, gene models, variants. In Python this usually means <code>pyGenomeTracks</code> or a static matplotlib figure. Here we build an interactive, zoomable view with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — from one portable spec.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-data-shape" class="level2">
<h2 class="anchored" data-anchor-id="the-data-shape">The data shape</h2>
<p>A Genome figure is a list of <strong>tracks</strong> that share one coordinate axis — each with a <code>type</code>. Real browser views stack several: here we build four — <strong>gene models</strong> (<code>box</code>, multi-exon, connected), <strong>coverage across three tissues</strong> (<code>bar</code>), an <strong>expression heatmap</strong> (<code>heatmap</code>), and <strong>variant markers</strong> (<code>triangle</code>).</p>
<div id="a793e16b" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> random</span>
<span id="cb2-2">random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Gene models: each gene is a set of exon [start, end] intervals, drawn connected.</span></span>
<span id="cb2-5">genes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb2-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>):</span>
<span id="cb2-7">    start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">120</span></span>
<span id="cb2-8">    exons <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [[start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))]</span>
<span id="cb2-9">    genes.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"GENE</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dir"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"right"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>,</span>
<span id="cb2-10">                  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(70,130,220)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outline"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(0,0,0)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: exons})</span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Coverage and expression: one entry per binned position, three tissues each.</span></span>
<span id="cb2-13">offsets  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">22</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">22</span>)]</span>
<span id="cb2-14">coverage <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"p</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"offset"</span>: o,</span>
<span id="cb2-15">             <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">45</span>), random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">45</span>), random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">45</span>)]}</span>
<span id="cb2-16">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, o <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(offsets)]</span>
<span id="cb2-17">express  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"p</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"offset"</span>: o,</span>
<span id="cb2-18">             <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(random.gauss(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)]}</span>
<span id="cb2-19">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, o <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(offsets)]</span>
<span id="cb2-20"></span>
<span id="cb2-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Variants: point markers at genomic positions.</span></span>
<span id="cb2-22">snps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"rs</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"offset"</span>: random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">45</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">520</span>),</span>
<span id="cb2-23">         <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(200,40,40)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outline"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(0,0,0)"</span>} <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)]</span>
<span id="cb2-24"></span>
<span id="cb2-25">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tracks"</span>: [</span>
<span id="cb2-26">    {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Genes (exon models)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"connect"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: genes},</span>
<span id="cb2-27">    {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Coverage — Heart / Liver / Kidney"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bar"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"height"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">120</span>,</span>
<span id="cb2-28">     <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(80,80,200)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outline"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(60,60,60)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: coverage},</span>
<span id="cb2-29">    {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Expression (z-score)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"heatmap"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"height"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: express},</span>
<span id="cb2-30">    {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SNPs"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"triangle"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: snps},</span>
<span id="cb2-31">]}</span></code></pre></div>
</div>
</section>
<section id="the-plot" class="level2">
<h2 class="anchored" data-anchor-id="the-plot">The plot</h2>
<div id="020b62c8" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Genome"</span>,</span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"background"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(245,245,245)"</span>,</span>
<span id="cb3-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"featureStaggered"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb3-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Multi-track genome browser: genes, coverage, expression and variants"</span>,</span>
<span id="cb3-10">}</span>
<span id="cb3-11"></span>
<span id="cb3-12">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"genome"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">760</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">520</span>)</span>
<span id="cb3-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-14">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="genome" width="760" height="520"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("genome");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart genome removed for re-rendering.");
  } else {
    console.log("Chart genome ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart genome could not be cleaned for re-rendering:", error);
}

var chart_genome = new CanvasXpress({"renderTo": "genome", "data": {"tracks": [{"name": "Genes (exon models)", "type": "box", "connect": true, "data": [{"id": "GENE1", "dir": "right", "fill": "rgb(70,130,220)", "outline": "rgb(0,0,0)", "data": [[40, 58], [70, 88]]}, {"id": "GENE2", "dir": "left", "fill": "rgb(70,130,220)", "outline": "rgb(0,0,0)", "data": [[160, 178], [190, 208], [220, 238], [250, 268]]}, {"id": "GENE3", "dir": "right", "fill": "rgb(70,130,220)", "outline": "rgb(0,0,0)", "data": [[280, 298], [310, 328], [340, 358], [370, 388]]}, {"id": "GENE4", "dir": "left", "fill": "rgb(70,130,220)", "outline": "rgb(0,0,0)", "data": [[400, 418], [430, 448]]}]}, {"name": "Coverage \u2014 Heart / Liver / Kidney", "type": "bar", "height": 120, "fill": "rgb(80,80,200)", "outline": "rgb(60,60,60)", "data": [{"id": "p0", "offset": 50, "data": [31, 38, 45]}, {"id": "p1", "offset": 72, "data": [12, 8, 38]}, {"id": "p2", "offset": 94, "data": [24, 43, 22]}, {"id": "p3", "offset": 116, "data": [20, 38, 42]}, {"id": "p4", "offset": 138, "data": [43, 38, 33]}, {"id": "p5", "offset": 160, "data": [17, 22, 17]}, {"id": "p6", "offset": 182, "data": [41, 32, 8]}, {"id": "p7", "offset": 204, "data": [12, 18, 45]}, {"id": "p8", "offset": 226, "data": [10, 27, 9]}, {"id": "p9", "offset": 248, "data": [25, 38, 32]}, {"id": "p10", "offset": 270, "data": [35, 33, 44]}, {"id": "p11", "offset": 292, "data": [36, 16, 31]}, {"id": "p12", "offset": 314, "data": [14, 10, 16]}, {"id": "p13", "offset": 336, "data": [39, 21, 24]}, {"id": "p14", "offset": 358, "data": [35, 27, 34]}, {"id": "p15", "offset": 380, "data": [40, 32, 44]}, {"id": "p16", "offset": 402, "data": [30, 42, 45]}, {"id": "p17", "offset": 424, "data": [34, 45, 22]}, {"id": "p18", "offset": 446, "data": [29, 9, 25]}, {"id": "p19", "offset": 468, "data": [18, 28, 42]}, {"id": "p20", "offset": 490, "data": [44, 44, 14]}, {"id": "p21", "offset": 512, "data": [21, 44, 25]}]}, {"name": "Expression (z-score)", "type": "heatmap", "height": 90, "data": [{"id": "p0", "offset": 50, "data": [-0.08, 0.35, 1.84]}, {"id": "p1", "offset": 72, "data": [-2.41, 1.53, 0.95]}, {"id": "p2", "offset": 94, "data": [-0.48, 0.3, -0.47]}, {"id": "p3", "offset": 116, "data": [1.65, 0.21, -0.22]}, {"id": "p4", "offset": 138, "data": [-0.23, -0.2, -0.18]}, {"id": "p5", "offset": 160, "data": [-0.88, 2.06, -1.91]}, {"id": "p6", "offset": 182, "data": [-3.61, -0.12, -0.15]}, {"id": "p7", "offset": 204, "data": [0.37, -0.2, -0.15]}, {"id": "p8", "offset": 226, "data": [0.33, 0.97, -0.45]}, {"id": "p9", "offset": 248, "data": [-0.37, 1.94, 0.53]}, {"id": "p10", "offset": 270, "data": [-0.99, 2.32, 0.78]}, {"id": "p11", "offset": 292, "data": [-0.59, -1.17, 0.3]}, {"id": "p12", "offset": 314, "data": [-0.83, -1.06, -1.3]}, {"id": "p13", "offset": 336, "data": [-0.51, 1.11, -0.43]}, {"id": "p14", "offset": 358, "data": [-1.45, 0.67, 0.07]}, {"id": "p15", "offset": 380, "data": [0.84, 1.2, -0.17]}, {"id": "p16", "offset": 402, "data": [-0.14, -0.05, -1.13]}, {"id": "p17", "offset": 424, "data": [0.67, 1.37, 0.17]}, {"id": "p18", "offset": 446, "data": [-0.24, -0.26, -0.78]}, {"id": "p19", "offset": 468, "data": [-0.8, -0.4, -0.84]}, {"id": "p20", "offset": 490, "data": [-0.44, -1.58, 0.35]}, {"id": "p21", "offset": 512, "data": [0.05, -1.15, -2.3]}]}, {"name": "SNPs", "type": "triangle", "data": [{"id": "rs1000", "offset": 173, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1001", "offset": 366, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1002", "offset": 278, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1003", "offset": 197, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1004", "offset": 348, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1005", "offset": 352, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1006", "offset": 208, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1007", "offset": 135, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}, {"id": "rs1008", "offset": 231, "fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"}]}], "x": null, "z": null}, "config": {"graphType": "Genome", "background": "rgb(245,245,245)", "featureStaggered": true, "title": "Multi-track genome browser: genes, coverage, expression and variants"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Scroll/drag to pan and zoom into a region; every track stays locked to the shared coordinate axis, so the gene models, coverage, expression and variants line up position-for-position. Swap each track for your own pileup, annotation and VCF-derived data.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>The tracks and <code>config</code> <strong>are</strong> the figure — one portable JSON spec that renders the identical browser view from R or JavaScript, and can be validated and re-rendered later.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../network-graphs-in-python/">Interactive network graphs in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>genome</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/genome-tracks-in-python/</guid>
  <pubDate>Fri, 30 Oct 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/genome-tracks-in-python/thumbnail.png" medium="image" type="image/png" height="272" width="144"/>
</item>
<item>
  <title>Oncoprints (mutation landscapes) in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/oncoprint-in-python/</link>
  <description><![CDATA[ 




<p>An oncoprint is the standard way to show a <strong>mutation landscape</strong>: genes down one axis, tumours along the other, each cell stacking the alterations that gene carries in that sample — copy-number amplification/deletion plus mutation type — with frequencies alongside. In Python there is no first-class oncoprint; people hand-build one in matplotlib. Here we build an interactive one with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a>, from a single portable spec.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-data-shape" class="level2">
<h2 class="anchored" data-anchor-id="the-data-shape">The data shape</h2>
<p>An oncoprint is a <code>Heatmap</code> with <strong>overlay matrices</strong>: a base matrix (<code>y</code>, here expression) plus same-shaped layers for copy-number (<code>data2</code>) and mutation (<code>data3</code>). Each overlay cell is a string like <code>"Amplification"</code>, <code>"Missense"</code>, or <code>""</code> for none.</p>
<div id="4be930d8" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> random</span>
<span id="cb2-2">random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb2-3"></span>
<span id="cb2-4">genes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TP53"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"KRAS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PIK3CA"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PTEN"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EGFR"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BRAF"</span>,</span>
<span id="cb2-5">         <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"APC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RB1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NF1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MYC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CDKN2A"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ARID1A"</span>]</span>
<span id="cb2-6">samples <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"T</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:02d}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>)]</span>
<span id="cb2-7">mutrate <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {g: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(genes))) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(genes)}</span>
<span id="cb2-8"></span>
<span id="cb2-9">CNA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Amplification"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Deletion"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> MUT <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Missense"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Nonsense"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Truncating"</span>]</span>
<span id="cb2-10">base, cna, mut <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], [], []</span>
<span id="cb2-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> genes:</span>
<span id="cb2-12">    base.append([<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(random.gauss(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> samples])</span>
<span id="cb2-13">    cna.append([random.choice(CNA) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> random.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> mutrate[g] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> samples])</span>
<span id="cb2-14">    mut.append([random.choice(MUT) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> random.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> mutrate[g] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> samples])</span>
<span id="cb2-15"></span>
<span id="cb2-16">subtype <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [random.choice([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Basal"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Luminal"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HER2"</span>]) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> samples]</span>
<span id="cb2-17">pathway <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TSG"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Oncogene"</span>)[i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(genes))]</span></code></pre></div>
</div>
</section>
<section id="the-plot" class="level2">
<h2 class="anchored" data-anchor-id="the-plot">The plot</h2>
<p>The overlays go in the <code>y</code> object alongside the base <code>data</code>; <code>oncoprintCNA</code> / <code>oncoprintMUT</code> name them, and <code>xAxis</code> lists the samples.</p>
<div id="34910405" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: genes, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: samples, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: base, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data2"</span>: cna, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data3"</span>: mut},</span>
<span id="cb3-6">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Subtype"</span>: subtype}, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pathway"</span>: pathway}}</span>
<span id="cb3-7">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Heatmap"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"oncoprintCNA"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data2"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"oncoprintMUT"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data3"</span>,</span>
<span id="cb3-8">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"overlaysThickness"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: samples,</span>
<span id="cb3-9">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mutation landscape: 12 genes across 28 tumours"</span>}</span>
<span id="cb3-10"></span>
<span id="cb3-11">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"onco"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">820</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">440</span>)</span>
<span id="cb3-12"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-13">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="onco" width="820" height="440"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("onco");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart onco removed for re-rendering.");
  } else {
    console.log("Chart onco ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart onco could not be cleaned for re-rendering:", error);
}

var chart_onco = new CanvasXpress({"renderTo": "onco", "data": {"y": {"vars": ["TP53", "KRAS", "PIK3CA", "PTEN", "EGFR", "BRAF", "APC", "RB1", "NF1", "MYC", "CDKN2A", "ARID1A"], "smps": ["T01", "T02", "T03", "T04", "T05", "T06", "T07", "T08", "T09", "T10", "T11", "T12", "T13", "T14", "T15", "T16", "T17", "T18", "T19", "T20", "T21", "T22", "T23", "T24", "T25", "T26", "T27", "T28"], "data": [[-1.18, -1.15, 0.67, -2.29, -0.14, -2.26, 1.1, 0.2, 1.36, -0.5, 0.4, -0.29, -0.74, 0.15, -1.26, -0.35, 0.7, 0.06, -0.41, 2.19, 0.06, -0.59, 0.16, -0.52, -0.39, -0.35, 2.03, 0.02], [-1.0, -0.21, 0.11, 1.34, 0.51, -0.98, -0.3, 0.16, 0.22, -0.13, -1.91, 0.08, 1.11, 1.19, 1.34, -0.44, 0.11, -0.46, -0.52, 0.23, 0.47, -0.69, -3.65, 1.11, 1.64, -2.19, -1.11, 0.33], [-1.04, -1.21, 0.58, 0.1, -1.35, 0.52, 0.29, 1.49, -0.2, -0.21, -0.7, 0.13, 0.5, 0.18, -0.26, 0.58, 0.09, 0.25, -0.96, 0.21, -1.02, -0.86, 0.16, 2.15, 1.02, 0.0, -0.18, 1.01], [-1.31, -1.0, 1.25, 1.14, -0.39, 1.17, -0.43, 0.72, -1.1, -0.21, -1.06, 1.27, -0.23, -0.15, -0.02, 1.1, 1.81, -1.05, -0.16, -0.05, 0.19, -1.04, -1.4, -0.72, -0.77, -0.85, 0.84, -0.52], [-0.73, -0.24, 0.0, -1.21, 0.49, 0.54, -1.13, 1.18, 0.68, 1.43, -0.24, -0.35, -0.22, -0.38, 0.95, 0.95, 0.15, 2.04, -0.88, 0.11, 0.07, -0.23, -0.05, -0.33, 1.44, 2.0, -0.3, -0.65], [-1.63, -1.48, -0.41, -1.46, 0.38, 0.87, 2.9, 1.3, -1.69, 0.34, 0.31, 0.61, 1.32, 0.37, -0.12, -0.79, -1.07, 0.26, -0.26, -0.55, 1.86, 0.39, 0.67, -1.1, 1.47, -0.59, 0.15, 1.8], [0.59, -1.33, 1.55, -0.45, -0.24, -0.75, 0.37, -0.91, 0.25, 0.27, 0.38, 0.68, -0.37, -0.73, 1.57, 0.66, -0.22, -0.08, 0.5, 0.17, -1.24, 1.55, 1.31, -0.43, 0.13, 1.05, -0.58, 0.68], [0.85, 0.15, -0.84, 0.76, -0.29, -0.97, 1.83, -0.2, 1.36, -0.71, -0.6, -1.09, 0.29, -0.91, -1.26, -0.84, -0.81, -0.11, 0.38, 0.2, -0.81, 1.04, 0.1, -1.58, -0.8, 2.16, -0.24, 1.57], [0.78, 0.92, 0.58, 0.29, -0.96, 0.2, 1.73, -1.22, -1.34, -1.18, 0.03, -0.05, -0.23, -0.43, -0.49, 0.82, 0.09, -1.31, -0.82, 0.32, 0.08, -0.63, 0.99, -0.78, -1.77, -0.98, 0.65, -0.69], [-0.21, 0.04, 0.92, 1.45, -1.98, -0.0, 1.37, -0.54, -0.98, -0.9, 0.22, 1.02, -0.31, -1.8, 0.48, -0.95, 0.14, -0.1, 0.24, -0.55, -0.45, 0.72, 0.69, 1.77, 0.85, 0.45, -0.51, 0.4], [0.86, -0.44, -1.55, -0.3, 2.26, -0.94, 0.85, -0.06, 1.16, 2.01, 0.96, 0.51, -0.11, -1.22, -1.74, 1.46, -0.39, 1.21, 0.26, -0.48, -0.69, 0.94, -0.62, -0.27, -0.34, 0.1, 0.78, 0.48], [-0.84, -0.71, 1.87, 2.58, -0.68, -0.83, -1.0, -0.11, 0.73, 2.1, 0.57, 1.03, 0.84, -0.36, 1.06, 0.11, -1.09, -0.46, 0.67, -0.21, 0.04, 0.61, -0.72, -0.25, -0.54, 1.28, 0.35, 0.99]], "data2": [["Amplification", "", "Amplification", "", "", "", "", "Amplification", "", "", "", "", "Amplification", "", "", "", "", "", "", "Deletion", "", "", "", "", "", "Amplification", "", ""], ["", "", "", "", "Deletion", "", "", "Deletion", "", "Deletion", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], ["Deletion", "", "", "", "", "", "", "", "", "Deletion", "", "", "", "Deletion", "", "", "", "", "", "", "Amplification", "", "", "", "", "", "", ""], ["", "", "", "", "", "Amplification", "", "", "", "", "", "Deletion", "", "", "", "", "", "", "Amplification", "", "Amplification", "", "Deletion", "", "", "", "Amplification", ""], ["Deletion", "", "Deletion", "", "", "", "", "", "", "Deletion", "", "", "", "", "", "", "", "", "", "Amplification", "", "", "", "", "", "", "", ""], ["Deletion", "Amplification", "", "", "", "Deletion", "", "", "", "", "", "", "", "", "", "", "", "Amplification", "", "", "", "Deletion", "", "", "", "", "", ""], ["Amplification", "", "Amplification", "", "", "", "", "", "", "", "", "", "", "Amplification", "", "", "", "Deletion", "", "", "Amplification", "", "", "", "", "", "", ""], ["Amplification", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Deletion", "", "", "", "", "", "", "", "", "", "", "", ""], ["", "", "", "", "", "", "", "", "", "", "Deletion", "", "Deletion", "", "", "Deletion", "Deletion", "", "", "", "", "", "", "", "", "", "", ""], ["", "", "Amplification", "", "", "", "", "Deletion", "", "", "Deletion", "", "", "", "", "", "", "Amplification", "", "", "", "", "", "", "", "", "", ""], ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Amplification", "", "", "", "", "Deletion", ""], ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]], "data3": [["Truncating", "", "Truncating", "", "Truncating", "Missense", "Missense", "", "", "Nonsense", "", "Nonsense", "Truncating", "", "Nonsense", "Missense", "Truncating", "", "", "Truncating", "", "Nonsense", "Missense", "", "", "Nonsense", "Missense", "Truncating"], ["", "Truncating", "", "Nonsense", "", "", "", "", "Truncating", "Nonsense", "Missense", "", "", "", "", "", "", "Nonsense", "", "", "", "", "", "Truncating", "", "", "Truncating", ""], ["", "", "", "", "Missense", "", "Nonsense", "", "Nonsense", "", "Nonsense", "Missense", "Truncating", "", "Missense", "", "", "Truncating", "", "Nonsense", "", "Nonsense", "", "", "Nonsense", "", "", ""], ["", "", "", "Nonsense", "", "", "Missense", "", "Truncating", "Truncating", "Nonsense", "", "Truncating", "", "", "", "Nonsense", "Truncating", "", "", "", "Missense", "Nonsense", "Truncating", "", "Truncating", "", "Missense"], ["", "", "Nonsense", "Missense", "", "Nonsense", "", "", "", "Missense", "", "", "Missense", "", "", "Missense", "", "", "", "", "Truncating", "Nonsense", "", "", "Missense", "", "", ""], ["", "", "", "Missense", "Nonsense", "Nonsense", "", "", "Missense", "", "", "", "", "", "Nonsense", "", "Missense", "", "", "", "Nonsense", "", "", "Nonsense", "", "", "", ""], ["", "", "Nonsense", "", "", "", "", "Nonsense", "", "Missense", "", "Missense", "", "", "", "", "", "", "", "", "", "Missense", "", "Truncating", "", "", "", "Truncating"], ["Nonsense", "", "", "", "", "Truncating", "", "Truncating", "Truncating", "", "", "", "", "", "", "", "", "", "Nonsense", "Missense", "Nonsense", "", "", "Missense", "", "Truncating", "", "Nonsense"], ["", "Nonsense", "Nonsense", "", "", "", "Missense", "", "", "", "", "", "", "", "Missense", "Missense", "", "Nonsense", "", "", "", "Missense", "", "", "Truncating", "Nonsense", "", ""], ["", "Nonsense", "", "", "", "", "", "", "", "", "", "", "", "", "", "Missense", "", "", "", "", "Truncating", "", "", "", "", "", "", "Missense"], ["", "", "", "", "", "", "Truncating", "", "Truncating", "", "", "", "", "Truncating", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], ["Missense", "", "", "", "", "", "", "Truncating", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Truncating", ""]]}, "x": {"Subtype": ["Basal", "Luminal", "HER2", "HER2", "Basal", "Basal", "Luminal", "HER2", "HER2", "Basal", "Basal", "Luminal", "Basal", "HER2", "Luminal", "Luminal", "Luminal", "HER2", "HER2", "HER2", "HER2", "Luminal", "Luminal", "Basal", "HER2", "HER2", "Luminal", "Luminal"]}, "z": {"Pathway": ["TSG", "Oncogene", "TSG", "Oncogene", "TSG", "Oncogene", "TSG", "Oncogene", "TSG", "Oncogene", "TSG", "Oncogene"]}}, "config": {"graphType": "Heatmap", "oncoprintCNA": "data2", "oncoprintMUT": "data3", "overlaysThickness": 100, "xAxis": ["T01", "T02", "T03", "T04", "T05", "T06", "T07", "T08", "T09", "T10", "T11", "T12", "T13", "T14", "T15", "T16", "T17", "T18", "T19", "T20", "T21", "T22", "T23", "T24", "T25", "T26", "T27", "T28"], "title": "Mutation landscape: 12 genes across 28 tumours"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>canvasXpress sorts the waterfall for you and shows the alteration frequency per row. Hover a cell to read the exact alteration; swap the overlays for your own MAF / CNA calls.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>The base matrix, the overlays and the <code>config</code> <strong>are</strong> the figure — one portable JSON spec that renders the identical oncoprint from R or JavaScript, and can be validated and re-rendered later.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../clustered-heatmap-in-python/">A clustered heatmap in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>oncoprint</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/oncoprint-in-python/</guid>
  <pubDate>Tue, 27 Oct 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/oncoprint-in-python/thumbnail.png" medium="image" type="image/png" height="73" width="144"/>
</item>
<item>
  <title>Circular (Circos-style) multi-track plots in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/circos-plots-in-python/</link>
  <description><![CDATA[ 




<p>A circular (Circos-style) plot wraps a genome — or any ordered set of segments — into a ring, stacks several <strong>data tracks</strong> around it, and draws <strong>ribbons</strong> for relationships between positions. In Python the usual tool is <code>pyCirclize</code>. Here we build an interactive one with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a>, from a single portable spec.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-data-shape" class="level2">
<h2 class="anchored" data-anchor-id="the-data-shape">The data shape</h2>
<p>The matrix is <strong>tracks × segments</strong> (rows are the tracks you draw, columns are the positions around the ring). A sample annotation segments the ring (here into chromosomes), and <code>circularConnections</code> is a list of <code>[colour, from, to]</code> ribbons.</p>
<div id="08da4624" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> random</span>
<span id="cb2-2">random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb2-3"></span>
<span id="cb2-4">segments <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"s</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)]</span>
<span id="cb2-5">tracks   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Expression"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Methylation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CopyNumber"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Density"</span>]</span>
<span id="cb2-6">data_m   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(random.gauss(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> segments] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> tracks]</span>
<span id="cb2-7"></span>
<span id="cb2-8">region <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"chr</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)]</span>
<span id="cb2-9">cols   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(220,40,40)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(40,120,220)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(40,160,60)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgb(240,150,20)"</span>]</span>
<span id="cb2-10">conns  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [[random.choice(cols), random.choice(segments), random.choice(segments)] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>)]</span></code></pre></div>
</div>
</section>
<section id="the-plot" class="level2">
<h2 class="anchored" data-anchor-id="the-plot">The plot</h2>
<p><code>circularTrackGraphType</code> picks a renderer per track (<code>bar</code>, <code>heatmap</code>, <code>line</code>, <code>dot</code>), <code>circularTrackGraphWeight</code> sets each track’s radial thickness, and <code>segregateSamplesBy</code> splits the ring by the annotation.</p>
<div id="d4acc2a2" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: tracks, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: segments, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: data_m}, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Region"</span>: region}}</span>
<span id="cb3-6">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Circular"</span>,</span>
<span id="cb3-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circularConnections"</span>: conns,</span>
<span id="cb3-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circularTrackGraphType"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bar"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"heatmap"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"line"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dot"</span>],</span>
<span id="cb3-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circularTrackGraphWeight"</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>],</span>
<span id="cb3-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circularTrackName"</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>],</span>
<span id="cb3-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"segregateSamplesBy"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Region"</span>],</span>
<span id="cb3-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Circos-style multi-track plot with connections"</span>,</span>
<span id="cb3-14">}</span>
<span id="cb3-15"></span>
<span id="cb3-16">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circ"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">560</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">560</span>)</span>
<span id="cb3-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-18">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="circ" width="560" height="560"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("circ");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart circ removed for re-rendering.");
  } else {
    console.log("Chart circ ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart circ could not be cleaned for re-rendering:", error);
}

var chart_circ = new CanvasXpress({"renderTo": "circ", "data": {"y": {"vars": ["Expression", "Methylation", "CopyNumber", "Density"], "smps": ["s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55", "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63", "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71", "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79", "s80"], "data": [[0.37, 2.53, 1.1, 1.11, 0.65, 0.38, 0.69, -0.0, -0.7, -0.86, -1.12, 0.34, 0.67, 1.76, 0.62, 0.39, 0.78, 0.1, -1.8, 1.18, -0.36, 0.34, -0.16, 3.09, 1.28, 0.54, -1.05, 1.03, -0.81, 1.3, -1.45, 0.02, 1.07, -0.77, 0.23, 0.28, 1.09, -0.39, 0.83, 2.27, -1.42, -0.77, 0.6, -0.56, -1.27, 1.61, 1.12, 1.28, 1.25, 0.88, -0.72, -2.34, 0.66, -0.99, 0.18, 0.54, -1.17, -0.21, 1.95, 0.94, -1.55, -0.07, 0.14, 0.73, 0.91, 0.07, -0.11, 1.04, -1.36, 1.32, 0.48, -0.39, -0.48, 0.37, -1.41, -2.32, 0.51, 1.63, -0.05, 0.16], [0.08, -0.91, 0.51, 0.94, 0.12, 1.02, -0.98, 0.35, -0.7, -0.44, 0.35, 0.24, 0.95, 0.75, -1.16, 1.4, -1.57, -0.05, 0.36, -0.05, 0.55, 0.06, -0.99, 0.86, -0.04, -0.93, 0.07, -0.02, 0.35, -0.59, 0.18, -0.18, 1.65, -0.37, 1.31, -0.08, 1.16, 2.38, -0.39, 0.15, -0.92, -0.72, -0.57, 0.1, 0.95, 0.91, -0.5, 0.15, -1.49, 0.6, -0.24, -1.1, -0.74, 0.59, 0.1, 0.66, -0.45, 0.16, -0.24, -1.55, -0.16, -0.14, -0.7, 0.8, 2.18, 1.45, 0.04, -1.18, -0.19, -0.64, 0.16, 1.21, -0.05, -1.44, 1.38, 0.06, 1.39, -0.89, 2.54, -1.24], [0.14, 0.83, -2.62, -0.8, -1.62, 1.74, 0.71, -0.97, -1.77, -1.78, 0.17, -0.82, 0.37, -0.54, -1.73, 1.84, 0.5, -0.71, -0.35, 1.33, 0.83, -1.27, 1.49, -0.63, 0.59, -1.23, -0.68, 0.8, -1.22, 0.08, 0.42, -0.67, 1.48, 0.68, -0.14, 1.03, 1.39, 1.26, -0.12, 0.82, 0.4, -1.12, -0.36, 2.06, -0.81, 0.5, 1.73, -0.38, -0.01, -0.76, 0.52, -1.24, 0.46, -0.84, 0.34, -1.74, -1.11, 0.94, 0.6, -3.1, 1.54, -0.84, 0.9, 1.04, -0.17, -0.39, -1.96, 0.47, 1.89, -1.28, 1.14, 0.75, 0.96, -1.09, -0.12, 0.25, 1.73, -0.96, -0.54, -0.79], [0.87, -1.62, -0.21, -1.34, -0.35, 0.76, -0.56, 0.69, -0.49, -0.06, -0.17, -0.91, 0.41, 0.65, -0.82, 0.68, 0.09, -0.45, 0.14, 0.82, 0.74, 1.49, 0.25, 0.2, -1.53, -0.56, 0.58, -1.14, -0.96, 1.83, -0.1, -1.14, -2.16, -0.9, 2.31, -0.04, 0.6, 0.66, -0.51, 0.33, 0.03, -0.35, 1.01, -0.86, -0.78, -0.68, 1.21, -0.51, 1.8, -1.37, -1.02, -2.68, -0.95, 0.06, 0.68, -1.02, -0.55, 1.41, -0.52, 0.08, 0.62, -1.0, 1.22, -0.22, 0.76, -0.32, 0.25, 1.2, 0.2, -1.86, -0.31, -0.41, -0.21, 0.16, -1.66, 1.74, -0.89, 1.27, -0.4, -0.38]]}, "x": {"Region": ["chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr2", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr3", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4", "chr4"]}, "z": null}, "config": {"graphType": "Circular", "circularConnections": [["rgb(220,40,40)", "s11", "s24"], ["rgb(240,150,20)", "s75", "s17"], ["rgb(240,150,20)", "s73", "s75"], ["rgb(220,40,40)", "s48", "s65"], ["rgb(220,40,40)", "s77", "s48"], ["rgb(40,160,60)", "s14", "s41"], ["rgb(220,40,40)", "s62", "s22"], ["rgb(40,120,220)", "s62", "s47"], ["rgb(40,160,60)", "s48", "s55"], ["rgb(40,160,60)", "s5", "s19"], ["rgb(40,160,60)", "s8", "s5"], ["rgb(40,120,220)", "s66", "s47"], ["rgb(240,150,20)", "s47", "s61"], ["rgb(40,120,220)", "s39", "s18"], ["rgb(40,160,60)", "s3", "s57"], ["rgb(40,160,60)", "s75", "s34"], ["rgb(240,150,20)", "s38", "s38"], ["rgb(240,150,20)", "s64", "s58"]], "circularTrackGraphType": ["bar", "heatmap", "line", "dot"], "circularTrackGraphWeight": [0.3, 0.2, 0.25, 0.25], "circularTrackName": [1, 2, 3, 4], "segregateSamplesBy": ["Region"], "title": "Circos-style multi-track plot with connections"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Each ring is one track; the inner ribbons are the connections. Hover a segment to read its values; swap the matrix and ribbons for your own genomic tracks and interactions.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>The matrix, the connections and the <code>config</code> <strong>are</strong> the figure — one portable JSON spec that renders the identical circular plot from R or JavaScript, and can be validated and re-rendered later.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../genome-tracks-in-python/">Genome browser tracks in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>circos</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/circos-plots-in-python/</guid>
  <pubDate>Sat, 24 Oct 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/circos-plots-in-python/thumbnail.png" medium="image" type="image/png" height="139" width="144"/>
</item>
<item>
  <title>Choropleth maps in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/choropleth-maps-in-python/</link>
  <description><![CDATA[ 




<p>A choropleth shades each region by a value — emissions, incidence, turnout, income. It is the most common map in data analysis and the easiest to get <em>subtly wrong</em>: most “my map is all one colour” complaints are not rendering bugs but scale bugs. Here we build a choropleth in Python with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> that stays vivid and honest on exactly the kind of heavy-tailed data that flattens naive maps. The join and the colouring happen inside the render, so every figure is one portable spec you can re-run from Python, R or the browser.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress pandas</span></code></pre></div>
</section>
<section id="first-the-trap-colour-encodes-a-rate-not-a-count" class="level2">
<h2 class="anchored" data-anchor-id="first-the-trap-colour-encodes-a-rate-not-a-count">First, the trap: colour encodes a <em>rate</em>, not a <em>count</em></h2>
<p>A choropleth fills an <strong>area</strong>, and area is a size channel your eye cannot help reading. Shade regions by a raw count — total cases, total emissions, total sales — and big, populous regions light up simply because they are big and populous. You have drawn a population map with extra steps.</p>
<p>The fix is almost always to map a <strong>rate or density</strong>: cases per 100k, emissions per capita, sales per store. Reserve raw counts for a <em>proportional-symbol</em> map (a sized bubble at each centroid), where the size channel carries the count honestly. Decide which question you are answering before you pick the geometry — this one choice prevents most misleading maps.</p>
</section>
<section id="one-value-per-region" class="level2">
<h2 class="anchored" data-anchor-id="one-value-per-region">One value per region</h2>
<p>A choropleth needs exactly one measurement per shape. In canvasxpress the <strong>columns</strong> (<code>smps</code>) are the regions — they match the map by name — and each <strong>row</strong> (<code>vars</code>) is a variable you can colour by. Here it’s CO₂ emissions per country for 2018. We load a prepared table; swap it for your own (any <code>country → value</code> table works).</p>
<div id="1d78e58c" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb2-2"></span>
<span id="cb2-3">dat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(</span>
<span id="cb2-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://www.canvasxpress.org/data/r/cX-CO2-dat.txt"</span>,</span>
<span id="cb2-5">    sep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\t</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, index_col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb2-6">)</span>
<span id="cb2-7">smp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(</span>
<span id="cb2-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://www.canvasxpress.org/data/r/cX-CO2-smp.txt"</span>,</span>
<span id="cb2-9">    sep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\t</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, index_col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb2-10">).reindex(dat.columns)        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># align annotation to the country order</span></span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(dat.shape)              <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (1, N): one row (CO2) x N countries</span></span>
<span id="cb2-13">dat.iloc[:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>]</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>(1, 198)</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="1">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">Afghanistan</th>
<th data-quarto-table-cell-role="th">Albania</th>
<th data-quarto-table-cell-role="th">Algeria</th>
<th data-quarto-table-cell-role="th">Andorra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">CO2</td>
<td>10.452666</td>
<td>5.402999</td>
<td>164.309295</td>
<td>0.46421</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="the-map-quantile-classes-on-a-viridis-ramp" class="level2">
<h2 class="anchored" data-anchor-id="the-map-quantile-classes-on-a-viridis-ramp">The map: quantile classes on a viridis ramp</h2>
<p><code>y</code> carries the matrix (<code>vars</code> = the variable, <code>smps</code> = the countries, <code>data</code> = the values); the optional <code>x</code> block adds per-country annotations (continent, ISO code) for richer tooltips. The two choices that make this map <em>work</em> are in the colour scale: a seven-stop viridis <code>colorSpectrum</code>, and <code>colorSpectrumBreaksMethod = "quantile"</code>, which puts an equal number of countries in every colour class. On skewed data that guarantee is what keeps all seven colours on the map.</p>
<div id="f4223f77" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb4-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb4-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb4-4"></span>
<span id="cb4-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb4-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {</span>
<span id="cb4-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(dat.index),            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ["CO2"]</span></span>
<span id="cb4-8">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(dat.columns),          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># country names</span></span>
<span id="cb4-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: dat.values.tolist(),        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [[values]]</span></span>
<span id="cb4-10">    },</span>
<span id="cb4-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {</span>
<span id="cb4-12">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Continent"</span>: smp[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Continent"</span>].tolist(),</span>
<span id="cb4-13">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Code"</span>:      smp[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Code"</span>].tolist(),</span>
<span id="cb4-14">    },</span>
<span id="cb4-15">}</span>
<span id="cb4-16"></span>
<span id="cb4-17">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb4-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Map"</span>,</span>
<span id="cb4-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>:   <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CO2"</span>,</span>
<span id="cb4-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topoJSON"</span>:  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://www.canvasxpress.org/data/maps/WORLD.json"</span>,</span>
<span id="cb4-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mapId"</span>:     <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"co2Quantile"</span>,</span>
<span id="cb4-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorSpectrum"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#440154"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#443983"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#31688e"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#21918c"</span>,</span>
<span id="cb4-23">                      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#35b779"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#90d743"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#fde725"</span>],</span>
<span id="cb4-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorSpectrumBreaksMethod"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"quantile"</span>,</span>
<span id="cb4-25">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mapColor"</span>:        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#d9dde3"</span>,</span>
<span id="cb4-26">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mapOutlineColor"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#ffffff"</span>,</span>
<span id="cb4-27">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"legendPosition"</span>:  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bottom"</span>,</span>
<span id="cb4-28">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>:    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CO2 emissions per country (2018)"</span>,</span>
<span id="cb4-29">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"subtitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Seven quantile classes: each colour holds about 28 of 198 countries"</span>,</span>
<span id="cb4-30">}</span>
<span id="cb4-31"></span>
<span id="cb4-32">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"co2quant"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">760</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">520</span>)</span>
<span id="cb4-33"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb4-34">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="co2quant" width="760" height="520"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("co2quant");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart co2quant removed for re-rendering.");
  } else {
    console.log("Chart co2quant ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart co2quant could not be cleaned for re-rendering:", error);
}

var chart_co2quant = new CanvasXpress({"renderTo": "co2quant", "data": {"y": {"vars": ["CO2"], "smps": ["Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Anguilla", "Antigua & Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo", "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia", "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Fiji", "Finland", "France", "French Polynesia", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Greenland", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Moldova", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Democratic People's Republic of Korea", "The former Yugoslav Republic of Macedonia", "Norway", "Oman", "Pakistan", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "Sao Tome and Principe", "Saudi Arabia", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "Republic of Korea", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe"], "data": [[10.452666, 5.402999, 164.309295, 0.46421, 37.678605, 0.147145, 0.505574, 185.029897, 6.296603, 0.943234, 415.953947, 66.719678, 37.488394, 2.03001, 31.594487, 85.718805, 1.207134, 61.871676, 100.207836, 0.612205, 7.759753, 0.648945, 1.662172, 22.345503, 22.086102, 6.815418, 466.649304, 0.173555, 9.560399, 43.551599, 4.140342, 0.568028, 15.479031, 7.566796, 586.504635, 0.609509, 0.300478, 1.008035, 85.829114, 9956.568523, 92.228209, 0.245927, 3.518309, 0.072706, 8.249118, 17.718646, 26.084446, 7.332762, 104.411211, 2.231343, 34.65143, 0.389975, 25.305221, 41.817989, 251.460913, 6.018265, 5.90578, 0.708769, 17.710953, 16.184949, 2.123769, 45.849349, 331.725446, 0.780633, 4.803117, 0.56324, 9.862173, 755.362342, 14.479998, 71.797869, 0.511728, 0.278597, 19.411335, 3.032114, 0.308612, 2.342628, 3.366964, 10.470701, 42.505723, 49.628491, 3.674529, 2591.323739, 576.58439, 755.402186, 211.270294, 38.803394, 62.212641, 348.085029, 8.009662, 1135.688, 24.923803, 319.647412, 17.136703, 0.068879, 104.217567, 10.16888, 32.26245, 7.859287, 27.565431, 2.425558, 1.27446, 45.205986, 0.14375, 13.669492, 9.56852, 2.216456, 4.187806, 1.470252, 249.144498, 1.565092, 3.273276, 1.531581, 0.153065, 3.934804, 4.901611, 451.080829, 5.877784, 64.508256, 2.123147, 65.367444, 8.383478, 26.095603, 4.154302, 0.049746, 13.410432, 160.170147, 8.20904, 35.080341, 5.377193, 2.093847, 136.078346, 0.007653, 38.162935, 6.980909, 43.817657, 71.029916, 247.425382, 12.096333, 6.786146, 8.103032, 54.210259, 138.924391, 337.705742, 51.482481, 109.24468, 76.951219, 1691.360426, 1.080098, 0.011319, 0.249014, 0.362202, 0.079232, 0.264106, 0.267864, 0.126126, 576.757836, 46.0531, 0.60536, 0.987559, 38.28806, 36.087837, 14.487844, 0.298477, 0.658329, 634.934068, 1.539884, 269.654254, 22.973233, 22.372399, 2.551817, 41.766183, 36.895485, 25.877689, 273.104667, 7.473265, 11.501889, 292.452995, 0.520422, 3.167303, 0.164545, 37.865571, 30.357093, 419.194747, 78.034724, 0.01148, 5.384767, 231.694165, 188.541366, 380.138559, 5424.881502, 6.251839, 113.93837, 0.145412, 129.596274, 211.774129, 9.945288, 6.930094, 11.340575]]}, "x": {"Continent": ["Asia", "Europe", "Africa", "Europe", "Africa", "North America", "North America", "South America", "Asia", "North America", "Oceania", "Europe", "Europe", "North America", "Asia", "Asia", "North America", "Europe", "Europe", "North America", "Africa", "North America", "Asia", "South America", "Europe", "Africa", "South America", "North America", "Asia", "Europe", "Africa", "Africa", "Asia", "Africa", "North America", "Africa", "Africa", "Africa", "South America", "Asia", "South America", "Africa", "Africa", "Oceania", "Central America", "Europe", "North America", "Europe", "Europe", "Africa", "Europe", "Africa", "North America", "South America", "Africa", "Central America", "Africa", "Africa", "Europe", "Africa", "Oceania", "Europe", "Europe", "Oceania", "Africa", "Africa", "Asia", "Europe", "Africa", "Europe", "North America", "North America", "Central America", "Africa", "Africa", "South America", "North America", "Central America", "Asia", "Europe", "Europe", "Asia", "Asia", "Asia", "Asia", "Europe", "Asia", "Europe", "North America", "Asia", "Asia", "Asia", "Africa", "Oceania", "Asia", "Asia", "Asia", "Europe", "Asia", "Africa", "Africa", "Africa", "Europe", "Europe", "Europe", "Asia", "Africa", "Africa", "Asia", "Asia", "Africa", "Europe", "Oceania", "Africa", "Africa", "North America", "Europe", "Asia", "Europe", "Africa", "Africa", "Asia", "Africa", "Oceania", "Asia", "Europe", "Oceania", "Oceania", "Central America", "Africa", "Africa", "Oceania", "Asia", "Europe", "Europe", "Asia", "Asia", "Central America", "Oceania", "South America", "South America", "Asia", "Europe", "Europe", "Africa", "Europe", "Asia", "Africa", "Africa", "North America", "North America", "North America", "North America", "Oceania", "Africa", "Asia", "Europe", "Africa", "Africa", "Asia", "Europe", "Europe", "Oceania", "Africa", "Asia", "Africa", "Europe", "Asia", "Africa", "South America", "Europe", "Europe", "Asia", "Asia", "Asia", "Africa", "Asia", "Asia", "Africa", "Oceania", "North America", "Africa", "Asia", "Asia", "Oceania", "Africa", "Europe", "Asia", "Europe", "North America", "South America", "Asia", "Oceania", "South America", "Asia", "Asia", "Africa", "Africa"], "Code": ["AFG", "ALB", "DZA", "AND", "AGO", "AIA", "ATG", "ARG", "ARM", "ABW", "AUS", "AUT", "AZE", "BHS", "BHR", "BGD", "BRB", "BLR", "BEL", "BLZ", "BEN", "BMU", "BTN", "BOL", "BIH", "BWA", "BRA", "VGB", "BRN", "BGR", "BFA", "BDI", "KHM", "CMR", "CAN", "CPV", "CAF", "TCD", "CHL", "CHN", "COL", "COM", "COG", "COK", "CRI", "HRV", "CUB", "CYP", "CZE", "COD", "DNK", "DJI", "DOM", "ECU", "EGY", "SLV", "GNQ", "ERI", "EST", "ETH", "FJI", "FIN", "FRA", "PYF", "GAB", "GMB", "GEO", "DEU", "GHA", "GRC", "GRL", "GRD", "GTM", "GIN", "GNB", "GUY", "HTI", "HND", "HKG", "HUN", "ISL", "IND", "IDN", "IRN", "IRQ", "IRL", "ISR", "ITA", "JAM", "JPN", "JOR", "KAZ", "KEN", "KIR", "KWT", "KGZ", "LAO", "LVA", "LBN", "LSO", "LBR", "LBY", "LIE", "LTU", "LUX", "MAC", "MDG", "MWI", "MYS", "MDV", "MLI", "MLT", "MHL", "MRT", "MUS", "MEX", "MDA", "MNG", "MNE", "MAR", "MOZ", "MMR", "NAM", "NRU", "NPL", "NLD", "NCL", "NZL", "NIC", "NER", "NGA", "NIU", "PRK", "MKD", "NOR", "OMN", "PAK", "PAN", "PNG", "PRY", "PER", "PHL", "POL", "PRT", "QAT", "ROU", "RUS", "RWA", "SHN", "KNA", "LCA", "SPM", "VCT", "WSM", "STP", "SAU", "SRB", "SYC", "SLE", "SGP", "SVK", "SVN", "SLB", "SOM", "KOR", "SSD", "ESP", "LKA", "SDN", "SUR", "SWE", "CHE", "SYR", "TWN", "TJK", "TZA", "THA", "TLS", "TGO", "TON", "TTO", "TUN", "TUR", "TKM", "TUV", "UGA", "UKR", "ARE", "GBR", "USA", "URY", "UZB", "VUT", "VEN", "VNM", "YEM", "ZMB", "ZWE"]}, "z": null}, "config": {"graphType": "Map", "colorBy": "CO2", "topoJSON": "https://www.canvasxpress.org/data/maps/WORLD.json", "mapId": "co2Quantile", "colorSpectrum": ["#440154", "#443983", "#31688e", "#21918c", "#35b779", "#90d743", "#fde725"], "colorSpectrumBreaksMethod": "quantile", "mapColor": "#d9dde3", "mapOutlineColor": "#ffffff", "legendPosition": "bottom", "title": "CO2 emissions per country (2018)", "subtitle": "Seven quantile classes: each colour holds about 28 of 198 countries"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Every band of the ramp is doing work: the darkest purples are the smallest emitters, the yellows the largest, and the legend’s break values tell you the class edges are <em>data-driven</em>, not evenly spaced. Hover any country for its name, continent and value.</p>
</section>
<section id="why-not-just-a-plain-linear-ramp" class="level2">
<h2 class="anchored" data-anchor-id="why-not-just-a-plain-linear-ramp">Why not just a plain linear ramp?</h2>
<p>Because the data is <strong>heavy-tailed</strong> — a few countries emit thousands of megatonnes while most emit almost nothing. On a linear scale, <strong>195 of these 198 countries fall into the bottom fifth of the range</strong>, so a continuous ramp paints nearly the whole world one pale tone and spends its colour on two or three outliers:</p>
<div id="54fe8306" class="cell" data-execution_count="3">
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">linear <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Map"</span>,</span>
<span id="cb5-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>:   <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CO2"</span>,</span>
<span id="cb5-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topoJSON"</span>:  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://www.canvasxpress.org/data/maps/WORLD.json"</span>,</span>
<span id="cb5-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mapId"</span>:     <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"co2Linear"</span>,</span>
<span id="cb5-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"legendPosition"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>,</span>
<span id="cb5-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"theme"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"solarized"</span>,</span>
<span id="cb5-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>:    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The same data on a plain linear ramp"</span>,</span>
<span id="cb5-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"subtitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"195 of 198 countries sit in the bottom fifth of the scale - the map goes flat"</span>,</span>
<span id="cb5-10">}</span>
<span id="cb5-11"></span>
<span id="cb5-12">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"co2lin"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>linear, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">700</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">480</span>)</span>
<span id="cb5-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb5-14">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="co2lin" width="700" height="480"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("co2lin");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart co2lin removed for re-rendering.");
  } else {
    console.log("Chart co2lin ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart co2lin could not be cleaned for re-rendering:", error);
}

var chart_co2lin = new CanvasXpress({"renderTo": "co2lin", "data": {"y": {"vars": ["CO2"], "smps": ["Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Anguilla", "Antigua & Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo", "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia", "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Fiji", "Finland", "France", "French Polynesia", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Greenland", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Moldova", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Democratic People's Republic of Korea", "The former Yugoslav Republic of Macedonia", "Norway", "Oman", "Pakistan", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "Sao Tome and Principe", "Saudi Arabia", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "Republic of Korea", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe"], "data": [[10.452666, 5.402999, 164.309295, 0.46421, 37.678605, 0.147145, 0.505574, 185.029897, 6.296603, 0.943234, 415.953947, 66.719678, 37.488394, 2.03001, 31.594487, 85.718805, 1.207134, 61.871676, 100.207836, 0.612205, 7.759753, 0.648945, 1.662172, 22.345503, 22.086102, 6.815418, 466.649304, 0.173555, 9.560399, 43.551599, 4.140342, 0.568028, 15.479031, 7.566796, 586.504635, 0.609509, 0.300478, 1.008035, 85.829114, 9956.568523, 92.228209, 0.245927, 3.518309, 0.072706, 8.249118, 17.718646, 26.084446, 7.332762, 104.411211, 2.231343, 34.65143, 0.389975, 25.305221, 41.817989, 251.460913, 6.018265, 5.90578, 0.708769, 17.710953, 16.184949, 2.123769, 45.849349, 331.725446, 0.780633, 4.803117, 0.56324, 9.862173, 755.362342, 14.479998, 71.797869, 0.511728, 0.278597, 19.411335, 3.032114, 0.308612, 2.342628, 3.366964, 10.470701, 42.505723, 49.628491, 3.674529, 2591.323739, 576.58439, 755.402186, 211.270294, 38.803394, 62.212641, 348.085029, 8.009662, 1135.688, 24.923803, 319.647412, 17.136703, 0.068879, 104.217567, 10.16888, 32.26245, 7.859287, 27.565431, 2.425558, 1.27446, 45.205986, 0.14375, 13.669492, 9.56852, 2.216456, 4.187806, 1.470252, 249.144498, 1.565092, 3.273276, 1.531581, 0.153065, 3.934804, 4.901611, 451.080829, 5.877784, 64.508256, 2.123147, 65.367444, 8.383478, 26.095603, 4.154302, 0.049746, 13.410432, 160.170147, 8.20904, 35.080341, 5.377193, 2.093847, 136.078346, 0.007653, 38.162935, 6.980909, 43.817657, 71.029916, 247.425382, 12.096333, 6.786146, 8.103032, 54.210259, 138.924391, 337.705742, 51.482481, 109.24468, 76.951219, 1691.360426, 1.080098, 0.011319, 0.249014, 0.362202, 0.079232, 0.264106, 0.267864, 0.126126, 576.757836, 46.0531, 0.60536, 0.987559, 38.28806, 36.087837, 14.487844, 0.298477, 0.658329, 634.934068, 1.539884, 269.654254, 22.973233, 22.372399, 2.551817, 41.766183, 36.895485, 25.877689, 273.104667, 7.473265, 11.501889, 292.452995, 0.520422, 3.167303, 0.164545, 37.865571, 30.357093, 419.194747, 78.034724, 0.01148, 5.384767, 231.694165, 188.541366, 380.138559, 5424.881502, 6.251839, 113.93837, 0.145412, 129.596274, 211.774129, 9.945288, 6.930094, 11.340575]]}, "x": {"Continent": ["Asia", "Europe", "Africa", "Europe", "Africa", "North America", "North America", "South America", "Asia", "North America", "Oceania", "Europe", "Europe", "North America", "Asia", "Asia", "North America", "Europe", "Europe", "North America", "Africa", "North America", "Asia", "South America", "Europe", "Africa", "South America", "North America", "Asia", "Europe", "Africa", "Africa", "Asia", "Africa", "North America", "Africa", "Africa", "Africa", "South America", "Asia", "South America", "Africa", "Africa", "Oceania", "Central America", "Europe", "North America", "Europe", "Europe", "Africa", "Europe", "Africa", "North America", "South America", "Africa", "Central America", "Africa", "Africa", "Europe", "Africa", "Oceania", "Europe", "Europe", "Oceania", "Africa", "Africa", "Asia", "Europe", "Africa", "Europe", "North America", "North America", "Central America", "Africa", "Africa", "South America", "North America", "Central America", "Asia", "Europe", "Europe", "Asia", "Asia", "Asia", "Asia", "Europe", "Asia", "Europe", "North America", "Asia", "Asia", "Asia", "Africa", "Oceania", "Asia", "Asia", "Asia", "Europe", "Asia", "Africa", "Africa", "Africa", "Europe", "Europe", "Europe", "Asia", "Africa", "Africa", "Asia", "Asia", "Africa", "Europe", "Oceania", "Africa", "Africa", "North America", "Europe", "Asia", "Europe", "Africa", "Africa", "Asia", "Africa", "Oceania", "Asia", "Europe", "Oceania", "Oceania", "Central America", "Africa", "Africa", "Oceania", "Asia", "Europe", "Europe", "Asia", "Asia", "Central America", "Oceania", "South America", "South America", "Asia", "Europe", "Europe", "Africa", "Europe", "Asia", "Africa", "Africa", "North America", "North America", "North America", "North America", "Oceania", "Africa", "Asia", "Europe", "Africa", "Africa", "Asia", "Europe", "Europe", "Oceania", "Africa", "Asia", "Africa", "Europe", "Asia", "Africa", "South America", "Europe", "Europe", "Asia", "Asia", "Asia", "Africa", "Asia", "Asia", "Africa", "Oceania", "North America", "Africa", "Asia", "Asia", "Oceania", "Africa", "Europe", "Asia", "Europe", "North America", "South America", "Asia", "Oceania", "South America", "Asia", "Asia", "Africa", "Africa"], "Code": ["AFG", "ALB", "DZA", "AND", "AGO", "AIA", "ATG", "ARG", "ARM", "ABW", "AUS", "AUT", "AZE", "BHS", "BHR", "BGD", "BRB", "BLR", "BEL", "BLZ", "BEN", "BMU", "BTN", "BOL", "BIH", "BWA", "BRA", "VGB", "BRN", "BGR", "BFA", "BDI", "KHM", "CMR", "CAN", "CPV", "CAF", "TCD", "CHL", "CHN", "COL", "COM", "COG", "COK", "CRI", "HRV", "CUB", "CYP", "CZE", "COD", "DNK", "DJI", "DOM", "ECU", "EGY", "SLV", "GNQ", "ERI", "EST", "ETH", "FJI", "FIN", "FRA", "PYF", "GAB", "GMB", "GEO", "DEU", "GHA", "GRC", "GRL", "GRD", "GTM", "GIN", "GNB", "GUY", "HTI", "HND", "HKG", "HUN", "ISL", "IND", "IDN", "IRN", "IRQ", "IRL", "ISR", "ITA", "JAM", "JPN", "JOR", "KAZ", "KEN", "KIR", "KWT", "KGZ", "LAO", "LVA", "LBN", "LSO", "LBR", "LBY", "LIE", "LTU", "LUX", "MAC", "MDG", "MWI", "MYS", "MDV", "MLI", "MLT", "MHL", "MRT", "MUS", "MEX", "MDA", "MNG", "MNE", "MAR", "MOZ", "MMR", "NAM", "NRU", "NPL", "NLD", "NCL", "NZL", "NIC", "NER", "NGA", "NIU", "PRK", "MKD", "NOR", "OMN", "PAK", "PAN", "PNG", "PRY", "PER", "PHL", "POL", "PRT", "QAT", "ROU", "RUS", "RWA", "SHN", "KNA", "LCA", "SPM", "VCT", "WSM", "STP", "SAU", "SRB", "SYC", "SLE", "SGP", "SVK", "SVN", "SLB", "SOM", "KOR", "SSD", "ESP", "LKA", "SDN", "SUR", "SWE", "CHE", "SYR", "TWN", "TJK", "TZA", "THA", "TLS", "TGO", "TON", "TTO", "TUN", "TUR", "TKM", "TUV", "UGA", "UKR", "ARE", "GBR", "USA", "URY", "UZB", "VUT", "VEN", "VNM", "YEM", "ZMB", "ZWE"]}, "z": null}, "config": {"graphType": "Map", "colorBy": "CO2", "topoJSON": "https://www.canvasxpress.org/data/maps/WORLD.json", "mapId": "co2Linear", "legendPosition": "left", "theme": "solarized", "title": "The same data on a plain linear ramp", "subtitle": "195 of 198 countries sit in the bottom fifth of the scale - the map goes flat"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>This is the single most common choropleth failure. The cure is <strong>classing</strong>:</p>
<ul>
<li><code>"colorSpectrumBreaksMethod": "quantile"</code> — equal <em>counts</em> per class. Every colour is used, by construction. The right default for skewed data and for “which regions rank high/low” questions.</li>
<li><code>"colorSpectrumBreaksMethod": "jenks"</code> — natural breaks that minimise within-class variance. Best when the data has genuine clusters with gaps between them; on smoothly heavy-tailed data like this it piles almost everything into the bottom class, so check the legend before you trust it.</li>
<li>Three to seven classes is the usable range — beyond that, readers cannot match colours to the legend.</li>
</ul>
</section>
<section id="choose-the-palette-on-purpose" class="level2">
<h2 class="anchored" data-anchor-id="choose-the-palette-on-purpose">Choose the palette on purpose</h2>
<p>The palette is the scale’s grammar, not decoration:</p>
<ul>
<li><p><strong>Sequential</strong> (dark → light of ordered hues, like viridis above) for a quantity that only goes up: counts, rates, concentrations.</p></li>
<li><p><strong>Diverging</strong> (two hues meeting at a neutral midpoint) when values are meaningful <em>above and below a reference</em>: change vs.&nbsp;last year, difference from a target, a signed index. Give a three-colour <code>colorSpectrum</code> and pin the midpoint with <code>colorSpectrumZeroValue</code>:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Change"</span>,</span>
<span id="cb6-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"colorSpectrum"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#2166ac"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#f7f7f7"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#b2182b"</span>],  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># blue - neutral - red</span></span>
<span id="cb6-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"colorSpectrumZeroValue"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,                          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># value mapped to the middle colour</span></span></code></pre></div>
<p>Never use a diverging palette for a purely positive quantity — the neutral midpoint invents a “normal” the data does not have.</p></li>
</ul>
<p>Viridis and the ColorBrewer ramps are colour-blind-safe and perceptually ordered; a rainbow ramp is neither, so readers cannot tell which end means “more”. Keep the <em>same</em> scale across small multiples so maps stay comparable.</p>
</section>
<section id="polish-legend-labels-and-base-styling" class="level2">
<h2 class="anchored" data-anchor-id="polish-legend-labels-and-base-styling">Polish: legend, labels and base styling</h2>
<ul>
<li><code>subtitle</code> / <code>source</code> — caption units and provenance.</li>
<li><code>"legendNumberFormat": {"style": "decimal", "decimals": 1, "suffix": "%"}</code> — format legend ticks.</li>
<li><code>mapColor</code> / <code>mapOutlineColor</code> — the fill for <strong>no-data</strong> regions (a neutral grey) and the shape borders, so missing data reads as missing rather than as a value.</li>
<li><code>"showMapLabels": True</code> — draw region names (best on few-region maps; clutters a world map).</li>
<li><code>"legendInside": True</code> — float the legend over empty ocean to reclaim width.</li>
</ul>
</section>
<section id="beyond-the-world-map" class="level2">
<h2 class="anchored" data-anchor-id="beyond-the-world-map">Beyond the world map</h2>
<ul>
<li><strong>Other boundaries.</strong> Point <code>topoJSON</code> at any shape file — US states, a country’s provinces, counties, custom districts. The join key is just the shape name.</li>
<li><strong>Projection.</strong> <code>"mapProjection": "albers"</code> (equal-area) or <code>"mercator"</code>. Equal-area projections matter for choropleths: Mercator inflates high latitudes and exaggerates their visual weight.</li>
<li><strong>Categorical maps.</strong> Point <code>colorBy</code> at a categorical column for a qualitative choropleth with a discrete legend.</li>
<li><strong>Markers.</strong> Add <code>decorations</code> to drop labelled points on cities or call out specific regions.</li>
</ul>
<p>The whole figure — data, boundaries, classing rule and palette — is one portable spec you can store, validate and re-render from R or JavaScript.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../choropleth-maps-in-r/">Choropleth maps in R</a></li>
<li><a href="../choropleth-maps-in-javascript/">Choropleth maps in JavaScript</a></li>
<li><a href="../clustered-heatmap-in-python/">Clustered heatmaps in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>maps</category>
  <category>choropleth</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/choropleth-maps-in-python/</guid>
  <pubDate>Wed, 07 Oct 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/choropleth-maps-in-python/thumbnail.png" medium="image" type="image/png" height="112" width="144"/>
</item>
<item>
  <title>Sankey / alluvial diagrams in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/sankey-diagrams-in-python/</link>
  <description><![CDATA[ 




<p>A Sankey (or alluvial) diagram shows how a quantity <strong>flows through a sequence of categorical stages</strong> — patients moving from a cohort, to a treatment, to an outcome; or reads from a sample, to a mapping status, to a feature. The width of each stream is the magnitude. Here we build one in Python with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — interactive and reproducible.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-data-shape" class="level2">
<h2 class="anchored" data-anchor-id="the-data-shape">The data shape</h2>
<p>canvasXpress builds a Sankey from a table where <strong>each row is one path</strong> through the stages, plus a frequency/weight. Swap this simulated clinical flow for your own counts.</p>
<div id="e29bcdc4" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> random</span>
<span id="cb2-2">random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-3"></span>
<span id="cb2-4">cohorts  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cohort A"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cohort B"</span>]</span>
<span id="cb2-5">treats   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Drug 1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Drug 2"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Placebo"</span>]</span>
<span id="cb2-6">outcomes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Response"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stable"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Progression"</span>]</span>
<span id="cb2-7"></span>
<span id="cb2-8">Cohort, Treatment, Outcome, Freq <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], [], [], []</span>
<span id="cb2-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> co <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> cohorts:</span>
<span id="cb2-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tr <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> treats:</span>
<span id="cb2-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ou <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> outcomes:</span>
<span id="cb2-12">            base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> ou <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Response"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> ou <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stable"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span></span>
<span id="cb2-13">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Placebo"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> ou <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Response"</span>:</span>
<span id="cb2-14">                base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>                                   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># placebo responds less</span></span>
<span id="cb2-15">            Cohort.append(co)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> Treatment.append(tr)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> Outcome.append(ou)</span>
<span id="cb2-16">            Freq.append(base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> random.randint(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>))</span></code></pre></div>
</div>
<p>The value (<code>Freq</code>) is the single measured variable; the stage columns are sample annotations (<code>x</code>).</p>
<div id="dfe556ab" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">ids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"r</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(Freq))]</span>
<span id="cb3-6">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Freq"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: ids, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [Freq]},</span>
<span id="cb3-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cohort"</span>: Cohort, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treatment"</span>: Treatment, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Outcome"</span>: Outcome},</span>
<span id="cb3-9">}</span>
<span id="cb3-10"></span>
<span id="cb3-11">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sankey"</span>,</span>
<span id="cb3-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sankeyAxes"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cohort"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treatment"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Outcome"</span>],</span>
<span id="cb3-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Freq"</span>],</span>
<span id="cb3-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Outcome"</span>,</span>
<span id="cb3-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sankeyType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"proportional"</span>,</span>
<span id="cb3-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphOrientation"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"horizontal"</span>,</span>
<span id="cb3-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Patient flow: cohort to treatment to outcome"</span>,</span>
<span id="cb3-19">}</span>
<span id="cb3-20"></span>
<span id="cb3-21">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sankey"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">700</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb3-22"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-23">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="sankey" width="700" height="500"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("sankey");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart sankey removed for re-rendering.");
  } else {
    console.log("Chart sankey ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart sankey could not be cleaned for re-rendering:", error);
}

var chart_sankey = new CanvasXpress({"renderTo": "sankey", "data": {"y": {"vars": ["Freq"], "smps": ["r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18"], "data": [[44, 27, 23, 43, 40, 29, 27, 37, 21, 43, 40, 15, 52, 38, 15, 26, 33, 22]]}, "x": {"Cohort": ["Cohort A", "Cohort A", "Cohort A", "Cohort A", "Cohort A", "Cohort A", "Cohort A", "Cohort A", "Cohort A", "Cohort B", "Cohort B", "Cohort B", "Cohort B", "Cohort B", "Cohort B", "Cohort B", "Cohort B", "Cohort B"], "Treatment": ["Drug 1", "Drug 1", "Drug 1", "Drug 2", "Drug 2", "Drug 2", "Placebo", "Placebo", "Placebo", "Drug 1", "Drug 1", "Drug 1", "Drug 2", "Drug 2", "Drug 2", "Placebo", "Placebo", "Placebo"], "Outcome": ["Response", "Stable", "Progression", "Response", "Stable", "Progression", "Response", "Stable", "Progression", "Response", "Stable", "Progression", "Response", "Stable", "Progression", "Response", "Stable", "Progression"]}, "z": null}, "config": {"graphType": "Sankey", "sankeyAxes": ["Cohort", "Treatment", "Outcome"], "xAxis": ["Freq"], "colorBy": "Outcome", "sankeyType": "proportional", "graphOrientation": "horizontal", "title": "Patient flow: cohort to treatment to outcome"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Hover any stream to see the count; the widths are proportional to the frequency, so you can read the flow at a glance. <code>sankeyType</code> can also be <code>"aligned"</code> (classic alluvial) or <code>"equal"</code>.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>The <code>data</code>+<code>config</code> <strong>is</strong> the figure — one portable JSON spec. The same spec renders the identical Sankey from R or JavaScript, and can be validated and re-rendered later.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../volcano-plots-in-python/">Interactive volcano plots in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>sankey</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/sankey-diagrams-in-python/</guid>
  <pubDate>Sun, 27 Sep 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/sankey-diagrams-in-python/thumbnail.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Violin and half (split) violin plots in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/violin-plots-in-python/</link>
  <description><![CDATA[ 




<p>A violin plot shows the <strong>full shape of a distribution</strong> instead of collapsing it to a box’s quartiles. And when you want to compare two conditions at the same position, a <strong>split (half) violin</strong> puts one condition on each half. Here we build both in Python with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — interactive and reproducible.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="the-data" class="level2">
<h2 class="anchored" data-anchor-id="the-data">The data</h2>
<p>A measurement across a few dose groups and two conditions. Swap in your own long-format table.</p>
<div id="74452c30" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-2"></span>
<span id="cb2-3">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-4">doses <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Low"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Medium"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"High"</span>]</span>
<span id="cb2-5">conds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Control"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treated"</span>]</span>
<span id="cb2-6"></span>
<span id="cb2-7">value, Dose, Condition <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], [], []</span>
<span id="cb2-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> doses:</span>
<span id="cb2-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> co <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> conds:</span>
<span id="cb2-10">        mu <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Low"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Medium"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"High"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>}[d] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> co <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treated"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb2-11">        value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rng.normal(mu, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb2-12">        Dose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> [d] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span></span>
<span id="cb2-13">        Condition <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> [co] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span></span></code></pre></div>
</div>
<p>In canvasXpress terms a violin is a <code>Boxplot</code> graph with the violin turned on: one measured variable × N observations, with the grouping columns as sample annotations (<code>x</code>).</p>
<div id="82408076" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">ids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"o</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(value))]</span>
<span id="cb3-6">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: ids, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [value]},</span>
<span id="cb3-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dose"</span>: Dose, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Condition"</span>: Condition}}</span></code></pre></div>
</div>
</section>
<section id="a-full-violin-per-group" class="level2">
<h2 class="anchored" data-anchor-id="a-full-violin-per-group">A full violin per group</h2>
<div id="fdb54479" class="cell" data-execution_count="3">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"violin"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb4-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Boxplot"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showViolinBoxplot"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"violinScale"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"area"</span>,</span>
<span id="cb4-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"groupingFactors"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dose"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smpTitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dose"</span>,</span>
<span id="cb4-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distribution of value by dose"</span>,</span>
<span id="cb4-5">}, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">650</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb4-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb4-7">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="violin" width="650" height="500"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("violin");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart violin removed for re-rendering.");
  } else {
    console.log("Chart violin ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart violin could not be cleaned for re-rendering:", error);
}

var chart_violin = new CanvasXpress({"renderTo": "violin", "data": {"y": {"vars": ["value"], "smps": ["o1", "o2", "o3", "o4", "o5", "o6", "o7", "o8", "o9", "o10", "o11", "o12", "o13", "o14", "o15", "o16", "o17", "o18", "o19", "o20", "o21", "o22", "o23", "o24", "o25", "o26", "o27", "o28", "o29", "o30", "o31", "o32", "o33", "o34", "o35", "o36", "o37", "o38", "o39", "o40", "o41", "o42", "o43", "o44", "o45", "o46", "o47", "o48", "o49", "o50", "o51", "o52", "o53", "o54", "o55", "o56", "o57", "o58", "o59", "o60", "o61", "o62", "o63", "o64", "o65", "o66", "o67", "o68", "o69", "o70", "o71", "o72", "o73", "o74", "o75", "o76", "o77", "o78", "o79", "o80", "o81", "o82", "o83", "o84", "o85", "o86", "o87", "o88", "o89", "o90", "o91", "o92", "o93", "o94", "o95", "o96", "o97", "o98", "o99", "o100", "o101", "o102", "o103", "o104", "o105", "o106", "o107", "o108", "o109", "o110", "o111", "o112", "o113", "o114", "o115", "o116", "o117", "o118", "o119", "o120", "o121", "o122", "o123", "o124", "o125", "o126", "o127", "o128", "o129", "o130", "o131", "o132", "o133", "o134", "o135", "o136", "o137", "o138", "o139", "o140", "o141", "o142", "o143", "o144", "o145", "o146", "o147", "o148", "o149", "o150", "o151", "o152", "o153", "o154", "o155", "o156", "o157", "o158", "o159", "o160", "o161", "o162", "o163", "o164", "o165", "o166", "o167", "o168", "o169", "o170", "o171", "o172", "o173", "o174", "o175", "o176", "o177", "o178", "o179", "o180", "o181", "o182", "o183", "o184", "o185", "o186", "o187", "o188", "o189", "o190", "o191", "o192", "o193", "o194", "o195", "o196", "o197", "o198", "o199", "o200", "o201", "o202", "o203", "o204", "o205", "o206", "o207", "o208", "o209", "o210", "o211", "o212", "o213", "o214", "o215", "o216", "o217", "o218", "o219", "o220", "o221", "o222", "o223", "o224", "o225", "o226", "o227", "o228", "o229", "o230", "o231", "o232", "o233", "o234", "o235", "o236", "o237", "o238", "o239", "o240"], "data": [[6.41, 6.99, 6.4, 4.44, 7.09, 6.54, 5.36, 6.7, 6.44, 6.35, 6.03, 6.66, 5.12, 5.8, 5.42, 6.72, 6.05, 5.65, 5.06, 5.69, 6.01, 5.67, 7.55, 7.21, 2.75, 3.73, 5.79, 5.49, 6.26, 6.26, 8.54, 4.67, 5.55, 8.45, 6.78, 6.8, 5.38, 4.02, 6.2, 6.13, 6.03, 6.68, 7.41, 6.37, 7.38, 7.61, 7.54, 6.89, 8.21, 8.57, 7.89, 6.52, 8.38, 6.9, 8.55, 6.21, 8.6, 7.48, 6.0, 7.12, 7.56, 7.83, 6.32, 6.17, 7.74, 6.94, 7.78, 8.41, 5.52, 7.81, 8.97, 7.14, 6.53, 8.4, 7.8, 8.58, 7.09, 5.72, 7.37, 6.97, 8.93, 8.23, 6.04, 6.57, 9.06, 8.82, 7.23, 8.0, 8.53, 8.56, 9.05, 8.31, 7.89, 7.69, 9.27, 5.3, 7.83, 8.04, 6.29, 8.4, 7.22, 9.03, 7.85, 8.8, 9.46, 8.46, 6.95, 6.18, 10.1, 7.87, 7.17, 8.17, 7.77, 9.02, 8.04, 8.02, 7.14, 8.56, 6.76, 8.8, 11.33, 7.67, 6.54, 10.24, 12.56, 8.3, 8.0, 10.21, 8.49, 8.89, 9.08, 10.14, 9.01, 9.83, 9.29, 8.49, 9.12, 8.36, 9.51, 8.15, 8.19, 11.25, 9.44, 9.44, 10.11, 8.99, 9.23, 10.01, 9.84, 8.11, 10.5, 8.79, 8.23, 8.42, 9.03, 11.45, 8.09, 9.69, 6.93, 9.5, 11.08, 9.72, 9.24, 10.28, 10.84, 10.8, 12.37, 10.25, 9.29, 9.85, 9.91, 10.13, 9.96, 10.21, 7.99, 11.0, 9.31, 8.59, 10.77, 11.58, 10.59, 10.19, 8.88, 13.45, 11.06, 8.63, 9.06, 10.1, 8.13, 10.2, 9.45, 11.47, 11.15, 6.75, 10.05, 8.06, 11.33, 10.2, 10.66, 8.72, 13.69, 13.92, 10.22, 11.95, 10.69, 11.47, 9.98, 13.74, 10.34, 11.14, 12.1, 10.72, 11.21, 10.82, 11.34, 10.1, 10.97, 11.25, 11.1, 11.57, 11.15, 12.4, 11.11, 11.34, 10.7, 10.87, 9.98, 12.12, 10.13, 10.6, 11.93, 11.98, 11.02, 9.08, 12.0, 11.81, 9.81, 12.42, 10.66, 10.15]]}, "x": {"Dose": ["Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High"], "Condition": ["Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated"]}, "z": null}, "config": {"graphType": "Boxplot", "showViolinBoxplot": true, "violinScale": "area", "groupingFactors": ["Dose"], "xAxis": ["value"], "smpTitle": "Dose", "title": "Distribution of value by dose"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
</section>
<section id="a-split-half-violin-comparing-two-conditions" class="level2">
<h2 class="anchored" data-anchor-id="a-split-half-violin-comparing-two-conditions">A split (half) violin comparing two conditions</h2>
<p>Group by <strong>both</strong> factors, colour by condition, and set <code>violinSide = "split"</code> — the two conditions share each dose position, one on each half.</p>
<div id="bf5e059e" class="cell" data-execution_count="4">
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"violinSplit"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb5-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Boxplot"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showViolinBoxplot"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"violinScale"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"area"</span>,</span>
<span id="cb5-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"groupingFactors"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dose"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Condition"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Condition"</span>,</span>
<span id="cb5-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"violinSide"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"split"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"violinTrim"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smpTitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dose"</span>,</span>
<span id="cb5-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Control vs Treated — split violin by dose"</span>,</span>
<span id="cb5-6">}, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">650</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb5-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb5-8">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="violinSplit" width="650" height="500"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("violinSplit");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart violinSplit removed for re-rendering.");
  } else {
    console.log("Chart violinSplit ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart violinSplit could not be cleaned for re-rendering:", error);
}

var chart_violinSplit = new CanvasXpress({"renderTo": "violinSplit", "data": {"y": {"vars": ["value"], "smps": ["o1", "o2", "o3", "o4", "o5", "o6", "o7", "o8", "o9", "o10", "o11", "o12", "o13", "o14", "o15", "o16", "o17", "o18", "o19", "o20", "o21", "o22", "o23", "o24", "o25", "o26", "o27", "o28", "o29", "o30", "o31", "o32", "o33", "o34", "o35", "o36", "o37", "o38", "o39", "o40", "o41", "o42", "o43", "o44", "o45", "o46", "o47", "o48", "o49", "o50", "o51", "o52", "o53", "o54", "o55", "o56", "o57", "o58", "o59", "o60", "o61", "o62", "o63", "o64", "o65", "o66", "o67", "o68", "o69", "o70", "o71", "o72", "o73", "o74", "o75", "o76", "o77", "o78", "o79", "o80", "o81", "o82", "o83", "o84", "o85", "o86", "o87", "o88", "o89", "o90", "o91", "o92", "o93", "o94", "o95", "o96", "o97", "o98", "o99", "o100", "o101", "o102", "o103", "o104", "o105", "o106", "o107", "o108", "o109", "o110", "o111", "o112", "o113", "o114", "o115", "o116", "o117", "o118", "o119", "o120", "o121", "o122", "o123", "o124", "o125", "o126", "o127", "o128", "o129", "o130", "o131", "o132", "o133", "o134", "o135", "o136", "o137", "o138", "o139", "o140", "o141", "o142", "o143", "o144", "o145", "o146", "o147", "o148", "o149", "o150", "o151", "o152", "o153", "o154", "o155", "o156", "o157", "o158", "o159", "o160", "o161", "o162", "o163", "o164", "o165", "o166", "o167", "o168", "o169", "o170", "o171", "o172", "o173", "o174", "o175", "o176", "o177", "o178", "o179", "o180", "o181", "o182", "o183", "o184", "o185", "o186", "o187", "o188", "o189", "o190", "o191", "o192", "o193", "o194", "o195", "o196", "o197", "o198", "o199", "o200", "o201", "o202", "o203", "o204", "o205", "o206", "o207", "o208", "o209", "o210", "o211", "o212", "o213", "o214", "o215", "o216", "o217", "o218", "o219", "o220", "o221", "o222", "o223", "o224", "o225", "o226", "o227", "o228", "o229", "o230", "o231", "o232", "o233", "o234", "o235", "o236", "o237", "o238", "o239", "o240"], "data": [[6.41, 6.99, 6.4, 4.44, 7.09, 6.54, 5.36, 6.7, 6.44, 6.35, 6.03, 6.66, 5.12, 5.8, 5.42, 6.72, 6.05, 5.65, 5.06, 5.69, 6.01, 5.67, 7.55, 7.21, 2.75, 3.73, 5.79, 5.49, 6.26, 6.26, 8.54, 4.67, 5.55, 8.45, 6.78, 6.8, 5.38, 4.02, 6.2, 6.13, 6.03, 6.68, 7.41, 6.37, 7.38, 7.61, 7.54, 6.89, 8.21, 8.57, 7.89, 6.52, 8.38, 6.9, 8.55, 6.21, 8.6, 7.48, 6.0, 7.12, 7.56, 7.83, 6.32, 6.17, 7.74, 6.94, 7.78, 8.41, 5.52, 7.81, 8.97, 7.14, 6.53, 8.4, 7.8, 8.58, 7.09, 5.72, 7.37, 6.97, 8.93, 8.23, 6.04, 6.57, 9.06, 8.82, 7.23, 8.0, 8.53, 8.56, 9.05, 8.31, 7.89, 7.69, 9.27, 5.3, 7.83, 8.04, 6.29, 8.4, 7.22, 9.03, 7.85, 8.8, 9.46, 8.46, 6.95, 6.18, 10.1, 7.87, 7.17, 8.17, 7.77, 9.02, 8.04, 8.02, 7.14, 8.56, 6.76, 8.8, 11.33, 7.67, 6.54, 10.24, 12.56, 8.3, 8.0, 10.21, 8.49, 8.89, 9.08, 10.14, 9.01, 9.83, 9.29, 8.49, 9.12, 8.36, 9.51, 8.15, 8.19, 11.25, 9.44, 9.44, 10.11, 8.99, 9.23, 10.01, 9.84, 8.11, 10.5, 8.79, 8.23, 8.42, 9.03, 11.45, 8.09, 9.69, 6.93, 9.5, 11.08, 9.72, 9.24, 10.28, 10.84, 10.8, 12.37, 10.25, 9.29, 9.85, 9.91, 10.13, 9.96, 10.21, 7.99, 11.0, 9.31, 8.59, 10.77, 11.58, 10.59, 10.19, 8.88, 13.45, 11.06, 8.63, 9.06, 10.1, 8.13, 10.2, 9.45, 11.47, 11.15, 6.75, 10.05, 8.06, 11.33, 10.2, 10.66, 8.72, 13.69, 13.92, 10.22, 11.95, 10.69, 11.47, 9.98, 13.74, 10.34, 11.14, 12.1, 10.72, 11.21, 10.82, 11.34, 10.1, 10.97, 11.25, 11.1, 11.57, 11.15, 12.4, 11.11, 11.34, 10.7, 10.87, 9.98, 12.12, 10.13, 10.6, 11.93, 11.98, 11.02, 9.08, 12.0, 11.81, 9.81, 12.42, 10.66, 10.15]]}, "x": {"Dose": ["Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Low", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "Medium", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High", "High"], "Condition": ["Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated", "Treated"]}, "z": null}, "config": {"graphType": "Boxplot", "showViolinBoxplot": true, "violinScale": "area", "groupingFactors": ["Dose", "Condition"], "colorBy": "Condition", "violinSide": "split", "violinTrim": false, "xAxis": ["value"], "smpTitle": "Dose", "title": "Control vs Treated \u2014 split violin by dose"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Hover to read the density and summary stats. <code>violinSide</code> can also be <code>"lt"</code> or <code>"rb"</code> for a one-sided half violin.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>The <code>data</code>+<code>config</code> <strong>is</strong> the figure — one portable JSON spec that renders the identical violins from R or JavaScript.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../volcano-plots-in-python/">Interactive volcano plots in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>violin</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/violin-plots-in-python/</guid>
  <pubDate>Sat, 26 Sep 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/violin-plots-in-python/thumbnail.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Clustered heatmaps in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/clustered-heatmap-in-python/</link>
  <description><![CDATA[ 




<p>The clustered heatmap is the default way to look at an expression matrix: rows and columns reordered by similarity, dendrograms on the margins, and sample metadata alongside. Here we build one in Python with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — clustering happens inside the render, so you pass a plain matrix and get an interactive, reproducible figure.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="an-expression-matrix-with-sample-metadata" class="level2">
<h2 class="anchored" data-anchor-id="an-expression-matrix-with-sample-metadata">An expression matrix with sample metadata</h2>
<p>Swap this simulated block for your own matrix (genes in rows, samples in columns) and a table of per-sample annotations.</p>
<div id="573c5662" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb2-3"></span>
<span id="cb2-4">rng   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-5">ng, ns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span></span>
<span id="cb2-6">genes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Gene</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(ng)]</span>
<span id="cb2-7">samps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"S</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(ns)]</span>
<span id="cb2-8">cond  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tumor"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (ns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Normal"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (ns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb2-9"></span>
<span id="cb2-10">m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, (ng, ns))</span>
<span id="cb2-11">tumor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, c <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(cond) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tumor"</span>]</span>
<span id="cb2-12">normal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, c <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(cond) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Normal"</span>]</span>
<span id="cb2-13">m[np.ix_(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>),  tumor)]  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># first block up in Tumor</span></span>
<span id="cb2-14">m[np.ix_(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>), normal)] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># second block up in Normal</span></span>
<span id="cb2-15"></span>
<span id="cb2-16">expr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(m.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>genes, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>samps)</span></code></pre></div>
</div>
</section>
<section id="build-the-spec" class="level2">
<h2 class="anchored" data-anchor-id="build-the-spec">Build the spec</h2>
<p>The matrix goes in as <code>data</code>, and the sample annotation becomes an annotation track over the columns. <code>samplesClustered</code> / <code>variablesClustered</code> turn on hierarchical clustering with dendrograms.</p>
<div id="3a926301" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: genes, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: samps, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: expr.values.tolist()},</span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Condition"</span>: cond},</span>
<span id="cb3-8">}</span>
<span id="cb3-9"></span>
<span id="cb3-10">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Heatmap"</span>,</span>
<span id="cb3-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"samplesClustered"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"variablesClustered"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb3-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorSpectrum"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"navy"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"firebrick3"</span>],</span>
<span id="cb3-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showSmpDendrogram"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showVarDendrogram"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb3-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Clustered expression heatmap"</span>,</span>
<span id="cb3-16">}</span>
<span id="cb3-17"></span>
<span id="cb3-18">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"heatmap"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">650</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">550</span>)</span>
<span id="cb3-19"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-20">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="heatmap" width="650" height="550"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("heatmap");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart heatmap removed for re-rendering.");
  } else {
    console.log("Chart heatmap ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart heatmap could not be cleaned for re-rendering:", error);
}

var chart_heatmap = new CanvasXpress({"renderTo": "heatmap", "data": {"y": {"vars": ["Gene1", "Gene2", "Gene3", "Gene4", "Gene5", "Gene6", "Gene7", "Gene8", "Gene9", "Gene10", "Gene11", "Gene12", "Gene13", "Gene14", "Gene15", "Gene16", "Gene17", "Gene18", "Gene19", "Gene20", "Gene21", "Gene22", "Gene23", "Gene24", "Gene25", "Gene26", "Gene27", "Gene28", "Gene29", "Gene30", "Gene31", "Gene32", "Gene33", "Gene34", "Gene35", "Gene36", "Gene37", "Gene38", "Gene39", "Gene40"], "smps": ["S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "S12", "S13", "S14", "S15", "S16", "S17", "S18", "S19", "S20", "S21", "S22", "S23", "S24", "S25", "S26", "S27", "S28", "S29", "S30"], "data": [[2.346, 2.822, 2.33, 0.697, 2.905, 2.446, 1.463, 2.581, 2.365, 2.294, 2.028, 2.547, 1.264, 1.837, 1.518, 0.599, 0.04, -0.292, -0.782, -0.257, 0.008, -0.276, 1.294, 1.007, -2.711, -1.889, -0.175, -0.422, 0.214, 0.217], [4.118, 0.888, 1.622, 4.043, 2.647, 2.663, 1.486, 0.352, 2.167, 2.109, 0.773, 1.317, 1.928, 1.055, 1.902, 0.095, 0.036, -0.506, 0.594, 0.891, 0.321, -0.818, 0.732, -0.501, 0.879, -1.072, 0.914, -0.02, -1.249, -0.314], [2.054, 2.273, 1.018, 0.893, 2.2, 1.533, 2.236, 2.76, 0.351, 2.254, 3.225, 1.702, 1.189, 2.752, 2.253, 0.896, -0.345, -1.482, -0.11, -0.446, 0.775, 0.194, -1.631, -1.195, 0.884, 0.68, -0.64, -0.001, 0.446, 0.468], [2.876, 2.256, 1.905, 1.741, 3.056, -0.251, 1.861, 2.033, 0.575, 2.333, 1.349, 2.862, 1.874, 2.669, 3.219, 0.383, -0.876, -1.514, 1.753, -0.111, -0.689, 0.144, -0.191, 0.852, 0.034, 0.014, -0.715, 0.47, -1.034, 0.666], [3.524, 0.475, -0.466, 2.617, 4.548, 0.999, 0.749, 2.589, 1.159, 1.494, 1.652, 2.532, 1.595, 2.278, 1.823, -0.845, -0.32, -0.95, 0.007, -1.124, -1.093, 1.457, -0.053, -0.054, 0.512, -0.421, -0.229, 0.425, 0.282, -1.159], [2.833, 1.41, 0.944, 1.1, 1.609, 3.627, 0.824, 2.16, -0.138, 1.998, 2.9, 1.763, 1.371, 2.232, 2.7, 0.664, 1.972, 0.209, -0.592, -0.126, -0.072, 0.109, -0.03, 0.174, -1.671, 0.83, -0.575, -1.173, 0.638, 1.317], [2.493, 2.161, 1.068, 4.872, 2.88, 0.861, 1.22, 2.087, 0.445, 2.169, 1.541, 3.226, 2.962, -0.711, 2.042, -1.617, 1.11, 0.168, 0.548, -1.065, 1.828, 2.02, -1.065, 0.373, -0.673, -0.024, -1.266, 1.867, -0.969, -0.296], [2.501, 1.352, 1.761, 1.436, 1.867, 0.829, 1.562, 1.793, 1.666, 2.057, 1.707, 2.753, 1.677, 1.863, 1.335, -0.527, -1.264, 0.519, -1.143, -0.746, 0.359, 0.403, -0.4, -2.019, 0.421, 0.26, -1.412, 0.77, -0.701, -1.126], [2.096, 1.822, 2.203, 0.394, 3.812, 1.397, 0.46, 2.619, 1.645, 2.325, 1.66, 1.94, 2.246, 1.253, 2.679, -0.47, -0.87, 0.077, 0.445, -0.229, -0.863, 0.62, -1.76, -1.031, 0.04, -1.361, 0.028, -0.055, 0.899, -0.915], [1.374, 2.333, -0.458, 5.1, 1.301, 1.27, 2.861, 1.96, 0.221, 2.627, 2.855, 1.55, 1.718, 2.486, 1.091, 0.438, 0.199, -0.675, -1.392, -0.226, -0.875, 1.001, 0.144, 0.782, 0.135, 0.263, -0.783, 0.668, 1.785, -0.31], [1.407, 1.842, 1.519, 1.299, 2.138, 1.709, 3.439, 2.0, 2.324, 2.952, 1.699, 3.437, 1.367, 1.192, 1.634, -0.115, -1.401, -0.035, -1.667, 1.392, -0.081, -0.642, -0.908, -0.384, -0.223, -1.045, -0.92, -0.187, -0.521, 0.939], [3.138, 2.016, 2.474, 0.665, 2.637, 1.969, 2.485, 3.6, -0.281, 2.261, 0.901, 2.592, 0.687, 1.505, 2.203, 0.614, 0.075, -0.793, -0.554, 0.885, -0.005, -1.684, 0.844, 0.416, 0.873, -0.337, 0.828, -1.061, 0.57, -0.49], [2.674, 3.006, 1.264, 1.949, 2.039, 3.19, 2.711, 0.781, 2.458, 2.745, 4.124, 0.321, 1.464, 3.333, 0.645, -1.199, 0.517, 1.018, -0.669, 0.54, 0.117, 1.519, -0.002, 0.99, -0.903, -0.185, -0.097, 1.139, 0.58, -0.752], [2.682, 2.771, 1.888, 1.742, 1.806, 0.305, 2.189, 2.235, 1.134, 2.742, 0.627, 1.448, 1.525, 3.988, 0.401, 0.563, 0.942, 0.378, 1.182, -1.003, -2.28, 0.767, -1.196, -0.326, -1.179, 1.052, 0.865, -0.72, 0.903, 0.121], [1.861, 2.057, 1.797, 2.615, 2.31, 1.651, 3.006, 1.389, 2.287, 2.422, 3.479, 1.495, 3.743, 2.176, 1.806, -0.672, 0.586, 0.049, -1.104, -1.128, -0.556, -0.676, 1.09, 1.376, 0.869, 0.358, -0.428, 0.054, 0.885, 2.131], [2.913, 1.72, 2.038, 1.517, 1.218, 1.816, 2.196, 3.836, 2.052, 3.357, 3.767, 2.079, 3.608, 2.715, 1.582, 0.265, 0.023, -0.232, -0.199, 0.144, 0.434, -0.885, -0.009, -1.522, 0.261, 0.624, 0.164, 0.286, 0.59, -0.665], [1.761, 2.511, 3.002, 2.395, 4.553, 1.909, 3.0, 3.267, 1.866, 1.179, 0.817, 2.162, 3.11, 2.272, 2.173, -0.379, 0.561, -2.136, 0.232, 0.028, -1.37, 2.176, -1.387, -1.078, -1.201, 1.11, -0.888, 0.669, 0.588, 0.26], [0.692, 1.388, 3.673, 0.709, 1.168, 1.838, 2.809, 2.252, 2.742, 0.933, 2.945, 2.569, 0.405, 3.54, 4.292, -0.769, 0.056, 1.397, -1.481, -1.99, -1.297, -0.567, -0.578, 0.607, 0.269, -1.246, 0.567, 1.874, 1.197, 0.991], [2.02, 2.984, 1.034, 2.751, 1.913, 3.131, 2.466, 0.91, 2.128, 3.218, 0.871, 1.441, 1.231, 0.504, 2.961, 1.311, 0.8, 0.243, -0.052, 0.239, -0.732, 0.894, 1.045, 0.933, -0.531, 0.078, -0.166, 1.789, 0.18, -1.882], [2.399, 3.882, 2.685, 2.879, 2.036, 0.029, 0.19, 0.754, 1.873, 2.31, 2.689, 1.66, 2.957, 1.72, 1.296, 0.852, -0.914, -2.729, -1.06, 0.094, -3.08, -0.357, -0.332, -1.426, -1.483, -0.462, -0.547, 1.26, 0.375, -1.581], [-0.855, 0.705, 1.896, 0.386, 0.311, 1.861, -0.023, -0.309, -1.413, -0.513, 2.179, -1.422, 0.011, -1.408, 0.128, 2.888, 1.756, 2.73, 2.721, 2.447, 3.716, 2.779, 1.695, 1.319, 1.155, 2.476, 1.676, 4.729, 3.842, 1.785], [-0.329, 1.69, -1.883, -0.452, 0.951, -0.912, -0.477, -0.351, 0.661, 0.138, 0.402, 0.595, 0.03, 1.111, -0.729, 0.564, 0.223, 0.379, 1.449, 3.03, 2.174, 1.401, 0.93, 1.471, 1.596, 1.435, 0.567, 1.524, 3.017, -0.175], [-0.241, -2.121, 0.183, -0.747, -2.086, 0.101, 1.817, 0.109, 1.162, -0.072, -2.158, 0.49, -0.418, -1.462, 0.785, 2.287, 1.475, 2.868, 1.128, 2.643, 1.06, 2.534, 0.899, 3.489, 2.254, 3.433, 1.178, 1.524, 2.84, -0.744], [-1.067, 1.033, 0.465, 0.979, -0.31, 0.564, -0.731, -1.372, -1.695, -0.552, -0.549, -0.629, -3.549, -1.999, -0.533, 2.287, 1.421, 1.123, -0.308, 4.021, 0.899, 3.683, 3.561, 2.274, 1.427, 2.132, 0.847, 2.261, 2.003, 2.532], [0.95, 1.733, -0.388, 1.043, -0.792, -0.895, -0.618, -0.982, 0.98, 0.923, 1.272, -0.025, 0.274, -0.578, -1.151, 2.447, 2.268, 0.893, 2.585, 0.258, 1.821, 1.37, 1.471, 0.917, 2.952, 2.566, 3.183, 2.13, 0.702, 1.621], [-1.192, 0.447, 1.199, 0.316, -0.613, -0.383, 0.19, -1.46, 0.135, 0.183, -0.56, -0.434, 0.154, -0.838, -0.84, 2.76, 2.203, 3.659, 0.992, 0.199, 2.919, 2.934, 1.238, 0.507, 1.928, 0.222, 1.631, -0.211, 1.732, -0.151], [-0.269, 1.485, -0.301, 0.735, -0.677, -0.928, -1.535, 1.002, -0.097, 1.582, -1.22, -0.265, 0.036, 1.368, 1.777, 1.305, 0.82, 0.216, 3.289, 1.864, 1.303, 1.899, -0.609, 0.223, 2.884, 2.344, 2.098, 0.946, 2.535, 3.726], [-1.277, -0.038, -0.488, 0.308, -0.039, -0.201, -0.936, -0.07, -0.668, -0.2, -0.118, 0.6, -0.636, -0.377, 1.018, 1.728, 1.684, 2.81, 2.219, 2.037, 2.166, 0.707, 2.408, 3.274, 2.53, 0.394, 2.235, 1.047, 1.727, 2.084], [-1.237, 1.292, -0.112, 0.75, 0.593, 1.303, 1.152, -1.513, 0.005, -2.172, -0.484, 0.678, 0.878, 1.254, -0.412, 2.286, 2.064, 3.234, 3.555, 1.608, 5.752, 1.964, 1.601, 2.568, 2.727, 2.516, 1.32, 3.444, 2.026, 3.51], [1.367, -1.299, -1.004, -1.024, 0.227, 0.032, 0.248, -0.833, 0.407, 1.385, -1.354, -0.214, 0.231, -0.147, -0.214, 3.752, 3.267, 2.833, 1.223, 4.226, 2.346, 1.407, 1.648, 1.496, 4.107, 2.191, 2.049, -0.167, 2.724, 0.929], [-1.143, 0.6, -0.876, 0.823, 1.109, -1.802, -0.149, -1.587, -0.075, 0.899, -1.377, 1.789, -0.325, -1.198, -0.139, 2.777, 0.607, 1.986, 0.61, 3.188, 2.138, 1.557, 3.017, 0.693, 1.588, 3.828, 1.857, 3.338, 2.176, 1.28], [-0.266, 0.057, -0.43, -0.845, -0.802, -1.504, 0.089, 0.372, 0.727, -1.828, 0.784, -0.039, -1.451, 0.076, 0.793, 2.5, 2.703, 2.923, 2.874, 1.943, -0.104, 1.219, 2.335, 1.509, 2.664, 2.777, 2.027, 3.859, 1.004, 2.911], [-0.493, -0.8, 0.569, -0.636, 0.839, -1.186, 0.016, -0.863, -0.254, -0.391, -1.148, 0.636, -1.264, -0.999, 0.873, 2.955, 2.649, 2.322, 4.26, 0.773, 1.239, 0.989, 2.881, 2.271, 3.094, 2.956, 1.758, 1.165, 0.992, 4.196], [0.952, 0.578, -0.354, -0.213, -0.359, -0.339, -2.418, -0.076, -0.397, 0.275, 0.195, 0.839, -0.028, 0.782, -2.575, 0.884, 3.711, 0.766, 1.707, 2.693, 1.103, 2.708, 0.558, 0.072, 0.657, 0.332, 1.968, 1.668, 2.314, 0.95], [2.529, -0.11, -0.06, 0.442, -0.258, -0.646, 0.072, 0.905, 0.652, 0.928, -0.578, -0.788, 1.991, -0.252, 0.466, 2.726, 3.409, 0.637, 1.508, 1.555, 1.687, -0.424, 1.892, -0.905, 2.287, 2.527, 2.587, 0.785, 2.945, 1.126], [-1.237, -0.99, -0.857, 0.164, 0.816, -2.11, -0.549, 0.894, 0.196, 0.502, -1.505, 0.949, -1.569, 0.19, 1.361, 3.879, 2.512, 2.881, 1.394, 1.519, 3.169, 2.002, 1.873, 0.589, 2.151, 2.646, 1.206, 1.493, 3.58, 2.178], [-0.289, -1.137, -0.62, -0.25, 1.369, -0.61, 1.794, -0.929, -0.358, 0.844, -0.24, -0.83, -0.132, 0.449, -1.716, 1.751, 1.891, 1.596, 2.735, 1.431, 1.635, 2.038, 2.729, 1.779, 3.517, 1.092, 3.287, 1.142, 1.837, 2.364], [2.055, 0.896, -0.406, 1.299, -0.214, -0.791, 0.449, 0.094, 0.954, -0.55, 0.382, 0.635, 0.278, -0.029, -0.698, 2.904, 2.137, 2.496, 1.649, 2.013, 0.963, 2.086, 2.765, 2.093, 2.859, 2.313, 3.364, 1.81, 0.361, 2.432], [-0.165, -0.974, 0.651, 0.264, 0.445, -0.332, 0.197, 0.254, 1.775, -0.684, -0.01, 0.364, -1.725, -1.603, 2.166, 0.233, 2.575, 1.152, 1.237, 0.017, 1.099, 2.784, 0.611, 2.595, 2.313, 4.018, 1.525, 3.263, 2.889, 1.713], [-1.663, 1.509, -1.364, -0.473, 0.883, 1.116, -0.845, -0.032, -0.259, 1.182, 2.505, -1.83, 0.916, -2.858, 0.014, 0.891, 3.992, 2.166, 1.263, 1.501, 1.425, 2.188, 1.842, 2.656, 3.54, 2.701, 0.774, 0.376, 1.245, 3.053]]}, "x": {"Condition": ["Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Tumor", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal"]}, "z": null}, "config": {"graphType": "Heatmap", "samplesClustered": true, "variablesClustered": true, "colorSpectrum": ["navy", "white", "firebrick3"], "showSmpDendrogram": true, "showVarDendrogram": true, "title": "Clustered expression heatmap"}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Rows and columns are reordered by similarity, the dendrograms show the clustering, and the samples separate cleanly by condition. Hover a cell for its gene, sample and value; the whole figure is one portable spec you can store, validate and re-render from R or JavaScript.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../volcano-plots-in-python/">Interactive volcano plots in Python</a></li>
<li><a href="../kaplan-meier-in-python/">Kaplan–Meier survival curves in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>heatmap</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/clustered-heatmap-in-python/</guid>
  <pubDate>Thu, 24 Sep 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/clustered-heatmap-in-python/thumbnail.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Kaplan–Meier survival curves in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/kaplan-meier-in-python/</link>
  <description><![CDATA[ 




<p>Kaplan–Meier curves summarize time-to-event data: the step-down survival probability over time, usually split by a group like treatment arm. Here we build one in Python with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — it computes the survival steps for you from a <strong>time</strong> column and a <strong>censoring</strong> column — and the result is interactive and reproducible.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="a-survival-table" class="level2">
<h2 class="anchored" data-anchor-id="a-survival-table">A survival table</h2>
<p>Swap this simulated block for your own data: per subject you need a follow-up <strong>time</strong>, a <strong>censoring indicator</strong> (1 = censored, 0 = event), and the grouping variable.</p>
<div id="91061f02" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-2"></span>
<span id="cb2-3">rng  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-4">n    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb2-5">arm  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.choice([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treatment"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Control"</span>], n)</span>
<span id="cb2-6">base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(arm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treatment"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>)     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># treatment survives longer</span></span>
<span id="cb2-7">time <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rng.exponential(base), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-8">cens <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.binomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, n)                  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1 = censored, 0 = event</span></span>
<span id="cb2-9">subj <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Subj</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n)]</span></code></pre></div>
</div>
</section>
<section id="build-the-spec" class="level2">
<h2 class="anchored" data-anchor-id="build-the-spec">Build the spec</h2>
<p>The two columns — the time and its matching censor flag — go in as the variable samples, and the arm rides along as a variable annotation. The key is <code>graphType="KaplanMeier"</code> and passing <strong>both</strong> columns to <code>xAxis</code>.</p>
<div id="dc83aedb" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-6">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Subjects are the variables (rows); each row holds [Time, Time-Censor].</span></span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: subj, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Time"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Time-Censor"</span>],</span>
<span id="cb3-8">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [[t, c] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> t, c <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(time.tolist(), cens.tolist())]},</span>
<span id="cb3-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arm"</span>: arm.tolist()},</span>
<span id="cb3-10">}</span>
<span id="cb3-11"></span>
<span id="cb3-12">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"KaplanMeier"</span>,</span>
<span id="cb3-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Time"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Time-Censor"</span>],</span>
<span id="cb3-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arm"</span>,</span>
<span id="cb3-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Overall survival by treatment arm"</span>,</span>
<span id="cb3-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxisTitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Time (weeks)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yAxisTitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Probability of survival"</span>,</span>
<span id="cb3-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"invertCensored"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,               <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># draw censoring ticks</span></span>
<span id="cb3-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showKMConfidenceIntervals"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb3-20">}</span>
<span id="cb3-21"></span>
<span id="cb3-22">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"km"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">650</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb3-23"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-24">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="km" width="650" height="500"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("km");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart km removed for re-rendering.");
  } else {
    console.log("Chart km ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart km could not be cleaned for re-rendering:", error);
}

var chart_km = new CanvasXpress({"renderTo": "km", "data": {"y": {"vars": ["Subj1", "Subj2", "Subj3", "Subj4", "Subj5", "Subj6", "Subj7", "Subj8", "Subj9", "Subj10", "Subj11", "Subj12", "Subj13", "Subj14", "Subj15", "Subj16", "Subj17", "Subj18", "Subj19", "Subj20", "Subj21", "Subj22", "Subj23", "Subj24", "Subj25", "Subj26", "Subj27", "Subj28", "Subj29", "Subj30", "Subj31", "Subj32", "Subj33", "Subj34", "Subj35", "Subj36", "Subj37", "Subj38", "Subj39", "Subj40", "Subj41", "Subj42", "Subj43", "Subj44", "Subj45", "Subj46", "Subj47", "Subj48", "Subj49", "Subj50", "Subj51", "Subj52", "Subj53", "Subj54", "Subj55", "Subj56", "Subj57", "Subj58", "Subj59", "Subj60", "Subj61", "Subj62", "Subj63", "Subj64", "Subj65", "Subj66", "Subj67", "Subj68", "Subj69", "Subj70", "Subj71", "Subj72", "Subj73", "Subj74", "Subj75", "Subj76", "Subj77", "Subj78", "Subj79", "Subj80", "Subj81", "Subj82", "Subj83", "Subj84", "Subj85", "Subj86", "Subj87", "Subj88", "Subj89", "Subj90", "Subj91", "Subj92", "Subj93", "Subj94", "Subj95", "Subj96", "Subj97", "Subj98", "Subj99", "Subj100", "Subj101", "Subj102", "Subj103", "Subj104", "Subj105", "Subj106", "Subj107", "Subj108", "Subj109", "Subj110", "Subj111", "Subj112", "Subj113", "Subj114", "Subj115", "Subj116", "Subj117", "Subj118", "Subj119", "Subj120", "Subj121", "Subj122", "Subj123", "Subj124", "Subj125", "Subj126", "Subj127", "Subj128", "Subj129", "Subj130", "Subj131", "Subj132", "Subj133", "Subj134", "Subj135", "Subj136", "Subj137", "Subj138", "Subj139", "Subj140", "Subj141", "Subj142", "Subj143", "Subj144", "Subj145", "Subj146", "Subj147", "Subj148", "Subj149", "Subj150", "Subj151", "Subj152", "Subj153", "Subj154", "Subj155", "Subj156", "Subj157", "Subj158", "Subj159", "Subj160", "Subj161", "Subj162", "Subj163", "Subj164", "Subj165", "Subj166", "Subj167", "Subj168", "Subj169", "Subj170", "Subj171", "Subj172", "Subj173", "Subj174", "Subj175", "Subj176", "Subj177", "Subj178", "Subj179", "Subj180", "Subj181", "Subj182", "Subj183", "Subj184", "Subj185", "Subj186", "Subj187", "Subj188", "Subj189", "Subj190", "Subj191", "Subj192", "Subj193", "Subj194", "Subj195", "Subj196", "Subj197", "Subj198", "Subj199", "Subj200"], "smps": ["Time", "Time-Censor"], "data": [[118.6, 0], [25.1, 0], [6.6, 1], [143.3, 0], [145.7, 1], [39.1, 0], [38.5, 0], [6.1, 0], [88.3, 0], [13.3, 0], [11.8, 0], [52.9, 1], [226.1, 0], [9.9, 0], [22.4, 0], [7.7, 0], [14.2, 0], [9.5, 0], [21.6, 1], [61.0, 0], [112.6, 0], [24.2, 0], [94.6, 0], [31.6, 0], [18.7, 0], [4.5, 0], [19.0, 0], [22.8, 0], [45.1, 1], [72.8, 0], [45.2, 0], [159.3, 1], [78.3, 1], [81.7, 0], [268.0, 1], [79.6, 1], [49.6, 0], [34.4, 0], [40.8, 0], [7.1, 0], [118.1, 0], [4.2, 0], [5.1, 0], [68.0, 0], [55.4, 0], [24.7, 1], [67.6, 0], [69.8, 1], [6.6, 0], [92.4, 0], [64.8, 0], [28.3, 0], [72.7, 0], [43.3, 0], [101.4, 0], [54.5, 0], [14.6, 1], [6.5, 0], [120.8, 1], [16.8, 1], [95.5, 1], [93.4, 0], [16.7, 0], [72.7, 0], [26.5, 0], [29.1, 0], [103.1, 0], [8.2, 0], [119.0, 0], [17.7, 0], [30.8, 0], [16.8, 0], [53.9, 0], [27.6, 1], [78.1, 0], [1.2, 1], [16.2, 0], [59.7, 1], [43.3, 1], [101.3, 1], [27.8, 0], [16.6, 0], [72.1, 0], [0.7, 0], [28.8, 0], [35.2, 0], [34.7, 0], [39.2, 0], [125.5, 0], [35.3, 1], [100.0, 0], [1.7, 0], [9.1, 1], [42.0, 0], [146.9, 0], [10.1, 0], [11.5, 1], [17.6, 1], [48.6, 0], [36.2, 0], [83.1, 1], [41.6, 0], [100.2, 0], [34.2, 0], [12.2, 0], [76.7, 0], [16.2, 1], [7.7, 0], [119.4, 0], [30.4, 0], [36.1, 0], [38.7, 0], [22.7, 1], [5.1, 1], [16.7, 1], [97.4, 0], [19.7, 0], [9.4, 0], [120.6, 0], [6.9, 1], [2.1, 0], [13.4, 0], [81.0, 0], [74.3, 0], [4.5, 0], [8.9, 0], [15.0, 0], [45.1, 0], [101.9, 0], [89.1, 1], [26.3, 0], [55.0, 0], [49.0, 1], [27.3, 0], [31.0, 0], [37.3, 0], [1.0, 0], [6.9, 0], [40.0, 0], [2.4, 0], [55.7, 1], [27.9, 0], [71.1, 0], [29.3, 1], [9.2, 1], [97.4, 0], [24.2, 0], [29.9, 1], [1.7, 0], [37.1, 1], [74.9, 0], [21.6, 0], [49.6, 0], [0.9, 1], [11.0, 0], [1.6, 0], [24.3, 1], [42.1, 0], [53.8, 0], [2.1, 1], [5.4, 0], [141.0, 1], [10.8, 1], [5.0, 1], [167.0, 1], [55.8, 1], [68.3, 1], [0.5, 0], [3.9, 0], [133.8, 1], [112.6, 1], [3.2, 1], [102.1, 1], [64.8, 0], [14.7, 0], [14.7, 0], [38.1, 1], [16.0, 0], [94.4, 0], [31.2, 0], [6.7, 0], [38.0, 1], [24.1, 0], [73.6, 0], [48.9, 0], [33.2, 0], [12.0, 0], [1.5, 1], [3.7, 0], [89.6, 0], [18.9, 1], [134.0, 1], [14.8, 1], [161.7, 0], [1.5, 1], [11.1, 0], [19.9, 0], [82.1, 0], [36.8, 0], [63.7, 1]]}, "z": {"Arm": ["Treatment", "Control", "Control", "Control", "Treatment", "Treatment", "Control", "Control", "Treatment", "Treatment", "Control", "Treatment", "Treatment", "Control", "Treatment", "Treatment", "Control", "Control", "Treatment", "Treatment", "Control", "Control", "Control", "Control", "Control", "Treatment", "Treatment", "Control", "Treatment", "Treatment", "Treatment", "Treatment", "Control", "Treatment", "Treatment", "Treatment", "Control", "Treatment", "Control", "Treatment", "Treatment", "Control", "Treatment", "Treatment", "Treatment", "Treatment", "Treatment", "Control", "Control", "Control", "Treatment", "Control", "Treatment", "Control", "Control", "Treatment", "Control", "Treatment", "Treatment", "Control", "Treatment", "Control", "Treatment", "Treatment", "Treatment", "Control", "Treatment", "Control", "Treatment", "Control", "Control", "Control", "Treatment", "Treatment", "Control", "Control", "Control", "Treatment", "Treatment", "Treatment", "Treatment", "Control", "Control", "Control", "Treatment", "Control", "Control", "Treatment", "Treatment", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treatment", "Treatment", "Control", "Control", "Treatment", "Control", "Control", "Control", "Control", "Treatment", "Control", "Control", "Treatment", "Treatment", "Treatment", "Treatment", "Treatment", "Control", "Control", "Control", "Control", "Control", "Treatment", "Treatment", "Control", "Treatment", "Control", "Treatment", "Control", "Control", "Treatment", "Control", "Treatment", "Control", "Control", "Treatment", "Treatment", "Treatment", "Control", "Control", "Control", "Control", "Control", "Control", "Control", "Treatment", "Treatment", "Treatment", "Treatment", "Control", "Control", "Treatment", "Control", "Control", "Control", "Treatment", "Treatment", "Control", "Treatment", "Control", "Control", "Control", "Treatment", "Control", "Treatment", "Control", "Treatment", "Treatment", "Control", "Control", "Control", "Treatment", "Control", "Control", "Treatment", "Treatment", "Control", "Control", "Treatment", "Treatment", "Treatment", "Treatment", "Control", "Treatment", "Treatment", "Control", "Control", "Treatment", "Control", "Treatment", "Control", "Treatment", "Control", "Treatment", "Control", "Treatment", "Control", "Treatment", "Treatment", "Control", "Control", "Treatment", "Treatment", "Control"]}, "x": null}, "config": {"graphType": "KaplanMeier", "xAxis": ["Time", "Time-Censor"], "colorBy": "Arm", "title": "Overall survival by treatment arm", "xAxisTitle": "Time (weeks)", "yAxisTitle": "Probability of survival", "invertCensored": true, "showKMConfidenceIntervals": false}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>Hover any step for the time and survival probability; the tick marks are censored subjects. canvasxpress derives the survival curve from the raw table, so you never precompute the steps — and the same spec re-renders the identical curve from R or JavaScript.</p>
</section>
<section id="a-common-gotcha" class="level2">
<h2 class="anchored" data-anchor-id="a-common-gotcha">A common gotcha</h2>
<p>The survival transform only fires with <code>graphType="KaplanMeier"</code>. A bare <code>"Scatter2D"</code> gives a raw scatter of the censor values instead — survival probability is <em>computed</em> by the engine, not a column in your data.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li><a href="../volcano-plots-in-python/">Interactive volcano plots in Python</a></li>
<li>Gallery: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>survival</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/kaplan-meier-in-python/</guid>
  <pubDate>Wed, 23 Sep 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/kaplan-meier-in-python/thumbnail.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Interactive volcano plots in Python with canvasxpress</title>
  <dc:creator>Isaac Neuhaus</dc:creator>
  <link>https://neuhausi.github.io/canvasxpress-blog/posts/python/volcano-plots-in-python/</link>
  <description><![CDATA[ 




<p>A volcano plot is the workhorse of differential-expression analysis: log fold change on x, statistical significance on y, and the interesting genes pushed to the top corners. Here we build one in Python with <a href="https://pypi.org/project/canvasxpress/">canvasxpress</a> — interactive (zoom, hover, filter) and <strong>reproducible</strong>: the whole figure is one portable specification you can store and re-render from Python, R or JavaScript.</p>
<section id="install" class="level2">
<h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> install canvasxpress</span></code></pre></div>
</section>
<section id="a-differential-expression-table" class="level2">
<h2 class="anchored" data-anchor-id="a-differential-expression-table">A differential-expression table</h2>
<p>Swap this simulated block for your own results — the output of any DE pipeline works, as long as you have a log fold change and a significance value per gene.</p>
<div id="f792880b" class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb2-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> norm</span>
<span id="cb2-4"></span>
<span id="cb2-5">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-6">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span></span>
<span id="cb2-7">genes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Gene</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n)]</span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate a realistic volcano: most genes have no real effect, a minority are</span></span>
<span id="cb2-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># differentially expressed. Significance follows effect size / standard error, which</span></span>
<span id="cb2-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># is what gives a volcano its shape.</span></span>
<span id="cb2-12">de     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>                              <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ~12% truly changed</span></span>
<span id="cb2-13">sign   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.choice([<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], n)</span>
<span id="cb2-14">effect <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(de, sign <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> rng.random(n)), <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># true log2FC</span></span>
<span id="cb2-15">se     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.22</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> rng.random(n)                        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># per-gene standard error</span></span>
<span id="cb2-16">logfc  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> effect <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, se)                        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># observed log2FC</span></span>
<span id="cb2-17">pval   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> norm.sf(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(logfc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> se))                   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># z-test p-value</span></span>
<span id="cb2-18">neglogp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.minimum(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>np.log10(pval), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>)</span>
<span id="cb2-19"></span>
<span id="cb2-20">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logFC"</span>: logfc.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-log-pVal"</span>: neglogp.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>genes)</span>
<span id="cb2-21"></span>
<span id="cb2-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> classify(fc, p):</span>
<span id="cb2-23">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> fc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.3</span>:   <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Increased"</span></span>
<span id="cb2-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> fc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.3</span>:  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Decreased"</span></span>
<span id="cb2-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NoChange"</span></span>
<span id="cb2-26"></span>
<span id="cb2-27">group <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [classify(fc, p) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fc, p <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logFC"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-log-pVal"</span>])]</span>
<span id="cb2-28">fold  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logFC"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>()).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div>
</div>
</section>
<section id="build-the-spec" class="level2">
<h2 class="anchored" data-anchor-id="build-the-spec">Build the spec</h2>
<p>canvasxpress takes a <code>data</code> object (a value matrix plus annotations) and a <code>config</code>. We put the two measurements as the variable’s samples and carry the regulation call and fold change as variable annotations (<code>z</code>).</p>
<div id="c8eabcc0" class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.canvas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CanvasXpress</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> canvasxpress.render.jupyter <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> CXNoteBook</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb3-4"></span>
<span id="cb3-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-6">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Genes are the variables (rows); each row holds [logFC, -log-pVal].</span></span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vars"</span>: genes, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smps"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logFC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-log-pVal"</span>],</span>
<span id="cb3-8">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>: [[fc, p] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fc, p <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logFC"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-log-pVal"</span>])]},</span>
<span id="cb3-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Group"</span>: group, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FC"</span>: fold.tolist()},</span>
<span id="cb3-10">}</span>
<span id="cb3-11"></span>
<span id="cb3-12">config <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"graphType"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scatter2D"</span>,</span>
<span id="cb3-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Publication-ready volcano plot"</span>,</span>
<span id="cb3-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logFC"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yAxis"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-log-pVal"</span>],</span>
<span id="cb3-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAxisTitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log2 fold change"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yAxisTitle"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-log10 p-value"</span>,</span>
<span id="cb3-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Group"</span>,</span>
<span id="cb3-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"colorKey"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Group"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Increased"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgba(197,27,38,0.75)"</span>,</span>
<span id="cb3-19">                            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Decreased"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgba(33,102,172,0.75)"</span>,</span>
<span id="cb3-20">                            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NoChange"</span>:  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgba(150,150,150,0.35)"</span>}},</span>
<span id="cb3-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sizeBy"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sizes"</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>],</span>
<span id="cb3-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"showDecorations"</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb3-23">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"decorations"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"line"</span>: [</span>
<span id="cb3-24">        {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"color"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgba(120,120,120,0.8)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"width"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>},</span>
<span id="cb3-25">        {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"color"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgba(120,120,120,0.8)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"width"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>},</span>
<span id="cb3-26">        {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"color"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rgba(120,120,120,0.8)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"width"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.301</span>},</span>
<span id="cb3-27">    ]},</span>
<span id="cb3-28">}</span>
<span id="cb3-29"></span>
<span id="cb3-30">cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> CanvasXpress(render_to<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"volcano"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>config, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">650</span>, height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb3-31"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> CXNoteBook(cx).render():</span>
<span id="cb3-32">    display(part)</span></code></pre></div>
<div class="cell-output cell-output-display">

</div>
<div class="cell-output cell-output-display">

<div style="display: grid; grid-template-columns: repeat(1, 1fr); gap: 10px; width: 100%;">
  <div><canvas id="volcano" width="650" height="500"></canvas></div>
</div>
</div>
<div class="cell-output cell-output-display">
<script type="application/javascript">

// 1. First, handle CSS Insertion and wait for it to be completely ready
new Promise((cssResolve, cssReject) => {
    const cssUrl = "https://www.canvasxpress.org/dist/canvasXpress.css";
    let existingLink = document.querySelector(`head link[href="${cssUrl}"]`);

    if (!existingLink) {
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = cssUrl;
        link.onload = () => {
            link.dataset.state = "loaded";
            link.dispatchEvent(new Event("assetLoaded"));
            cssResolve();
        };
        link.onerror = () => {
            link.dataset.state = "failed";
            link.dispatchEvent(new Event("assetFailed"));
            cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
        };
        document.head.appendChild(link);
    } else if (existingLink.dataset.state === "loaded") {
        cssResolve();
    } else if (existingLink.dataset.state === "failed") {
        cssReject(new Error(`Failed to load CSS: ${cssUrl}`));
    } else {
        // Safe queueing for subsequent runs initiated while CSS is downloading
        existingLink.addEventListener('assetLoaded', () => cssResolve(), { once: true });
        existingLink.addEventListener('assetFailed', () => cssReject(new Error(`Failed to load CSS: ${cssUrl}`)), { once: true });
    }
})
.then(() => {
    // 2. CSS is guaranteed ready. Now handle JS Insertion
    return new Promise((jsResolve, jsReject) => {
        const scriptUrl = 'https://www.canvasxpress.org/dist/canvasXpress.min.js';
        let existingScript = document.querySelector(`script[src="${scriptUrl}"]`);

        if (existingScript) {
            if (existingScript.dataset.state === "loaded") {
                jsResolve();
            } else if (existingScript.dataset.state === "failed") {
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            } else {
                // Safe queueing for subsequent runs initiated while JS is downloading
                existingScript.addEventListener('assetLoaded', () => jsResolve(), { once: true });
                existingScript.addEventListener('assetFailed', () => jsReject(new Error(`Failed to load script: ${scriptUrl}`)), { once: true });
            }
        } else {
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptUrl;
            script.dataset.state = "loading";

            script.onload = () => {
                script.dataset.state = "loaded";
                script.dispatchEvent(new Event("assetLoaded"));
                jsResolve();
            };
            script.onerror = () => {
                script.dataset.state = "failed";
                script.dispatchEvent(new Event("assetFailed"));
                jsReject(new Error(`Failed to load script: ${scriptUrl}`));
            };
            document.head.appendChild(script);
        }
    });
})
.then(() => { 
    // 3. Both CSS and JS are ready in order. Run user payload.
    
try {
  // 1. Get the chart object using the HTML element ID
  let myChart = CanvasXpress.getObject("volcano");
  
  // 2. Check if the chart exists before trying to delete it
  if (myChart) {
    myChart.destroy();
    console.log("Chart volcano removed for re-rendering.");
  } else {
    console.log("Chart volcano ready for rendering.");
  }
} catch (error) {
  // 3. Handle any unexpected errors safely
  console.error("Chart volcano could not be cleaned for re-rendering:", error);
}

var chart_volcano = new CanvasXpress({"renderTo": "volcano", "data": {"y": {"vars": ["Gene1", "Gene2", "Gene3", "Gene4", "Gene5", "Gene6", "Gene7", "Gene8", "Gene9", "Gene10", "Gene11", "Gene12", "Gene13", "Gene14", "Gene15", "Gene16", "Gene17", "Gene18", "Gene19", "Gene20", "Gene21", "Gene22", "Gene23", "Gene24", "Gene25", "Gene26", "Gene27", "Gene28", "Gene29", "Gene30", "Gene31", "Gene32", "Gene33", "Gene34", "Gene35", "Gene36", "Gene37", "Gene38", "Gene39", "Gene40", "Gene41", "Gene42", "Gene43", "Gene44", "Gene45", "Gene46", "Gene47", "Gene48", "Gene49", "Gene50", "Gene51", "Gene52", "Gene53", "Gene54", "Gene55", "Gene56", "Gene57", "Gene58", "Gene59", "Gene60", "Gene61", "Gene62", "Gene63", "Gene64", "Gene65", "Gene66", "Gene67", "Gene68", "Gene69", "Gene70", "Gene71", "Gene72", "Gene73", "Gene74", "Gene75", "Gene76", "Gene77", "Gene78", "Gene79", "Gene80", "Gene81", "Gene82", "Gene83", "Gene84", "Gene85", "Gene86", "Gene87", "Gene88", "Gene89", "Gene90", "Gene91", "Gene92", "Gene93", "Gene94", "Gene95", "Gene96", "Gene97", "Gene98", "Gene99", "Gene100", "Gene101", "Gene102", "Gene103", "Gene104", "Gene105", "Gene106", "Gene107", "Gene108", "Gene109", "Gene110", "Gene111", "Gene112", "Gene113", "Gene114", "Gene115", "Gene116", "Gene117", "Gene118", "Gene119", "Gene120", "Gene121", "Gene122", "Gene123", "Gene124", "Gene125", "Gene126", "Gene127", "Gene128", "Gene129", "Gene130", "Gene131", "Gene132", "Gene133", "Gene134", "Gene135", "Gene136", "Gene137", "Gene138", "Gene139", "Gene140", "Gene141", "Gene142", "Gene143", "Gene144", "Gene145", "Gene146", "Gene147", "Gene148", "Gene149", "Gene150", "Gene151", "Gene152", "Gene153", "Gene154", "Gene155", "Gene156", "Gene157", "Gene158", "Gene159", "Gene160", "Gene161", "Gene162", "Gene163", "Gene164", "Gene165", "Gene166", "Gene167", "Gene168", "Gene169", "Gene170", "Gene171", "Gene172", "Gene173", "Gene174", "Gene175", "Gene176", "Gene177", "Gene178", "Gene179", "Gene180", "Gene181", "Gene182", "Gene183", "Gene184", "Gene185", "Gene186", "Gene187", "Gene188", "Gene189", "Gene190", "Gene191", "Gene192", "Gene193", "Gene194", "Gene195", "Gene196", "Gene197", "Gene198", "Gene199", "Gene200", "Gene201", "Gene202", "Gene203", "Gene204", "Gene205", "Gene206", "Gene207", "Gene208", "Gene209", "Gene210", "Gene211", "Gene212", "Gene213", "Gene214", "Gene215", "Gene216", "Gene217", "Gene218", "Gene219", "Gene220", "Gene221", "Gene222", "Gene223", "Gene224", "Gene225", "Gene226", "Gene227", "Gene228", "Gene229", "Gene230", "Gene231", "Gene232", "Gene233", "Gene234", "Gene235", "Gene236", "Gene237", "Gene238", "Gene239", "Gene240", "Gene241", "Gene242", "Gene243", "Gene244", "Gene245", "Gene246", "Gene247", "Gene248", "Gene249", "Gene250", "Gene251", "Gene252", "Gene253", "Gene254", "Gene255", "Gene256", "Gene257", "Gene258", "Gene259", "Gene260", "Gene261", "Gene262", "Gene263", "Gene264", "Gene265", "Gene266", "Gene267", "Gene268", "Gene269", "Gene270", "Gene271", "Gene272", "Gene273", "Gene274", "Gene275", "Gene276", "Gene277", "Gene278", "Gene279", "Gene280", "Gene281", "Gene282", "Gene283", "Gene284", "Gene285", "Gene286", "Gene287", "Gene288", "Gene289", "Gene290", "Gene291", "Gene292", "Gene293", "Gene294", "Gene295", "Gene296", "Gene297", "Gene298", "Gene299", "Gene300", "Gene301", "Gene302", "Gene303", "Gene304", "Gene305", "Gene306", "Gene307", "Gene308", "Gene309", "Gene310", "Gene311", "Gene312", "Gene313", "Gene314", "Gene315", "Gene316", "Gene317", "Gene318", "Gene319", "Gene320", "Gene321", "Gene322", "Gene323", "Gene324", "Gene325", "Gene326", "Gene327", "Gene328", "Gene329", "Gene330", "Gene331", "Gene332", "Gene333", "Gene334", "Gene335", "Gene336", "Gene337", "Gene338", "Gene339", "Gene340", "Gene341", "Gene342", "Gene343", "Gene344", "Gene345", "Gene346", "Gene347", "Gene348", "Gene349", "Gene350", "Gene351", "Gene352", "Gene353", "Gene354", "Gene355", "Gene356", "Gene357", "Gene358", "Gene359", "Gene360", "Gene361", "Gene362", "Gene363", "Gene364", "Gene365", "Gene366", "Gene367", "Gene368", "Gene369", "Gene370", "Gene371", "Gene372", "Gene373", "Gene374", "Gene375", "Gene376", "Gene377", "Gene378", "Gene379", "Gene380", "Gene381", "Gene382", "Gene383", "Gene384", "Gene385", "Gene386", "Gene387", "Gene388", "Gene389", "Gene390", "Gene391", "Gene392", "Gene393", "Gene394", "Gene395", "Gene396", "Gene397", "Gene398", "Gene399", "Gene400", "Gene401", "Gene402", "Gene403", "Gene404", "Gene405", "Gene406", "Gene407", "Gene408", "Gene409", "Gene410", "Gene411", "Gene412", "Gene413", "Gene414", "Gene415", "Gene416", "Gene417", "Gene418", "Gene419", "Gene420", "Gene421", "Gene422", "Gene423", "Gene424", "Gene425", "Gene426", "Gene427", "Gene428", "Gene429", "Gene430", "Gene431", "Gene432", "Gene433", "Gene434", "Gene435", "Gene436", "Gene437", "Gene438", "Gene439", "Gene440", "Gene441", "Gene442", "Gene443", "Gene444", "Gene445", "Gene446", "Gene447", "Gene448", "Gene449", "Gene450", "Gene451", "Gene452", "Gene453", "Gene454", "Gene455", "Gene456", "Gene457", "Gene458", "Gene459", "Gene460", "Gene461", "Gene462", "Gene463", "Gene464", "Gene465", "Gene466", "Gene467", "Gene468", "Gene469", "Gene470", "Gene471", "Gene472", "Gene473", "Gene474", "Gene475", "Gene476", "Gene477", "Gene478", "Gene479", "Gene480", "Gene481", "Gene482", "Gene483", "Gene484", "Gene485", "Gene486", "Gene487", "Gene488", "Gene489", "Gene490", "Gene491", "Gene492", "Gene493", "Gene494", "Gene495", "Gene496", "Gene497", "Gene498", "Gene499", "Gene500", "Gene501", "Gene502", "Gene503", "Gene504", "Gene505", "Gene506", "Gene507", "Gene508", "Gene509", "Gene510", "Gene511", "Gene512", "Gene513", "Gene514", "Gene515", "Gene516", "Gene517", "Gene518", "Gene519", "Gene520", "Gene521", "Gene522", "Gene523", "Gene524", "Gene525", "Gene526", "Gene527", "Gene528", "Gene529", "Gene530", "Gene531", "Gene532", "Gene533", "Gene534", "Gene535", "Gene536", "Gene537", "Gene538", "Gene539", "Gene540", "Gene541", "Gene542", "Gene543", "Gene544", "Gene545", "Gene546", "Gene547", "Gene548", "Gene549", "Gene550", "Gene551", "Gene552", "Gene553", "Gene554", "Gene555", "Gene556", "Gene557", "Gene558", "Gene559", "Gene560", "Gene561", "Gene562", "Gene563", "Gene564", "Gene565", "Gene566", "Gene567", "Gene568", "Gene569", "Gene570", "Gene571", "Gene572", "Gene573", "Gene574", "Gene575", "Gene576", "Gene577", "Gene578", "Gene579", "Gene580", "Gene581", "Gene582", "Gene583", "Gene584", "Gene585", "Gene586", "Gene587", "Gene588", "Gene589", "Gene590", "Gene591", "Gene592", "Gene593", "Gene594", "Gene595", "Gene596", "Gene597", "Gene598", "Gene599", "Gene600", "Gene601", "Gene602", "Gene603", "Gene604", "Gene605", "Gene606", "Gene607", "Gene608", "Gene609", "Gene610", "Gene611", "Gene612", "Gene613", "Gene614", "Gene615", "Gene616", "Gene617", "Gene618", "Gene619", "Gene620", "Gene621", "Gene622", "Gene623", "Gene624", "Gene625", "Gene626", "Gene627", "Gene628", "Gene629", "Gene630", "Gene631", "Gene632", "Gene633", "Gene634", "Gene635", "Gene636", "Gene637", "Gene638", "Gene639", "Gene640", "Gene641", "Gene642", "Gene643", "Gene644", "Gene645", "Gene646", "Gene647", "Gene648", "Gene649", "Gene650", "Gene651", "Gene652", "Gene653", "Gene654", "Gene655", "Gene656", "Gene657", "Gene658", "Gene659", "Gene660", "Gene661", "Gene662", "Gene663", "Gene664", "Gene665", "Gene666", "Gene667", "Gene668", "Gene669", "Gene670", "Gene671", "Gene672", "Gene673", "Gene674", "Gene675", "Gene676", "Gene677", "Gene678", "Gene679", "Gene680", "Gene681", "Gene682", "Gene683", "Gene684", "Gene685", "Gene686", "Gene687", "Gene688", "Gene689", "Gene690", "Gene691", "Gene692", "Gene693", "Gene694", "Gene695", "Gene696", "Gene697", "Gene698", "Gene699", "Gene700", "Gene701", "Gene702", "Gene703", "Gene704", "Gene705", "Gene706", "Gene707", "Gene708", "Gene709", "Gene710", "Gene711", "Gene712", "Gene713", "Gene714", "Gene715", "Gene716", "Gene717", "Gene718", "Gene719", "Gene720", "Gene721", "Gene722", "Gene723", "Gene724", "Gene725", "Gene726", "Gene727", "Gene728", "Gene729", "Gene730", "Gene731", "Gene732", "Gene733", "Gene734", "Gene735", "Gene736", "Gene737", "Gene738", "Gene739", "Gene740", "Gene741", "Gene742", "Gene743", "Gene744", "Gene745", "Gene746", "Gene747", "Gene748", "Gene749", "Gene750", "Gene751", "Gene752", "Gene753", "Gene754", "Gene755", "Gene756", "Gene757", "Gene758", "Gene759", "Gene760", "Gene761", "Gene762", "Gene763", "Gene764", "Gene765", "Gene766", "Gene767", "Gene768", "Gene769", "Gene770", "Gene771", "Gene772", "Gene773", "Gene774", "Gene775", "Gene776", "Gene777", "Gene778", "Gene779", "Gene780", "Gene781", "Gene782", "Gene783", "Gene784", "Gene785", "Gene786", "Gene787", "Gene788", "Gene789", "Gene790", "Gene791", "Gene792", "Gene793", "Gene794", "Gene795", "Gene796", "Gene797", "Gene798", "Gene799", "Gene800", "Gene801", "Gene802", "Gene803", "Gene804", "Gene805", "Gene806", "Gene807", "Gene808", "Gene809", "Gene810", "Gene811", "Gene812", "Gene813", "Gene814", "Gene815", "Gene816", "Gene817", "Gene818", "Gene819", "Gene820", "Gene821", "Gene822", "Gene823", "Gene824", "Gene825", "Gene826", "Gene827", "Gene828", "Gene829", "Gene830", "Gene831", "Gene832", "Gene833", "Gene834", "Gene835", "Gene836", "Gene837", "Gene838", "Gene839", "Gene840", "Gene841", "Gene842", "Gene843", "Gene844", "Gene845", "Gene846", "Gene847", "Gene848", "Gene849", "Gene850", "Gene851", "Gene852", "Gene853", "Gene854", "Gene855", "Gene856", "Gene857", "Gene858", "Gene859", "Gene860", "Gene861", "Gene862", "Gene863", "Gene864", "Gene865", "Gene866", "Gene867", "Gene868", "Gene869", "Gene870", "Gene871", "Gene872", "Gene873", "Gene874", "Gene875", "Gene876", "Gene877", "Gene878", "Gene879", "Gene880", "Gene881", "Gene882", "Gene883", "Gene884", "Gene885", "Gene886", "Gene887", "Gene888", "Gene889", "Gene890", "Gene891", "Gene892", "Gene893", "Gene894", "Gene895", "Gene896", "Gene897", "Gene898", "Gene899", "Gene900", "Gene901", "Gene902", "Gene903", "Gene904", "Gene905", "Gene906", "Gene907", "Gene908", "Gene909", "Gene910", "Gene911", "Gene912", "Gene913", "Gene914", "Gene915", "Gene916", "Gene917", "Gene918", "Gene919", "Gene920", "Gene921", "Gene922", "Gene923", "Gene924", "Gene925", "Gene926", "Gene927", "Gene928", "Gene929", "Gene930", "Gene931", "Gene932", "Gene933", "Gene934", "Gene935", "Gene936", "Gene937", "Gene938", "Gene939", "Gene940", "Gene941", "Gene942", "Gene943", "Gene944", "Gene945", "Gene946", "Gene947", "Gene948", "Gene949", "Gene950", "Gene951", "Gene952", "Gene953", "Gene954", "Gene955", "Gene956", "Gene957", "Gene958", "Gene959", "Gene960", "Gene961", "Gene962", "Gene963", "Gene964", "Gene965", "Gene966", "Gene967", "Gene968", "Gene969", "Gene970", "Gene971", "Gene972", "Gene973", "Gene974", "Gene975", "Gene976", "Gene977", "Gene978", "Gene979", "Gene980", "Gene981", "Gene982", "Gene983", "Gene984", "Gene985", "Gene986", "Gene987", "Gene988", "Gene989", "Gene990", "Gene991", "Gene992", "Gene993", "Gene994", "Gene995", "Gene996", "Gene997", "Gene998", "Gene999", "Gene1000"], "smps": ["logFC", "-log-pVal"], "data": [[-0.213, 0.418], [-0.302, 0.266], [0.141, 0.197], [0.267, 0.161], [-0.237, 0.14], [-1.016, 1.076], [1.814, 1.966], [0.03, 0.028], [-0.329, 0.623], [-2.339, 4.804], [0.48, 0.794], [0.185, 0.128], [-0.0, 0.001], [-0.411, 0.532], [-0.06, 0.04], [-0.274, 0.16], [-0.662, 1.928], [1.197, 2.14], [0.302, 0.179], [-0.087, 0.14], [-0.439, 0.485], [-0.366, 0.269], [1.119, 1.825], [0.252, 0.157], [-0.57, 0.753], [0.332, 0.427], [0.115, 0.207], [0.244, 0.221], [-0.1, 0.052], [-0.121, 0.067], [0.046, 0.078], [-1.338, 7.843], [-0.357, 0.817], [-0.662, 0.511], [-0.0, 0.0], [-0.581, 0.981], [1.112, 1.222], [-0.129, 0.13], [0.3, 0.332], [1.158, 1.379], [-0.207, 0.122], [-0.096, 0.121], [0.137, 0.173], [0.299, 0.457], [-0.757, 0.562], [-0.778, 0.923], [-0.481, 0.351], [-0.737, 1.717], [-0.524, 0.375], [0.306, 0.39], [0.519, 0.484], [0.505, 0.907], [0.027, 0.02], [0.087, 0.054], [-0.187, 0.265], [0.669, 0.467], [0.18, 0.108], [0.519, 0.439], [0.252, 0.172], [-0.745, 1.403], [0.13, 0.204], [0.941, 1.856], [-0.175, 0.266], [0.05, 0.047], [0.539, 0.429], [0.039, 0.047], [-0.192, 0.341], [2.101, 3.12], [-0.449, 0.29], [0.192, 0.186], [0.411, 0.678], [-0.588, 0.426], [0.133, 0.228], [-0.344, 0.418], [-0.178, 0.111], [1.225, 1.438], [1.056, 1.104], [-0.648, 0.798], [0.287, 0.211], [0.006, 0.006], [-1.318, 1.362], [1.062, 1.078], [-0.41, 0.257], [-0.171, 0.11], [0.116, 0.075], [1.119, 3.422], [-0.405, 0.374], [-0.015, 0.02], [-0.616, 0.439], [0.049, 0.028], [0.613, 0.681], [-0.664, 0.528], [-1.059, 0.976], [0.891, 1.593], [0.214, 0.154], [0.187, 0.29], [0.632, 2.01], [-1.454, 1.781], [0.284, 0.412], [0.294, 0.313], [0.698, 0.876], [-0.688, 0.495], [0.332, 0.233], [0.491, 0.494], [-1.17, 1.215], [0.359, 0.526], [0.373, 0.807], [0.195, 0.241], [0.27, 0.22], [0.281, 0.329], [-0.203, 0.11], [0.265, 0.227], [-0.48, 0.468], [-0.119, 0.076], [-0.418, 0.419], [0.31, 0.504], [-0.139, 0.177], [-0.061, 0.05], [-0.625, 1.146], [0.121, 0.15], [-0.295, 0.333], [0.928, 0.869], [-1.144, 1.1], [0.106, 0.118], [-0.137, 0.176], [-0.092, 0.156], [-1.22, 7.247], [0.379, 0.459], [-0.278, 0.42], [0.65, 0.774], [-0.194, 0.303], [0.414, 0.359], [-0.881, 1.111], [-0.235, 0.137], [-0.196, 0.123], [-0.099, 0.14], [-0.799, 0.976], [-0.777, 1.266], [-0.01, 0.014], [0.29, 0.254], [-1.003, 0.806], [-0.107, 0.145], [-0.341, 0.902], [-0.093, 0.113], [-0.252, 0.25], [-0.262, 0.34], [0.089, 0.058], [0.054, 0.056], [0.248, 0.153], [-0.079, 0.107], [-0.255, 0.407], [-0.155, 0.083], [-0.085, 0.131], [-0.996, 1.019], [-0.097, 0.149], [-0.505, 1.038], [-1.064, 1.341], [-0.536, 0.402], [-0.353, 0.297], [0.483, 0.3], [-0.238, 0.132], [0.149, 0.212], [0.643, 0.808], [0.043, 0.034], [0.111, 0.141], [-0.394, 0.325], [0.522, 0.371], [0.02, 0.012], [0.025, 0.014], [-0.404, 0.604], [-0.484, 0.473], [-0.216, 0.315], [0.047, 0.028], [0.73, 0.543], [-0.723, 0.909], [-0.188, 0.158], [0.735, 0.673], [1.502, 1.614], [-0.06, 0.086], [-0.337, 0.242], [0.479, 0.325], [-0.369, 0.593], [0.189, 0.216], [-0.776, 1.054], [-0.249, 0.201], [-0.033, 0.027], [-0.232, 0.189], [-0.557, 0.747], [-0.078, 0.067], [0.02, 0.019], [-0.416, 0.35], [0.802, 0.611], [-0.255, 0.142], [0.027, 0.023], [-1.46, 8.766], [0.716, 0.739], [-0.285, 0.166], [0.03, 0.015], [0.151, 0.103], [0.239, 0.254], [-0.487, 1.202], [0.508, 0.585], [-0.08, 0.053], [-0.433, 0.341], [-0.029, 0.019], [-1.193, 1.285], [-0.218, 0.366], [0.08, 0.062], [0.597, 0.744], [-0.048, 0.037], [-1.275, 2.311], [-0.163, 0.122], [0.231, 0.399], [-0.094, 0.17], [0.195, 0.182], [-0.181, 0.14], [-1.438, 3.059], [-0.482, 0.505], [-0.278, 0.294], [0.717, 0.598], [1.987, 2.83], [-0.064, 0.081], [-0.4, 0.345], [0.25, 0.219], [0.118, 0.198], [-0.143, 0.231], [1.198, 1.251], [0.501, 0.413], [1.622, 7.238], [0.029, 0.02], [0.083, 0.045], [0.467, 0.478], [-0.728, 0.79], [-0.453, 0.379], [0.041, 0.031], [-0.968, 0.848], [0.571, 0.998], [-0.208, 0.274], [-0.117, 0.176], [1.838, 4.488], [1.927, 6.302], [-0.02, 0.015], [-1.555, 6.379], [-0.43, 0.456], [0.109, 0.088], [-0.216, 0.25], [1.477, 1.756], [-1.05, 1.581], [-1.639, 2.815], [-0.647, 0.453], [0.233, 0.14], [0.016, 0.01], [-0.45, 1.362], [-0.24, 0.182], [0.449, 0.642], [-0.238, 0.312], [-1.365, 2.045], [-1.373, 5.078], [0.395, 0.299], [-0.669, 0.566], [0.007, 0.008], [-0.431, 0.837], [0.667, 0.483], [1.745, 12.916], [-0.023, 0.013], [1.353, 1.646], [-0.931, 0.986], [-0.087, 0.148], [0.108, 0.058], [0.118, 0.146], [-0.045, 0.025], [-0.28, 0.258], [-0.156, 0.165], [-0.141, 0.189], [0.103, 0.187], [1.709, 6.397], [0.549, 1.314], [-0.039, 0.064], [1.504, 2.189], [0.516, 0.331], [0.048, 0.036], [0.63, 0.499], [-0.606, 0.409], [0.042, 0.06], [-0.495, 0.598], [-0.373, 0.412], [-0.224, 0.288], [-0.023, 0.014], [0.126, 0.097], [0.395, 0.713], [-0.449, 0.287], [-1.666, 8.592], [-1.148, 5.557], [-0.526, 0.422], [-0.208, 0.2], [-0.614, 0.583], [0.102, 0.179], [0.27, 0.525], [-1.816, 6.269], [-0.276, 0.326], [0.632, 0.718], [-0.089, 0.089], [0.492, 0.845], [-2.028, 2.45], [-0.054, 0.07], [-0.49, 0.526], [-0.185, 0.239], [0.49, 0.362], [0.56, 0.537], [-1.367, 2.004], [0.399, 0.441], [-0.515, 0.599], [0.176, 0.094], [-0.078, 0.067], [-0.948, 1.075], [0.231, 0.419], [-0.337, 0.314], [0.243, 0.165], [1.332, 2.472], [-1.39, 1.763], [0.325, 0.255], [-0.008, 0.01], [-0.23, 0.21], [-1.319, 7.667], [0.05, 0.07], [1.179, 1.466], [0.007, 0.008], [0.799, 2.947], [1.135, 1.905], [-0.433, 0.35], [0.619, 1.067], [-0.167, 0.224], [-0.046, 0.05], [-0.222, 0.471], [-0.325, 0.751], [0.504, 0.578], [-0.225, 0.308], [0.14, 0.127], [-0.928, 0.768], [-0.407, 0.29], [0.289, 0.189], [0.314, 0.189], [0.121, 0.082], [0.172, 0.158], [0.052, 0.075], [0.573, 0.49], [0.464, 1.034], [0.203, 0.234], [-0.046, 0.047], [-0.719, 0.528], [-0.328, 0.211], [-0.118, 0.134], [0.58, 0.81], [-0.717, 0.929], [-0.198, 0.381], [-0.241, 0.53], [0.428, 0.402], [-0.336, 0.323], [-0.992, 1.196], [-2.472, 3.753], [0.083, 0.111], [-2.084, 2.742], [0.349, 0.549], [0.706, 0.522], [-0.348, 0.611], [-0.155, 0.148], [-0.006, 0.004], [-0.489, 0.897], [-0.354, 0.69], [-0.238, 0.299], [-0.029, 0.027], [0.155, 0.089], [-0.663, 1.26], [0.111, 0.074], [-0.101, 0.058], [-0.07, 0.121], [-0.18, 0.212], [0.66, 0.487], [0.775, 0.888], [-0.153, 0.211], [-0.101, 0.082], [-0.686, 0.99], [-0.287, 0.185], [0.395, 0.282], [-0.056, 0.054], [0.221, 0.122], [-0.038, 0.057], [0.038, 0.02], [0.168, 0.275], [2.031, 4.358], [-0.851, 1.323], [-0.156, 0.094], [-1.351, 2.479], [-0.004, 0.004], [-0.327, 0.244], [-0.252, 0.268], [0.667, 0.909], [0.215, 0.135], [0.444, 0.578], [0.298, 0.268], [1.045, 1.027], [-0.161, 0.097], [-0.147, 0.1], [-0.056, 0.035], [0.654, 1.836], [-0.217, 0.181], [0.012, 0.008], [0.398, 0.769], [0.611, 0.447], [-0.278, 0.209], [0.473, 1.089], [0.135, 0.2], [0.393, 0.829], [1.166, 4.175], [-1.162, 1.62], [-0.2, 0.339], [0.602, 0.807], [-0.255, 0.316], [0.042, 0.027], [-0.481, 0.394], [-0.183, 0.134], [0.062, 0.043], [0.004, 0.003], [0.095, 0.058], [0.278, 0.256], [-0.49, 0.873], [-0.144, 0.222], [1.074, 1.41], [-1.216, 1.295], [-0.369, 0.281], [0.458, 0.372], [-1.12, 1.183], [-0.224, 0.41], [-0.519, 0.375], [0.369, 0.932], [-0.434, 0.415], [0.27, 0.278], [-0.18, 0.277], [1.537, 2.617], [-0.314, 0.59], [-0.361, 0.85], [-0.27, 0.194], [-0.916, 0.773], [-0.078, 0.066], [0.074, 0.043], [0.285, 0.166], [0.894, 0.897], [0.611, 0.807], [-0.764, 0.569], [-0.258, 0.344], [0.573, 1.04], [-0.031, 0.02], [-0.245, 0.155], [0.375, 0.546], [-0.236, 0.274], [0.218, 0.455], [-0.081, 0.118], [0.498, 0.708], [0.841, 2.781], [0.189, 0.384], [0.64, 0.538], [1.069, 0.973], [-0.23, 0.371], [-0.151, 0.155], [-0.323, 0.806], [-0.742, 1.072], [-0.139, 0.209], [0.08, 0.059], [0.7, 0.677], [-0.241, 0.17], [0.52, 1.251], [0.112, 0.067], [0.562, 0.421], [-0.092, 0.099], [-0.89, 0.682], [0.615, 0.945], [-0.102, 0.113], [1.202, 4.23], [-0.261, 0.149], [0.416, 0.252], [-0.099, 0.06], [-0.13, 0.139], [-0.048, 0.056], [1.525, 1.819], [-0.764, 0.647], [-0.554, 0.485], [-1.072, 5.634], [-0.196, 0.338], [0.09, 0.066], [-0.325, 0.757], [-0.141, 0.085], [0.773, 0.56], [0.053, 0.027], [0.126, 0.074], [-0.097, 0.164], [0.024, 0.031], [-1.274, 1.139], [-0.809, 1.003], [0.109, 0.159], [-0.396, 1.127], [0.358, 0.706], [1.357, 1.403], [-0.452, 0.654], [-1.306, 1.558], [-2.871, 4.515], [0.115, 0.112], [-0.079, 0.042], [0.877, 0.734], [0.126, 0.185], [2.094, 12.785], [0.573, 0.406], [-0.619, 0.478], [-0.132, 0.079], [-0.481, 0.415], [-0.238, 0.135], [-0.234, 0.231], [-0.163, 0.099], [0.809, 0.738], [-0.254, 0.25], [-0.448, 0.655], [-0.183, 0.293], [-0.352, 0.213], [-0.385, 0.267], [-0.117, 0.074], [-0.158, 0.189], [0.685, 0.558], [0.282, 0.426], [-0.423, 0.365], [0.29, 0.474], [0.616, 0.775], [-0.008, 0.005], [-0.5, 0.411], [0.284, 0.17], [-0.067, 0.035], [0.193, 0.126], [-0.261, 0.55], [0.862, 1.43], [-0.122, 0.079], [1.585, 1.812], [-0.14, 0.264], [0.062, 0.054], [-1.582, 1.67], [-0.895, 0.719], [-1.641, 1.879], [0.292, 0.489], [-0.53, 0.784], [-1.067, 0.925], [0.768, 0.587], [-0.343, 0.204], [-1.088, 1.249], [0.621, 0.553], [0.172, 0.209], [0.185, 0.126], [0.234, 0.296], [-1.242, 1.279], [0.682, 0.717], [0.486, 0.746], [0.548, 1.205], [-0.588, 1.428], [-1.239, 4.53], [0.987, 0.837], [-0.328, 0.38], [1.378, 2.208], [0.527, 1.139], [0.316, 0.196], [-0.443, 0.271], [-0.609, 0.695], [-0.38, 0.233], [1.004, 0.811], [-0.462, 0.39], [-0.512, 1.102], [0.169, 0.12], [0.435, 0.79], [1.645, 1.861], [0.851, 0.696], [0.309, 0.497], [-0.699, 1.106], [-0.197, 0.139], [-0.12, 0.14], [0.104, 0.06], [-0.429, 0.438], [0.445, 0.384], [0.572, 0.697], [0.083, 0.049], [-0.165, 0.103], [0.132, 0.08], [0.162, 0.163], [0.325, 0.382], [-0.287, 0.398], [0.983, 0.847], [0.015, 0.019], [-0.062, 0.058], [0.168, 0.32], [-0.375, 0.306], [0.626, 0.43], [1.056, 1.518], [0.107, 0.186], [0.087, 0.083], [-0.256, 0.192], [0.454, 0.882], [0.55, 0.6], [-1.428, 3.618], [0.239, 0.489], [-0.405, 0.294], [-0.428, 0.619], [-0.022, 0.025], [-0.364, 0.294], [-0.701, 0.955], [-0.483, 0.686], [-0.351, 0.707], [-0.679, 0.467], [-0.074, 0.052], [0.26, 0.255], [-0.562, 0.562], [-0.326, 0.332], [-0.969, 0.939], [-0.133, 0.076], [-1.382, 3.708], [2.455, 3.468], [0.706, 1.262], [-0.506, 0.46], [0.09, 0.047], [1.48, 2.034], [-0.137, 0.238], [-0.213, 0.162], [0.409, 0.277], [-0.069, 0.109], [-0.1, 0.122], [-0.017, 0.014], [0.508, 0.657], [-0.193, 0.105], [0.099, 0.151], [0.07, 0.086], [0.378, 0.318], [-0.057, 0.077], [-0.266, 0.211], [-0.374, 0.315], [0.113, 0.086], [-1.085, 1.928], [-0.121, 0.103], [0.086, 0.08], [0.975, 1.734], [0.307, 0.361], [-0.688, 1.187], [0.396, 0.708], [0.068, 0.049], [0.735, 0.796], [0.658, 0.741], [-0.042, 0.031], [0.631, 0.505], [-0.421, 0.272], [0.263, 0.531], [-0.123, 0.113], [1.98, 4.868], [0.219, 0.38], [-0.448, 0.609], [0.154, 0.143], [0.111, 0.191], [-0.03, 0.024], [-0.485, 1.134], [0.115, 0.105], [-0.105, 0.129], [0.322, 0.629], [-0.271, 0.548], [0.465, 0.481], [0.028, 0.047], [1.061, 1.948], [-0.254, 0.51], [0.534, 0.464], [-0.296, 0.232], [-0.284, 0.471], [0.429, 0.544], [0.346, 0.258], [0.295, 0.525], [-1.014, 0.977], [-0.665, 0.644], [0.401, 0.25], [-0.446, 0.406], [0.318, 0.723], [0.706, 1.015], [-0.075, 0.048], [0.013, 0.01], [0.01, 0.009], [-0.101, 0.114], [-0.021, 0.013], [-0.069, 0.088], [0.258, 0.175], [-0.12, 0.132], [-0.265, 0.22], [-0.204, 0.117], [-0.316, 0.267], [-0.053, 0.029], [0.143, 0.229], [0.977, 1.4], [-0.891, 0.986], [-0.415, 0.774], [-0.039, 0.024], [0.017, 0.011], [-0.02, 0.016], [1.155, 1.213], [-0.405, 1.168], [1.575, 1.67], [-0.338, 0.692], [-0.183, 0.118], [0.984, 3.015], [1.13, 6.247], [1.342, 2.016], [-0.418, 0.401], [-0.62, 0.531], [-1.071, 1.001], [-0.317, 0.315], [-0.358, 0.339], [0.426, 0.39], [-0.604, 0.927], [0.132, 0.08], [0.506, 0.398], [-0.075, 0.096], [-1.06, 1.216], [-0.227, 0.311], [0.15, 0.168], [-0.169, 0.132], [0.95, 1.511], [-0.144, 0.11], [-0.101, 0.116], [0.242, 0.163], [-0.146, 0.224], [-1.137, 6.426], [0.109, 0.134], [0.413, 0.419], [-0.385, 0.259], [0.024, 0.022], [-0.045, 0.063], [0.498, 0.314], [0.461, 0.386], [0.146, 0.164], [-1.545, 5.432], [0.529, 1.136], [1.061, 3.924], [0.949, 0.994], [0.15, 0.229], [-0.858, 0.902], [-1.605, 3.861], [-0.755, 0.803], [-0.049, 0.045], [-0.565, 1.371], [0.161, 0.332], [-0.502, 0.366], [1.047, 1.007], [-0.206, 0.328], [0.02, 0.02], [-0.607, 0.757], [-0.087, 0.046], [0.019, 0.016], [0.254, 0.214], [0.554, 1.874], [2.052, 15.693], [0.464, 0.366], [-0.153, 0.126], [-0.07, 0.107], [-0.174, 0.116], [-0.271, 0.399], [0.459, 0.306], [-0.03, 0.015], [0.378, 0.232], [-1.367, 4.952], [0.203, 0.159], [1.174, 1.126], [0.201, 0.151], [0.242, 0.469], [-0.286, 0.383], [-0.063, 0.041], [-0.14, 0.135], [0.163, 0.231], [-1.32, 2.063], [-1.435, 1.577], [0.224, 0.162], [0.063, 0.066], [-0.477, 0.881], [0.009, 0.011], [0.448, 0.677], [-0.423, 0.385], [0.786, 0.611], [0.273, 0.356], [0.148, 0.095], [0.365, 0.222], [-0.291, 0.327], [0.48, 0.368], [-0.956, 0.74], [-0.354, 0.521], [0.311, 0.276], [-0.665, 0.506], [0.608, 1.449], [0.112, 0.177], [-0.713, 0.731], [0.552, 0.545], [-0.197, 0.114], [1.08, 1.308], [0.389, 0.249], [0.053, 0.04], [0.897, 1.033], [2.181, 3.256], [0.14, 0.129], [0.583, 0.774], [0.104, 0.068], [0.223, 0.427], [1.268, 2.307], [-0.046, 0.057], [-0.375, 0.39], [-0.138, 0.266], [1.233, 6.288], [0.259, 0.225], [-0.757, 1.376], [-0.18, 0.123], [1.281, 1.985], [-0.032, 0.025], [-0.66, 0.51], [0.757, 2.707], [1.214, 1.111], [-0.397, 0.886], [-0.96, 4.075], [0.632, 0.435], [-0.579, 1.264], [0.336, 0.341], [-0.597, 0.861], [0.382, 0.551], [1.302, 2.203], [-0.782, 0.626], [-0.0, 0.0], [1.773, 3.039], [-0.351, 0.211], [0.273, 0.268], [-0.247, 0.285], [-0.231, 0.209], [-0.464, 0.344], [0.008, 0.005], [0.378, 0.229], [0.404, 0.523], [-1.024, 0.864], [-0.414, 0.504], [-0.096, 0.171], [-1.539, 2.343], [0.653, 0.464], [0.218, 0.284], [-0.054, 0.029], [0.097, 0.056], [0.041, 0.039], [-0.021, 0.012], [-0.16, 0.17], [0.417, 0.362], [-0.018, 0.013], [-0.02, 0.022], [-0.467, 0.548], [-0.277, 0.292], [-0.144, 0.238], [0.402, 0.266], [-0.63, 1.063], [0.292, 0.354], [1.266, 1.159], [-0.284, 0.303], [0.952, 1.643], [0.345, 0.229], [0.095, 0.093], [-1.361, 1.295], [-0.304, 0.295], [-0.364, 0.427], [-0.017, 0.016], [-0.229, 0.266], [0.343, 0.202], [-0.23, 0.207], [-0.063, 0.096], [1.43, 7.476], [-0.131, 0.081], [-0.316, 0.196], [0.043, 0.022], [-0.326, 0.693], [-0.544, 0.937], [-0.006, 0.003], [-0.36, 0.245], [-0.892, 0.801], [0.287, 0.459], [0.419, 0.313], [0.138, 0.089], [-0.353, 0.222], [-0.085, 0.072], [-1.38, 1.948], [0.277, 0.411], [-0.849, 0.819], [0.063, 0.106], [0.013, 0.007], [-0.629, 0.587], [0.234, 0.271], [-0.108, 0.134], [0.852, 1.211], [0.694, 0.619], [-0.038, 0.019], [-0.264, 0.15], [-0.334, 0.305], [-0.266, 0.327], [0.089, 0.124], [-0.837, 0.818], [-1.039, 1.348], [0.23, 0.315], [-0.065, 0.049], [0.312, 0.344], [1.418, 1.666], [0.078, 0.116], [0.543, 1.068], [-0.091, 0.114], [-0.279, 0.264], [0.385, 0.5], [-1.85, 3.469], [0.444, 0.472], [-0.0, 0.0], [-0.27, 0.2], [0.044, 0.031], [0.031, 0.04], [0.509, 0.673], [0.44, 0.398], [0.107, 0.075], [-1.242, 2.24], [-0.296, 0.462], [0.126, 0.075], [-1.245, 1.999], [0.522, 0.476], [-0.001, 0.0], [-0.404, 1.015], [0.158, 0.242], [-0.52, 0.427], [-0.126, 0.193], [-0.398, 1.13], [-0.531, 0.343], [0.039, 0.059], [-0.055, 0.03], [0.205, 0.112], [-0.304, 0.333], [0.297, 0.24], [-0.411, 0.86], [-0.412, 0.247], [-1.772, 2.101], [-0.115, 0.123], [-0.143, 0.237], [-0.124, 0.076], [0.403, 0.24], [0.382, 0.713], [0.35, 0.222], [-0.165, 0.097], [-0.642, 1.313], [0.565, 1.157], [0.412, 0.703], [0.163, 0.186], [0.516, 0.638], [0.274, 0.402], [-0.245, 0.285], [0.36, 0.321], [0.605, 0.614], [0.576, 0.373], [-0.027, 0.032], [-0.26, 0.156], [0.809, 1.753], [0.088, 0.104], [0.362, 0.233], [-0.71, 0.794], [0.388, 0.306], [1.006, 0.877], [-0.519, 0.41], [0.77, 0.705], [-0.001, 0.001], [0.246, 0.287], [0.217, 0.19], [-0.289, 0.315], [0.091, 0.112], [0.81, 0.779], [-0.671, 0.57], [-1.923, 2.347], [-0.498, 0.441], [0.353, 0.338], [-0.185, 0.191], [0.124, 0.114], [0.721, 0.596], [-0.661, 0.585], [-0.721, 2.104], [0.015, 0.01], [-0.117, 0.065], [0.982, 0.898], [0.187, 0.188], [-0.832, 0.726], [-0.039, 0.021], [-0.409, 0.357], [0.174, 0.102], [-0.138, 0.196], [-0.234, 0.135], [0.616, 0.471], [-0.715, 1.045], [0.173, 0.108], [1.517, 2.888], [0.198, 0.126], [-0.908, 1.753], [-2.059, 3.765], [-0.104, 0.166], [1.173, 1.005]]}, "z": {"Group": ["NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "Increased", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "Increased", "Decreased", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "Decreased", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "Increased", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "Decreased", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Decreased", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "Increased", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "Increased", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "NoChange", "Increased", "NoChange", "NoChange", "Decreased", "NoChange", "NoChange"], "FC": [1.16, 1.23, 1.1, 1.2, 1.18, 2.02, 3.52, 1.02, 1.26, 5.06, 1.39, 1.14, 1.0, 1.33, 1.04, 1.21, 1.58, 2.29, 1.23, 1.06, 1.36, 1.29, 2.17, 1.19, 1.48, 1.26, 1.08, 1.18, 1.07, 1.09, 1.03, 2.53, 1.28, 1.58, 1.0, 1.5, 2.16, 1.09, 1.23, 2.23, 1.15, 1.07, 1.1, 1.23, 1.69, 1.71, 1.4, 1.67, 1.44, 1.24, 1.43, 1.42, 1.02, 1.06, 1.14, 1.59, 1.13, 1.43, 1.19, 1.68, 1.09, 1.92, 1.13, 1.04, 1.45, 1.03, 1.14, 4.29, 1.37, 1.14, 1.33, 1.5, 1.1, 1.27, 1.13, 2.34, 2.08, 1.57, 1.22, 1.0, 2.49, 2.09, 1.33, 1.13, 1.08, 2.17, 1.32, 1.01, 1.53, 1.03, 1.53, 1.58, 2.08, 1.85, 1.16, 1.14, 1.55, 2.74, 1.22, 1.23, 1.62, 1.61, 1.26, 1.41, 2.25, 1.28, 1.3, 1.14, 1.21, 1.22, 1.15, 1.2, 1.39, 1.09, 1.34, 1.24, 1.1, 1.04, 1.54, 1.09, 1.23, 1.9, 2.21, 1.08, 1.1, 1.07, 2.33, 1.3, 1.21, 1.57, 1.14, 1.33, 1.84, 1.18, 1.15, 1.07, 1.74, 1.71, 1.01, 1.22, 2.0, 1.08, 1.27, 1.07, 1.19, 1.2, 1.06, 1.04, 1.19, 1.06, 1.19, 1.11, 1.06, 1.99, 1.07, 1.42, 2.09, 1.45, 1.28, 1.4, 1.18, 1.11, 1.56, 1.03, 1.08, 1.31, 1.44, 1.01, 1.02, 1.32, 1.4, 1.16, 1.03, 1.66, 1.65, 1.14, 1.66, 2.83, 1.04, 1.26, 1.39, 1.29, 1.14, 1.71, 1.19, 1.02, 1.17, 1.47, 1.06, 1.01, 1.33, 1.74, 1.19, 1.02, 2.75, 1.64, 1.22, 1.02, 1.11, 1.18, 1.4, 1.42, 1.06, 1.35, 1.02, 2.29, 1.16, 1.06, 1.51, 1.03, 2.42, 1.12, 1.17, 1.07, 1.14, 1.13, 2.71, 1.4, 1.21, 1.64, 3.96, 1.05, 1.32, 1.19, 1.09, 1.1, 2.29, 1.42, 3.08, 1.02, 1.06, 1.38, 1.66, 1.37, 1.03, 1.96, 1.49, 1.16, 1.08, 3.58, 3.8, 1.01, 2.94, 1.35, 1.08, 1.16, 2.78, 2.07, 3.11, 1.57, 1.18, 1.01, 1.37, 1.18, 1.37, 1.18, 2.58, 2.59, 1.31, 1.59, 1.0, 1.35, 1.59, 3.35, 1.02, 2.55, 1.91, 1.06, 1.08, 1.09, 1.03, 1.21, 1.11, 1.1, 1.07, 3.27, 1.46, 1.03, 2.84, 1.43, 1.03, 1.55, 1.52, 1.03, 1.41, 1.3, 1.17, 1.02, 1.09, 1.31, 1.37, 3.17, 2.22, 1.44, 1.16, 1.53, 1.07, 1.21, 3.52, 1.21, 1.55, 1.06, 1.41, 4.08, 1.04, 1.4, 1.14, 1.4, 1.47, 2.58, 1.32, 1.43, 1.13, 1.06, 1.93, 1.17, 1.26, 1.18, 2.52, 2.62, 1.25, 1.01, 1.17, 2.49, 1.04, 2.26, 1.0, 1.74, 2.2, 1.35, 1.54, 1.12, 1.03, 1.17, 1.25, 1.42, 1.17, 1.1, 1.9, 1.33, 1.22, 1.24, 1.09, 1.13, 1.04, 1.49, 1.38, 1.15, 1.03, 1.65, 1.26, 1.09, 1.49, 1.64, 1.15, 1.18, 1.35, 1.26, 1.99, 5.55, 1.06, 4.24, 1.27, 1.63, 1.27, 1.11, 1.0, 1.4, 1.28, 1.18, 1.02, 1.11, 1.58, 1.08, 1.07, 1.05, 1.13, 1.58, 1.71, 1.11, 1.07, 1.61, 1.22, 1.31, 1.04, 1.17, 1.03, 1.03, 1.12, 4.09, 1.8, 1.11, 2.55, 1.0, 1.25, 1.19, 1.59, 1.16, 1.36, 1.23, 2.06, 1.12, 1.11, 1.04, 1.57, 1.16, 1.01, 1.32, 1.53, 1.21, 1.39, 1.1, 1.31, 2.24, 2.24, 1.15, 1.52, 1.19, 1.03, 1.4, 1.14, 1.04, 1.0, 1.07, 1.21, 1.4, 1.1, 2.11, 2.32, 1.29, 1.37, 2.17, 1.17, 1.43, 1.29, 1.35, 1.21, 1.13, 2.9, 1.24, 1.28, 1.21, 1.89, 1.06, 1.05, 1.22, 1.86, 1.53, 1.7, 1.2, 1.49, 1.02, 1.19, 1.3, 1.18, 1.16, 1.06, 1.41, 1.79, 1.14, 1.56, 2.1, 1.17, 1.11, 1.25, 1.67, 1.1, 1.06, 1.62, 1.18, 1.43, 1.08, 1.48, 1.07, 1.85, 1.53, 1.07, 2.3, 1.2, 1.33, 1.07, 1.09, 1.03, 2.88, 1.7, 1.47, 2.1, 1.15, 1.06, 1.25, 1.1, 1.71, 1.04, 1.09, 1.07, 1.02, 2.42, 1.75, 1.08, 1.32, 1.28, 2.56, 1.37, 2.47, 7.32, 1.08, 1.06, 1.84, 1.09, 4.27, 1.49, 1.54, 1.1, 1.4, 1.18, 1.18, 1.12, 1.75, 1.19, 1.36, 1.14, 1.28, 1.31, 1.08, 1.12, 1.61, 1.22, 1.34, 1.22, 1.53, 1.01, 1.41, 1.22, 1.05, 1.14, 1.2, 1.82, 1.09, 3.0, 1.1, 1.04, 2.99, 1.86, 3.12, 1.22, 1.44, 2.1, 1.7, 1.27, 2.13, 1.54, 1.13, 1.14, 1.18, 2.37, 1.6, 1.4, 1.46, 1.5, 2.36, 1.98, 1.26, 2.6, 1.44, 1.24, 1.36, 1.53, 1.3, 2.01, 1.38, 1.43, 1.12, 1.35, 3.13, 1.8, 1.24, 1.62, 1.15, 1.09, 1.07, 1.35, 1.36, 1.49, 1.06, 1.12, 1.1, 1.12, 1.25, 1.22, 1.98, 1.01, 1.04, 1.12, 1.3, 1.54, 2.08, 1.08, 1.06, 1.19, 1.37, 1.46, 2.69, 1.18, 1.32, 1.35, 1.02, 1.29, 1.63, 1.4, 1.28, 1.6, 1.05, 1.2, 1.48, 1.25, 1.96, 1.1, 2.61, 5.48, 1.63, 1.42, 1.06, 2.79, 1.1, 1.16, 1.33, 1.05, 1.07, 1.01, 1.42, 1.14, 1.07, 1.05, 1.3, 1.04, 1.2, 1.3, 1.08, 2.12, 1.09, 1.06, 1.97, 1.24, 1.61, 1.32, 1.05, 1.66, 1.58, 1.03, 1.55, 1.34, 1.2, 1.09, 3.94, 1.16, 1.36, 1.11, 1.08, 1.02, 1.4, 1.08, 1.08, 1.25, 1.21, 1.38, 1.02, 2.09, 1.19, 1.45, 1.23, 1.22, 1.35, 1.27, 1.23, 2.02, 1.59, 1.32, 1.36, 1.25, 1.63, 1.05, 1.01, 1.01, 1.07, 1.01, 1.05, 1.2, 1.09, 1.2, 1.15, 1.24, 1.04, 1.1, 1.97, 1.85, 1.33, 1.03, 1.01, 1.01, 2.23, 1.32, 2.98, 1.26, 1.14, 1.98, 2.19, 2.54, 1.34, 1.54, 2.1, 1.25, 1.28, 1.34, 1.52, 1.1, 1.42, 1.05, 2.08, 1.17, 1.11, 1.12, 1.93, 1.1, 1.07, 1.18, 1.11, 2.2, 1.08, 1.33, 1.31, 1.02, 1.03, 1.41, 1.38, 1.11, 2.92, 1.44, 2.09, 1.93, 1.11, 1.81, 3.04, 1.69, 1.03, 1.48, 1.12, 1.42, 2.07, 1.15, 1.01, 1.52, 1.06, 1.01, 1.19, 1.47, 4.15, 1.38, 1.11, 1.05, 1.13, 1.21, 1.37, 1.02, 1.3, 2.58, 1.15, 2.26, 1.15, 1.18, 1.22, 1.04, 1.1, 1.12, 2.5, 2.7, 1.17, 1.04, 1.39, 1.01, 1.36, 1.34, 1.72, 1.21, 1.11, 1.29, 1.22, 1.39, 1.94, 1.28, 1.24, 1.59, 1.52, 1.08, 1.64, 1.47, 1.15, 2.11, 1.31, 1.04, 1.86, 4.53, 1.1, 1.5, 1.07, 1.17, 2.41, 1.03, 1.3, 1.1, 2.35, 1.2, 1.69, 1.13, 2.43, 1.02, 1.58, 1.69, 2.32, 1.32, 1.95, 1.55, 1.49, 1.26, 1.51, 1.3, 2.47, 1.72, 1.0, 3.42, 1.28, 1.21, 1.19, 1.17, 1.38, 1.01, 1.3, 1.32, 2.03, 1.33, 1.07, 2.91, 1.57, 1.16, 1.04, 1.07, 1.03, 1.01, 1.12, 1.34, 1.01, 1.01, 1.38, 1.21, 1.1, 1.32, 1.55, 1.22, 2.4, 1.22, 1.93, 1.27, 1.07, 2.57, 1.23, 1.29, 1.01, 1.17, 1.27, 1.17, 1.04, 2.69, 1.1, 1.24, 1.03, 1.25, 1.46, 1.0, 1.28, 1.86, 1.22, 1.34, 1.1, 1.28, 1.06, 2.6, 1.21, 1.8, 1.04, 1.01, 1.55, 1.18, 1.08, 1.81, 1.62, 1.03, 1.2, 1.26, 1.2, 1.06, 1.79, 2.05, 1.17, 1.05, 1.24, 2.67, 1.06, 1.46, 1.07, 1.21, 1.31, 3.61, 1.36, 1.0, 1.21, 1.03, 1.02, 1.42, 1.36, 1.08, 2.37, 1.23, 1.09, 2.37, 1.44, 1.0, 1.32, 1.12, 1.43, 1.09, 1.32, 1.44, 1.03, 1.04, 1.15, 1.23, 1.23, 1.33, 1.33, 3.42, 1.08, 1.1, 1.09, 1.32, 1.3, 1.27, 1.12, 1.56, 1.48, 1.33, 1.12, 1.43, 1.21, 1.19, 1.28, 1.52, 1.49, 1.02, 1.2, 1.75, 1.06, 1.29, 1.64, 1.31, 2.01, 1.43, 1.71, 1.0, 1.19, 1.16, 1.22, 1.07, 1.75, 1.59, 3.79, 1.41, 1.28, 1.14, 1.09, 1.65, 1.58, 1.65, 1.01, 1.08, 1.98, 1.14, 1.78, 1.03, 1.33, 1.13, 1.1, 1.18, 1.53, 1.64, 1.13, 2.86, 1.15, 1.88, 4.17, 1.07, 2.25]}, "x": null}, "config": {"graphType": "Scatter2D", "title": "Publication-ready volcano plot", "xAxis": ["logFC"], "yAxis": ["-log-pVal"], "xAxisTitle": "log2 fold change", "yAxisTitle": "-log10 p-value", "colorBy": "Group", "colorKey": {"Group": {"Increased": "rgba(197,27,38,0.75)", "Decreased": "rgba(33,102,172,0.75)", "NoChange": "rgba(150,150,150,0.35)"}}, "sizeBy": "FC", "sizes": [3, 6, 9, 12, 15], "showDecorations": true, "decorations": {"line": [{"color": "rgba(120,120,120,0.8)", "width": 1, "x": 1}, {"color": "rgba(120,120,120,0.8)", "width": 1, "x": -1}, {"color": "rgba(120,120,120,0.8)", "width": 1, "y": 1.301}]}}, "events": null}); 
;

 
})
.catch((error) => {
    console.error("CanvasXpress injection failed:", error);
});


</script>
</div>
</div>
<p>The chart is interactive — hover a point for its gene and values, drag to zoom, filter by regulation group in the toolbar. The dashed guides mark the ±1 log2FC and p = 0.05 cutoffs.</p>
</section>
<section id="why-reproducible" class="level2">
<h2 class="anchored" data-anchor-id="why-reproducible">Why “reproducible”</h2>
<p>Everything above serializes to one JSON specification — the <code>data</code> and the <code>config</code>. That spec is portable: the identical figure renders from the R (<code>canvasXpress</code>) and JavaScript packages, and it can be validated against a published schema and re-rendered later, so a figure in a paper can be regenerated and audited rather than just viewed.</p>
</section>
<section id="next" class="level2">
<h2 class="anchored" data-anchor-id="next">Next</h2>
<ul>
<li>Gallery of examples: <a href="https://canvasxpress.org/examples.html" class="uri">https://canvasxpress.org/examples.html</a></li>
<li>Coming from Plotly/Matplotlib: <a href="https://canvasxpress.org/migrate.html" class="uri">https://canvasxpress.org/migrate.html</a></li>
<li>Package: <a href="https://pypi.org/project/canvasxpress/" class="uri">https://pypi.org/project/canvasxpress/</a></li>
</ul>


</section>

 ]]></description>
  <category>Python</category>
  <category>canvasxpress</category>
  <category>bioinformatics</category>
  <category>visualization</category>
  <guid>https://neuhausi.github.io/canvasxpress-blog/posts/python/volcano-plots-in-python/</guid>
  <pubDate>Tue, 22 Sep 2026 04:00:00 GMT</pubDate>
  <media:content url="https://neuhausi.github.io/canvasxpress-blog/posts/python/volcano-plots-in-python/thumbnail.png" medium="image" type="image/png" height="108" width="144"/>
</item>
</channel>
</rss>
