You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
opensensmapR/inst/doc/osem-history.html

502 lines
188 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Norwin Roosen" />
<meta name="date" content="2018-05-26" />
<title>Visualising the History of openSenseMap.org</title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
<link href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20both%3B%0Amargin%3A%200%200%2010px%2010px%3B%0Apadding%3A%204px%3B%0Awidth%3A%20400px%3B%0Aborder%3A%201px%20solid%20%23CCCCCC%3B%0Aborder%2Dradius%3A%205px%3B%0Abackground%2Dcolor%3A%20%23f6f6f6%3B%0Afont%2Dsize%3A%2013px%3B%0Aline%2Dheight%3A%201%2E3%3B%0A%7D%0A%23TOC%20%2Etoctitle%20%7B%0Afont%2Dweight%3A%20bold%3B%0Afont%2Dsize%3A%2015px%3B%0Amargin%2Dleft%3A%205px%3B%0A%7D%0A%23TOC%20ul%20%7B%0Apadding%2Dleft%3A%2040px%3B%0Amargin%2Dleft%3A%20%2D1%2E5em%3B%0Amargin%2Dtop%3A%205px%3B%0Amargin%2Dbottom%3A%205px%3B%0A%7D%0A%23TOC%20ul%20ul%20%7B%0Amargin%2Dleft%3A%20%2D2em%3B%0A%7D%0A%23TOC%20li%20%7B%0Aline%2Dheight%3A%2016px%3B%0A%7D%0Atable%20%7B%0Amargin%3A%201em%20auto%3B%0Aborder%2Dwidth%3A%201px%3B%0Aborder%2Dcolor%3A%20%23DDDDDD%3B%0Aborder%2Dstyle%3A%20outset%3B%0Aborder%2Dcollapse%3A%20collapse%3B%0A%7D%0Atable%20th%20%7B%0Aborder%2Dwidth%3A%202px%3B%0Apadding%3A%205px%3B%0Aborder%2Dstyle%3A%20inset%3B%0A%7D%0Atable%20td%20%7B%0Aborder%2Dwidth%3A%201px%3B%0Aborder%2Dstyle%3A%20inset%3B%0Aline%2Dheight%3A%2018px%3B%0Apadding%3A%205px%205px%3B%0A%7D%0Atable%2C%20table%20th%2C%20table%20td%20%7B%0Aborder%2Dleft%2Dstyle%3A%20none%3B%0Aborder%2Dright%2Dstyle%3A%20none%3B%0A%7D%0Atable%20thead%2C%20table%20tr%2Eeven%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0A%7D%0Ap%20%7B%0Amargin%3A%200%2E5em%200%3B%0A%7D%0Ablockquote%20%7B%0Abackground%2Dcolor%3A%20%23f6f6f6%3B%0Apadding%3A%200%2E25em%200%2E75em%3B%0A%7D%0Ahr%20%7B%0Aborder%2Dstyle%3A%20solid%3B%0Aborder%3A%20none%3B%0Aborder%2Dtop%3A%201px%20solid%20%23777%3B%0Amargin%3A%2028px%200%3B%0A%7D%0Adl%20%7B%0Amargin%2Dleft%3A%200%3B%0A%7D%0Adl%20dd%20%7B%0Amargin%2Dbottom%3A%2013px%3B%0Amargin%2Dleft%3A%2013px%3B%0A%7D%0Adl%20dt%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Aul%20%7B%0Amargin%2Dtop%3A%200%3B%0A%7D%0Aul%20li%20%7B%0Alist%2Dstyle%3A%20circle%20outside%3B%0A%7D%0Aul%20ul%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0Apre%2C%20code%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0Aborder%2Dradius%3A%203px%3B%0Acolor%3A%20%23333%3B%0Awhite%2Dspace%3A%20pre%2Dwrap%3B%20%0A%7D%0Apre%20%7B%0Aborder%2Dradius%3A%203px%3B%0Amargin%3A%205px%200px%2010px%200px%3B%0Apadding%3A%2010px%3B%0A%7D%0Apre%3Anot%28%5Bclass%5D%29%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0A%7D%0Acode%20%7B%0Afont%2Dfamily%3A%20Consolas%2C%20Monaco%2C%20%27Courier%20New%27%2C%20monospace%3B%0Afont%2Dsize%3A%2085%25%3B%0A%7D%0Ap%20%3E%20code%2C%20li%20%3E%20code%20%7B%0Apadding%3A%202px%200px%3B%0A%7D%0Adiv%2Efigure%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0Aimg%20%7B%0Abackground%2Dcolor%3A%20%23FFFFFF%3B%0Apadding%3A%202px%3B%0Aborder%3A%201px%20solid%20%23DDDDDD%3B%0Aborder%2Dradius%3A%203px%3B%0Aborder%3A%201px%20solid%20%23CCCCCC%3B%0Amargin%3A%200%205px%3B%0A%7D%0Ah1%20%7B%0Amargin%2Dtop%3A%200%3B%0Afont%2Dsize%3A%2035px%3B%0Aline%2Dheight%3A%2040px%3B%0A%7D%0Ah2%20%7B%0Aborder%2Dbottom%3A%204px%20solid%20%23f7f7f7%3B%0Apadding%2Dtop%3A%2010px%3B%0Apadding%2Dbottom%3A%202px%3B%0Afont%2Dsize%3A%20145%25%3B%0A%7D%0Ah3%20%7B%0Aborder%2Dbottom%3A%202px%20solid%20%23f7f7f7%3B%0Apadding%2Dtop%3A%2010px%3B%0Afont%2Dsize%3A%20120%25%3B%0A%7D%0Ah4%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23f7f7f7%3B%0Amargin%2Dleft%3A%208px%3B%0Afont%2Dsize%3A%20105%25%3B%0A%7D%0Ah5%2C%20h6%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23ccc%3B%0Afont%2Dsize%3A%20105%25%3B%0A%7D%0Aa%20%7B%0Acolor%3A%20%230033dd%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0Aa%3Ahover%20%7B%0Acolor%3A%20%236666ff%3B%20%7D%0Aa%3Avisited%20%7B%0Acolor%3A%20%23800080%3B%20%7D%0Aa%3Avisited%3Ahover%20%7B%0Acolor%3A%20%23BB00BB%3B%20%7D%0Aa%5Bhref%5E%3D%22http
</head>
<body>
<h1 class="title toc-ignore">Visualising the History of openSenseMap.org</h1>
<h4 class="author"><em>Norwin Roosen</em></h4>
<h4 class="date"><em>2018-05-26</em></h4>
<div id="TOC">
<ul>
<li><a href="#plot-count-of-boxes-by-time">Plot count of boxes by time</a><ul>
<li><a href="#and-exposure">…and exposure</a></li>
<li><a href="#and-grouptag">…and grouptag</a></li>
</ul></li>
<li><a href="#plot-rate-of-growth-and-inactivity-per-week">Plot rate of growth and inactivity per week</a></li>
<li><a href="#plot-duration-of-boxes-being-active">Plot duration of boxes being active</a><ul>
<li><a href="#by-exposure">…by exposure</a></li>
<li><a href="#by-grouptag">…by grouptag</a></li>
<li><a href="#by-year-of-registration">…by year of registration</a></li>
</ul></li>
<li><a href="#more-visualisations">More Visualisations</a></li>
</ul>
</div>
<blockquote>
<p>This vignette serves as an example on data wrangling &amp; visualization with <code>opensensmapr</code>, <code>dplyr</code> and <code>ggplot2</code>.</p>
</blockquote>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># required packages:</span>
<span class="kw">library</span>(opensensmapr) <span class="co"># data download</span>
<span class="kw">library</span>(dplyr) <span class="co"># data wrangling</span>
<span class="kw">library</span>(ggplot2) <span class="co"># plotting</span>
<span class="kw">library</span>(lubridate) <span class="co"># date arithmetic</span>
<span class="kw">library</span>(zoo) <span class="co"># rollmean()</span></code></pre></div>
<p>openSenseMap.org has grown quite a bit in the last years; it would be interesting to see how we got to the current 1781 sensor stations, split up by various attributes of the boxes.</p>
<p>While <code>opensensmapr</code> provides extensive methods of filtering boxes by attributes on the server, we do the filtering within R to save time and gain flexibility. So the first step is to retrieve <em>all the boxes</em>:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># if you want to see results for a specific subset of boxes,</span>
<span class="co"># just specify a filter such as grouptag='ifgi' here</span>
boxes =<span class="st"> </span><span class="kw">osem_boxes</span>()</code></pre></div>
<div id="plot-count-of-boxes-by-time" class="section level1 tabset">
<h1>Plot count of boxes by time</h1>
<p>By looking at the <code>createdAt</code> attribute of each box we know the exact time a box was registered. With this approach we have no information about boxes that were deleted in the meantime, but thats okay for now.</p>
<div id="and-exposure" class="section level2">
<h2>…and exposure</h2>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">exposure_counts =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(exposure) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">count =</span> <span class="kw">row_number</span>(createdAt))
exposure_colors =<span class="st"> </span><span class="kw">c</span>(<span class="dt">indoor =</span> <span class="st">'red'</span>, <span class="dt">outdoor =</span> <span class="st">'lightgreen'</span>, <span class="dt">mobile =</span> <span class="st">'blue'</span>, <span class="dt">unknown =</span> <span class="st">'darkgrey'</span>)
<span class="kw">ggplot</span>(exposure_counts, <span class="kw">aes</span>(<span class="dt">x =</span> createdAt, <span class="dt">y =</span> count, <span class="dt">colour =</span> exposure)) +
<span class="st"> </span><span class="kw">geom_line</span>() +
<span class="st"> </span><span class="kw">scale_colour_manual</span>(<span class="dt">values =</span> exposure_colors) +
<span class="st"> </span><span class="kw">xlab</span>(<span class="st">'Registration Date'</span>) +<span class="st"> </span><span class="kw">ylab</span>(<span class="st">'senseBox count'</span>)</code></pre></div>
<p><img src="data:image/png;base64,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
<p>Outdoor boxes are growing <em>fast</em>! We can also see the introduction of <code>mobile</code> sensor “stations” in 2017. While mobile boxes are still few, we can expect a quick rise in 2018 once the new <a href="https://sensebox.de/blog/2018-03-06-senseBox_MCU">senseBox MCU with GPS support is released</a>.</p>
<p>Lets have a quick summary:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">exposure_counts %&gt;%
<span class="st"> </span><span class="kw">summarise</span>(
<span class="dt">oldest =</span> <span class="kw">min</span>(createdAt),
<span class="dt">newest =</span> <span class="kw">max</span>(createdAt),
<span class="dt">count =</span> <span class="kw">max</span>(count)
) %&gt;%
<span class="st"> </span><span class="kw">arrange</span>(<span class="kw">desc</span>(count))</code></pre></div>
<div class="kable-table">
<table>
<thead>
<tr class="header">
<th align="left">exposure</th>
<th align="left">oldest</th>
<th align="left">newest</th>
<th align="right">count</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left">outdoor</td>
<td align="left">2015-02-18 16:53:41</td>
<td align="left">2018-05-26 08:39:12</td>
<td align="right">1416</td>
</tr>
<tr class="even">
<td align="left">indoor</td>
<td align="left">2015-02-08 17:36:40</td>
<td align="left">2018-05-26 10:29:27</td>
<td align="right">290</td>
</tr>
<tr class="odd">
<td align="left">mobile</td>
<td align="left">2017-05-24 08:16:36</td>
<td align="left">2018-05-24 07:08:32</td>
<td align="right">55</td>
</tr>
<tr class="even">
<td align="left">unknown</td>
<td align="left">2014-05-28 15:36:14</td>
<td align="left">2016-06-25 15:11:11</td>
<td align="right">20</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="and-grouptag" class="section level2">
<h2>…and grouptag</h2>
<p>We can try to find out where the increases in growth came from, by analysing the box count by grouptag.</p>
<p>Caveats: Only a small subset of boxes has a grouptag, and we should assume that these groups are actually bigger. Also, we can see that grouptag naming is inconsistent (<code>Luftdaten</code>, <code>luftdaten.info</code>, …)</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grouptag_counts =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(grouptag) %&gt;%
<span class="st"> </span><span class="co"># only include grouptags with 8 or more members</span>
<span class="st"> </span><span class="kw">filter</span>(<span class="kw">length</span>(grouptag) &gt;=<span class="st"> </span><span class="dv">8</span> &amp;&amp;<span class="st"> </span>!<span class="kw">is.na</span>(grouptag)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">count =</span> <span class="kw">row_number</span>(createdAt))
<span class="co"># helper for sorting the grouptags by boxcount</span>
sortLvls =<span class="st"> </span>function(oldFactor, <span class="dt">ascending =</span> <span class="ot">TRUE</span>) {
lvls =<span class="st"> </span><span class="kw">table</span>(oldFactor) %&gt;%<span class="st"> </span><span class="kw">sort</span>(., <span class="dt">decreasing =</span> !ascending) %&gt;%<span class="st"> </span><span class="kw">names</span>()
<span class="kw">factor</span>(oldFactor, <span class="dt">levels =</span> lvls)
}
grouptag_counts$grouptag =<span class="st"> </span><span class="kw">sortLvls</span>(grouptag_counts$grouptag, <span class="dt">ascending =</span> <span class="ot">FALSE</span>)
<span class="kw">ggplot</span>(grouptag_counts, <span class="kw">aes</span>(<span class="dt">x =</span> createdAt, <span class="dt">y =</span> count, <span class="dt">colour =</span> grouptag)) +
<span class="st"> </span><span class="kw">geom_line</span>(<span class="kw">aes</span>(<span class="dt">group =</span> grouptag)) +
<span class="st"> </span><span class="kw">xlab</span>(<span class="st">'Registration Date'</span>) +<span class="st"> </span><span class="kw">ylab</span>(<span class="st">'senseBox count'</span>)</code></pre></div>
<p><img src="data:image/png;base64,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
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grouptag_counts %&gt;%
<span class="st"> </span><span class="kw">summarise</span>(
<span class="dt">oldest =</span> <span class="kw">min</span>(createdAt),
<span class="dt">newest =</span> <span class="kw">max</span>(createdAt),
<span class="dt">count =</span> <span class="kw">max</span>(count)
) %&gt;%
<span class="st"> </span><span class="kw">arrange</span>(<span class="kw">desc</span>(count))</code></pre></div>
<div class="kable-table">
<table>
<thead>
<tr class="header">
<th align="left">grouptag</th>
<th align="left">oldest</th>
<th align="left">newest</th>
<th align="right">count</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left">Luftdaten</td>
<td align="left">2017-03-14 17:01:16</td>
<td align="left">2018-05-21 02:20:50</td>
<td align="right">109</td>
</tr>
<tr class="even">
<td align="left">ifgi</td>
<td align="left">2016-06-17 08:04:54</td>
<td align="left">2018-05-15 10:27:02</td>
<td align="right">35</td>
</tr>
<tr class="odd">
<td align="left">MakeLight</td>
<td align="left">2015-02-18 16:53:41</td>
<td align="left">2018-02-02 13:50:21</td>
<td align="right">15</td>
</tr>
<tr class="even">
<td align="left">Bad_Hersfeld</td>
<td align="left">2017-07-18 13:32:03</td>
<td align="left">2018-03-22 09:10:07</td>
<td align="right">13</td>
</tr>
<tr class="odd">
<td align="left">luftdaten.info</td>
<td align="left">2017-05-01 10:15:44</td>
<td align="left">2018-05-17 11:47:21</td>
<td align="right">12</td>
</tr>
<tr class="even">
<td align="left">dwih-sp</td>
<td align="left">2016-08-09 08:06:02</td>
<td align="left">2016-11-23 10:16:04</td>
<td align="right">11</td>
</tr>
<tr class="odd">
<td align="left">Che Aria Tira?</td>
<td align="left">2018-03-11 10:50:42</td>
<td align="left">2018-03-11 23:11:20</td>
<td align="right">10</td>
</tr>
<tr class="even">
<td align="left">Luftdaten.info</td>
<td align="left">2017-04-03 14:10:20</td>
<td align="left">2018-04-16 16:31:24</td>
<td align="right">10</td>
</tr>
<tr class="odd">
<td align="left">Feinstaub</td>
<td align="left">2017-04-08 06:38:25</td>
<td align="left">2018-03-29 17:27:55</td>
<td align="right">9</td>
</tr>
<tr class="even">
<td align="left">PGKN</td>
<td align="left">2018-04-08 07:01:57</td>
<td align="left">2018-04-27 18:38:51</td>
<td align="right">9</td>
</tr>
<tr class="odd">
<td align="left">Raumanmeri</td>
<td align="left">2017-03-13 11:35:39</td>
<td align="left">2017-04-27 05:36:20</td>
<td align="right">9</td>
</tr>
<tr class="even">
<td align="left">Sofia</td>
<td align="left">2017-04-11 04:40:11</td>
<td align="left">2018-03-15 13:26:56</td>
<td align="right">9</td>
</tr>
<tr class="odd">
<td align="left">IKG</td>
<td align="left">2017-03-21 19:02:11</td>
<td align="left">2017-12-18 14:30:21</td>
<td align="right">8</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="plot-rate-of-growth-and-inactivity-per-week" class="section level1">
<h1>Plot rate of growth and inactivity per week</h1>
<p>First we group the boxes by <code>createdAt</code> into bins of one week:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">bins =<span class="st"> 'week'</span>
mvavg_bins =<span class="st"> </span><span class="dv">6</span>
growth =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">week =</span> <span class="kw">cut</span>(<span class="kw">as.Date</span>(createdAt), <span class="dt">breaks =</span> bins)) %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(week) %&gt;%
<span class="st"> </span><span class="kw">summarize</span>(<span class="dt">count =</span> <span class="kw">length</span>(week)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">event =</span> <span class="st">'registered'</span>)</code></pre></div>
<p>We can do the same for <code>updatedAt</code>, which informs us about the last change to a box, including uploaded measurements. This method of determining inactive boxes is fairly inaccurate and should be considered an approximation, because we have no information about intermediate inactive phases. Also deleted boxes would probably have a big impact here.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">inactive =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="co"># remove boxes that were updated in the last two days,</span>
<span class="st"> </span><span class="co"># b/c any box becomes inactive at some point by definition of updatedAt</span>
<span class="st"> </span><span class="kw">filter</span>(updatedAt &lt;<span class="st"> </span><span class="kw">now</span>() -<span class="st"> </span><span class="kw">days</span>(<span class="dv">2</span>)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">week =</span> <span class="kw">cut</span>(<span class="kw">as.Date</span>(updatedAt), <span class="dt">breaks =</span> bins)) %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(week) %&gt;%
<span class="st"> </span><span class="kw">summarize</span>(<span class="dt">count =</span> <span class="kw">length</span>(week)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">event =</span> <span class="st">'inactive'</span>)</code></pre></div>
<p>Now we can combine both datasets for plotting:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">boxes_by_date =<span class="st"> </span><span class="kw">bind_rows</span>(growth, inactive) %&gt;%<span class="st"> </span><span class="kw">group_by</span>(event)
<span class="kw">ggplot</span>(boxes_by_date, <span class="kw">aes</span>(<span class="dt">x =</span> <span class="kw">as.Date</span>(week), <span class="dt">colour =</span> event)) +
<span class="st"> </span><span class="kw">xlab</span>(<span class="st">'Time'</span>) +<span class="st"> </span><span class="kw">ylab</span>(<span class="kw">paste</span>(<span class="st">'rate per '</span>, bins)) +
<span class="st"> </span><span class="kw">scale_x_date</span>(<span class="dt">date_breaks=</span><span class="st">&quot;years&quot;</span>, <span class="dt">date_labels=</span><span class="st">&quot;%Y&quot;</span>) +
<span class="st"> </span><span class="kw">scale_colour_manual</span>(<span class="dt">values =</span> <span class="kw">c</span>(<span class="dt">registered =</span> <span class="st">'lightgreen'</span>, <span class="dt">inactive =</span> <span class="st">'grey'</span>)) +
<span class="st"> </span><span class="kw">geom_point</span>(<span class="kw">aes</span>(<span class="dt">y =</span> count), <span class="dt">size =</span> <span class="fl">0.5</span>) +
<span class="st"> </span><span class="co"># moving average, make first and last value NA (to ensure identical length of vectors)</span>
<span class="st"> </span><span class="kw">geom_line</span>(<span class="kw">aes</span>(<span class="dt">y =</span> <span class="kw">rollmean</span>(count, mvavg_bins, <span class="dt">fill =</span> <span class="kw">list</span>(<span class="ot">NA</span>, <span class="ot">NULL</span>, <span class="ot">NA</span>))))</code></pre></div>
<p><img src="data:image/png;base64,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
<p>We see a sudden rise in early 2017, which lines up with the fast growing grouptag <code>Luftdaten</code>. This was enabled by an integration of openSenseMap.org into the firmware of the air quality monitoring project <a href="https://luftdaten.info">luftdaten.info</a>. The dips in mid 2017 and early 2018 could possibly be explained by production/delivery issues of the senseBox hardware, but I have no data on the exact time frames to verify.</p>
</div>
<div id="plot-duration-of-boxes-being-active" class="section level1 tabset">
<h1>Plot duration of boxes being active</h1>
<p>While we are looking at <code>createdAt</code> and <code>updatedAt</code>, we can also extract the duration of activity of each box, and look at metrics by exposure and grouptag once more:</p>
<div id="by-exposure" class="section level2">
<h2>…by exposure</h2>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">duration =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(exposure) %&gt;%
<span class="st"> </span><span class="kw">filter</span>(!<span class="kw">is.na</span>(updatedAt)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">duration =</span> <span class="kw">difftime</span>(updatedAt, createdAt, <span class="dt">units=</span><span class="st">'days'</span>))
<span class="kw">ggplot</span>(duration, <span class="kw">aes</span>(<span class="dt">x =</span> exposure, <span class="dt">y =</span> duration)) +
<span class="st"> </span><span class="kw">geom_boxplot</span>() +
<span class="st"> </span><span class="kw">coord_flip</span>() +<span class="st"> </span><span class="kw">ylab</span>(<span class="st">'Duration active in Days'</span>)</code></pre></div>
<p><img src="data:image/png;base64,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
<p>The time of activity averages at only 152 days, though there are boxes with 759 days of activity, spanning a large chunk of openSenseMaps existence.</p>
</div>
<div id="by-grouptag" class="section level2">
<h2>…by grouptag</h2>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">duration =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(grouptag) %&gt;%
<span class="st"> </span><span class="co"># only include grouptags with 8 or more members</span>
<span class="st"> </span><span class="kw">filter</span>(<span class="kw">length</span>(grouptag) &gt;=<span class="st"> </span><span class="dv">8</span> &amp;&amp;<span class="st"> </span>!<span class="kw">is.na</span>(grouptag) &amp;&amp;<span class="st"> </span>!<span class="kw">is.na</span>(updatedAt)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">duration =</span> <span class="kw">difftime</span>(updatedAt, createdAt, <span class="dt">units=</span><span class="st">'days'</span>))
<span class="kw">ggplot</span>(duration, <span class="kw">aes</span>(<span class="dt">x =</span> grouptag, <span class="dt">y =</span> duration)) +
<span class="st"> </span><span class="kw">geom_boxplot</span>() +
<span class="st"> </span><span class="kw">coord_flip</span>() +<span class="st"> </span><span class="kw">ylab</span>(<span class="st">'Duration active in Days'</span>)</code></pre></div>
<p><img src="data:image/png;base64,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
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">duration %&gt;%
<span class="st"> </span><span class="kw">summarize</span>(
<span class="dt">duration_avg =</span> <span class="kw">round</span>(<span class="kw">mean</span>(duration)),
<span class="dt">duration_min =</span> <span class="kw">round</span>(<span class="kw">min</span>(duration)),
<span class="dt">duration_max =</span> <span class="kw">round</span>(<span class="kw">max</span>(duration)),
<span class="dt">oldest_box =</span> <span class="kw">round</span>(<span class="kw">max</span>(<span class="kw">difftime</span>(<span class="kw">now</span>(), createdAt, <span class="dt">units=</span><span class="st">'days'</span>)))
) %&gt;%
<span class="st"> </span><span class="kw">arrange</span>(<span class="kw">desc</span>(duration_avg))</code></pre></div>
<div class="kable-table">
<table>
<thead>
<tr class="header">
<th align="left">grouptag</th>
<th align="left">duration_avg</th>
<th align="left">duration_min</th>
<th align="left">duration_max</th>
<th align="left">oldest_box</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left">dwih-sp</td>
<td align="left">627 days</td>
<td align="left">549 days</td>
<td align="left">655 days</td>
<td align="left">655 days</td>
</tr>
<tr class="even">
<td align="left">Feinstaub</td>
<td align="left">219 days</td>
<td align="left">4 days</td>
<td align="left">413 days</td>
<td align="left">413 days</td>
</tr>
<tr class="odd">
<td align="left">ifgi</td>
<td align="left">207 days</td>
<td align="left">0 days</td>
<td align="left">622 days</td>
<td align="left">708 days</td>
</tr>
<tr class="even">
<td align="left">Sofia</td>
<td align="left">200 days</td>
<td align="left">15 days</td>
<td align="left">410 days</td>
<td align="left">410 days</td>
</tr>
<tr class="odd">
<td align="left">Bad_Hersfeld</td>
<td align="left">197 days</td>
<td align="left">65 days</td>
<td align="left">312 days</td>
<td align="left">312 days</td>
</tr>
<tr class="even">
<td align="left">Luftdaten</td>
<td align="left">187 days</td>
<td align="left">0 days</td>
<td align="left">424 days</td>
<td align="left">438 days</td>
</tr>
<tr class="odd">
<td align="left">luftdaten.info</td>
<td align="left">183 days</td>
<td align="left">9 days</td>
<td align="left">360 days</td>
<td align="left">390 days</td>
</tr>
<tr class="even">
<td align="left">IKG</td>
<td align="left">163 days</td>
<td align="left">70 days</td>
<td align="left">260 days</td>
<td align="left">431 days</td>
</tr>
<tr class="odd">
<td align="left">Luftdaten.info</td>
<td align="left">86 days</td>
<td align="left">5 days</td>
<td align="left">376 days</td>
<td align="left">418 days</td>
</tr>
<tr class="even">
<td align="left">Che Aria Tira?</td>
<td align="left">75 days</td>
<td align="left">71 days</td>
<td align="left">76 days</td>
<td align="left">76 days</td>
</tr>
<tr class="odd">
<td align="left">Raumanmeri</td>
<td align="left">45 days</td>
<td align="left">7 days</td>
<td align="left">318 days</td>
<td align="left">439 days</td>
</tr>
<tr class="even">
<td align="left">PGKN</td>
<td align="left">35 days</td>
<td align="left">29 days</td>
<td align="left">48 days</td>
<td align="left">48 days</td>
</tr>
</tbody>
</table>
</div>
<p>The time of activity averages at only 191 days, though there are boxes with 655 days of activity, spanning a large chunk of openSenseMaps existence.</p>
</div>
<div id="by-year-of-registration" class="section level2">
<h2>…by year of registration</h2>
<p>This is less useful, as older boxes are active for a longer time by definition. If you have an idea how to compensate for that, please send a <a href="https://github.com/sensebox/opensensmapr/pulls">Pull Request</a>!</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># NOTE: boxes older than 2016 missing due to missing updatedAt in database</span>
duration =<span class="st"> </span>boxes %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">year =</span> <span class="kw">cut</span>(<span class="kw">as.Date</span>(createdAt), <span class="dt">breaks =</span> <span class="st">'year'</span>)) %&gt;%
<span class="st"> </span><span class="kw">group_by</span>(year) %&gt;%
<span class="st"> </span><span class="kw">filter</span>(!<span class="kw">is.na</span>(updatedAt)) %&gt;%
<span class="st"> </span><span class="kw">mutate</span>(<span class="dt">duration =</span> <span class="kw">difftime</span>(updatedAt, createdAt, <span class="dt">units=</span><span class="st">'days'</span>))
<span class="kw">ggplot</span>(duration, <span class="kw">aes</span>(<span class="dt">x =</span> <span class="kw">substr</span>(<span class="kw">as.character</span>(year), <span class="dv">0</span>, <span class="dv">4</span>), <span class="dt">y =</span> duration)) +
<span class="st"> </span><span class="kw">geom_boxplot</span>() +
<span class="st"> </span><span class="kw">coord_flip</span>() +<span class="st"> </span><span class="kw">ylab</span>(<span class="st">'Duration active in Days'</span>) +<span class="st"> </span><span class="kw">xlab</span>(<span class="st">'Year of Registration'</span>)</code></pre></div>
<p><img src="data:image/png;base64,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
</div>
</div>
<div id="more-visualisations" class="section level1">
<h1>More Visualisations</h1>
<p>Other visualisations come to mind, and are left as an exercise to the reader. If you implemented some, feel free to add them to this vignette via a <a href="https://github.com/sensebox/opensensmapr/pulls">Pull Request</a>.</p>
<ul>
<li>growth by phenomenon</li>
<li>growth by location -&gt; (interactive) map</li>
<li>set inactive rate in relation to total box count</li>
<li>filter timespans with big dips in growth rate, and extrapolate the amount of senseBoxes that could be on the platform today, assuming there were no production issues ;)</li>
</ul>
</div>
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>