|
69 | 69 | <script src="../site_libs/quarto-search/fuse.min.js"></script> |
70 | 70 | <script src="../site_libs/quarto-search/quarto-search.js"></script> |
71 | 71 | <meta name="quarto:offset" content="../"> |
| 72 | +<link href="../images/logo-dk-favicon.png" rel="icon" type="image/png"> |
72 | 73 | <script src="../site_libs/quarto-html/quarto.js" type="module"></script> |
73 | 74 | <script src="../site_libs/quarto-html/tabsets/tabsets.js" type="module"></script> |
74 | 75 | <script src="../site_libs/quarto-html/popper.min.js"></script> |
@@ -254,7 +255,7 @@ <h1 class="title">Comet charts in Python</h1> |
254 | 255 | <p><a href="https://www.zanarmstrong.com/#/infovisresearch/">Zan Armstrong’s comet chart</a> has been on my list of hobby projects for a while now. I think it is an elegant solution to visualize statistical mix effects and address Simpson’s paradox, and particularly useful when working with longitudinal data involving different sub-populations. Recently I found a good excuse to spend some time to actually use it as part of a exploratory data analysis on a project.</p> |
255 | 256 | <p>Since I mostly work in Python and have recently fallen in love with <a href="https://altair-viz.github.io/index.html">Altair</a> — for the same reasons as <a href="http://fernandoi.cl/blog/posts/altair/">Fernando explains here</a> — I wondered how the comet chart could be implemented using the <a href="https://idl.cs.washington.edu/papers/vega-lite/">grammar of interactive graphics</a>. It took me a while to figure out how to actually plot the comets. In a previous version, I had <a href="https://github.com/dkapitan/comet-chart/blob/master/comet-chart.ipynb">drawn glyphs using Bokeh</a>. While Altair allows you to plot any SVG path in a graph, this felt a bit hacky and not quite in line with the philosophy of using a grammar of graphics.</p> |
256 | 257 | <p>Thankfully <a href="https://github.com/altair-viz/altair/issues/2395#issuecomment-766454328">Mattijn was quick to suggest using trail-marks</a>, after which it was almost as easy as pie. So here’s an example using a dataset of 20,000 flights for 59 destination airports.</p> |
257 | | -<div id="3ffa05b3" class="cell" data-execution_count="1"> |
| 258 | +<div id="e132e73b" class="cell" data-execution_count="1"> |
258 | 259 | <div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> altair <span class="im">as</span> alt</span> |
259 | 260 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> |
260 | 261 | <span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> vega_datasets</span> |
@@ -329,31 +330,31 @@ <h1 class="title">Comet charts in Python</h1> |
329 | 330 | <span id="cb1-72"><a href="#cb1-72" aria-hidden="true" tabindex="-1"></a></span> |
330 | 331 | <span id="cb1-73"><a href="#cb1-73" aria-hidden="true" tabindex="-1"></a>comet_chart(df) <span class="op">+</span> comet_chart(total, stroke<span class="op">=</span><span class="st">"black"</span>)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div> |
331 | 332 | <div class="cell-output cell-output-stderr"> |
332 | | -<pre><code>/tmp/ipykernel_2960/2480947234.py:23: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead. |
| 333 | +<pre><code>/tmp/ipykernel_2785/2480947234.py:23: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead. |
333 | 334 | .fillna(method="bfill") |
334 | | -/tmp/ipykernel_2960/2480947234.py:37: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead. |
| 335 | +/tmp/ipykernel_2785/2480947234.py:37: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead. |
335 | 336 | .fillna(method="bfill")</code></pre> |
336 | 337 | </div> |
337 | 338 | <div class="cell-output cell-output-display" data-execution_count="1"> |
338 | 339 |
|
339 | 340 | <style> |
340 | | - #altair-viz-775876fe9c21434e979203c9c01c7b03.vega-embed { |
| 341 | + #altair-viz-b0f7a2c044be49169c3796a05b6d90ce.vega-embed { |
341 | 342 | width: 100%; |
342 | 343 | display: flex; |
343 | 344 | } |
344 | 345 |
|
345 | | - #altair-viz-775876fe9c21434e979203c9c01c7b03.vega-embed details, |
346 | | - #altair-viz-775876fe9c21434e979203c9c01c7b03.vega-embed details summary { |
| 346 | + #altair-viz-b0f7a2c044be49169c3796a05b6d90ce.vega-embed details, |
| 347 | + #altair-viz-b0f7a2c044be49169c3796a05b6d90ce.vega-embed details summary { |
347 | 348 | position: relative; |
348 | 349 | } |
349 | 350 | </style> |
350 | | -<div id="altair-viz-775876fe9c21434e979203c9c01c7b03"></div> |
| 351 | +<div id="altair-viz-b0f7a2c044be49169c3796a05b6d90ce"></div> |
351 | 352 | <script type="text/javascript"> |
352 | 353 | var VEGA_DEBUG = (typeof VEGA_DEBUG == "undefined") ? {} : VEGA_DEBUG; |
353 | 354 | (function(spec, embedOpt){ |
354 | 355 | let outputDiv = document.currentScript.previousElementSibling; |
355 | | - if (outputDiv.id !== "altair-viz-775876fe9c21434e979203c9c01c7b03") { |
356 | | - outputDiv = document.getElementById("altair-viz-775876fe9c21434e979203c9c01c7b03"); |
| 356 | + if (outputDiv.id !== "altair-viz-b0f7a2c044be49169c3796a05b6d90ce") { |
| 357 | + outputDiv = document.getElementById("altair-viz-b0f7a2c044be49169c3796a05b6d90ce"); |
357 | 358 | } |
358 | 359 |
|
359 | 360 | const paths = { |
|
0 commit comments