<?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>Epiverse-TRACE: tools for outbreak analytics</title>
<link>https://epiverse-trace.github.io/blog.html#category=DOI</link>
<atom:link href="https://epiverse-trace.github.io/blog-doi.xml" rel="self" type="application/rss+xml"/>
<description>A place for Epiverse-TRACE to share their reflections, learnings, and showcase available tools.</description>
<generator>quarto-1.9.31</generator>
<lastBuildDate>Mon, 25 Aug 2025 00:00:00 GMT</lastBuildDate>
<item>
  <title>Epiverse community engagement and software sustainability for research software</title>
  <dc:creator>Joshua W. Lambert</dc:creator>
  <link>https://epiverse-trace.github.io/posts/epi-community-contrib/</link>
  <description><![CDATA[ 





<p>Software that is developed for research or by researchers can be difficult to maintain given the incentive and funding structures in academia. This remains true for epidemiology, with a large volume of software written during the COVID-19 pandemic, much of which is now abandonware<sup>1</sup>. This does not mean that the software developed to understand the COVID-19 pandemic was bad or does not have utility in understanding future epidemics and pandemics, but just that the capacity to maintain and further develop these tools is not available now the pandemic is no <a href="https://www.who.int/news/item/05-05-2023-statement-on-the-fifteenth-meeting-of-the-international-health-regulations-(2005)-emergency-committee-regarding-the-coronavirus-disease-(covid-19)-pandemic">longer considered an acute public health emergency</a>.</p>
<p>These issues around software sustainability and the academic structures that hinder software longevity were raised by <span class="citation" data-cites="kucharskiCOVID19ResponseIllustrates2020">Kucharski et al. (2020)</span> and were one of the leading reasons for the <a href="https://epiverse-trace.github.io/">Epiverse-TRACE initiative</a>. Alongside the developing novel software (R packages), Epiverse also has a commitment to support the community of package developers in epidemiology and outbreak analytics. The initiative also tries to improve community collaboration and contribution friendliness of open-source software.</p>
<p>This blog post highlights some recent work by Epiverse software engineers to collaborate on research software, or researchware, to help improve an R package that was initially written in the early days of the COVID-19 pandemic (January 2020 - May 2020) to assess the effectiveness of isolation and contact tracing effectiveness <span class="citation" data-cites="hellewellFeasibilityControllingCOVID192020">(Hellewell et al. 2020)</span>. It built on code written for the 2014-2016 West Africa Ebola outbreak to provide insights into ring vaccination <span class="citation" data-cites="kucharskiEffectivenessRingVaccination2016">(Kucharski et al. 2016)</span>. These applications and the general nature of the questions the package addresses suggest that it could be of great help in future infectious disease outbreaks, but has lacked developer resources without pandemic-related priorities.</p>
<section id="the-r-package" class="level2">
<h2 class="anchored" data-anchor-id="the-r-package">The R package</h2>
<p>The R package in question is <a href="https://github.com/epiforecasts/ringbp">{ringbp}</a>. The package has two pieces of functionality: 1) to simulate an infectious disease outbreak using a branching process model with non-pharmaceutical interventions; and 2) to calculate the proportion of simulated outbreaks that are contained (i.e.&nbsp;do not cause a large sustained human-to-human epidemic). The utility of the package’s general model framework has been shown by serving as a template for other epidemiological research such as <a href="https://sophiemeakin.github.io/pepbp/">post-exposure prophylaxis</a>, <a href="https://github.com/lgs85/covidhm">network effects on control</a> <span class="citation" data-cites="firthUsingRealworldNetwork2020">(Firth et al. 2020)</span> and the <a href="https://github.com/timcdlucas/ringbp">impact of self-reporting and isolation adherence</a> <span class="citation" data-cites="davisImperfectToolContact2020">(Davis et al. 2020)</span>.</p>
</section>
<section id="the-problem" class="level2">
<h2 class="anchored" data-anchor-id="the-problem">The problem</h2>
<p>It is understandable that because {ringbp} was written in haste to produce insights to inform pandemic response it did not adhere to all software best practices. Usability, documentation, testing, code style, and (computational) performance could be improved. Certain aspects of model code, like parameterisations, were hard-coded, not providing users the full flexibility that the model could allow.</p>
</section>
<section id="epiverse-contribution" class="level2">
<h2 class="anchored" data-anchor-id="epiverse-contribution">Epiverse contribution</h2>
<p>In the recent months Epiverse has collaborated with {ringbp} developers Seb Funk (also a member of Epiverse) and Carl Pearson (external collaborator), based at the London School of Hygiene and Tropical Medicine and University of North Carolina, respectively, to try and improve the R package, both internally and from the user-experience. The following sections will give brief summaries of some of the collaborative developments.</p>
<section id="user-interface" class="level3">
<h3 class="anchored" data-anchor-id="user-interface">User interface</h3>
<p>The user experience of the package has been refactored. The main simulation function <code>scenario_sim()</code> remains, but its arguments have been modularised to better group model parameters and control arguments. This also makes the package easier to develop further without necessarily introducing many breaking changes and prevents the number of top-level function arguments from expanding.</p>
</section>
<div class="columns">
<div class="column" style="width:47.5%;">
<section id="old" class="level3">
<h3 class="anchored" data-anchor-id="old">Old</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scenario_sim</span>(</span>
<span id="cb1-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.sim =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb1-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">num.initial.cases =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb1-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cap_max_days =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">365</span>,</span>
<span id="cb1-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cap_cases =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>,</span>
<span id="cb1-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r0isolated =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r0community =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>,</span>
<span id="cb1-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">disp.iso =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">disp.com =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.16</span>,</span>
<span id="cb1-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">k =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>,</span>
<span id="cb1-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">delay_shape =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>,</span>
<span id="cb1-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">delay_scale =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb1-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prop.asym =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prop.ascertain =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb1-15">)</span></code></pre></div></div>
</section>
</div><div class="column" style="width:5%;">
<!-- empty column to create gap -->
</div><div class="column" style="width:47.5%;">
<section id="new" class="level3">
<h3 class="anchored" data-anchor-id="new">New</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scenario_sim</span>(</span>
<span id="cb2-2"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb2-3"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">initial_cases =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb2-4"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">offspring =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">offspring_opts</span>(</span>
<span id="cb2-5">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">community =</span> \(n) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnbinom</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mu =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.16</span>),</span>
<span id="cb2-6">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">isolated =</span> \(n) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnbinom</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mu =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb2-7">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asymptomatic =</span> \(n) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnbinom</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mu =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.16</span>)</span>
<span id="cb2-8">  ),</span>
<span id="cb2-9"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">delays =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">delay_opts</span>(</span>
<span id="cb2-10">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">incubation_period =</span> \(n) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rweibull</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">shape =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.32</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.49</span>),</span>
<span id="cb2-11">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">onset_to_isolation =</span> \(n) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rweibull</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">shape =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb2-12">  ),</span>
<span id="cb2-13"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">event_probs =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">event_prob_opts</span>(</span>
<span id="cb2-14">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asymptomatic =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb2-15">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">presymptomatic_transmission =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>,</span>
<span id="cb2-16">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">symptomatic_ascertained =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb2-17">  ),</span>
<span id="cb2-18"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">interventions =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">intervention_opts</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">quarantine =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb2-19"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sim =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sim_opts</span>(</span>
<span id="cb2-20">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cap_max_days =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">365</span>,</span>
<span id="cb2-21">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cap_cases =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span></span>
<span id="cb2-22">  )</span>
<span id="cb2-23">)</span></code></pre></div></div>
</section>
</div>
</div>
<p>The new API gives the user more control over the model’s parameterisation. The incubation period is now specified by the user instead of being set to an estimate for COVID-19. The way offspring and delay distribution functions are specified also means that any distributional or non-parametric form can be supplied, relaxing the assumption that the onset-to-isolation has to be a Weibull distribution.</p>
<p>Users can now specify the proportion of presymptomatic transmission rather than having to understand the skew normal parameterisation used by the simulation model, making it easier to get started with the package for new users.</p>
<p>Lastly on user-facing changes, the naming and style of function arguments has been standardised for consistent use of <a href="https://en.wikipedia.org/wiki/Snake_case">snakecase</a> style and abbreviations.</p>
<section id="documentation" class="level3">
<h3 class="anchored" data-anchor-id="documentation">Documentation</h3>
<p>Function documentation already used {roxygen2}, but did not make use of inheritance or comprehensively document the function output or usage. We used <code>@inheritParams</code> from {roxygen2} to deduplicate, added <code>@return</code> documentation to all functions. We also improved the function argument documentation by following a structure of: <code>&lt;type&gt;: description</code>, for example:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span>param sim a <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">list</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span> with class <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">&lt;ringbp_sim_opts&gt;</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> the simulation control</span>
<span id="cb3-2">  options <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> the \pkg{ringbp} model, returned by [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sim_opts</span>()]</span></code></pre></div></div>
<p>Exported functions now have informative examples (<code>@examples</code>) to showcase how the functions should be used. Function examples now always run (removing <code>\dontrun{}</code>) to catch any errors.</p>
<p>The <a href="https://github.com/anthonynorth/roxyglobals">{roxyglobals}</a> package has been added to automate the management of global variables with the use of the <code>@autoglobal</code> tag.</p>
<p>Vignettes are useful long-form package documentation. Thus far we’ve added one vignette to the package and plan to add more where relevant.</p>
</section>
<section id="bug-fixes" class="level3">
<h3 class="anchored" data-anchor-id="bug-fixes">Bug fixes</h3>
<p>Perhaps more important that any of the software best practices and user interface is the correctness of the code. In our developments we’ve uncovered a few bugs in the previous version of {ringbp}. Errors in the timing of quarantining infected individuals, sampling from the onset-to-isolation distribution, and calculating the generation time from the incubation period have all been identified and fixed.</p>
</section>
<section id="testing" class="level3">
<h3 class="anchored" data-anchor-id="testing">Testing</h3>
<p>To ensure the correctness of the code is maintained with continued package development we have added regression (<a href="https://testthat.r-lib.org/articles/snapshotting.html">snapshot</a>) unit tests. These tests automatically detect if updates to the code cause breaking changes to the output of the exported functions. In combination with continuous integration these regression tests aid developers in finding and fixing bugs.</p>
</section>
<section id="miscellaneous" class="level3">
<h3 class="anchored" data-anchor-id="miscellaneous">Miscellaneous</h3>
<p>There are various other changes in {ringbp} from our work. Examples include: input checking, not specifying erroneous function defaults, updating the package website, and functions that return <code>data.table</code> objects no longer <a href="https://cran.r-project.org/web/packages/data.table/vignettes/datatable-faq.html#sec:why-do-i-have-to-type-dt-sometimes-twice-after-using-to-print-the-result-to-console">returning silently</a>. Mentioned in the introduction, model performance has been incrementally improved, but we’ve not focused on this aspect, and the package will benefit from time spent focusing on this in the future; especially if the set and complexity of non-pharmaceutical interventions in the model expands.</p>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>The {ringbp} R package implements a simple but informative model for infectious disease transmission and interventions. When originally written it included many well-developed aspects, but the time constraints of real-time outbreak response meant several improvements were possible.</p>
<p>Epiverse-TRACE has the opportunity to not only develop new tooling for pandemic preparedness and response, but to contribute to the ecosystem of open-source software in infectious disease epidemiology. We hope that by covering the collaborative developments of {ringbp}, it can illustrate the benefits of bringing software up to date with best practices, and make tools available, accessible and robust when a new epidemic or pandemic occurs, in turn hopefully removing the need for redeveloping similar software in the future.</p>
<p>These efforts are not limited to {ringbp}. Similar contributions have been made to other packages, including <a href="https://epiforecasts.io/EpiNow2/">EpiNow2</a>, and open source communities such as the <a href="https://github.com/epinowcast/">epinowcast</a> community, where documentation, testing, and code enhancements have helped strengthen the forecasting and nowcasting software ecosystem in the last couple of years.</p>
<p>Enhancing the accessibility of software for users and developers by improving its documentation and user interface will hopefully provide a gateway for more external contributors to engage with the project. In the public health landscape of temporal surges in capacity and priorities, better enabling community contributions to open-source software should aid software sustainability.</p>
<p>All of the changes discussed in this blog post can be found in the <a href="https://epiforecasts.io/ringbp/news/index.html">{ringbp} news</a>. For details of developments see the <a href="https://github.com/epiforecasts/ringbp/pulls?q=is%3Apr+is%3Aclosed">pull request history of {ringbp} on GitHub</a>.</p>
</section>
<section id="acknowledgements" class="level2">
<h2 class="anchored" data-anchor-id="acknowledgements">Acknowledgements</h2>
<p>Thanks to Seb Funk, Carl Pearson and James Azam for helpful feedback when drafting this post and for their collaboration on the {ringbp} project.</p>



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-davisImperfectToolContact2020" class="csl-entry">
Davis, Emma L., Tim C. D. Lucas, Anna Borlase, et al. 2020. <em>An Imperfect Tool: Contact Tracing Could Provide Valuable Reductions in <span>COVID-19</span> Transmission If Good Adherence Can Be Achieved and Maintained</em>. <a href="https://doi.org/10.1101/2020.06.09.20124008">https://doi.org/10.1101/2020.06.09.20124008</a>.
</div>
<div id="ref-firthUsingRealworldNetwork2020" class="csl-entry">
Firth, Josh A., Joel Hellewell, Petra Klepac, et al. 2020. <span>“Using a Real-World Network to Model Localized <span>COVID-19</span> Control Strategies.”</span> <em>Nature Medicine</em> 26 (10): 1616–22. <a href="https://doi.org/10.1038/s41591-020-1036-8">https://doi.org/10.1038/s41591-020-1036-8</a>.
</div>
<div id="ref-hellewellFeasibilityControllingCOVID192020" class="csl-entry">
Hellewell, Joel, Sam Abbott, Amy Gimma, et al. 2020. <span>“Feasibility of Controlling <span>COVID-19</span> Outbreaks by Isolation of Cases and Contacts.”</span> <em>The Lancet Global Health</em> 8 (4): e488–96. <a href="https://doi.org/10.1016/S2214-109X(20)30074-7">https://doi.org/10.1016/S2214-109X(20)30074-7</a>.
</div>
<div id="ref-kucharskiEffectivenessRingVaccination2016" class="csl-entry">
Kucharski, Adam J., Rosalind M. Eggo, Conall H. Watson, Anton Camacho, Sebastian Funk, and W. John Edmunds. 2016. <span>“Effectiveness of <span>Ring Vaccination</span> as <span>Control Strategy</span> for <span>Ebola Virus Disease</span>.”</span> <em>Emerging Infectious Diseases</em> 22 (1): 105–8. <a href="https://doi.org/10.3201/eid2201.151410">https://doi.org/10.3201/eid2201.151410</a>.
</div>
<div id="ref-kucharskiCOVID19ResponseIllustrates2020" class="csl-entry">
Kucharski, Adam J., Sebastian Funk, and Rosalind M. Eggo. 2020. <span>“The <span>COVID-19</span> Response Illustrates That Traditional Academic Reward Structures and Metrics Do Not Reflect Crucial Contributions to Modern Science.”</span> <em>PLOS Biology</em> 18 (10): e3000913. <a href="https://doi.org/10.1371/journal.pbio.3000913">https://doi.org/10.1371/journal.pbio.3000913</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p><a href="https://dictionary.cambridge.org/dictionary/english/abandonware">Defined by Cambridge Dictionary</a> as: “software that is no longer produced or supported by the company that originally made it”.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{w._lambert2025,
  author = {W. Lambert, Joshua},
  title = {Epiverse Community Engagement and Software Sustainability for
    Research Software},
  date = {2025-08-25},
  url = {https://epiverse-trace.github.io/posts/epi-community-contrib/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-w._lambert2025" class="csl-entry quarto-appendix-citeas">
W. Lambert, Joshua. 2025. <span>“Epiverse Community Engagement and
Software Sustainability for Research Software.”</span> August 25. <a href="https://epiverse-trace.github.io/posts/epi-community-contrib/">https://epiverse-trace.github.io/posts/epi-community-contrib/</a>.
</div></div></section></div> ]]></description>
  <category>open-source</category>
  <category>R</category>
  <category>R package</category>
  <category>epidemiology</category>
  <category>community</category>
  <category>Epiverse</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/epi-community-contrib/</guid>
  <pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Key considerations for retiring/superseding an R package</title>
  <dc:creator>James Mba Azam</dc:creator>
  <dc:creator>Hugo Gruson</dc:creator>
  <dc:creator>Sebastian Funk</dc:creator>
  <link>https://epiverse-trace.github.io/posts/superseding-bpmodels/</link>
  <description><![CDATA[ 





<p>Most of our work at Epiverse TRACE involves either developing an R package from scratch or adopting and maintaining an existing R package. In the former case, decision-making during development is guided by internal policies documented in the <a href="https://epiverse-trace.github.io/blueprints/">Epiverse-TRACE blueprints</a>. However, a less common scenario for us has been taking on the maintenance of an existing package — a situation we recently encountered with the <a href="https://epiforecasts.github.io/bpmodels/">bpmodels</a> R package.</p>
<p>In this post, I want to share some considerations and lessons learned from maintaining bpmodels, originally developed by Sebastian Funk at the London School of Hygiene &amp; Tropical Medicine (with contributions by Zhian Kamvar and Flavio Finger), and the decision to retire/supersede it with <a href="https://epiverse-trace.github.io/blueprints/">epichains</a>. The aim is not to define strict rules but to spark a conversation about good enough practices and alternative approaches that the R developer community has used or would like to be used more widely.</p>
<p>One of the first considerations was the scope of the package. When maintaining or re-imagining an R package, assessing its scope and identifying opportunities for refinement is crucial. For example, some packages have evolved significantly in the broader R ecosystem to better align with user needs. We will highlight a few examples. <a href="https://github.com/hadley/plyr">plyr</a> was split into <a href="https://dplyr.tidyverse.org/index.html">dplyr</a> and <a href="https://purrr.tidyverse.org/index.html">purrr</a> for manipulating data frame and list objects respectively, reflecting more specialized functionality based on object types. Similarly, reshape evolved into <a href="https://github.com/hadley/reshape">reshape2</a><sup>1</sup> and currently into <a href="https://tidyr.tidyverse.org/index.html">tidyr</a>, with each iteration simplifying and improving upon its predecessor. Another example is the <a href="https://github.com/njtierney/naniar/#a-note-on-the-name">renaming</a> of ggmissing into the more generalized <a href="https://naniar.njtierney.com/">naniar</a>. In the epidemiology ecosystem, two examples include the evolution of the <a href="https://epiforecasts.github.io/EpiNow/">EpiNow</a> into <a href="https://epiforecasts.github.io/EpiNow2/">EpiNow2</a> and <a href="https://www.repidemicsconsortium.org/incidence/">incidence</a> to <a href="https://www.reconverse.org/incidence2/index.html">incidence2</a>.</p>
<p>For bpmodels, we wanted to <a href="https://github.com/epiverse-trace/epichains/issues/142">unify the simulation functions</a> (existing as two functions previously) and improve the function signature by <a href="https://github.com/epiverse-trace/epichains/pull/33">renaming</a> several of the arguments for readability. We also wanted to <a href="https://github.com/epiverse-trace/epichains/issues/4">introduce an object-oriented workflow</a> to aid in interoperability (in some inputs and outputs) with existing tools such as <a href="https://www.repidemicsconsortium.org/epicontacts/">epicontacts</a> and <a href="https://epiverse-trace.github.io/epiparameter/">epiparameter</a>. Moreover, the object-oriented backend would also allow us to implement custom methods for printing, summarising and aggregating the simulation output. Some of these considerations would have been less disruptive and in line with the concept of progressive enhancement discussed in <a href="https://epiverse-trace.github.io/posts/progressive-enhancement/">a previous blogpost</a>. However, the change in function name and signature would have led to a lot of disruptions including <a href="https://r-pkgs.org/lifecycle.html#deprecating-a-function">deprecating</a> the existing functions and arguments.</p>
<p>One thing is clear from the examples on scope changes - they often lead to name changes. Another important decision was whether to rebrand the package with a new name. A new name can signal a fresh approach and address limitations of the original package. The most popular example is the renaming of ggplot to <a href="https://ggplot2.tidyverse.org/index.html">ggplot2</a>. Others include renaming reshape to reshape2 and further, tidyr. However, changing a package’s name can be disruptive and cause <a href="https://r-pkgs.org/lifecycle.html#sec-lifecycle-breaking-change-definition">breaking changes</a> in downstream packages or workflows that use them. The process, if not well handled, can lead to confusion and frustration in the user and developer community. With this in mind and to enable reproducibility of existing work using bpmodels, we decided to fork the <a href="https://epiforecasts.github.io/bpmodels/">bpmodels</a> repository to the Epiverse-TRACE GitHub organisation and maintain the old package. At the same time, we introduced epichains as the successor. The name reflects the fact that it is a package for simulating and analysing <em>epidemiological transmission chains</em>.</p>
<p>A second key consideration is the plans that the original package author(s) may have had and their views on any future changes. In our case, this was fairly straightforward because the maintainer of the original package was fully involved in the refactoring process. We were able to reach and receive approval from another package author who had made substantial contributions. More generally, however, bringing all package authors on board with, for example, changes in scope and name is an important step in taking on maintenance of a package and one that should not be neglected.</p>
<p>We also had to consider whether to archive bpmodels or allow it to co-exist with epichains. We decided to keep bpmodels accessible to sustain the reproducibility of existing code using the package. The package was moved back to the epiforecasts <a href="https://epiforecasts.github.io/bpmodels/">GitHub organisation</a> where it originated from. We, however, added a <a href="https://github.com/epiforecasts/bpmodels/blob/main/README.Rmd#L19">lifecycle badge</a> to communicate the package’s retired status and text in the README about <a href="https://github.com/epiforecasts/bpmodels/blob/main/README.Rmd#L29">our plans</a> to only maintain the required infrastructure to keep the package running but not to add any new features.</p>
<p>Another technical consideration was how to handle previous contributions recorded as commit histories. When forking a package, it’s important to decide whether to retain the commit history. Options include squashing the history to start with a clean slate, which risks losing visibility of past contributions, or tagging the HEAD commit of the original repository and building from there. For bpmodels, we decided to go with the second approach, which allowed us to keep the GitHub commit history intact to retain the contributions of its original authors.</p>
<p><a href="https://semver.org/">Semantic versioning</a> was another <a href="https://github.com/epiverse-trace/epichains/issues/32">key decision point</a>. Since epichains was not going to be available immediately but would be developed in the open (on GitHub), we needed to consider how to communicate that to potential users. We decided to start at version <code>0.0.0.9999</code> to signal an experimental and unstable phase<sup>2</sup> while iterating on features through <a href="https://github.com/epiverse-trace/epichains/releases/tag/v0.1.0">minor releases</a>.</p>
<p>Throughout this process, we drew inspiration from various sources. Hadley Wickham’s <a href="https://github.com/hadley/reshape/blob/master/README.md#introduction">reasoning</a> for reshape2 as a reboot of reshape and Nicholas Tierney’s <a href="https://github.com/njtierney/naniar/#a-note-on-the-name">reason</a> for renaming ggmissing to naniar were helpful. Additionally, a talk at UseR! 2024 entitled <a href="https://userconf2024.sched.com/event/1c90V/r-evolution-the-retirement-of-r-packages-with-many-reverse-dependencies-edzer-pebesma-university-of-muenster-roger-bivand-norwegian-school-of-economics">“retiring packages with extensive reverse dependencies”</a> offered practical advice.</p>
<p>This transition has raised several questions for the community. How do you decide whether to supersede or deprecate a package? What strategies have worked for maintaining backward compatibility while introducing new tools? How do you document and communicate major changes to users? How is all of this done while appropriately crediting past contributions and retain discoverability and citation/use tracking?</p>
<p>We’d love to hear your thoughts and experiences. Let’s start a conversation about maintaining and evolving open-source tools in a sustainable way.</p>




<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Notice the URL points to <a href="https://github.com/hadley/reshape">reshape</a> instead of reshape2 although the README mentions the latter. The README however lays out the reasons for the evolution.↩︎</p></li>
<li id="fn2"><p>See more details on R package versioning and what they communicate in the <a href="https://r-pkgs.org/lifecycle.html#sec-lifecycle-evolution">R packages book</a>.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{mba_azam2025,
  author = {Mba Azam, James and Gruson, Hugo and Funk, Sebastian},
  title = {Key Considerations for Retiring/Superseding an {R} Package},
  date = {2025-02-03},
  url = {https://epiverse-trace.github.io/posts/superseding-bpmodels/},
  doi = {10.59350/zabx5-3x070},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-mba_azam2025" class="csl-entry quarto-appendix-citeas">
Mba Azam, James, Hugo Gruson, and Sebastian Funk. 2025. <span>“Key
Considerations for Retiring/Superseding an R Package.”</span> February
3. <a href="https://doi.org/10.59350/zabx5-3x070">https://doi.org/10.59350/zabx5-3x070</a>.
</div></div></section></div> ]]></description>
  <category>software lifecycles</category>
  <category>R</category>
  <category>R package</category>
  <category>software design</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/superseding-bpmodels/</guid>
  <pubDate>Mon, 03 Feb 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Licensing R packages with code and data: learnings from submitting to CRAN</title>
  <dc:creator>Joshua Lambert</dc:creator>
  <dc:creator>Chris Hartgerink</dc:creator>
  <link>https://epiverse-trace.github.io/posts/data-licensing-cran.html</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>This is a follow-up blog post to the <a href="data-licensing.html"><em>Dual licensing R packages with code and data</em></a> post published in September 2024. It contains learnings from submitting <strong>epiparameter</strong> to CRAN with a dual license.</p>
</div>
</div>
<section id="overview-of-previous-blog-post-on-r-package-licensing" class="level3">
<h3 class="anchored" data-anchor-id="overview-of-previous-blog-post-on-r-package-licensing">Overview of previous blog post on R package licensing</h3>
<p>We previously published a <a href="data-licensing.html">post on the Epiverse-TRACE blog discussing the importance of licensing code and data for open source</a>. It covered the differences between open source licenses for code and those that are required for other forms of information, in our case, data. R packages most commonly distribute code, and therefore require an <a href="https://cran.r-project.org/doc/FAQ/R-exts.html#Licensing">appropriate open source license</a>. Less frequently, R packages are used to bundle and share data, so-called <a href="https://r-pkgs.org/data.html">“data packages”</a>, and require an applicable license for reuse and redistribution. We recommend reading <a href="data.licensing.html">the original blog post</a> for a more in-depth explanation of each of these points.</p>
<p>However, since publishing the original post, the last section, <em>Licensing code and data in one R package</em>, has become outdated given our experience submitting the epiparameter package to CRAN with a dual-license. This blog post provides an updated <em>Licensing code and data in one R package</em> section with learnings from epiparameter package development and CRAN submission.</p>
</section>
<section id="licensing-code-and-data-in-one-r-package" class="level3">
<h3 class="anchored" data-anchor-id="licensing-code-and-data-in-one-r-package">Licensing code and data in one R package</h3>
<p>If you are developing an R package that has both code and data as primary objects of (roughly) equal importance, a software license inadequately covers the data, and a data license inadequately covers the code. Dual licensing can help resolve this issue. This means there is one license for code (for example, <a href="https://mit-license.org">MIT license</a>) and another license for the included data (for example, <a href="https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt">Public Domain Dedication</a>).</p>
<p>After conducting an online search, dual licensing for R packages seems rare. An interesting example of dual licensing is the <a href="https://github.com/igraph/igraphdata/blob/main/LICENSE"><strong>igraphdata</strong> package</a>, which contains several licenses: One for each dataset included in the package. Similar to igraphdata, we dual licensed the <a href="https://github.com/epiverse-trace/epiparameter"><strong>epiparameter</strong> package</a>, which until versus v0.4.0 contained both code and data. We <a href="https://github.com/epiverse-trace/epiparameter/blob/v0.3.0/DESCRIPTION#L28">licensed the code using the <code>DESCRIPTION</code> file</a> and used <a href="https://github.com/epiverse-trace/epiparameter/blob/v0.3.0/LICENSE">the <code>LICENSE</code> file</a> to license the data under CC0. Concretely, we included this additional text in <code>LICENSE</code> to clarify the dual license and that we recommend citing the original source regardless:</p>
<blockquote class="blockquote">
<p>All data included in the epiparameter R package is licensed under CC0 (<a href="https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt" class="uri">https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt</a>). This includes the parameter database (extdata/parameters.json) and data in the data/ folder. Please cite the individual parameter entries in the database when used.</p>
</blockquote>
<p>However, upon submission of epiparameter to CRAN, the dual licensing approach was rejected. The CRAN package reviewer stated:</p>
<blockquote class="blockquote">
<p>A package can only be licensed as a whole. It can have a single license or a set of <em>alternative</em> licenes. If the data have to be licensed differently then the code, you have to provide the data in a separate data package with the other license.</p>
</blockquote>
<p>Therefore, we decided to separate the data, originally stored in epiparameter, into a package called <a href="https://github.com/epiverse-trace/epiparameterDB"><strong>epiparameterDB</strong></a>. This package is solely <a href="https://github.com/epiverse-trace/epiparameterDB/blob/main/DESCRIPTION#L15">licensed under CC0</a>, and epiparameter can then also be solely <a href="https://github.com/epiverse-trace/epiparameter/blob/main/DESCRIPTION#L28">licensed under MIT</a>. Both packages are now hosted on CRAN using a single license dedicated to code or data.</p>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Tip
</div>
</div>
<div class="callout-body-container callout-body">
<p>It is often desirable to host an R package on CRAN as it enables it to be easily installed (from binary if on Mac or Windows), it gives the package some validity as a non-trivial and secure piece of software to install and use.</p>
<p>It is not necessary nor beneficial for all R packages to be hosted on CRAN, and it does come with some drawbacks, such as the dual licensing restriction of code and data, but for our case with the epiparameter package, we deemed it better to host on CRAN and split the code and data into epiparameter and epiparameterDB, respectively.</p>
</div>
</div>
<p>When including data in your R package from other sources it is important to check that the license of your package and the data is compatible<sup>1</sup>, or that the individual data license is clearly stated, as in igraphdata. For epiparameterDB, we consider model estimates as facts (that is, not copyrightable).</p>
<hr>
<p>This blogpost provides an addendum to our original post <a href="data-licensing.html">Dual licensing R packages with code and data</a>, providing our experience and outcomes from submitting epiparameter – and the resulting epiparmeterDB package – to CRAN in a conformant manner. In addition to the requirements and benefits of open source licensing of open software and data in the first post, we hope this follow-up post provides practical information that will be of use to other R package developers, or software developers and open data curators more broadly.</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>See <a href="https://juliasilge.com/blog/sentiment-lexicons/">this blog post by Julia Silge on including external data sets into an R package and rectifying incompatibilities with license</a>↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{lambert2025,
  author = {Lambert, Joshua and Hartgerink, Chris},
  title = {Licensing {R} Packages with Code and Data: Learnings from
    Submitting to {CRAN}},
  date = {2025-01-20},
  url = {https://epiverse-trace.github.io/posts/data-licensing-cran.html},
  doi = {10.59350/afsfa-bx908},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-lambert2025" class="csl-entry quarto-appendix-citeas">
Lambert, Joshua, and Chris Hartgerink. 2025. <span>“Licensing R Packages
with Code and Data: Learnings from Submitting to CRAN.”</span> January
20. <a href="https://doi.org/10.59350/afsfa-bx908">https://doi.org/10.59350/afsfa-bx908</a>.
</div></div></section></div> ]]></description>
  <category>R</category>
  <category>open-source</category>
  <category>package development</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/data-licensing-cran.html</guid>
  <pubDate>Mon, 20 Jan 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Dual licensing R packages with code and data</title>
  <dc:creator>Joshua Lambert</dc:creator>
  <dc:creator>Chris Hartgerink</dc:creator>
  <link>https://epiverse-trace.github.io/posts/data-licensing.html</link>
  <description><![CDATA[ 





<p>Licenses are an important topic within open source. Without licenses, information or code can be publicly available but not legally available for reuse or redistribution. The open source software community’s most common licenses are <a href="https://mit-license.org">the MIT license</a> or the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GNU GPLv3</a>.</p>
<p>When you read the MIT or GNU license, you can see they are rather specific:</p>
<blockquote class="blockquote">
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”) [MIT License]</p>
</blockquote>
<p>and</p>
<blockquote class="blockquote">
<p>The GNU General Public License is a free, copyleft license for software and other kinds of works.</p>
</blockquote>
<p>They aim to cover primarily software, not other forms of information such as, for example, data.</p>
<section id="licensing-only-code-in-r-packages" class="level3">
<h3 class="anchored" data-anchor-id="licensing-only-code-in-r-packages">Licensing only code in R packages</h3>
<p>Given the importance of a license for redistribution, CRAN requires R packages to contain an <a href="https://cran.r-project.org/doc/FAQ/R-exts.html#Licensing">open-source license</a>.<sup>1</sup> As one of the most important distributors for R packages historically, this rule has become the de facto standard.</p>
<p>An R package is licensed appropriately when the license is stated in the metadata <code>DESCRIPTION</code> file and, if necessary, in the <code>LICENSE</code> file. We recommend including the <code>LICENSE</code> file, with the license year and exact copyright holder (for example, an organization or a specific individual). Some R package developers choose to include a copy of the license but this is <a href="https://r-pkgs.org/license.html#key-files">not bundled in the R package when it is built</a>. You can <a href="https://github.com/epiverse-trace/cfr/blob/29ee12aa9b8a49eedb9207d95c25c13d7d4e0ace/DESCRIPTION#L27">find an example of a <code>DESCRIPTION</code> file here</a> and <a href="https://github.com/epiverse-trace/cfr/blob/main/LICENSE">find an example <code>LICENSE</code> here</a>.</p>
</section>
<section id="licensing-only-data-in-r-packages" class="level3">
<h3 class="anchored" data-anchor-id="licensing-only-data-in-r-packages">Licensing only data in R packages</h3>
<p>It can be the case that an R package is primarily used to bundle and share a data set, for example to allow a user to easily download the data and load it into R. For example, <a href="https://github.com/jennybc/gapminder"><strong>gapminder</strong></a> and <a href="https://github.com/allisonhorst/palmerpenguins"><strong>palmerpenguins</strong></a>. As an aside, some in the R developer community<sup>2</sup> dissuade the use of R packages used primarily for data, often referred to as <a href="https://r-pkgs.org/data.html">“data packages”</a>, and instead advocate to host data online and use the several API packages available in R to access the data. <!-- Data packages are often small, openly accessibly data sets that are used to showcase the functionality of a package. In these cases the data is secondary to the code, and as such many of the R packages with these "toy" data sets only state a software license.  --></p>
<p>Software licenses do not apply to data. One piece of data cannot be copyrighted, as facts cannot be copyrighted, but a collection of data in a database can come with rights. In Europe, UK, and Russia, databases can have rights if they are a substantial and original piece of work.<sup>3</sup> This is called <a href="https://en.wikipedia.org/wiki/Database_right">the “sui generis” database right</a>. The USA and Brazil do not recognize this database right. Data compiled from various databases that themselves are copyrighted would need to follow the licenses of those respective databases.</p>
<p>Data need licenses such as the Public Domain Dedication or the Creative Commons Attribution to maximize redistribution. Such <a href="https://r-pkgs.org/license.html#code-you-write">general licenses</a> help minimize differences among countries that do and do not recognize database rights. Given that any copyright limitations (even attribution) mean they only apply when the database right is recognized, we recommend the most minimal option: The Public Domain Dedication. This levels the playing field for reuse and redistribution, no matter the jurisdiction.</p>
</section>
<section id="licensing-code-and-data-in-one-r-package" class="level3">
<h3 class="anchored" data-anchor-id="licensing-code-and-data-in-one-r-package">Licensing code and data in one R package</h3>
<div class="callout callout-style-default callout-warning callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Warning
</div>
</div>
<div class="callout-body-container callout-body">
<p>This section on dual licensing was first published in September 2024. Since publishing, the <strong>epiparameter</strong> package is no longer dual licensed due to CRAN requirements.</p>
<p>Please <a href="data-licensing-cran.html#licensing-code-and-data-in-one-r-package">click here to see the updated version of the this section in a new post</a>, which updates the <em>Licensing code and data in one R package</em> section in light of our experience dual licensing an R package and CRAN.</p>
</div>
</div>
<p>But what to do if your R package has both code and data as primary objects of (roughly) equal importance?</p>
<p>In these cases a software license inadequately covers the data, and a data license inadequately covers the code. Dual licensing can help resolve this issue. This means there is one license for code (for example, MIT license) and another license for the included data (for example, Public Domain Dedication).</p>
<p>After conducting an online search, dual licensing for R packages seems rare. An interesting example of dual licensing is the <a href="https://github.com/igraph/igraphdata/blob/main/LICENSE"><strong>igraphdata</strong> package</a>, which contains several licenses: One for each dataset included in the package. Similar to igraphdata, in our own <a href="https://github.com/epiverse-trace/epiparameter"><strong>epiparameter</strong> package</a> we dual licensed the code and data as well. We <a href="https://github.com/epiverse-trace/epiparameter/blob/4f7008063040fc4a0b436a9e4d2adb9bb7022f6c/DESCRIPTION#L21">licensed the code using the <code>DESCRIPTION</code> file</a> and used <a href="https://github.com/epiverse-trace/epiparameter/blob/main/LICENSE">the <code>LICENSE</code> file</a> to license the data under CC0. Concretely, we include this additional text in <code>LICENSE</code> to clarify the dual license and that we recommend citing the original source regardless:</p>
<blockquote class="blockquote">
<p>All data included in the epiparameter R package is licensed under CC0 (<a href="https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt" class="uri">https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt</a>). This includes the parameter database (extdata/parameters.json) and data in the data/ folder. Please cite the individual parameter entries in the database when used.</p>
</blockquote>
<p>When including data in your R package from other sources it is important to check that the license of your package and the data is compatible<sup>4</sup>, or that the individual data license is clearly stated, as in igraphdata. For epiparameter, we consider model estimates as facts (that is, not copyrightable).</p>
<hr>
<p>This blogpost helps explain a pattern of dual licensing rarely seen in the wild, and how to implement it in a CRAN conformant manner. By sharing this, we hope that those cases where people want to license both code and data, have a resource we wish we had while exploring this topic. Whether or not data packages and combined code + data packages should exist, is a question for another day.</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>For a full list of license accepted by CRAN see: <a href="https://svn.r-project.org/R/trunk/share/licenses/license.db" class="uri">https://svn.r-project.org/R/trunk/share/licenses/license.db</a> and they also accept stating the license as <a href="https://cran.r-project.org/doc/manuals/R-exts.html#Licensing-1">“Unlimited” for unrestricted distribution</a>.↩︎</p></li>
<li id="fn2"><p>A discussion of data and R packages can be found here: <a href="https://github.com/ropensci/unconf17/issues/61" class="uri">https://github.com/ropensci/unconf17/issues/61</a>. This thread is used as an example of some thoughts on packaging data in R but we acknowledge it is from 2017 so the opinions of the individuals in this thread may have changed.↩︎</p></li>
<li id="fn3"><p>To see the legal definition of the database right in Europe, and what constitutes it, see the <a href="https://eur-lex.europa.eu/eli/dir/1996/9/oj/eng">European Union Directive 96/9/EC</a>↩︎</p></li>
<li id="fn4"><p>See <a href="https://juliasilge.com/blog/sentiment-lexicons/">this blog post by Julia Silge on including external data sets into an R package and rectifying incompatibilities with license</a>↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{lambert2024,
  author = {Lambert, Joshua and Hartgerink, Chris},
  title = {Dual Licensing {R} Packages with Code and Data},
  date = {2024-09-23},
  url = {https://epiverse-trace.github.io/posts/data-licensing.html},
  doi = {10.59350/4c9r0-71526},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-lambert2024" class="csl-entry quarto-appendix-citeas">
Lambert, Joshua, and Chris Hartgerink. 2024. <span>“Dual Licensing R
Packages with Code and Data.”</span> September 23. <a href="https://doi.org/10.59350/4c9r0-71526">https://doi.org/10.59350/4c9r0-71526</a>.
</div></div></section></div> ]]></description>
  <category>R</category>
  <category>open-source</category>
  <category>package development</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/data-licensing.html</guid>
  <pubDate>Mon, 23 Sep 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Some thoughts after a trial run of GitHub’s Copilot Workspace</title>
  <dc:creator>Joshua W. Lambert</dc:creator>
  <dc:creator>James Mba Azam</dc:creator>
  <dc:creator>Pratik Gupte</dc:creator>
  <dc:creator>Adam Kucharski</dc:creator>
  <link>https://epiverse-trace.github.io/posts/copilot-workspace/</link>
  <description><![CDATA[ 





<p>GitHub recently previewed <a href="https://github.blog/2024-04-29-github-copilot-workspace/">‘Copilot Workspace’</a>, which aims to use generative AI to assist software developers. Rather than just giving in-line suggestions, as GitHub copilot does, workspace allows users to map out and execute entire projects. We got early preview access to the tool, so decided to see how well it performed for our needs in Epiverse-TRACE.</p>
<p>In the Epiverse-TRACE initiative we aim to develop an ecosystem of epidemic analytics tools as <a href="https://digitalpublicgoods.net/">Digital Public Goods</a> in the form of R packages. We aim to <a href="https://epiverse-trace.github.io/blueprints/">follow best-practices</a> given that our tools will be used to inform public health decisions. For efficiency, we use a range of development tools, including integrated development environments (IDE), such as RStudio and Visual Studio Code, other R packages to help check and document our code, for example {lintr} and {roxygen2}, and version control and code sharing tools, git and GitHub.</p>
<p>Given the rapid development and increasing availability to artificial intelligence (AI) models, specifically large language models, offer the potential to be another development tool to add to the arsenal of researchers and software engineers to enhance productivity and improve the reliability of the code we write and others depend upon <span class="citation" data-cites="vanHoek2024">(Hoek et al. 2024)</span>. Large language models like ChatGPT from OpenAI, Gemini from Google, Claude from Anthropic, as well as many others and new ones frequently appearing, have presented opportunities to quickly generate material – text, code and images – from text prompts.</p>
<p>A small group of Epiverse-TRACE professors and research software engineers decided to explore the suitability of one such, GitHub Copilot integrated with GitHub Workspaces, for some typical use cases encountered in our day-to-day work. We do note that many other such tools are available, and we chose Copilot in Workspaces as our code is hosted on GitHub, making for easy evaluation of the specific contribution of the AI tool. However, some of our broad conclusions are based on using other tools for similar tasks.</p>
<p>The aim of this blog post is to summarise our experiences with Copilot and Workspaces, and share our thoughts more generally about how the current feature set of AI-powered development tools could help with our daily development tasks, and with research software development at large. We evaluated Copilot workspace across three tasks of varying difficulty and requirements:</p>
<ul>
<li><p>Experiment 1: Exporting an R function by updating the documentation</p></li>
<li><p>Experiment 2: Adding a basic epidemic model to an existing R package that contains other epidemiological models</p></li>
<li><p>Experiment 3: Conducting a code review on an R package</p></li>
</ul>
<section id="experiment-1-export-an-r-function-by-updating-the-documentation" class="level2">
<h2 class="anchored" data-anchor-id="experiment-1-export-an-r-function-by-updating-the-documentation">Experiment 1: Export an R function by updating the documentation</h2>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Difficulty level: basic</p>
</div>
</div>
<p>The first experiment was on the {EpiNow2} R package. An existing <a href="https://github.com/epiforecasts/EpiNow2/issues/681">Issue #681</a> was chosen. It was a simple task to evaluate Copilot workspace’s ability to interpret requests that require small changes to the codebase of a package (i.e.&nbsp;can be achieved in a single commit by changing less than 5 lines of code). The issue stated that an internal function, <code>epinow2_cmdstan_model()</code> should be exported, with the issue description explaining this would help users specify custom options for running the models.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://epiverse-trace.github.io/posts/copilot-workspace/epinow2_issue.png" class="img-fluid figure-img"></p>
<figcaption>Screenshot of EpiNow2 package issue 681 which was used as an example application of GitHub Copilot Workspace.</figcaption>
</figure>
</div>
<!-- markdownlint-disable MD024 -->
<section id="outcome" class="level3">
<h3 class="anchored" data-anchor-id="outcome">Outcome</h3>
<p>The specification provided by Copilot workspace diagnosed the issue requirements, mentioning that the <code>NAMESPACE</code> file, which stores information on functions offered by a package and functions imported from other packages, would have to be updated for the R package to export this currently unexported function. The proposed solution also addressed the desired changes, stating that the function was to be exported and the keyword <code>internal</code> would be removed. The automatically generated plan proposed to edit the file documentation and <code>NAMESPACE</code>, but we edited this to more specifically replace the <code>@keyword internal</code> {roxygen} tag with <code>@export</code>.</p>
</section>
<section id="our-thoughts" class="level3">
<h3 class="anchored" data-anchor-id="our-thoughts">Our thoughts</h3>
<p>The implementation offered by GitHub copilot workspace was correct and replaced <code>@keywords internal</code> with <code>@export</code> in the correct function documentation <code>epinow2_stan_model()</code>.</p>
<p>However, it also changed the formatting of one of the function arguments (<code>@param model</code>) by moving some text to the next line and added a comma to the last but one item listed in the sentence. (It seems AI has taken a side on the Oxford comma debate).</p>
<p>Overall, this test case of GitHub copilot workspace was a partial success. It correctly recognised the links between inline R function documentation, Roxygen tags, and the R-specific documentation files in <code>man/</code>. However, it (naturally) does not have a mechanistic understanding of package development and how changing tags in documentation is used to auto-update doc files using development tools. It correctly modified the part of the file needed to export an internal function. This showcases an example of where this technology can be beneficial: those new to a language or paradigm that have not yet picked up all of the development details that are often second nature to experienced developers. In this example, the time taken to make this change in GitHub copilot workspace was likely ~10x longer than what our RSEs would take. However, if someone was used to developing in say, Python, and was new to the conventions of exporting functions in R using {roxygen} documentation, this test case shows how copilot workspace can reliably assist. On the other hand, because these changes make no reference to standard development tools, they would not help new developers learn how or where to use them.</p>
<p>The changes made will still require the user to manually run the documentation (using either <code>devtools::document()</code> or <code>roxygen2::roxygenize()</code>) to update the package <code>NAMESPACE</code> for the function to be exported. Our recommendation would be for AI tools to integrate with and call development tools used by developers (analogous to pre-commit hooks running tools before committing) to make sure this is taken care of all in a single generative step.</p>
</section>
</section>
<section id="experiment-2-add-a-simple-epidemic-model-to-an-r-package-that-contains-more-complex-models" class="level2">
<h2 class="anchored" data-anchor-id="experiment-2-add-a-simple-epidemic-model-to-an-r-package-that-contains-more-complex-models">Experiment 2: Add a simple epidemic model to an R package that contains more complex models</h2>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Difficulty level: moderate to high</p>
</div>
</div>
<p>{epidemics} is an Epiverse-TRACE R package that exports a range of compartmental epidemiological models of varying complexities and applications.</p>
<p>In the second test case, we created an issue in the {epidemics} R package requesting a basic SIR model, with the issue description requesting the model to have no age structure and to use existing functionality in the package to specify a disease intervention. Additionally, the issue requested that the model be solved with the {deSolve} R package, which is a differential equation solver in R. A basic SIR model would have been new to the package, but one of several other compartmental models, and simpler than the models already implemented.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://epiverse-trace.github.io/posts/copilot-workspace/epidemics_issue.png" class="img-fluid figure-img"></p>
<figcaption>Screenshot of epidemics package issue 238 which was used as an example application of GitHub Copilot Workspace.</figcaption>
</figure>
</div>
<section id="outcome-1" class="level3">
<h3 class="anchored" data-anchor-id="outcome-1">Outcome</h3>
<p>GitHub copilot workspace outlined the existing functionality in the package and proposed changes including adding a new file called <code>R/model_sir.R</code>, which follows the <code>model_*.R</code> naming convention used in {epidemics}. As requested, copilot also proposed that the new SIR model would support the use of interventions that are already been implemented in the package.</p>
</section>
<section id="our-thoughts-1" class="level3">
<h3 class="anchored" data-anchor-id="our-thoughts-1">Our thoughts</h3>
<p>The code generated was an R function that constructed a basic SIR model, and this was well documented using a {roxygen2} documentation block. However, several aspects of the code generated did not match the proposal generated by copilot workspace, and the code contained inadvisable coding practices in R (i.e.&nbsp;code smells). Firstly the SIR model itself. The model implemented follows the standard set of differential equations that are solved using {deSolve}, as requested in our prompt. However, the model does not have any options to input interventions, which the proposed solution by GitHub copilot workspace suggested it would. The second downside is the use of <code>require(deSolve)</code> in the function body of the generated code. This is bad practice in R package development as functions should namespace any functions that are being called from other packages (e.g.&nbsp;<code>packagename::func_name()</code>).</p>
<p>This task required copilot workspace to understand the contents and conventions of the {epidemics} R package and generate a simple compartmental model which would integrate with the infrastructure in the package for defining interventions in models. Although it correctly summarised the package contents, its attempt to answer the specific request from our prompt had many inaccuracies. The generated code is likely influenced by the many examples of SIR models written in R on the internet and on GitHub. These might be R scripts or gists and thus coding practises used there are not always appropriate for writing code to be distributed in an R package, resulting in decisions like having <code>require(deSolve)</code> in the function.</p>
<p>AI-generated code like that seen in this example showcases where users need to be diligent and not assume that the text descriptions from copilot match the code. In the end, this was a test example and was unlikely to be merged into {epidemics} even if the code was correct. However, with the code generated, it presents almost no use; it would require as much time for an RSE to refactor this function as it would to write one from scratch following the design principles and demands of the {epidemics} package.</p>
</section>
</section>
<section id="experiment-3-conducting-a-code-review-on-an-r-package" class="level2">
<h2 class="anchored" data-anchor-id="experiment-3-conducting-a-code-review-on-an-r-package">Experiment 3: Conducting a code review on an R package</h2>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Difficulty level: moderate to high</p>
</div>
</div>
<p>In the last test case, we requested GitHub copilot workspace to conduct a <a href="https://github.com/epiverse-trace/simulist/pull/117">code review of the entire code base of a package</a>. At Epiverse-TRACE, it is standard practise to conduct a full package review. As any code base develops, including R packages, more commits are added and often the number of lines of code increases. Reviewing all of these changes before releasing a new version of the package is a timely undertaking for package reviewers. If AI tools could review the code base, similar to how static code analysers work, and suggest improvements to, for example, code style, memory efficiency, documentation, unit testing, UX/UI, it would greatly improve efficiency before releasing the code.</p>
<section id="outcome-2" class="level3">
<h3 class="anchored" data-anchor-id="outcome-2">Outcome</h3>
<p>Here, Copilot provided no analysis of the code base. It regurgitated the changes described in the <a href="https://epiverse-trace.github.io/blueprints/code-review.html#full-package-review">package review pull request</a>, likely from a mix of the pull request description and the changelog (<code>NEWS.md</code> file), and did not analyse any of the code. Therefore, it provided no additional use than if the reviewer had just read the <code>NEWS</code>.</p>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Based on our trials we observe that GitHub copilot Workspace may not provide a significant benefit to research software engineers in domain-specific R package development, where problems are complex and bespoke solutions are common. The evidence above suggests there’s still a long way to go before AI-powered tools can produce unsupervised code projects equivalent to that of a research software engineer. One observation is that generative AI is better trained for some purposes than others, biased by the amount of training data/information available. This makes it struggle in niche areas with a relatively smaller public code base to train models with (e.g.&nbsp;R functions for epidemic analysis are much rarer than generic JavaScript functions for web design). A second is that AI models don’t seem to understand how different parts of a codebase link together, so they provide solutions that are inconsistent with the requirements of the codebase (design principles, code style, etc). These models may, however, be more useful for more common tasks, such as building dashboard templates.</p>
<p>The test cases we experimented with suggest that this tool will not replace, and at times not even enhance development when the task requires a more integrated development than generating a standalone script. These tools are evolving rapidly and we are sure improvements will continue. In the short term tools like GitHub copilot workspace need to be used responsibly with an awareness of their limitations and not a blind trust that the code it writes is always correct. We would caution against relying on generative AI tools alone to develop software with potentially large-scale impacts - scrutiny by trained developers is still key. Research software engineers will play a key part in this as they will ensure that code and software written with and by AI tools meet required standards, are trustworthy, and are not potentially harmful. Where we see generative AI tools being more immediately useful in research software development is in <a href="https://billyquilty.substack.com/p/llmlinelist-enabling-rapid-outbreak">tasks that require sifting through or summarising vast amounts of information</a>; for example, in querying software documentation, or to help get started with a new programming framework or language.</p>
<p><strong>All authors thank Hugo Gruson and Chris Hartgerink for their valuable feedback and contributions to this post.</strong></p>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-vanHoek2024" class="csl-entry">
Hoek, Albert Jan van, Sebastian Funk, Stefan Flasche, et al. 2024. <span>“Importance of Investing Time and Money in Integrating Large Language Model-Based Agents into Outbreak Analytics Pipelines.”</span> <em>The Lancet Microbe</em>, ahead of print, May. <a href="https://doi.org/10.1016/s2666-5247(24)00104-6">https://doi.org/10.1016/s2666-5247(24)00104-6</a>.
</div>
</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{w._lambert2024,
  author = {W. Lambert, Joshua and Mba Azam, James and Gupte, Pratik and
    Kucharski, Adam},
  title = {Some Thoughts After a Trial Run of {GitHub’s} {Copilot}
    {Workspace}},
  date = {2024-07-15},
  url = {https://epiverse-trace.github.io/posts/copilot-workspace/},
  doi = {10.59350/ncsre-v2w98},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-w._lambert2024" class="csl-entry quarto-appendix-citeas">
W. Lambert, Joshua, James Mba Azam, Pratik Gupte, and Adam Kucharski.
2024. <span>“Some Thoughts After a Trial Run of GitHub’s Copilot
Workspace.”</span> July 15. <a href="https://doi.org/10.59350/ncsre-v2w98">https://doi.org/10.59350/ncsre-v2w98</a>.
</div></div></section></div> ]]></description>
  <category>AI</category>
  <category>GitHub</category>
  <category>Copilot Workspace</category>
  <category>R</category>
  <category>R package</category>
  <category>software development</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/copilot-workspace/</guid>
  <pubDate>Mon, 15 Jul 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Improving Ecosystem Interoperability Iteratively via Progressive Enhancement</title>
  <dc:creator>Hugo Gruson</dc:creator>
  <link>https://epiverse-trace.github.io/posts/progressive-enhancement/</link>
  <description><![CDATA[ 





<p>We are continuing our post series on S3 object orientation and interoperability in R. We have previously discussed <a href="../parent-class">what makes a good S3 class and how to choose a good parent for it, as well as when to write or not write a custom method</a>. We have highlighted in particular how classes inheriting from data.frames can simplify user experience because of familiarity, and reduce developer workload due to the pre-existing S3 methods.</p>
<p>We have detailed how to improve compatibility with the tidyverse by explaining:</p>
<ul>
<li><a href="https://hugogruson.fr/posts/compa-tibble/">how functions taking data.frames or data.frames subclass should also allow compatibility with tibble, which can be done in a few steps</a></li>
<li><a href="../extend-dataframes">how to ensure class attributes are preserved whenever possible while using dplyr functions</a>.</li>
</ul>
<p>Here, we are going to explore how to start adding support in the ecosystem for the new S3 classes while minimizing user-facing breaking changes. We have previously delved into this topic with our post <a href="../s3-generic">“Convert Your R Function to an S3 Generic: Benefits, Pitfalls &amp; Design Considerations”</a> and this is a wider and higher-level view of the same topic.</p>
<p>The strategy presented here is the variation of a common concept in web development and the web ecosystem: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement">progressive enhancement</a>. This philosophy aims to support browsers with a common set of essential features, and even richer features for browser with the most recent updates. It makes sense to think about this philosophy with the prism of introducing new classes to a new software ecosystem as it has the similar constraints of multiple stakeholders with different interests and timelines. The application of progressive enhancement in this context means that users or packages that have not (yet) adopted the new classes are not penalized compared to users or packages that have.</p>
<section id="adding-class-support-to-function-inputs-via-progressive-enhancement" class="level2">
<h2 class="anchored" data-anchor-id="adding-class-support-to-function-inputs-via-progressive-enhancement">Adding class support to function inputs via progressive enhancement</h2>
<p>The goal here is to allow functions to accept the new classes as inputs, while keeping the old behaviour unchanged for unclassed objects (or with a different class than the new one).</p>
<p>This can conveniently be done in an almost transparent way by converting the old function to the S3 generic, and using the default method to handle the old behaviour. The practical steps, and minor caveats, have been previously described in the post <a href="../s3-generic">“Convert Your R Function to an S3 Generic: Benefits, Pitfalls &amp; Design Considerations”</a>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://epiverse-trace.github.io/posts/progressive-enhancement/convert_to_generic.svg" class="img-fluid figure-img"></p>
<figcaption>A before / after type image showing the conversion of a function to a generic with a default method keeping the exisiting behaviour.</figcaption>
</figure>
</div>
<p>For a different, additional, example, we can consider a function working on patient-level data, which previously only accepted a <code>data.frame</code> as input:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' Compute length of stay in hospital on a patient-level dataset</span></span>
<span id="cb1-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb1-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param data A data.frame containing patient-level data</span></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param admission_column The name of the column containing the admission date</span></span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param discharge_column The name of the column containing the discharge date</span></span>
<span id="cb1-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @returns A numeric vector of hospitalization durations in days</span></span>
<span id="cb1-8">compute_hospitalization_duration <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, admission_column, discharge_column) {</span>
<span id="cb1-9"></span>
<span id="cb1-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">difftime</span>(</span>
<span id="cb1-11">    data[[discharge_column]],</span>
<span id="cb1-12">    data[[admission_column]],</span>
<span id="cb1-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"days"</span></span>
<span id="cb1-14">  )</span>
<span id="cb1-15"></span>
<span id="cb1-16">}</span></code></pre></div></div>
<p>We want to add support for <code>linelist</code> objects, as defined in the <a href="https://epiverse-trace.github.io/linelist">linelist package</a>. <code>linelist</code> objects inherit from <code>data.frame</code> and contain an additional <code>tags</code> attribute. In particular, <code>linelist</code> objects can have a <code>date_admission</code> and <code>date_discharge</code> tag. This means we can use the tags to automatically detect the columns to use.</p>
<p>But we want the function to keep working for standard <code>data.frame</code>s, <code>tibble</code>s, etc. We can follow the steps described in the previous post to convert the function to a generic, and add a default method to handle the old behaviour:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">compute_hospitalization_duration <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, ...) {</span>
<span id="cb2-2"></span>
<span id="cb2-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">UseMethod</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"compute_hospitalization_duration"</span>)</span>
<span id="cb2-4"></span>
<span id="cb2-5">}</span>
<span id="cb2-6"></span>
<span id="cb2-7">compute_hospitalization_duration.default <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, admission_column, discharge_column) {</span>
<span id="cb2-8"></span>
<span id="cb2-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">difftime</span>(</span>
<span id="cb2-10">    data[[discharge_column]],</span>
<span id="cb2-11">    data[[admission_column]],</span>
<span id="cb2-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"days"</span></span>
<span id="cb2-13">  )</span>
<span id="cb2-14"></span>
<span id="cb2-15">}</span>
<span id="cb2-16"></span>
<span id="cb2-17">compute_hospitalization_duration.linelist <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, ...) {</span>
<span id="cb2-18"></span>
<span id="cb2-19">  x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> linelist<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tags_df</span>(data)</span>
<span id="cb2-20"></span>
<span id="cb2-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">compute_hospitalization_duration</span>(</span>
<span id="cb2-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> x,</span>
<span id="cb2-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">admission_column =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"date_admission"</span>,</span>
<span id="cb2-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">discharge_column =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"date_discharge"</span></span>
<span id="cb2-25">  )</span>
<span id="cb2-26"></span>
<span id="cb2-27">}</span></code></pre></div></div>
<p>If the function was already a generic, then a new method for the new class should be added, leaving everything else unchanged.</p>
</section>
<section id="adding-class-support-to-function-outputs-via-progressive-enhancement" class="level2">
<h2 class="anchored" data-anchor-id="adding-class-support-to-function-outputs-via-progressive-enhancement">Adding class support to function outputs via progressive enhancement</h2>
<p>Adding class support to function outputs is often more challenging. A common option is to add a new argument to the function, which would be a boolean indicating whether the output should be of the new class or not. But this doesn’t fit in the view of progressive enhancement, as it would require users to change their code to benefit from the new classes, or to suffer from breaking changes.</p>
<p>While the new argument approach is sometimes indeed the only possible method, there are some situations where we can have an approach truly following the progressive enhancement philosophy.</p>
<p>In particular, this is the case when the old output was already inheriting from the parent of the new class (hence the importance of carefully choosing the parent class). In this situation, the new attributes from the new class should not interfere with existing code for downstream analysis.</p>
<p>In this case, let’s consider a function that was previously returning an unclassed <code>data.frame</code> with patient-level data:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">create_patient_dataset <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n_patients =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) {</span>
<span id="cb3-2"></span>
<span id="cb3-3">  data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb3-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">patient_id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq_len</span>(n_patients),</span>
<span id="cb3-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</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;">99</span>, n_patients, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb3-6">  )</span>
<span id="cb3-7"></span>
<span id="cb3-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(data)</span>
<span id="cb3-9"></span>
<span id="cb3-10">}</span></code></pre></div></div>
<p>We want to start returning a <code>linelist</code> object. Because <code>linelist</code> objects are <code>data.frame</code>s (or <code>tibble</code>s) with an extra <code>attr</code>, it can be done in a transparent way:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">create_patient_dataset <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n_patients =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) {</span>
<span id="cb4-2"></span>
<span id="cb4-3">  data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb4-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">patient_id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq_len</span>(n_patients),</span>
<span id="cb4-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</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;">99</span>, n_patients, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb4-6">  )</span>
<span id="cb4-7"></span>
<span id="cb4-8">  data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> linelist<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">make_linelist</span>(</span>
<span id="cb4-9">    data,</span>
<span id="cb4-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"patient_id"</span>,</span>
<span id="cb4-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"age"</span></span>
<span id="cb4-12">  )</span>
<span id="cb4-13"></span>
<span id="cb4-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(data)</span>
<span id="cb4-15"></span>
<span id="cb4-16">}</span>
<span id="cb4-17"></span>
<span id="cb4-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">inherits</span>(data, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data.frame"</span>)</span></code></pre></div></div>
<p>For a more realistic example, you can also see the work in progress to integrate the <a href="https://github.com/socialcontactdata/contactmatrix">new <code>contactmatrix</code> standard format</a> for social contact data to the <a href="https://github.com/Bisaloo/contactdata">contactdata package</a>.</p>
<p>This is however only true if code in downstream analysis follows good practices in checking for the class of an object <sup>1</sup>. If existing code was testing equality of the class to a certain value, it will break when the new class value is appended. This is described in a <a href="https://developer.r-project.org/Blog/public/2019/11/09/when-you-think-class.-think-again/index.html">post on the R developer blog, when base R was adding a new <code>array</code> class value to <code>matrix</code> objects</a>. Class inheritance should never be tested via <code>class(x) == "some_class"</code>. Instead, <code>inherits(x, "some_class")</code> or <code>is(x, "some_class")</code> should be used to future-proof the code and allow appending an additional in the future.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Object oriented programming and S3 classes offer a convenient way to iteratively add interoperability in the ecosystem in a way that is minimally disruptive to users and developers. Newly classed input support can be added via custom methods (after converting the existing function to a generic if necessary). Newly classed output support can be added via progressive enhancement, by ensuring that the new class is a subclass of the old one and that downstream code uses good practices to test class inheritance.</p>
<p><strong>Thanks to James Azam and Tim Taylor for their very valuable feedback on this post.</strong></p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>This is now <a href="https://github.com/r-devel/r-svn/commit/77ebdff5adc200dfe9bc850bc4447088830d2ee0">enforced in R packages by R CMD check</a>, and via the <a href="https://lintr.r-lib.org/reference/class_equals_linter.html"><code>class_equals_linter()</code></a> in the <a href="https://lintr.r-lib.org/">lintr package</a>.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{gruson2024,
  author = {Gruson, Hugo},
  title = {Improving {Ecosystem} {Interoperability} {Iteratively} via
    {Progressive} {Enhancement}},
  date = {2024-07-05},
  url = {https://epiverse-trace.github.io/posts/progressive-enhancement/},
  doi = {10.59350/tdkxg-nd950},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-gruson2024" class="csl-entry quarto-appendix-citeas">
Gruson, Hugo. 2024. <span>“Improving Ecosystem Interoperability
Iteratively via Progressive Enhancement.”</span> July 5. <a href="https://doi.org/10.59350/tdkxg-nd950">https://doi.org/10.59350/tdkxg-nd950</a>.
</div></div></section></div> ]]></description>
  <category>R</category>
  <category>interoperability</category>
  <category>S3</category>
  <category>progressive enhancement</category>
  <category>ecosystem</category>
  <category>lifecycle</category>
  <category>object-oriented programming</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/progressive-enhancement/</guid>
  <pubDate>Fri, 05 Jul 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>2024 mpox outbreak: common analytics tasks and available R tools</title>
  <dc:creator>James Azam</dc:creator>
  <dc:creator>Hugo Gruson</dc:creator>
  <dc:creator>Adam Kucharski</dc:creator>
  <link>https://epiverse-trace.github.io/posts/mpox-preparedness/</link>
  <description><![CDATA[ 





<p>There are ongoing outbreaks of mpox globally. The Democratic Republic of Congo (DRC) is so far the worst hit with a total of 7,851 cases and 384 deaths reported between January 1 and May 26, 2024 <sup>1</sup>. Before 2022, there were few reports of sustained mpox transmission globally. However, during the following year (Jan 1, 2022, and Jan 29, 2023), 110 countries in all six WHO Regions had reported a total of 85,473 confirmed cases and 89 deaths between them <span class="citation" data-cites="laurenson2023description">(<span class="nocase">Laurenson-Schafer et al.</span> 2023)</span>.</p>
<p>Mpox is transmitted through respiratory droplets and direct contact with infected persons. The disease is characterized by fever, cough, and a rash, with the mean incubation period estimated to be about 7.8 days <span class="citation" data-cites="ward2022transmission">(Ward et al. 2022)</span>. Infected individuals may experience severe symptoms leading to hospitalisation or death. There are two genetic clades: clade I and clade II, which also has subclades IIa and IIb <span class="citation" data-cites="laurenson2023description">(<span class="nocase">Laurenson-Schafer et al.</span> 2023)</span>.</p>
<p>Several analyses of the potential impact of outbreaks at country level have already emerged in 2024. The US CDC, for example, has analysed the potential size of outbreaks resulting from transmission within and between households <sup>2</sup> and the risk of Clade 1 mpox outbreaks among some key populations associated with key transmission routes <sup>3</sup>. Another group of researchers have estimated the transmissibility of mpox in the DRC from more recent (2010 - 2019) surveillance data to update existing estimates, which are based on old data <span class="citation" data-cites="charniga2024updating">(<span class="nocase">Charniga, McCollum, et al.</span> 2024)</span>. However, tackling ongoing outbreaks around the world will require a coordinated response from the global health community.</p>
<p>The Epiverse-TRACE team is developing a set of analytical tools that could help support decision-makers during outbreaks. This post provides an overview of the tasks that such tools can be applied to in the context of the ongoing mpox outbreaks.</p>
<section id="common-outbreak-analytics-tasks" class="level2">
<h2 class="anchored" data-anchor-id="common-outbreak-analytics-tasks">Common outbreak analytics tasks</h2>
<p>Outbreak analytics in the context of the ongoing mpox outbreak involves several tasks that can be handled by existing and emerging R tools. Some of the tasks include estimating the transmission potential, forecasting infection dynamics, estimating severity, and assessing the impact of interventions.</p>
<p>Here, we briefly describe some common tasks, data required, and the ready R tools/packages developed by the Epiverse-TRACE team and the wider community.</p>
<section id="cleaning-and-validating-data" class="level3">
<h3 class="anchored" data-anchor-id="cleaning-and-validating-data">Cleaning and validating data</h3>
<div class="callout callout-style-simple callout-none no-icon">
<div class="callout-body d-flex">
<div class="callout-icon-container">
<i class="callout-icon no-icon"></i>
</div>
<div class="callout-body-container">
<p>Data cleaning is often the first task in outbreak analytics. This usually involves identifying and correcting errors in the data, standardizing the format of key variables, and ensuring that the data is in a format that is fit for analysis. Data validation is also important to ensure that the data is accurate.</p>
</div>
</div>
</div>
<p><a href="https://epiverse-trace.github.io/cleanepi/"><code>{cleanepi}</code></a> is useful for cleaning individual-level datasets, and <a href="https://epiverse-trace.github.io/linelist/"><code>{linelist}</code></a> can be used to tag and validate key variables in datasets that might change over time. The <a href="https://epiverse-trace.github.io/numberize/"><code>{numberize}</code></a> package can also be used to convert numbers written as text. It currently has functionality for English, Spanish, and French.</p>
</section>
<section id="estimating-transmission-potential" class="level3">
<h3 class="anchored" data-anchor-id="estimating-transmission-potential">Estimating transmission potential</h3>
<div class="callout callout-style-simple callout-none no-icon">
<div class="callout-body d-flex">
<div class="callout-icon-container">
<i class="callout-icon no-icon"></i>
</div>
<div class="callout-body-container">
<p>A key initial question during emerging outbreaks is the transmission potential of the disease. This is typically quantified using parameters such as: the basic reproduction number, <img src="https://latex.codecogs.com/png.latex?R_0">; the time-varying reproduction number, <img src="https://latex.codecogs.com/png.latex?R_t">; and <img src="https://latex.codecogs.com/png.latex?k">, which captures individual heterogeneity in transmission (i.e.&nbsp;“superspreading” potential). These quantities are useful to assess the potential for further spread of the disease and the impact of interventions.</p>
</div>
</div>
</div>
<section id="population-level-transmissibility-r_0-and-r_t" class="level4">
<h4 class="anchored" data-anchor-id="population-level-transmissibility-r_0-and-r_t">Population-level transmissibility (<img src="https://latex.codecogs.com/png.latex?R_0"> and <img src="https://latex.codecogs.com/png.latex?R_t">)</h4>
<p>The basic reproduction number, <img src="https://latex.codecogs.com/png.latex?R_0">, is the average number of secondary cases produced by a single infected individual in a completely susceptible population. The time-varying reproduction number, <img src="https://latex.codecogs.com/png.latex?R_t">, on the other hand, is the average number of secondary cases produced by a single infected individual at time <img src="https://latex.codecogs.com/png.latex?t"> in a partially susceptible population. <img src="https://latex.codecogs.com/png.latex?R_t"> is a more useful quantity during an outbreak as it accounts for the impact of interventions and changes in population immunity.</p>
<p>If data is available on the daily number of reported cases, <a href="https://epiforecasts.io/EpiNow2/"><code>{EpiNow2}</code></a> and <a href="https://mrc-ide.github.io/EpiEstim/"><code>{EpiEstim}</code></a> can be used to estimate <img src="https://latex.codecogs.com/png.latex?R_t">. These packages require data on the time scale of transmission (i.e.&nbsp;the generation time, or the serial interval, which is <a href="https://royalsocietypublishing.org/doi/10.1098/rsif.2020.0756">commonly used as a proxy</a> for this). While <code>{EpiEstim}</code> focuses on retrospective estimation of <img src="https://latex.codecogs.com/png.latex?R_t">, <code>{EpiNow2}</code> is designed for both retrospective and real-time estimation.</p>
<p>In estimating <img src="https://latex.codecogs.com/png.latex?R_t">, one practical consideration is the impact of various delays (biological and reporting) on the estimates <span class="citation" data-cites="charniga2024best park2024estimating gostic2020practical">(<span class="nocase">Charniga, Park, et al.</span> 2024; <span class="nocase">Park et al.</span> 2024; Katelyn M. Gostic 2020)</span>. <code>{EpiNow2}</code> adjusts for these delays in various ways. For example, it accounts for the symptom onset and reporting delays by taking the incubation period and reporting delay as inputs. Moreover, <code>{EpiNow2}</code> can estimate the reporting delay from the data if data on incidence by date of onset and report are available.</p>
<p>Furthermore, dedicated packages have emerged for estimating epidemiological delays from data using best practices. <a href="https://epidist.epinowcast.org/articles/epidist.html"><code>{epidist}</code></a> offers the ability to estimate delay distributions, accounting for issues such as truncation (i.e., not all disease outcomes will yet be known in real-time).</p>
<p>If delay data are not available, published estimates of the incubation period and serial interval can be used. The <a href="https://epiverse-trace.github.io/epiparameter/"><code>{epiparameter}</code></a> package collates a database of epidemiological distributions from the literature and provides functions for interacting with the database. You can view the <a href="https://epiverse-trace.github.io/epiparameter/dev/articles/database">database</a> for currently available parameters (more entries are planned). Additionally, if only summary statistics are available (e.g.&nbsp;range and median), <code>{epiparameter}</code> can be used to extract the distribution parameters.</p>
</section>
<section id="individual-level-transmissibility-superspreading" class="level4">
<h4 class="anchored" data-anchor-id="individual-level-transmissibility-superspreading">Individual-level transmissibility (superspreading)</h4>
<div class="callout callout-style-simple callout-none no-icon">
<div class="callout-body d-flex">
<div class="callout-icon-container">
<i class="callout-icon no-icon"></i>
</div>
<div class="callout-body-container">
<p>The individual-level transmission heterogeneity (superspreading), often denoted as <img src="https://latex.codecogs.com/png.latex?k">, is an important measure for tailoring interventions at the individual level.</p>
</div>
</div>
</div>
<p>If we have data on the distribution of sizes of transmission clusters, the <a href="https://epiverse-trace.github.io/epichains/"><code>{epichains}</code></a> package provides functions to set up the likelihood function to estimate <img src="https://latex.codecogs.com/png.latex?R_0"> and <img src="https://latex.codecogs.com/png.latex?k">. The user inputs the negative binomial offspring, which assumes individuals exhibit heterogeneity in transmission. The parameters of the negative offspring distribution can then be estimated using existing maximum likelihood or bayesian frameworks.</p>
<p>Furthermore, if we have individual-level transmission chain data, the <a href="https://epiverse-trace.github.io/superspreading/"><code>{superspreading}</code></a> package can be used to estimate <img src="https://latex.codecogs.com/png.latex?R_0"> and <img src="https://latex.codecogs.com/png.latex?k"> from the offspring distribution. This package also provides functions to estimate the probability that an outbreak will not go extinct in its early stages because of randomness in transmission (e.g.&nbsp;if the primary spillover case(s) does not infect others).</p>
<p>If we have data on sexual contacts and the secondary attack rate, then we can also use <code>{superspreading}</code> to <a href="https://epiverse-trace.github.io/superspreading/articles/heterogeneous_network_outbreaks.html">calculate <img src="https://latex.codecogs.com/png.latex?R_0"> accounting for network effects</a>.</p>
</section>
</section>
<section id="forecasting-and-nowcasting-infection-dynamics" class="level3">
<h3 class="anchored" data-anchor-id="forecasting-and-nowcasting-infection-dynamics">Forecasting and nowcasting infection dynamics</h3>
<div class="callout callout-style-simple callout-none no-icon">
<div class="callout-body d-flex">
<div class="callout-icon-container">
<i class="callout-icon no-icon"></i>
</div>
<div class="callout-body-container">
<p>Forecasting and nowcasting of infections are crucial for planning and resource allocation during an outbreak. Forecasting is the prediction of future cases, deaths, or other outcomes, while nowcasting is the prediction of the current outbreak situation. These predictions can help public health authorities to anticipate the trajectory of the outbreak and to implement timely interventions.</p>
</div>
</div>
</div>
<p><a href="https://epiforecasts.io/EpiNow2/"><code>{EpiNow2}</code></a> and <a href="https://package.epinowcast.org/"><code>{epinowcast}</code></a> provide functions to forecast and nowcast the number of cases. The data required for <code>{EpiNow2}</code> has already been described in the previous section. The <code>{epinowcast}</code> package similarly requires data on the number of cases reported per date. <code>{epinowcast}</code> does not currently support forecasting but there are plans to add this functionality in future versions.</p>
</section>
<section id="estimating-disease-severity" class="level3">
<h3 class="anchored" data-anchor-id="estimating-disease-severity">Estimating disease severity</h3>
<div class="callout callout-style-simple callout-none no-icon">
<div class="callout-body d-flex">
<div class="callout-icon-container">
<i class="callout-icon no-icon"></i>
</div>
<div class="callout-body-container">
<p>The case fatality risk (CFR) is often used to assess the severity of a disease. CFR here refers to the proportion of deaths among confirmed cases.</p>
</div>
</div>
</div>
<p>With incidence data on the number of cases reported and the number of deaths reported, the <a href="https://epiverse-trace.github.io/cfr/"><code>{cfr}</code></a> package can be used to estimate the case fatality rate and its uncertainty. Importantly, it accounts for the delay between the onset of symptoms and death, which is crucial for accurate estimation of the case fatality rate.</p>
<p>Here again, <code>{EpiNow2}</code> can be used to estimate the time-varying case fatality ratio using the same data as for the reproduction number. <code>{EpiNow2}</code> can estimate other severity metrics, such as the case hospitalisation ratio, given data on cases and hospitalisations, and the hospitalisation fatality ratio, if data on hospitalisations and associated deaths are available.</p>
</section>
<section id="assessing-the-impact-of-interventions" class="level3">
<h3 class="anchored" data-anchor-id="assessing-the-impact-of-interventions">Assessing the impact of interventions</h3>
<div class="callout callout-style-simple callout-none no-icon">
<div class="callout-body d-flex">
<div class="callout-icon-container">
<i class="callout-icon no-icon"></i>
</div>
<div class="callout-body-container">
<p>mpox can be mitigated with behaviour change, treatment, and vaccination. Here, a few tools are available to assess the impact of intervention scenarios.</p>
</div>
</div>
</div>
<p><a href="https://epiverse-trace.github.io/epidemics/"><code>{epidemics}</code></a> provides ready compartmental models to estimate the impact of vaccination and non-pharmaceutical interventions like behaviour change, which can conceptually be modelled as a reduction in the transmission rate through changes in the population contact structure.</p>
<p>If we want to explore population-level outbreak dynamics, <code>{epidemics}</code> allows for stratifying the population into arbitrary groups, specifying the contact structure between these groups, and rates of interventions. The data required to run these models include: population structure, contact structure, and timing and magnitude of interventions. Data on social contact matrices can be obtained from the <a href="https://github.com/epiforecasts/socialmixr"><code>{socialmixr}</code></a> package.</p>
</section>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>In this post, we have outlined common outbreak analytics tasks relevant to the mpox outbreak, the data required, and R packages/tools that are currently available to facilitate these tasks. The tools described here are being developed by the Epiverse-TRACE team and the wider community, with the aim of ensuring high standards of research software development, and validation from end users, including epidemiologists, clinicians, and policy makers. The tools are designed to be user-friendly and well integrated, enabling one analysis task to easily feed into another. We <a href="https://epiverse-trace.github.io/get-involved.html">would therefore be keen to hear</a> from other groups interested in potentially collaborating or contributing on this growing ecosystem of tools.</p>
<p><em>Thanks to <a href="https://github.com/Karim-Mane">Karim Mane</a> and <a href="https://github.com/chartgerink">Chris Hartgerink</a> for their valuable comments on earlier drafts of this post.</em></p>



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-charniga2024updating" class="csl-entry">
<span class="nocase">Charniga, Kelly, Andrea M McCollum, Christine M Hughes, et al.</span> 2024. <span>“Updating Reproduction Number Estimates for Mpox in the Democratic Republic of Congo Using Surveillance Data.”</span> <em>The American Journal of Tropical Medicine and Hygiene</em> 110 (3): 561. https://doi.org/<a href="https://doi.org/10.4269/ajtmh.23-0215">https://doi.org/10.4269/ajtmh.23-0215</a>.
</div>
<div id="ref-charniga2024best" class="csl-entry">
<span class="nocase">Charniga, Kelly, Sang Woo Park, Andrei R Akhmetzhanov, et al.</span> 2024. <span>“Best Practices for Estimating and Reporting Epidemiological Delay Distributions of Infectious Diseases Using Public Health Surveillance and Healthcare Data.”</span> <em>arXiv Preprint arXiv:2405.08841</em>, ahead of print. https://doi.org/<a href="
https://doi.org/10.48550/arXiv.2405.08841"> https://doi.org/10.48550/arXiv.2405.08841</a>.
</div>
<div id="ref-gostic2020practical" class="csl-entry">
Katelyn M. Gostic, Edward B. Baskerville, Lauren McGough. 2020. <span>“Practical Considerations for Measuring the Effective Reproductive Number, Rt.”</span> <em>PLoS Computational Biology</em> 16 (12): e1008409. https://doi.org/<a href="https://doi.org/10.1371/journal.pcbi.1008409">https://doi.org/10.1371/journal.pcbi.1008409</a>.
</div>
<div id="ref-laurenson2023description" class="csl-entry">
<span class="nocase">Laurenson-Schafer, Henry, Nikola Sklenovská, Ana Hoxha, et al.</span> 2023. <span>“Description of the First Global Outbreak of Mpox: An Analysis of Global Surveillance Data.”</span> <em>The Lancet Global Health</em> 11 (7): e1012–23. https://doi.org/<a href="https://doi.org/10.1016/S2214-109X(23)00198-5">https://doi.org/10.1016/S2214-109X(23)00198-5</a>.
</div>
<div id="ref-park2024estimating" class="csl-entry">
<span class="nocase">Park, Sang Woo, Andrei R Akhmetzhanov, Kelly Charniga, et al.</span> 2024. <span>“Estimating Epidemiological Delay Distributions for Infectious Diseases.”</span> <em>medRxiv</em>, 2024–01. https://doi.org/<a href="https://doi.org/10.1101/2024.01.12.24301247">https://doi.org/10.1101/2024.01.12.24301247</a>.
</div>
<div id="ref-ward2022transmission" class="csl-entry">
Ward, Thomas, Rachel Christie, Robert S Paton, Fergus Cumming, and Christopher E Overton. 2022. <span>“Transmission Dynamics of Monkeypox in the United Kingdom: Contact Tracing Study.”</span> <em>Bmj</em> 379. https://doi.org/<a href="http://dx.doi.org/10.1136/ bmj-2022-073153">http://dx.doi.org/10.1136/ bmj-2022-073153</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p><a href="https://www.who.int/emergencies/disease-outbreak-news/item/2024-DON522">WHO Disease Outbreak News</a>↩︎</p></li>
<li id="fn2"><p><a href="https://www.cdc.gov/forecast-outbreak-analytics/about/modeling-forecasting/mpox-transmission.html">Modeling Household Transmission of Clade I Mpox in the United States</a>↩︎</p></li>
<li id="fn3"><p><a href="https://www.cdc.gov/forecast-outbreak-analytics/about/modeling-forecasting/mpox-gbmsm-technical-brief.html">Risk of Clade 1 Mpox Outbreaks Among Gay, Bisexual, and Other Men Who Have Sex With Men in the United States</a>↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{azam2024,
  author = {Azam, James and Gruson, Hugo and Kucharski, Adam},
  title = {2024 Mpox Outbreak: Common Analytics Tasks and Available {R}
    Tools},
  date = {2024-07-04},
  url = {https://epiverse-trace.github.io/posts/mpox-preparedness/},
  doi = {10.59350/z78kb-qrz59},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-azam2024" class="csl-entry quarto-appendix-citeas">
Azam, James, Hugo Gruson, and Adam Kucharski. 2024. <span>“2024 Mpox
Outbreak: Common Analytics Tasks and Available R Tools.”</span> July 4.
<a href="https://doi.org/10.59350/z78kb-qrz59">https://doi.org/10.59350/z78kb-qrz59</a>.
</div></div></section></div> ]]></description>
  <category>mpox</category>
  <category>outbreak</category>
  <category>outbreak analytics</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/mpox-preparedness/</guid>
  <pubDate>Thu, 04 Jul 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Choosing the Right Parent for R Object Classes</title>
  <dc:creator>Hugo Gruson</dc:creator>
  <link>https://epiverse-trace.github.io/posts/parent-class/</link>
  <description><![CDATA[ 





<p><a href="https://hugogruson.fr/posts/compa-tibble/">I have recently published</a> a <a href="https://epiverse-trace.github.io/posts/s3-generic/">series of blog posts</a> on the reasons why one may want to start using object-oriented programming (and more specifically R S3 classes) to improve interoperability with other tools from the ecosystem.</p>
<p>But there are still questions I have not addressed directly, even if they may have been implicitly included sometimes: what makes a good object class? What good practices in class &amp; function design can improve interoperability?</p>
<p>As you can expect from these questions, this post will present a subjective view on S3 class and method design. I will argue that it is often a good strategy to inherit from existing standards classes, and to leverage this inheritance relationship as much as possible.</p>
<section id="inherit-from-standard-classes" class="level2">
<h2 class="anchored" data-anchor-id="inherit-from-standard-classes">Inherit from standard classes</h2>
<p>A unique feature of R is the availability and centrality of <code>data.frame</code>s in the base language, whereas you need extra libraries for a similar functionality in most other languages (e.g., <a href="https://pandas.pydata.org/">pandas</a> in Python).</p>
<p><code>data.frame</code> is one of the first “complex” (in the sense of <a href="https://adv-r.hadley.nz/vectors-chap.html#atomic-vectors">non-atomic</a>) object most R learners will be exposed to and will develop a familiarity with. A good way to leverage this familiarity is to <a href="https://epiverse-trace.github.io/posts/extend-dataframes/">make your subclass a thin wrapper around <code>data.frame</code>s</a>.</p>
<p>This means that not only will users be able to get started with your package faster because of this familiarity, but you will also immediately benefit from the huge ecosystem of functions and packages working on <code>data.frame</code>s, such as the <a href="https://tidyverse.org">tidyverse</a>. If you want some examples, this is what collaborators and I did in the <a href="https://github.com/epiverse-trace/linelist">linelist</a>, <a href="https://github.com/rmaia/pavo">pavo</a>, <a href="https://github.com/epiforecasts/scoringutils">scoringutils</a>, <a href="https://github.com/epiverse-trace/epichains">epichains</a>, and <a href="https://github.com/epiverse-trace/vaccineff">vaccineff</a> R packages.</p>
<p>In some cases, the output is too complex to fit into a <code>data.frame</code>. Even in this situation, I would recommend inheriting from existing, well-established, classes for the same two reasons: familiarity and ecosystem. For example, for the <a href="https://github.com/epiverse-trace/serofoi">serofoi</a> R package, <a href="https://github.com/epiverse-trace/serofoi/pull/117">we have made the decision to inherit from <code>stanfit</code> objects, rather than a custom structure</a>.</p>
</section>
<section id="rely-on-parent-methods-as-much-as-possible" class="level2">
<h2 class="anchored" data-anchor-id="rely-on-parent-methods-as-much-as-possible">Rely on parent methods as much as possible</h2>
<p>A follow up recommendation from inheriting from standard classes is to leverage their methods wherever possible.</p>
<p><a href="https://github.com/epiverse-trace/linelist/pull/60">One of the first</a> <a href="https://github.com/epiverse-trace/linelist/pull/61">changes I made</a> when becoming maintainer of the <a href="https://github.com/epiverse-trace/linelist">linelist</a> package was to remove the <code>rename.linelist()</code> and <code>select.linelist()</code> methods. Indeed, they were, or could easily be, behaving identically as the parent <code>rename.data.frame()</code> and <code>select.data.frame()</code> methods. Rather than burdening the codebase and maintenance with an extra unnecessary method, it is much simpler and more robust to rely on the well-tested parent method. In fact, the <a href="https://dplyr.tidyverse.org/reference/dplyr_extending.html">dplyr documentation</a> explicitly recommends only writing methods for a couple of standard functions (including <code>[.subclass()</code> and <code>names&lt;-.subclass()</code>), which will enable the use of parent methods directly, rather than writing custom methods for each dplyr function.</p>
<p>Similarly, many developers have the reflex to write a custom <code>print.subclass()</code> method as part of the method implementation. While it may be justified in some cases, it is sometimes unnecessary. My recommendation would be to evaluate carefully what benefits the custom method brings over the default parent method.</p>
</section>
<section id="enable-conversion-to-standard-classes" class="level2">
<h2 class="anchored" data-anchor-id="enable-conversion-to-standard-classes">Enable conversion to standard classes</h2>
<p>If after careful consideration, extra metadata makes it too difficult to fit your new class into an existing class, you may sometimes have to define your own class from “scratch” (i.e., often <code>list()</code> in R).</p>
<p>But even in this case, you can still apply some of the ideas proposed earlier. As much as possible, you should provide helpers or methods to enable the streamlined conversion of your method to a standard class.</p>
<p>A good example here is the <a href="https://github.com/epiverse-trace/epiparameter">epiparameter</a> package, which provides a complex S3 class built on lists, including extensive metadata about probability distribution of epidemiological parameters. As such, this custom class cannot be used out of the box in most functions from other packages. <a href="https://github.com/epiverse-trace/epiparameter/blob/0f805b90f984def4851a78148f1cf44c3d480845/R/coercion.R#L18-L41">But an <code>as.function()</code> method is conveniently provided to enable the conversion of this probability distribution parameters into a density distribution</a>, which can then be used in functions which expect a <code>function</code> object.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>In summary, I recommend relying on well-established parent classes such as <code>data.frame</code>s or at least providing direct conversion functions to these standard classes, and using parent methods wherever possible rather than writing custom dedicated methods. This should help produce a package:</p>
<ul>
<li>more easily accessible for users because it uses objects that feel familiar</li>
<li>more maintainable because a lot of method writing is offloaded to the parent class</li>
<li>more likely to be interoperable because standard classes are a good way to pass data between functions or packages</li>
</ul>
<p><strong>Thanks to Chris Hartgerink, James Azam and Josh Lambert, for their very valuable feedback on this post.</strong></p>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{gruson2024,
  author = {Gruson, Hugo},
  title = {Choosing the {Right} {Parent} for {R} {Object} {Classes}},
  date = {2024-06-26},
  url = {https://epiverse-trace.github.io/posts/parent-class/},
  doi = {10.59350/fk6nv-1k973},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-gruson2024" class="csl-entry quarto-appendix-citeas">
Gruson, Hugo. 2024. <span>“Choosing the Right Parent for R Object
Classes.”</span> June 26. <a href="https://doi.org/10.59350/fk6nv-1k973">https://doi.org/10.59350/fk6nv-1k973</a>.
</div></div></section></div> ]]></description>
  <category>R</category>
  <category>R package</category>
  <category>object-oriented programming</category>
  <category>S3</category>
  <category>interoperability</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/parent-class/</guid>
  <pubDate>Wed, 26 Jun 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Things that can go wrong when using renv</title>
  <dc:creator>Hugo Gruson</dc:creator>
  <link>https://epiverse-trace.github.io/posts/renv-complications/</link>
  <description><![CDATA[ 





<p>Throughout the Epiverse project, we use the <a href="https://rstudio.github.io/renv/">renv R package</a> to ensure reproducibility of the training materials and the pipelines we are providing. But we sometimes get reports from users who struggle to rebuild the environment and run the code.</p>
<p>In this post, we dissect the source of these issues, explain why in reality renv is not at fault, and how this is caused by the inherent complexity of reproducibility. The renv documentation already includes <a href="https://rstudio.github.io/renv/articles/renv.html#caveats">caveats</a> explaining why some situations are bound to require more complex tools. This blog post reiterates some of these caveats and illustrates them with concrete examples.</p>
<p>Finally, we mention a couple of more complete (but more complex!) frameworks that can overcome the issues presented here. We do not explore these alternative framework in detail but provide links to more information.</p>
<section id="binaries-vs-building-from-source" class="level2">
<h2 class="anchored" data-anchor-id="binaries-vs-building-from-source">Binaries vs building from source</h2>
<p>Software, including R packages, can generally be delivered in two forms: as binaries or as source code. If you are building from the source code, you may in some case need a compilation toolchain on your computer. If that toolchain is missing, it can lead to errors such as:</p>
<blockquote class="blockquote">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb1-1">ld: warning: search path '/opt/gfortran/lib' not found</span>
<span id="cb1-2">ld: library 'gfortran' not found</span></code></pre></div></div>
</blockquote>
<p>Most of the time, regular users of R will not see these errors because they are installing binaries. Indeed, CRAN provides pre-compiled binaries for Windows and macOS for the last version of the package and R.</p>
<p>With renv, you often want to install older versions of the packages, which won’t be available as binaries from CRAN. This means you are more likely to have to compile the package yourself and see this kind of errors, even though renv is not causing them.</p>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Tip</span>gfortran issues on Apple Silicon computers
</div>
</div>
<div class="callout-body-container callout-body">
<p>If you are an Apple Silicon (Mac M1, M2, M3) user and encounter issues with gfortran, we have had success using the <a href="https://github.com/coatless-mac/macrtools/">macrtools R package</a> and we strongly recommend checking it out.</p>
</div>
</div>
</section>
<section id="beyond-renv-scope-incompatibility-with-system-dependency-versions" class="level2">
<h2 class="anchored" data-anchor-id="beyond-renv-scope-incompatibility-with-system-dependency-versions">Beyond renv scope: incompatibility with system dependency versions</h2>
<p>We <a href="../system-dependencies/">discussed previously the topic of system dependencies</a>, and <a href="https://blog.r-hub.io/2022/09/12/r-dependency/">dependencies on specific R versions</a>. These special dependencies can also be a source of headaches when using renv.</p>
<p>The heart of the issue is that renv provides a simplified solution to reproducibility: it focuses on R packages and their versions. But other sources of non-reproducibility are outside its scope. In many cases, this will not be a problem, as the main source of non-reproducibility, especially in the relatively short-term, will be R package versions.</p>
<p>But sometimes, it is possible that the <code>renv.lock</code> lockfile requires such an old version of an R package that it was written with a syntax that is no longer supported by recent R versions or modern compilers.</p>
<p>For example, a recent project (from 2023) was trying to install the version 0.60.1 of the <code>matrixStats</code> package (from 2021). This lead to this compilation error:</p>
<blockquote class="blockquote">
<p>error: ‘DOUBLE_XMAX’ undeclared (first use in this function); did you mean ‘DBL_MAX’?</p>
</blockquote>
<!-- markdownlint-disable MD033 -->
<details>
<summary>
Click to see the full error message
</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb2-1">! Error installing package 'matrixStats':</span>
<span id="cb2-2">=======================================</span>
<span id="cb2-3"></span>
<span id="cb2-4">* installing *source* package ‘matrixStats’ ...</span>
<span id="cb2-5">** package ‘matrixStats’ successfully unpacked and MD5 sums checked</span>
<span id="cb2-6">** using staged installation</span>
<span id="cb2-7">** libs</span>
<span id="cb2-8">using C compiler: ‘gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0’</span>
<span id="cb2-9">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c 000.init.c -o 000.init.o</span>
<span id="cb2-10">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c allocMatrix2.c -o allocMatrix2.o</span>
<span id="cb2-11">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c anyMissing.c -o anyMissing.o</span>
<span id="cb2-12">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c binCounts.c -o binCounts.o</span>
<span id="cb2-13">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c binMeans.c -o binMeans.o</span>
<span id="cb2-14">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c colCounts.c -o colCounts.o</span>
<span id="cb2-15">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c colOrderStats.c -o colOrderStats.o</span>
<span id="cb2-16">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c colRanges.c -o colRanges.o</span>
<span id="cb2-17">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c diff2.c -o diff2.o</span>
<span id="cb2-18">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c indexByRow.c -o indexByRow.o</span>
<span id="cb2-19">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c logSumExp.c -o logSumExp.o</span>
<span id="cb2-20">gcc -I"/usr/share/R/include" -DNDEBUG       -fpic  -g -O2 -ffile-prefix-map=/build/r-base-H0vbME/r-base-4.3.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2  -c mean2.c -o mean2.o</span>
<span id="cb2-21">In file included from mean2_lowlevel.h:14,</span>
<span id="cb2-22">                 from mean2.c:9:</span>
<span id="cb2-23">mean2_lowlevel_template.h: In function ‘mean2_int’:</span>
<span id="cb2-24">mean2_lowlevel_template.h:59:13: error: ‘DOUBLE_XMAX’ undeclared (first use in this function); did you mean ‘DBL_MAX’?</span>
<span id="cb2-25">   59 |   if (sum &gt; DOUBLE_XMAX) {</span>
<span id="cb2-26">      |             ^~~~~~~~~~~</span>
<span id="cb2-27">      |             DBL_MAX</span>
<span id="cb2-28">mean2_lowlevel_template.h:59:13: note: each undeclared identifier is reported only once for each function it appears in</span>
<span id="cb2-29">In file included from mean2_lowlevel.h:18,</span>
<span id="cb2-30">                 from mean2.c:9:</span>
<span id="cb2-31">mean2_lowlevel_template.h: In function ‘mean2_dbl’:</span>
<span id="cb2-32">mean2_lowlevel_template.h:59:13: error: ‘DOUBLE_XMAX’ undeclared (first use in this function); did you mean ‘DBL_MAX’?</span>
<span id="cb2-33">   59 |   if (sum &gt; DOUBLE_XMAX) {</span>
<span id="cb2-34">      |             ^~~~~~~~~~~</span>
<span id="cb2-35">      |             DBL_MAX</span>
<span id="cb2-36">make: *** [/usr/lib/R/etc/Makeconf:191: mean2.o] Error 1</span>
<span id="cb2-37">ERROR: compilation failed for package ‘matrixStats’</span></code></pre></div></div>
</details>
<p>The explanation for this error can be found in <a href="https://github.com/HenrikBengtsson/matrixStats/blob/799669fc6de6f55a74cab06cc6a97634aa24ab0e/NEWS.md?plain=1#L111-L113">the <code>matrixStats</code> release notes</a>, specifically the section for matrixStats 0.63.0:</p>
<blockquote class="blockquote">
<ul>
<li>Updated native code to use the C99 constant <code>DBL_MAX</code> instead of legacy S constant <code>DOUBLE_XMAX</code>, which is planned to be unsupported in R (&gt;= 4.2.0).</li>
</ul>
</blockquote>
</section>
<section id="some-solutions" class="level2">
<h2 class="anchored" data-anchor-id="some-solutions">Some solutions</h2>
<section id="alternative-package-managers" class="level3">
<h3 class="anchored" data-anchor-id="alternative-package-managers">Alternative package managers</h3>
<p>We discussed how many issues when using renv can arise during the package compilation from source. A potential solution would be to avoid this compilation step and always install pre-compiled binaries.</p>
<p>This is not possible while installing from CRAN as CRAN only provides binaries for recent versions of R and for a limited number of platforms.</p>
<p>But Posit for example provides a larger collection of binaries, for different package versions, and different platforms, via their Public <a href="https://packagemanager.posit.co/">Posit Package Manager (PPM)</a>.</p>
<p>Making sure you install from PPM rather than CRAN can be a first simple step to make some of the issues discussed here vanish.</p>
</section>
<section id="extending-the-scope-of-reproducibility" class="level3">
<h3 class="anchored" data-anchor-id="extending-the-scope-of-reproducibility">Extending the scope of reproducibility</h3>
<p>Another solution could be to add more complex reproducibility solutions that go beyond the scope of renv.</p>
<section id="renv-with-rig" class="level4">
<h4 class="anchored" data-anchor-id="renv-with-rig">renv with rig</h4>
<p>The R version is specified in <code>renv.lock</code> and to avoid incompatibility of older package versions with newer versions of R, you could run the declared R version. This can be achieved with various means but a convenient solution is the <a href="https://github.com/r-lib/rig">rig</a> tool.</p>
<p>There are even some <a href="https://github.com/r-lib/rig/issues/131">discussions</a> to integrate rig and renv more tightly and let rig detect automatically which R version to use based on the <code>renv.lock</code> file.</p>
</section>
<section id="docker-nix-and-others" class="level4">
<h4 class="anchored" data-anchor-id="docker-nix-and-others">Docker, Nix and others</h4>
<p>Alternatively, you could use other reproducibility toolkits that focus not just on the R package versions, but on the entire software stack (e.g., including the operating system, the system dependencies). These solutions can be more complex to set up and use, and we won’t detail them in this blog post but you can find more information in:</p>
<ul>
<li><a href="https://rstudio.github.io/renv/articles/docker.html">The “Using renv with Docker” renv vignette</a></li>
<li><a href="https://doi.org/10.32614/RJ-2017-065">the “An Introduction to Rocker: Docker Containers for R” paper</a></li>
<li><a href="https://www.brodrigues.co/blog/2023-07-13-nix_for_r_part1/">Bruno Rodrigues’ entire series of blog posts on Nix</a></li>
</ul>
</section>
</section>
<section id="conclusion-a-final-note-for-developers" class="level3">
<h3 class="anchored" data-anchor-id="conclusion-a-final-note-for-developers">Conclusion: a final note for developers</h3>
<p>renv is an elegant solution that focuses on the most immediate source of non-reproducibility. This however means it needs to be complemented by other tools in more complex cases.</p>
<p>Ultimately, reproducibility is a team effort. People who write code can minimise the risk of renv complications by keeping the packages they use close to their CRAN version and regularly updating their code and <code>renv.lock</code> accordingly. Other programming languages have automated tooling to help with this, via, e.g., the <a href="https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/">dependabot tool</a> which submits pull requests to update dependencies. There is no well established equivalent for R yet, but anyone willing to set this mechanism up can look at the code used by the <a href="https://github.com/carpentries/actions/tree/70ff4b4e8d50fdcd0eb33e7c33a4a6f305a82702/update-lockfile">Carpentries workbench</a> for this task.</p>
<p><em>Thanks to Pratik Gupte and Chris Hartgerink for their valuable comments on earlier drafts of this post.</em></p>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{gruson2024,
  author = {Gruson, Hugo},
  title = {Things That Can Go Wrong When Using Renv},
  date = {2024-01-31},
  url = {https://epiverse-trace.github.io/posts/renv-complications/},
  doi = {10.59350/hsy4m-6se90},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-gruson2024" class="csl-entry quarto-appendix-citeas">
Gruson, Hugo. 2024. <span>“Things That Can Go Wrong When Using
Renv.”</span> January 31. <a href="https://doi.org/10.59350/hsy4m-6se90">https://doi.org/10.59350/hsy4m-6se90</a>.
</div></div></section></div> ]]></description>
  <category>R</category>
  <category>reproducibility</category>
  <category>renv</category>
  <category>DOI</category>
  <guid>https://epiverse-trace.github.io/posts/renv-complications/</guid>
  <pubDate>Wed, 31 Jan 2024 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
