<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>R-bloggers</title>
	<atom:link href="https://www.r-bloggers.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.r-bloggers.com</link>
	<description>R news and tutorials contributed by hundreds of R bloggers</description>
	<lastBuildDate>Fri, 10 Apr 2026 17:14:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.18</generator>

<image>
	<url>https://i0.wp.com/www.r-bloggers.com/wp-content/uploads/2016/08/cropped-R_single_01-200.png?fit=32%2C32&#038;ssl=1</url>
	<title>R-bloggers</title>
	<link>https://www.r-bloggers.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">11524731</site>	<item>
		<title>New R Package {bdlnm} Released on CRAN: Bayesian Distributed Lag Non-Linear Models in R via INLA</title>
		<link>https://www.r-bloggers.com/2026/04/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/</link>
		
		<dc:creator><![CDATA[Pau Satorra]]></dc:creator>
		<pubDate>Fri, 10 Apr 2026 17:14:30 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://r-posts.com/?p=18982</guid>

					<description><![CDATA[<p>CRAN, GitHub TL;DR: {bdlnm} brings Bayesian Distributed Lag Non-Linear Models (B-DLNMs) to R using INLA, allowing to model complex DLNMs, quantify uncertainty, and produce rich visualizations. Background Climate change is increasing exposure to extreme environmental conditions such as heatwaves and air pollution. However, these exposures rarely have immediate effects. ...</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/">New R Package {bdlnm} Released on CRAN: Bayesian Distributed Lag Non-Linear Models in R via INLA</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/"> R-posts.com</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p><a href="https://cran.r-project.org/package=bdlnm" rel="nofollow" target="_blank">CRAN</a>, <a href="https://github.com/pasahe/bdlnm" rel="nofollow" target="_blank">GitHub</a></p>
<blockquote class="blockquote"><strong>TL;DR</strong>: {bdlnm} brings Bayesian Distributed Lag Non-Linear Models (B-DLNMs) to R using INLA, allowing to model complex DLNMs, quantify uncertainty, and produce rich visualizations.</blockquote>
<section id="background" class="level1">
<h1>Background</h1>
<p>Climate change is increasing exposure to extreme environmental conditions such as heatwaves and air pollution. However, these exposures rarely have immediate effects. For example:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>A heatwave today may increase mortality several days later</li>
	<li>Air pollution can have cumulative and delayed impacts</li>
</ul>
</li>
</ul>
<p>Distributed Lag Non-Linear Models (DLNMs) are the standard framework for studying these effects. They simultaneously model:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>How risk changes with exposure level (exposure-response)</li>
	<li>How risk evolve over time (lag-response)</li>
</ul>
</li>
</ul>
<p>Usually in the presence of non-linear effects, splines are used to define these two relationships. These two basis are then combined through a cross-basis function. </p>
<p>As datasets become larger and more complex (e.g., studies with different regions and longer time periods), classical approaches show limitations. Bayesian DLNMs extend this framework by:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>Supporting more flexible model structures</li>
	<li>Providing full posterior distributions</li>
	<li>Enabling richer uncertainty quantification</li>
</ul>
</li>
</ul>
<p><span>The new {bdlnm} package extends the framework of the {dlnm} package to a Bayesian setting, using Integrated Nested</span> Laplace Approximation (INLA), a fast alternative to MCMC for Bayesian inference.</p>
</section>
<section id="installing-and-loading-the-package" class="level1">
<h1>Installing and loading the package</h1>
<p>As of March 2026, the package is available on CRAN:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb1">
<pre>install.packages(&quot;bdlnm&quot;)
library(bdlnm)</pre>
</div>
</div>
</div>
<p>At least the stable version of INLA 23.4.24 (or newest) must be installed beforehand. You can install the newest stable INLA version by:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb2">
<pre>install.packages(
  &quot;INLA&quot;,
  repos = c(
    getOption(&quot;repos&quot;),
    INLA = &quot;https://inla.r-inla-download.org/R/stable&quot;
  ),
  dep = TRUE
)</pre>
</div>
</div>
</div>
<p>Now, let’s load all the libraries we will need for this short tutorial:</p>
<div class="cell">
<details class="code-fold">
<summary>Load required libraries</summary>
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb3">
<pre># DLNMs and splines
library(dlnm)
library(splines)

# Data manipulation
library(dplyr)
library(reshape2)
library(stringr)
library(lubridate)

# Visualization
library(ggplot2)
library(gganimate)
library(ggnewscale)
library(patchwork)
library(scales)
library(plotly)

# Tables
library(gt)

# Execution time
library(tictoc)</pre>
</div>
</div>
</details>
</div>
</section>
<section id="hands-on-example" class="level1">
<h1>Hands-on example</h1>
<p>We use the built-in london dataset with daily temperature and mortality (age 75+) from 2000-2012.</p>
<p>Before fitting any model, it is useful to explore the raw data. This plot shows daily mean temperature and mortality for the 75+ age group in London from 2000 to 2012, providing a first look at the time series we are trying to model:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb4">
<pre>col_mort &lt;- &quot;#2f2f2f&quot;
col_temp &lt;- &quot;#8e44ad&quot;

# Scaling parameters
a &lt;- (max(london$mort_75plus) - min(london$mort_75plus)) /
  (max(london$tmean) - min(london$tmean))
b &lt;- min(london$mort_75plus) - min(london$tmean) * a

p &lt;- ggplot(london, aes(x = yday(date))) +
  geom_line(
    aes(y = a * tmean + b, color = &quot;Mean Temperature&quot;),
    linewidth = 0.4
  ) +
  geom_line(
    aes(y = mort_75plus, color = &quot;Daily Mortality (+75 years)&quot;),
    linewidth = 0.4
  ) +
  facet_wrap(~year, ncol = 3) +
  scale_y_continuous(
    name = &quot;Daily Mortality (+75 years)&quot;,
    breaks = seq(0, 225, by = 50),
    sec.axis = sec_axis(
      name = &quot;Mean Temperature (°C)&quot;,
      transform = ~ (. - b) / a,
      breaks = seq(-10, 30, by = 10)
    )
  ) +
  scale_x_continuous(
    breaks = yday(as.Date(paste0(
      &quot;2000-&quot;,
      c(&quot;01&quot;, &quot;03&quot;, &quot;05&quot;, &quot;07&quot;, &quot;09&quot;, &quot;11&quot;),
      &quot;-01&quot;
    ))),
    labels = c(&quot;Jan&quot;, &quot;Mar&quot;, &quot;May&quot;, &quot;Jul&quot;, &quot;Sep&quot;, &quot;Nov&quot;),
    expand = c(0.01, 0)
  ) +
  scale_color_manual(
    values = c(
      &quot;Daily Mortality (+75 years)&quot; = col_mort,
      &quot;Mean Temperature&quot; = col_temp
    )
  ) +
  labs(x = NULL, color = NULL) +
  guides(color = &quot;none&quot;) +
  theme_minimal() +
  theme(
    axis.title.y.left = element_text(
      color = col_mort,
      face = &quot;bold&quot;,
      margin = margin(r = 8)
    ),
    axis.title.y.right = element_text(
      color = col_temp,
      face = &quot;bold&quot;,
      margin = margin(l = 8)
    ),
    axis.text.y.left = element_text(color = col_mort),
    axis.text.y.right = element_text(color = col_temp)
  ) +
  transition_reveal(as.numeric(date))

animate(p, nframes = 300, fps = 10, end_pause = 100)</pre>
</div>
</div>
<div class="cell-output-display">
<figure class="figure">
<p><img loading="lazy" fetchpriority="high" decoding="async" src="https://i0.wp.com/r-posts.com/wp-content/uploads/2026/03/tsevolution.gif?w=450" alt="" class="alignnone size-full wp-image-19043" data-recalc-dims="1" /><br />
<br />
<span style="font-size: 35px;font-weight: bold">Model overview</span></p>
</figure>
</div>
</div>
</section>
<section id="model-overview" class="level1">
<p>Conceptually, DLNMs model:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>
<p>Exposure-response: how risk changes with exposure level</p>
</li>
	<li>
<p>Lag-response: how risk unfold over time</p>
</li>
</ul>
</li>
</ul>
<p>A typical model is:</p>
<div>
<math display="block"> <msub><mi>Y</mi><mi>t</mi></msub> <mo>∼</mo> <mtext>Poisson</mtext> <mo stretchy="false">(</mo> <msub><mi>μ</mi><mi>t</mi></msub> <mo stretchy="false">)</mo> </math>
</div>
<div>
<math display="block"> <mi>log</mi> <mo stretchy="false">(</mo> <msub><mi>μ</mi><mi>t</mi></msub> <mo stretchy="false">)</mo> <mo>=</mo> <mi>α</mi> <mo>+</mo> <mi>cb</mi> <mo stretchy="false">(</mo> <msub><mi>x</mi><mi>t</mi></msub> <mo>,</mo> <mo>…</mo> <mo>,</mo> <msub> <mi>x</mi> <mrow><mi>t</mi><mo>–</mo><mi>L</mi></mrow> </msub> <mo stretchy="false">)</mo> <mo>·</mo> <mi>β</mi> <mo>+</mo> <munder> <mo>∑</mo> <mrow><mi>k</mi></mrow> </munder> <mi>
</mi> <msub><mi>γ</mi><mi>k</mi></msub> <msub> <mi>u</mi> <mrow><mi>k</mi><mi>t</mi></mrow> </msub> </math>
</div>
<p>where:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li><i>α</i> is the intercept</li>
	<li><i>cb</i>(·) is the cross-basis function, defining both the exposure-response and lag-response relationships</li>
	<li><i>β</i> are the coefficients associated with the cross-basis terms</li>
	<li><i>u</i><sub>kt</sub> are time-varying covariates with corresponding coefficients <i>γ</i><sub>k</sub></li>
</ul>
</li>
</ul>
</section>
<section id="model-specification-setup" class="level2">
<h2 class="anchored" data-anchor-id="model-specification-setup">Model specification & setup</h2>
<p>Before fitting the model, we have to define the spline-based exposure-response and lag-response functions using the {dlnm} package.</p>
<p>For our example, we will use common specifications in the literature in temperature-mortality studies:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>
<p>Exposure-response: natural spline with three knots placed at the 10th, 75th, and 90th percentiles of daily mean temperature</p>
</li>
	<li>
<p>Lag-response: natural spline with three knots equally spaced on the log scale up to a maximum lag of 21 days</p>
</li>
</ul>
</li>
</ul>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb5">
<pre># Exposure-response and lag-response spline parameters
dlnm_var &lt;- list(
  var_prc = c(10, 75, 90),
  var_fun = &quot;ns&quot;,
  lag_fun = &quot;ns&quot;,
  max_lag = 21,
  lagnk = 3
)

# Cross-basis parameters
argvar &lt;- list(
  fun = dlnm_var$var_fun,
  knots = quantile(london$tmean, dlnm_var$var_prc / 100, na.rm = TRUE),
  Bound = range(london$tmean, na.rm = TRUE)
)

arglag &lt;- list(
  fun = dlnm_var$lag_fun,
  knots = logknots(dlnm_var$max_lag, nk = dlnm_var$lagnk)
)

# Create crossbasis
cb &lt;- crossbasis(london$tmean, lag = dlnm_var$max_lag, argvar, arglag)</pre>
</div>
</div>
</div>
<p>As it’s commonly done in these scenarios, we will also control for the seasonality of the mortality time series using a natural spline with 8 degrees of freedom per year, which flexibly controls for long-term and seasonal trends in mortality:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb6">
<pre>seas &lt;- ns(london$date, df = round(8 * length(london$date) / 365.25))</pre>
</div>
</div>
</div>
<p>Finally, we also have to define the temperature values for which predictions will be generated:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb7">
<pre>temp &lt;- round(seq(min(london$tmean), max(london$tmean), by = 0.1), 1)</pre>
</div>
</div>
</div>
</section>
<section id="fit-the-model" class="level2">
<h2 class="anchored" data-anchor-id="fit-the-model">Fit the model</h2>
<p>Fit the previously defined Bayesian DLNM using the function <code>bdlnm()</code>. We draw 1000 samples from the posterior distribution and set a seed for reproducibility:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb8">
<pre>tictoc::tic()
mod &lt;- bdlnm(
  mort_75plus ~ cb + factor(dow) + seas,
  data = london,
  family = &quot;poisson&quot;,
  sample.arg = list(n = 1000, seed = 5243)
)
tictoc::toc()</pre>
<div class="cell-output cell-output-stdout">
<pre>8.33 sec elapsed</pre>
</div>
</div>
</div>
</div>
<p>Internally, <code>bdlnm()</code>:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>
<p>fits the model using INLA</p>
</li>
	<li>
<p>returns posterior samples for all parameters</p>
</li>
</ul>
</li>
</ul>
</section>
<section id="minimum-mortality-temperature" class="level2">
<h2 class="anchored" data-anchor-id="minimum-mortality-temperature">Minimum mortality temperature</h2>
<p>We estimate the minimum mortality temperature (MMT), defined as the temperature at which the overall mortality risk is minimized. This optimal value will later be used to center the estimated relative risks.</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb9">
<pre>tictoc::tic()
mmt &lt;- optimal_exposure(mod, exp_at = temp)
tictoc::toc()</pre>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre>7.3 sec elapsed</pre>
</div>
</div>
<p>The Bayesian framework, compared to the frequentist perspective, provides directly the full posterior distribution of the MMT. It is useful to inspect this distribution to assess whether multiple candidate optimal exposure values exist and to verify that the median provides a reasonable centering value:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb11">
<pre>ggplot(as.data.frame(mmt$est), aes(x = mmt$est)) +
  geom_histogram(
    fill = &quot;#A8C5DA&quot;,
    bins = length(unique(mmt$est)),
    alpha = 0.6,
    color = &quot;white&quot;
  ) +
  geom_density(
    aes(y = after_stat(density) * length(mmt$est) / length(unique(mmt$est))),
    color = &quot;#2E5E7E&quot;,
    linewidth = 1.2,
    adjust = 2 # &lt;-- key change: higher = smoother
  ) +
  geom_vline(
    xintercept = mmt$summary[&quot;0.5quant&quot;],
    color = &quot;#2E5E7E&quot;,
    linewidth = 1.1,
    linetype = &quot;dashed&quot;
  ) +
  scale_x_continuous(breaks = seq(min(mmt$est), max(mmt$est), by = 0.1)) +
  labs(x = &quot;Temperature (°C)&quot;, y = &quot;Frequency&quot;) +
  theme_minimal()</pre>
</div>
</div>
<div class="cell-output-display">
<figure class="figure">
<p><img loading="lazy" decoding="async" src="https://i0.wp.com/r-posts.com/wp-content/uploads/2026/04/mmt_plot.png?w=450" alt="" class="alignnone size-full wp-image-19044" srcset_temp="https://i0.wp.com/r-posts.com/wp-content/uploads/2026/04/mmt_plot.png?w=450 1344w, http://r-posts.com/wp-content/uploads/2026/04/mmt_plot-420x300.png 420w, http://r-posts.com/wp-content/uploads/2026/04/mmt_plot-450x321.png 450w, http://r-posts.com/wp-content/uploads/2026/04/mmt_plot-768x549.png 768w" sizes="(max-width: 1344px) 100vw, 1344px" data-recalc-dims="1" /></p>
</figure>
</div>
</div>
<p>The posterior distribution of the MMT is concentrated around 18.9ºC and is unimodal, so the median is a stable centering value for the relative risk estimates.</p>
<p>The posterior distribution of the MMT can also be visualized directly using the package’s <code>plot()</code> method: <code>plot(mmt)</code>.</p>
</section>
<section id="predict-exposure-lag-response-effects" class="level2">
<h2 class="anchored" data-anchor-id="predict-exposure-lag-response-effects">Predict exposure-lag-response effects</h2>
<p>We predict the exposure-lag-response association between temperature and mortality from the fitted model at the supplied temperature grid:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb12">
<pre>cen &lt;- mmt$summary[[&quot;0.5quant&quot;]]
tictoc::tic()
cpred &lt;- bcrosspred(mod, exp_at = temp, cen = cen)
tictoc::toc()</pre>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre>6.83 sec elapsed</pre>
</div>
</div>
<blockquote class="blockquote">
<p>Centering at the MMT means that relative risks (RR) are interpeted relative to this optimal temperature with minimum mortality.</p>
</blockquote>
<p>Several visualizations can be produced from these predictions. While simpler visualizations can be created using the package’s <code>plot()</code> method, here we will use fancier <code>ggplot2</code> visualizations:<br />
<br />
<span style="font-size: 29px;font-weight: bold">3D exposure-lag-response surface</span></p>
</section>
<section id="d-exposure-lag-response-surface" class="level2">
<p>We can plot the full exposure-lag-response association using a 3-D surface:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb14">
<pre>matRRfit_median &lt;- cpred$matRRfit.summary[,, &quot;0.5quant&quot;]
x &lt;- rownames(matRRfit_median)
y &lt;- colnames(matRRfit_median)
z &lt;- t(matRRfit_median)

zmin &lt;- min(z, na.rm = TRUE)
zmax &lt;- max(z, na.rm = TRUE)
mid &lt;- (1 - zmin) / (zmax - zmin)

plot_ly() |&gt;
  add_surface(
    x = x,
    y = y,
    z = z,
    surfacecolor = z,
    cmin = zmin,
    cmax = zmax,
    colorscale = list(
      c(0, &quot;#00696e&quot;),
      c(mid * 0.5, &quot;#80c8c8&quot;),
      c(mid, &quot;#f5f0e8&quot;),
      c(mid + (1 - mid) * 0.5, &quot;#c2714f&quot;),
      c(1, &quot;#6b1c1c&quot;)
    ),
    colorbar = list(title = &quot;RR&quot;)
  ) |&gt;
  add_surface(
    x = x,
    y = y,
    z = matrix(1, nrow = length(y), ncol = length(x)),
    colorscale = list(c(0, &quot;black&quot;), c(1, &quot;black&quot;)),
    opacity = 0.4,
    showscale = FALSE
  ) |&gt;
  layout(
    title = &quot;Exposure-Lag-Response Surface&quot;,
    scene = list(
      xaxis = list(title = &quot;Temperature (°C)&quot;),
      yaxis = list(title = &quot;Lag&quot;, tickvals = y, ticktext = gsub(&quot;lag&quot;, &quot;&quot;, y)),
      zaxis = list(title = &quot;RR&quot;),
      camera = list(eye = list(x = 1.5, y = -1.8, z = 0.8))
    )
  )</pre>
</div>
</div>
<figure style="text-align: center"><a href="https://pasahe.github.io/3dplot_bdlnm/" rel="nofollow" target="_blank"> <img loading="lazy" decoding="async" src="https://i2.wp.com/r-posts.com/wp-content/uploads/2026/04/3dplot_bdlnm.png?w=450" alt="" class="alignnone size-full wp-image-19049" data-recalc-dims="1" /> </a>
<figcaption><span style="font-size: 10pt">Click the image to explore the interactive Plotly version</span></figcaption>
</figure>
<div class="cell-output-display"><br />
The surface reveals two distinct risk regions. Hot temperatures produce a sharp, acute risk concentrated at the first lags, peaking at lag 0 and dissipating rapidly after the first lags. Cold temperatures produce a more modest and gradual increase in the first lags that does not fully disappear at longer lags. Intermediate temperatures near the MMT sit close to the RR = 1 reference plane across all lags.<br />
<br />
</div>
</div>
<p>The differential lag structure observed for heat- and cold-related mortality is consistent with known physiological mechanisms. Heat-related mortality tends to occur rapidly after exposure due to acute physiological stress, whereas cold-related mortality develops more gradually through delayed cardiovascular and respiratory effects, leading to increasing risk over longer lag periods.</p>
</section>
<section id="lag-response-curves" class="level2">
<h2 class="anchored" data-anchor-id="lag-response-curves">Lag-response curves</h2>
<p>We can also visualizes slices of the previous surface. For example, the lag-response relationship for different temperature values:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb15">
<pre>matRRfit &lt;- cbind(
  melt(cpred$matRRfit.summary[,, &quot;0.5quant&quot;], value.name = &quot;RR&quot;),
  RR_lci = melt(
    cpred$matRRfit.summary[,, &quot;0.025quant&quot;],
    value.name = &quot;RR_lci&quot;
  )$RR_lci,
  RR_uci = melt(
    cpred$matRRfit.summary[,, &quot;0.975quant&quot;],
    value.name = &quot;RR_uci&quot;
  )$RR_uci
) |&gt;
  rename(temperature = Var1, lag = Var2) |&gt;
  mutate(
    lag = as.numeric(gsub(&quot;lag&quot;, &quot;&quot;, lag))
  )

temps &lt;- cpred$exp_at

p &lt;- ggplot() +
  # Lag-responses curves colored by temperature
  geom_line(
    data = matRRfit,
    aes(x = lag, y = RR, group = temperature, color = temperature),
    alpha = 0.35,
    linewidth = 0.35
  ) +
  scale_color_gradientn(
    colours = c(
      &quot;#2166ac&quot;,
      &quot;#4393c3&quot;,
      &quot;#92c5de&quot;,
      &quot;#d1e5f0&quot;,
      &quot;#f7f7f7&quot;,
      &quot;#fddbc7&quot;,
      &quot;#f4a582&quot;,
      &quot;#d6604d&quot;,
      &quot;#b2182b&quot;
    ),
    name = &quot;Temperature&quot;
  ) +
  # Start a new color scale for highlighted curves
  ggnewscale::new_scale_color() +
  # RR = 1 reference
  geom_hline(
    yintercept = 1,
    linetype = &quot;dashed&quot;,
    color = &quot;grey30&quot;,
    linewidth = 0.5
  ) +
  scale_x_continuous(breaks = cpred$lag_at) +
  scale_y_continuous(trans = &quot;log10&quot;, breaks = pretty_breaks(6)) +
  labs(
    title = &quot;Lag-response curves by temperature&quot;,
    x = &quot;Lag (days)&quot;,
    y = &quot;Relative Risk (RR)&quot;
  ) +
  theme_minimal() +
  theme(legend.position = &quot;top&quot;, panel.grid.minor.x = element_blank()) +
  transition_states(
    temperature,
    transition_length = 1,
    state_length = 0
  ) +
  shadow_mark(past = TRUE, future = FALSE, alpha = 0.6)

animate(p, nframes = 300, fps = 15, end_pause = 100)</pre>
</div>
</div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p>Cold temperatures (blue) gradually increase in the initial lags and then decline gradually without fully disappearing in the longer lags. Hot temperatures (red) show a different pattern: a higher risk immediately after lag 0, which drops rapidly and largely dissipates after the first lags:<br />
<br />
<img loading="lazy" decoding="async" src="https://i2.wp.com/r-posts.com/wp-content/uploads/2026/04/lag_response.gif?w=450" alt="" class="alignnone size-full wp-image-19045" data-recalc-dims="1" /><br />
<br />
<span style="font-size: 29px;font-weight: bold">Exposure-responses curves</span></p>
</figure>
</div>
</div>
</div>
</section>
<section id="exposure-responses-curves" class="level2">
<p>We can also plot the exposure-responses curves by lag and the overall cumulative curve across all the lag period:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb16">
<pre>allRRfit &lt;- data.frame(
  temperature = as.numeric(rownames(cpred$allRRfit.summary)),
  lag = &quot;overall&quot;,
  RR = cpred$allRRfit.summary[, &quot;0.5quant&quot;],
  RR_lci = cpred$allRRfit.summary[, &quot;0.025quant&quot;],
  RR_uci = cpred$allRRfit.summary[, &quot;0.975quant&quot;]
)

RRfit &lt;- rbind(matRRfit, allRRfit)

# Split data
RRfit_lags &lt;- RRfit |&gt;
  filter(!lag %in% c(&quot;overall&quot;)) |&gt;
  mutate(lag = as.numeric(lag))
RRfit_overall &lt;- RRfit |&gt;
  filter(lag %in% c(&quot;overall&quot;))

temps &lt;- cpred$exp_at
t_cold &lt;- temps[which.min(abs(temps - quantile(temps, 0.01)))]
t_hot &lt;- temps[which.min(abs(temps - quantile(temps, 0.99)))]

# Top plot: exposure-response curves for each lag and overall
p_main &lt;- ggplot() +
  # Background: all lags, fading from vivid (small) to pale (large)
  geom_line(
    data = RRfit_lags,
    aes(x = temperature, y = RR, group = lag, color = lag),
    linewidth = 0.8
  ) +
  scale_color_gradientn(
    colours = c(
      &quot;black&quot;,
      &quot;#2b1d2f&quot;,
      &quot;#4a2f5e&quot;,
      &quot;#6a4c93&quot;,
      &quot;#8b6bb8&quot;,
      &quot;#b39cdb&quot;,
      &quot;#d8c9f1&quot;,
      &quot;#f3eef5&quot;
    ),
    values = scales::rescale(c(0, 0.5, 1, 2, 3, 4, 5, 10, 20))
  ) +
  new_scale_color() +
  new_scale_fill() +
  # Credible intervals
  geom_ribbon(
    data = RRfit_overall,
    aes(
      x = temperature,
      ymin = RR_lci,
      ymax = RR_uci,
      fill = &quot;1&quot;
    ),
    alpha = 0.2
  ) +
  # Highlighted curves
  geom_line(
    data = RRfit_overall,
    aes(x = temperature, y = RR, color = &quot;1&quot;),
    linewidth = 1.2
  ) +
  geom_hline(
    yintercept = 1,
    linetype = &quot;dashed&quot;
  ) +
  scale_color_manual(values = &quot;#a6761d&quot;, labels = &quot;Overall (CrI95%)&quot;) +
  scale_fill_manual(values = &quot;#a6761d&quot;, labels = &quot;Overall (CrI95%)&quot;) +
  scale_y_continuous(
    transform = &quot;log10&quot;,
    breaks = sort(c(0.8, pretty_breaks(5)(c(0.8, 4))))
  ) +
  labs(
    x = NULL,
    y = &quot;Relative Risk (RR)&quot;,
    color = NULL,
    fill = NULL
  ) +
  theme_minimal() +
  theme(
    legend.position = &quot;top&quot;,
    axis.text.x = element_blank(),
    plot.margin = margin(8, 8, 0, 8)
  )

# Bottom plot: histogram with percentile lines
p_hist &lt;- ggplot(london, aes(x = tmean)) +
  geom_histogram(
    aes(y = after_stat(density), fill = after_stat(x)),
    binwidth = 0.5,
    color = &quot;black&quot;,
    linewidth = 0.2
  ) +
  geom_vline(
    xintercept = t_cold,
    linetype = &quot;dashed&quot;,
    color = &quot;#053061&quot;,
    linewidth = 0.6
  ) +
  geom_vline(
    xintercept = t_hot,
    linetype = &quot;dashed&quot;,
    color = &quot;#67001f&quot;,
    linewidth = 0.6
  ) +
  geom_vline(
    xintercept = cen,
    linetype = &quot;dashed&quot;,
    color = &quot;grey20&quot;,
    linewidth = 0.6
  ) +
  annotate(
    &quot;text&quot;,
    x = t_cold,
    y = Inf,
    label = &quot;1st pct&quot;,
    vjust = 1.4,
    hjust = 1.1,
    size = 3.2,
    color = &quot;#053061&quot;
  ) +
  annotate(
    &quot;text&quot;,
    x = t_hot,
    y = Inf,
    label = &quot;99th pct&quot;,
    vjust = 1.4,
    hjust = -0.1,
    size = 3.2,
    color = &quot;#67001f&quot;
  ) +
  annotate(
    &quot;text&quot;,
    x = cen,
    y = Inf,
    label = &quot;MMT&quot;,
    vjust = 1.4,
    hjust = -0.1,
    size = 3.2,
    color = &quot;grey20&quot;
  ) +
  scale_x_continuous(limits = range(cpred$exp_at)) +
  scale_fill_gradientn(
    colours = c(
      &quot;#053061&quot;,
      &quot;#2166ac&quot;,
      &quot;#4393c3&quot;,
      &quot;#92c5de&quot;,
      &quot;#d1e5f0&quot;,
      &quot;#f7f7f7&quot;,
      &quot;#fddbc7&quot;,
      &quot;#f4a582&quot;,
      &quot;#d6604d&quot;,
      &quot;#b2182b&quot;,
      &quot;#67001f&quot;
    ),
    name = &quot;Temperature&quot;
  ) +
  labs(x = &quot;Temperature (°C)&quot;, y = &quot;Density&quot;) +
  theme_minimal() +
  theme(
    plot.margin = margin(20, 8, 8, 8),
    legend.position = &quot;bottom&quot;
  )

# Combine them:
p_main / p_hist + plot_layout(heights = c(3, 1))</pre>
</div>
</div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img loading="lazy" decoding="async" src="https://i1.wp.com/r-posts.com/wp-content/uploads/2026/04/exposure_response.png?w=450" alt="" class="alignnone size-full wp-image-19046" srcset_temp="https://i1.wp.com/r-posts.com/wp-content/uploads/2026/04/exposure_response.png?w=450 1920w, http://r-posts.com/wp-content/uploads/2026/04/exposure_response-375x300.png 375w, http://r-posts.com/wp-content/uploads/2026/04/exposure_response-450x360.png 450w, http://r-posts.com/wp-content/uploads/2026/04/exposure_response-768x614.png 768w, http://r-posts.com/wp-content/uploads/2026/04/exposure_response-1536x1229.png 1536w" sizes="auto, (max-width: 1920px) 100vw, 1920px" data-recalc-dims="1" /><br />
The overall cumulative curve (mustard) is clearly asymmetric: risk increases on both sides of the MMT, but the rise is much steeper for hot temperatures than for cold temperatures. The lag-0 curve (black), which reflects the immediate effect, behaves differently for cold than heat: it is below 1 at cold temperatures (reflecting the delayed nature of cold temperature effects) and increases approximately linearly for heat. The histogram confirms that most London days fall between 5°C and 20°C, so extreme temperatures, despite their high individual risks, are relatively rare events.<br />
<br />
<span style="font-size: 29px;font-weight: bold">Attributable risk</span></p>
</figure>
</div>
</div>
</div>
</section>
<section id="attributable-risk" class="level2">
<p>We can also calculate attributable numbers and fractions from a B-DLNM, which allows to quantify the impact of all the observed exposures in 75+ years mortality. We compute the number of mortality events attributable to the temperature exposures (attributable number) and the fraction of all the mortality events it constitutes (attributable fraction).</p>
<p>Two different perspectives can be used:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>
<p>Backward (<code>dir = &quot;back&quot;</code>): what today’s deaths were explained by past temperature exposures?</p>
</li>
	<li>
<p>Forward (<code>dir = &quot;forw&quot;</code>): what future deaths will today’s temperature exposure cause?</p>
</li>
</ul>
</li>
</ul>
<p>Let’s use the forward perspective, more commonly used:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb17">
<pre>tictoc::tic()
attr_forw &lt;- attributable(
  mod,
  london,
  name_date = &quot;date&quot;,
  name_exposure = &quot;tmean&quot;,
  name_cases = &quot;mort_75plus&quot;,
  cen = cen,
  dir = &quot;forw&quot;
)
tictoc::toc()</pre>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre>110.12 sec elapsed</pre>
</div>
</div>
</section>
<section id="attributable-fraction-evolution" class="level2">
<h2 class="anchored" data-anchor-id="attributable-fraction-evolution">Attributable fraction evolution</h2>
<p>We can plot the time series of daily attributable fractions (AF):</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb19">
<pre>col_af &lt;- &quot;black&quot;

temp_colours &lt;- c(
  &quot;#053061&quot;,
  &quot;#2166ac&quot;,
  &quot;#4393c3&quot;,
  &quot;#92c5de&quot;,
  &quot;#d1e5f0&quot;,
  &quot;#f7f7f7&quot;,
  &quot;#fddbc7&quot;,
  &quot;#f4a582&quot;,
  &quot;#d6604d&quot;,
  &quot;#b2182b&quot;,
  &quot;#67001f&quot;
)

af_med &lt;- attr_forw$af.summary[, &quot;0.5quant&quot;]

# Pre-compute range once
af_min &lt;- min(af_med, na.rm = TRUE) - 0.01
af_max &lt;- max(af_med, na.rm = TRUE) + 0.01

df &lt;- data.frame(
  date = london$date,
  x = yday(london$date),
  year = year(london$date),
  tmean = london$tmean,
  af = af_med
)

ggplot(df, aes(x = x)) +
  # Full-height temperature background per day
  geom_rect(
    aes(
      xmin = x - 0.5,
      xmax = x + 0.5,
      ymin = af_min,
      ymax = af_max,
      fill = tmean
    )
  ) +
  scale_fill_gradientn(
    colours = temp_colours,
    name = &quot;Temperature (°C)&quot;
  ) +
  # AF line on top
  geom_line(
    aes(y = af),
    color = col_af,
    linewidth = 0.7
  ) +
  scale_y_continuous(
    name = &quot;Attributable Fraction (AF)&quot;,
    breaks = seq(0, 1, by = 0.1),
    limits = c(af_min, af_max),
    expand = c(0, 0)
  ) +
  scale_x_continuous(
    breaks = yday(as.Date(paste0(
      &quot;2000-&quot;,
      c(&quot;01&quot;, &quot;03&quot;, &quot;05&quot;, &quot;07&quot;, &quot;09&quot;, &quot;11&quot;),
      &quot;-01&quot;
    ))),
    labels = c(&quot;Jan&quot;, &quot;Mar&quot;, &quot;May&quot;, &quot;Jul&quot;, &quot;Sep&quot;, &quot;Nov&quot;),
    expand = c(0, 0)
  ) +
  facet_wrap(~year, ncol = 3, axes = &quot;all_x&quot;) +
  labs(x = NULL) +
  theme_minimal(base_size = 11) +
  theme(
    panel.spacing.x = unit(0, &quot;pt&quot;),
    strip.text = element_text(face = &quot;bold&quot;, size = 10),
    legend.position = &quot;top&quot;,
    legend.key.width = unit(2.5, &quot;cm&quot;)
  )</pre>
</div>
</div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img loading="lazy" decoding="async" src="https://i2.wp.com/r-posts.com/wp-content/uploads/2026/04/attr_evolution.png?w=450" alt="" class="alignnone size-full wp-image-19047" srcset_temp="https://i2.wp.com/r-posts.com/wp-content/uploads/2026/04/attr_evolution.png?w=450 1344w, http://r-posts.com/wp-content/uploads/2026/04/attr_evolution-263x300.png 263w, http://r-posts.com/wp-content/uploads/2026/04/attr_evolution-450x514.png 450w, http://r-posts.com/wp-content/uploads/2026/04/attr_evolution-768x878.png 768w" sizes="auto, (max-width: 1344px) 100vw, 1344px" data-recalc-dims="1" /><br />
<br />
Sharp spikes in AF exceeding 60% are visible in summer 2003 and 2006, coinciding with the major European heatwaves. In general, summer episodes produce higher and more abrupt peaks in AF, whereas cold winter days are associated with more sustained elevations over time, though less pronounced in magnitude.</p>
</figure>
</div>
</div>
</div>
</section>
<section id="total-attributable-burden" class="level2">
<h2 class="anchored" data-anchor-id="total-attributable-burden">Total attributable burden</h2>
<p>Summing across the full study period, the table quantifies the total mortality burden attributable to non-optimal temperature exposures in the 75+ population:</p>
<div class="cell">
<div class="code-copy-outer-scaffold">
<div class="sourceCode cell-code" id="cb20">
<pre>rbind(
  &quot;Attributable fraction&quot; = attr_forw$aftotal.summary,
  &quot;Attributable number&quot; = attr_forw$antotal.summary
) |&gt;
  as.data.frame() |&gt;
  round(3) |&gt;
  gt(rownames_to_stub = TRUE)</pre>
</div>
</div>
</div>
<div style="width: 100%">
<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false" style="width: 100%;font-size: 12px;height: 140px">
<thead>
<tr class="gt_col_headings header" style="height: 28px">
<th id="a::stub" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col" style="height: 28px"></th>
<th id="mean" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col" style="height: 28px">mean</th>
<th id="sd" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col" style="height: 28px">sd</th>
<th id="a0.025quant" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col" style="height: 28px">0.025quant</th>
<th id="a0.5quant" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col" style="height: 28px">0.5quant</th>
<th id="a0.975quant" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col" style="height: 28px">0.975quant</th>
<th id="mode" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col" style="height: 28px">mode</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd" style="height: 56px">
<th id="stub_1_1" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row" style="height: 56px">Attributable fraction</th>
<td class="gt_row gt_right" headers="stub_1_1 mean" style="height: 56px">0.174</td>
<td class="gt_row gt_right" headers="stub_1_1 sd" style="height: 56px">0.018</td>
<td class="gt_row gt_right" headers="stub_1_1 0.025quant" style="height: 56px">0.139</td>
<td class="gt_row gt_right" headers="stub_1_1 0.5quant" style="height: 56px">0.175</td>
<td class="gt_row gt_right" headers="stub_1_1 0.975quant" style="height: 56px">0.207</td>
<td class="gt_row gt_right" headers="stub_1_1 mode" style="height: 56px">0.176</td>
</tr>
<tr class="even" style="height: 56px">
<th id="stub_1_2" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row" style="height: 56px">Attributable number</th>
<td class="gt_row gt_right" headers="stub_1_2 mean" style="height: 56px">68857.597</td>
<td class="gt_row gt_right" headers="stub_1_2 sd" style="height: 56px">7131.526</td>
<td class="gt_row gt_right" headers="stub_1_2 0.025quant" style="height: 56px">55071.066</td>
<td class="gt_row gt_right" headers="stub_1_2 0.5quant" style="height: 56px">69178.391</td>
<td class="gt_row gt_right" headers="stub_1_2 0.975quant" style="height: 56px">81995.459</td>
<td class="gt_row gt_right" headers="stub_1_2 mode" style="height: 56px">69842.155</td>
</tr>
</tbody>
</table>
</div>

Over the full 2000-2012 period, approximately 17.5<strong>%</strong> (95% CrI: 13.9%-20.7%) of all deaths in the London 75+ population were attributable to non-optimal temperatures, corresponding to roughly 69,178 deaths (95% CrI: 55,071-81,996).<br />
<br />
</section>
<section id="conclusions" class="level1">
<h1>Conclusions</h1>
<p>The {bdlnm} package provides a powerful and accessible implementation of Bayesian Distributed Lag Non-Linear Models in R. By combining the flexibility of DLNMs with full Bayesian inference via INLA, it enables researchers to better quantify uncertainty and fit complex exposure-lag-response relationships. This makes it a valuable tool for studying the health impacts of climate change and other environmental risks in increasingly data-rich settings.</p>
<p>This framework is not limited to environmental epidemiology. In fact it can be applied to any setting involving time-varying exposures and delayed effects (e.g., market shocks may affect asset prices over several days), making it a powerful and general tool for time series analysis.</p>
<p>Development is ongoing. Upcoming features include:</p>
<ul>
	<li style="list-style-type: none">
<ul>
	<li><strong>Multi-location analyses</strong>: pooling exposure-lag-response curves across different cities or regions within a single model</li>
	<li><strong>Spatial B-DLNMs (SB-DLNM)</strong>: explicitly modelling spatial heterogeneity in the exposure-lag-response curves of different regions</li>
</ul>
</li>
</ul>
<p>The package is on <a href="https://cran.r-project.org/package=bdlnm" rel="nofollow" target="_blank">CRAN</a>. Bug reports and contributions are welcome via <a href="https://github.com/pasahe/bdlnm" rel="nofollow" target="_blank">GitHub</a>.</p>
</section>
<section id="references" class="level1">
<h1>References</h1>
<ul>
	<li style="list-style-type: none">
<ul>
	<li>
<p>Gasparrini A. (2011). Distributed lag linear and non-linear models in R: the package dlnm. <em>Journal of Statistical Software</em>, 43(8), 1-20. <a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/10.18637/jss.v043.i08" class="uri" rel="nofollow" target="_blank">doi:10.18637/jss.v043.i08</a>.</p>
</li>
	<li>
<p>Quijal-Zamorano M., Martinez-Beneito M.A., Ballester J., Marí-Dell’Olmo M. (2024). Spatial Bayesian distributed lag non-linear models (SB-DLNM) for small-area exposure-lag-response epidemiological modelling. <em>International Journal of Epidemiology</em>, 53(3), dyae061. <a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/10.1093/ije/dyae061" class="uri" rel="nofollow" target="_blank">doi:10.1093/ije/dyae061</a>.</p>
</li>
	<li>
<p>Rue H., Martino S., Chopin N. (2009). Approximate Bayesian inference for latent Gaussian models by using integrated nested Laplace approximations. <em>Journal of the Royal Statistical Society: Series B</em>, 71(2), 319-392. <a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/10.1111/j.1467-9868.2008.00700.x" class="uri" rel="nofollow" target="_blank">doi:10.1111/j.1467-9868.2008.00700.x</a>.</p>
</li>
	<li>
<p>Gasparrini A., Leone M. (2014). Attributable risk from distributed lag models. <em>BMC Medical Research Methodology</em>, 14, 55. <a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/10.1186/1471-2288-14-55" class="uri" rel="nofollow" target="_blank">doi:10.1186/1471-2288-14-55</a>.</p>
</li>
</ul>
</li>
</ul>
</section><hr style="border-top: black solid 1px" /><a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/" rel="nofollow" target="_blank">New R Package {bdlnm} Released on CRAN: Bayesian Distributed Lag Non-Linear Models in R via INLA</a> was first posted on April 10, 2026 at 5:14 pm.<br />
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://r-posts.com/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/"> R-posts.com</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/new-r-package-bdlnm-released-on-cran-bayesian-distributed-lag-non-linear-models-in-r-via-inla/">New R Package {bdlnm} Released on CRAN: Bayesian Distributed Lag Non-Linear Models in R via INLA</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400475</post-id>	</item>
		<item>
		<title>Using R to Teach R: Lessons for Software Development</title>
		<link>https://www.r-bloggers.com/2026/04/using-r-to-teach-r-lessons-for-software-development/</link>
		
		<dc:creator><![CDATA[The Jumping Rivers Blog]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 23:59:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>As we approach the decennial (10-year) anniversary since Jumping Rivers was founded in 2016, it’s a good time to reflect on what we have achieved in that time and share some lessons learned.<br />
If you have read our blogs previously then you will be aware that Jumping Rivers is a ...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/using-r-to-teach-r-lessons-for-software-development/">Using R to Teach R: Lessons for Software Development</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/"> The Jumping Rivers Blog</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p>
<a href = "https://www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/">
<img src="https://i1.wp.com/www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/featured.png?w=400&#038;ssl=1" style="width:400px" class="image-center" style="display: block; margin: auto;" data-recalc-dims="1" />
</a>
</p>
<p>As we approach the decennial (10-year) anniversary since Jumping Rivers was founded in 2016, it’s a good time to reflect on what we have achieved in that time and share some lessons learned.</p>
<p>If you have read our blogs previously then you will be aware that Jumping Rivers is a consultancy and training provider in all things data science. But did you know that we offer over 50 different courses spanning R, Python, Git, SQL and more?</p>
<p>In this blog we will provide a glimpse into our internal process and share how we have streamlined the task of maintaining so many courses. Along the way we will share some good practices applicable to any big coding project, including packaging of source code and automated CI/CD.</p>
<aside class="advert">
<p>
Whether you want to start from scratch, or improve your skills, <a href="https://www.jumpingrivers.com/training/?utm_source=blog&#038;utm_medium=banner&#038;utm_campaign=2026-teaching-r-packages-reporting-gitlab" rel="nofollow" target="_blank">Jumping Rivers has a training course for you</a>.
</p>
</aside>
<h2 id="the-challenge">The challenge</h2>
<p>Let’s start by laying out the key challenges which face us.</p>
<h3 id="1-multilingual-support">1. Multilingual support</h3>
<p>Our <a href="https://www.jumpingrivers.com/training/all-courses/" rel="nofollow" target="_blank">course catalogue</a> consists of over 50 courses. The majority of these are either based on R or Python or both:</p>
<ul>
<li>50% R</li>
<li>30% Python</li>
<li>5% R and Python</li>
<li>15% other (Git, SQL, Tableau, Posit and more)</li>
</ul>
<p>At the very least, any solution that we come up with for standardising our courses must be compatible with both R and Python. Ideally it should also support some less taught languages including SQL and Git.</p>
<h3 id="2-maintenance">2. Maintenance</h3>
<p>The world of R and Python is constantly changing. The languages themselves receive frequent updates, as do publicly available R packages on <a href="https://cran.r-project.org/" rel="nofollow" target="_blank">CRAN</a> and Python packages on <a href="https://pypi.org/" rel="nofollow" target="_blank">PyPI</a>.</p>
<p>This has the consequence that code which worked one year ago (or even one day) may no longer be functional with the latest package versions. We will need some way to track this and ensure that the code examples covered in our courses remain relevant and error-free.</p>
<h3 id="3-demand">3. Demand</h3>
<p>We deliver over 100 courses per year. For a relatively small team of data scientists, this can be a lot to juggle!</p>
<p>In an ideal world, the process of building the course materials, setting up the cloud environment for training, and managing all of the administration that goes along with this should be automated. That way, the trainer can focus on providing the highest quality experience for the attendees without having to worry about things going wrong on the day.</p>
<h2 id="the-solution">The solution</h2>
<p>Our team is used to setting up data science workflows for clients, including automated reporting and migration of source code into packages. We have therefore applied these techniques in our internal processes, including training.</p>
<h3 id="automated-reporting">Automated reporting</h3>
<p>You write a document which has to be updated on a regular basis; this might include a monthly presentation showing the latest company revenues. Does this scenario sound familiar?</p>
<p>We <em>could</em> regenerate the plots and data tables and manually copy and paste these into the report document. Even better, we can take advantage of free-to-use automated reporting frameworks including <a href="https://rmarkdown.rstudio.com/" rel="nofollow" target="_blank">R Markdown</a> and <a href="https://quarto.org/" rel="nofollow" target="_blank">Quarto</a>.</p>
<p>R Markdown and Quarto both work as follows:</p>
<ul>
<li>
<p>We provide a “YAML header” at the top of the report document with configuration and formatting options:</p>
<pre>---
title: &quot;Introduction to Python&quot;
authors:
- &quot;Myles Mitchell&quot;
date: &quot;2026-04-02&quot;
output: pdf
---
</pre></li>
<li>
<p>The report body is formatted as Markdown and supports a mixture of plain text and code:</p>
<pre>## Introduction
At it&#39;s most basic, Python is essentially a calculator.
We can run basic calculations as follows:
```{python}
2 + 1
```
We can also assign the output of a calculation to a
variable so that it can be reused later:
```{python}
x = 2 + 1
print(x)
```
</pre></li>
</ul>
<p>Notice that we have included chunks of Python code. By making use of <em>chunk options</em> we can configure code chunks to be executed when rendering the report. Any outputs from the code (plots, tables, summary statistics) can then be displayed.</p>
<p>By migrating the code logic into the report itself, we can update our report assets at the click of a button whenever the data changes.</p>
<p>We have taken inspiration from this approach with our course notes and presentation slides. This forces us to be rigorous with the code examples. Any runtime errors that are produced by faulty or outdated code would be visible in the course notes and by extension to the attendees of our courses.</p>
<p>Crucially for us, R Markdown and Quarto are both compatible with R and Python. They also support syntax highlighting for languages like Git and SQL, as well as a variety of output formats including HTML and PDF.</p>
<img src="https://i2.wp.com/www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/quarto-flow-chart.png?w=578&#038;ssl=1" alt="Flow chart illustrating the automated reporting workflow with Quarto. Starting with a text-based .qmd file, this is converted into a Markdown format using Jupyter or knitr. Pandoc is then used to convert this into a variety of output formats including HTML, PDF and Word." data-recalc-dims="1" />
<h3 id="internal-r-packages">Internal R packages</h3>
<p>So we have settled on a solution for building our course notes. But we have 50 different courses, and setting these up from scratch each time is going to get tedious!</p>
<p>A good practice in any coding project is to avoid duplication as much as possible. Instead of copying and pasting code, we should really be migrating code into functions which are self contained, reusable and easy to test. This will mean fewer places to debug when things inevitably go wrong.</p>
<p>Following a similar philosophy for our training infrastructure, we have migrated any reusable assets for our courses—including logos, template files and styling—into a collection of internal R packages.</p>
<p>When building a new course, the developer can now focus on the aspects that are unique to that course:</p>
<ul>
<li>Code examples</li>
<li>Notes</li>
<li>Exercises</li>
<li>Presentation slides</li>
</ul>
<p>Everything else is taken care of automatically:</p>
<ul>
<li>The appearance of the course notes and presentation slides.</li>
<li>Build routines including converting the R Markdown / Quarto text files into HTML.</li>
</ul>
<p>In addition to course templates, we also have internal packages for managing the administrative side of training, including:</p>
<ul>
<li>Calculating pricing quotes for clients.</li>
<li>Generating post-course certificates.</li>
<li>Spinning up a bespoke <a href="https://posit.co/products/enterprise/workbench/" rel="nofollow" target="_blank">Posit Workbench</a> environment for the course.</li>
<li>Summarising attendee feedback.</li>
</ul>
<p>And the list goes on!</p>
<h3 id="gitlab-cicd">GitLab CI/CD</h3>
<p>With automated reporting and packaging of source code, we have created standardised routines that can be applied to any of our courses.</p>
<p>This does not change the fact that we have over 50 courses to maintain. We still need a way of testing our courses and tracking issues. This is where CI/CD (Continuous Integration / Continuous Development and Deployment) comes in.</p>
<p>CI/CD defines a framework for software development, including:</p>
<ul>
<li>Automated unit testing.</li>
<li>Branching of source code and code review.</li>
<li>Versioning and deployment of software.</li>
</ul>
<p>If you maintain software then you have likely come across version control with Git. Cloud platforms like <a href="https://gitlab.com/" rel="nofollow" target="_blank">GitLab</a> and <a href="https://github.com/" rel="nofollow" target="_blank">GitHub</a> provide tools for collaborative code development. Not only do they provide a cloud backup of your source code, they also provide the following features:</p>
<ul>
<li>CI/CD tools for automated testing, build and deployment.</li>
<li>Branch rules for enforcing good practices like code review and unit testing.</li>
<li>Versioning and tagging of source code.</li>
</ul>
<p>Each of our courses is maintained via it’s own GitLab repository. The CI/CD pipelines for our courses are defined in a separate repository along with the internal R packages mentioned above.</p>
<img src="https://i0.wp.com/www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/standardisation.png?w=578&#038;ssl=1" alt="Flow chart illustrating how we have standardised our GitLab training repositories. The templates are defined in a central repository and pushed downstream to our course repositories." data-recalc-dims="1" />
<p>When setting up a new course, the course repository will be automatically populated with the template CI/CD rules. All courses are therefore subject to the same stringent checks, including:</p>
<ul>
<li>Ensuring that the course notes build without errors.</li>
<li>Enforcing code review of any course updates before these are merged into the main branch.</li>
<li>Building and storing the <em>artifacts</em> (the rendered HTML notes and coding scripts) for the latest version of the course.</li>
</ul>
<p>These checks are triggered by any updates to a course. We also schedule monthly CI/CD pipelines for all courses, with any issues immediately flagged to our trainers.</p>
<p>We have also taken advantage of GitLab’s folder-like structure for organising code repositories. Within the Jumping Rivers project on GitLab, we have a subproject called “training”. All of our course-related repositories are located “downstream” from this project. This means that any settings or environment variables defined at the “training” level are automatically applied to all of our courses.</p>
<h2 id="in-summary">In summary</h2>
<p>The take-home lessons from this blog are applicable to any big coding project:</p>
<ul>
<li>Avoid duplication: migrate any reusable logic or assets into standalone packages.</li>
<li>Utilise CI/CD workflows using GitLab, GitHub or similar.</li>
<li>Focus on what matters by automating as much of the process as possible.</li>
</ul>
<p>Our training infrastructure has taken 10 years to build and is still constantly evolving; we have not even covered the full process in this blog! For a deeper dive, check out this <a href="https://youtu.be/MD0F3ChgqBE?si=EFSHE6MOqgU5I9UM" rel="nofollow" target="_blank">talk</a> by Myles at SatRdays London 2024.</p>
<p>For more on automated reporting, check out:</p>
<ul>
<li><a href="https://www.jumpingrivers.com/blog/quarto-for-python-users/" rel="nofollow" target="_blank">Quarto for the Python user</a>.</li>
<li><a href="https://www.jumpingrivers.com/blog/r-parameterised-presentations-quarto/" rel="nofollow" target="_blank">Parameterised presentations with Quarto</a>.</li>
</ul>
<p>For more on packaging of source code, check out:</p>
<ul>
<li><a href="https://www.jumpingrivers.com/blog/personal-r-package/" rel="nofollow" target="_blank">Writing a personal R package</a>.</li>
<li>Three-part series: <a href="https://www.jumpingrivers.com/blog/?search=creating+a+python+package" rel="nofollow" target="_blank">Creating a Python package</a>.</li>
<li>Four-part series: <a href="https://www.jumpingrivers.com/blog/?search=r+package+quality" rel="nofollow" target="_blank">R package quality</a>.</li>
</ul>
<p>
For updates and revisions to this article, see the <a href = "https://www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/">original post</a>
</p>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.jumpingrivers.com/blog/teaching-r-packages-reporting-gitlab/"> The Jumping Rivers Blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/using-r-to-teach-r-lessons-for-software-development/">Using R to Teach R: Lessons for Software Development</a>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">400414</post-id>	</item>
		<item>
		<title>Hold On Hope: publication lag times at cell biology journals</title>
		<link>https://www.r-bloggers.com/2026/04/hold-on-hope-publication-lag-times-at-cell-biology-journals/</link>
		
		<dc:creator><![CDATA[Stephen Royle]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 11:22:53 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://quantixed.org/?p=3723</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> I’ve posted about publication lag times previously. The “lag” refers to the time from submitting a paper and it appearing in a journal. Publication lag times are still a frustration for researchers. Although preprints circumvent the delay in sharing science with others, publication is still king when it comes ...</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/hold-on-hope-publication-lag-times-at-cell-biology-journals/">Hold On Hope: publication lag times at cell biology journals</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://quantixed.org/2026/04/09/hold-on-hope-publication-lag-times-at-cell-biology-journals/"> Rstats – quantixed</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p>I’ve posted about publication <a href="https://quantixed.org/tag/lag-times/" rel="nofollow" target="_blank">lag times</a> previously. The “lag” refers to the time from submitting a paper and it appearing in a journal.</p>



<p>Publication lag times are still a frustration for researchers. Although preprints circumvent the delay in sharing science with others, publication is still king when it comes to evaluation. Contracts are short and publication delays can be long…</p>



<p>I recently saw a post comparing <a href="https://sashagusev.github.io/Genetics_Pub_Dates/" rel="nofollow" target="_blank">median publication lag times for genetics journals</a>. This motivated me to update my code and rerun the analysis for cell biology journals to see what, if anything, has changed.</p>



<h2 class="wp-block-heading">Methodology</h2>



<p>I wrote an R package <a href="https://github.com/quantixed/PubMedLagR" rel="nofollow" target="_blank">PubMedLagR</a> which uses <code>{rentrez}</code> to retrieve the publication data from PubMed. Once we have this data, it is a matter of producing some plots which I have covered <a href="https://quantixed.org/2021/04/04/ten-years-vs-the-spread-ii-calculating-publication-lag-times-in-r/" data-type="post" data-id="2369" rel="nofollow" target="_blank">previously</a>. To ensure that we are only looking at research papers, we use <code>&quot;journal article&quot;[pt]</code> as a search term, and also remove from the data anything else (Reviews, Commentaries etc.). Feel free to use it to look at other journals.</p>



<h2 class="wp-block-heading">Caveats</h2>



<p>Before we get started, there are some caveats. The analysis is only as good as the PubMed data. Not all journals submit their date information to PubMed, while for others it is incomplete (as we’ll see below). There are inaccuracies for sure. I found a paper that was supposedly submitted on 1970-01-01, more than 40 years before the journal started. Also, it’s well known that some journals “restart the clock” on a paper by rejecting it and allowing resubmission, then only counting the resubmitted version. So, comparison between journals is a little tricky, but it allows us to look at trends.</p>



<h2 class="wp-block-heading">Let’s dive in</h2>



<p>We can use the following code to grab the data we are interested in.</p>


<pre>
library(PubMedLagR)
jrnl_list &lt;- c(&quot;J Cell Sci&quot;, &quot;Mol Biol Cell&quot;, &quot;J Cell Biol&quot;, &quot;Nat Cell Biol&quot;,
               &quot;EMBO J&quot;, &quot;Biochem J&quot;, &quot;Dev Cell&quot;, &quot;FASEB J&quot;, &quot;J Biol Chem&quot;,
               &quot;Cells&quot;, &quot;Front Cell Dev Biol&quot;, &quot;Nature Communications&quot;,
               &quot;Cell Reports&quot;, &quot;Mol Cell&quot;, &quot;Autophagy&quot;, &quot;Cell Death Differ&quot;,
               &quot;Cell Death Dis&quot;, &quot;Cell Res&quot;, &quot;Sci Adv&quot;, &quot;Cell&quot;)
yrs &lt;- 2006:2026
retrieve_journal_year_records(jrnl_list, yrs, batch_size = 250)
pprs &lt;- pubmed_xmls_to_df()
</pre>


<p>The list of journals is somewhat arbitrary. I have included Nature Communications and Science Advances although they carry many other papers besides cell biology. I included Cell (even though there’s not much cell biology in there these days) and left out Nature and Science.</p>



<p><strong>How many papers are in each of these journals and how has that changed over time?</strong></p>



<figure data-wp-context="{"imageId":"69d7ae27af126"}" data-wp-interactive="core/image" data-wp-key="69d7ae27af126" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" fetchpriority="high" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/journals_facet-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3724" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/journals_facet-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/journals_facet-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/journals_facet-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/journals_facet-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/journals_facet-2048x1170.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p>There’s a huge increase in the number of papers published by Nature Communications, Science Advances and Cell Reports. Nature Communications is a behemoth, publishing ~12,500 papers in 2025.</p>



<p>There was a boom and bust in publications at Front Cell Dev Biol and Cells which could be due to reputational problems (like <a href="https://arstechnica.com/science/2024/02/scientists-aghast-at-bizarre-ai-rat-with-huge-genitals-in-peer-reviewed-article/" rel="nofollow" target="_blank">this</a>). Other journals have declined. Most noticeably J Biol Chem, but others have taken a hit. The reasons behind these dynamics are discussed <a href="https://doi.org/10.1371/journal.pbio.3002234" rel="nofollow" target="_blank">elsewhere</a>.</p>



<h2 class="wp-block-heading">Median publication lag time</h2>



<p>We’ll use received-to-published as our measure of publication lag time. This is the time from submission to it appearing in the journal “in print”. It’s measured here in days.</p>



<figure data-wp-context="{"imageId":"69d7ae27af794"}" data-wp-interactive="core/image" data-wp-key="69d7ae27af794" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_facet-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3725" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_facet-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_facet-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_facet-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_facet-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_facet-2048x1170.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p>For the last 5 years, the median lag time at Nature Cell Biology is over one year. Other outlets are close to this, e.g. Cell, Dev Cell; whereas others linger around 200 days, or lower in the case of J Cell Sci, FASEB J et al. The journal Autophagy is missing here because there are no data for it. Others, like Sci Adv, MBoC have only minimal data available. The shortest lag times were for Cells (which might not surprise some people).</p>



<p>The lion’s share of this lag time is the time from submission to acceptance (received-accepted), with a small contribution from the time taken to formally publish the article (accepted-published).</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure data-wp-context="{"imageId":"69d7ae27afcd1"}" data-wp-interactive="core/image" data-wp-key="69d7ae27afcd1" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3726" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_acc_pub_facet-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3726" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_acc_pub_facet-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/lag_acc_pub_facet-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/lag_acc_pub_facet-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/lag_acc_pub_facet-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/lag_acc_pub_facet-2048x1170.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<figure data-wp-context="{"imageId":"69d7ae27b016a"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b016a" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3727" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_rec_acc_facet-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3727" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_rec_acc_facet-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_acc_facet-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_acc_facet-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_acc_facet-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_acc_facet-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>
</figure>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td>Journal</td><td>Year</td><td>Accepted-Published</td><td>Recieved-Published</td><td>Recieved-Accepted</td></tr><tr><td>Biochem J</td><td>2025</td><td>6</td><td>125</td><td>116</td></tr><tr><td>Cell</td><td>2025</td><td>29</td><td>308.5</td><td>275.5</td></tr><tr><td>Cell Death Differ</td><td>2025</td><td>13</td><td>235</td><td>221</td></tr><tr><td>Cell Death Dis</td><td>2025</td><td>18</td><td>218</td><td>193</td></tr><tr><td>Cell Rep</td><td>2025</td><td>23</td><td>233</td><td>209</td></tr><tr><td>Cell Res</td><td>2025</td><td>34</td><td>208.5</td><td>172</td></tr><tr><td>Cells</td><td>2025</td><td>16</td><td>57</td><td>41</td></tr><tr><td>Dev Cell</td><td>2025</td><td>27</td><td>322</td><td>296</td></tr><tr><td>EMBO J</td><td>2025</td><td>27</td><td>222</td><td>196</td></tr><tr><td>FASEB J</td><td>2025</td><td>13</td><td>131</td><td>117</td></tr><tr><td>Front Cell Dev Biol</td><td>2025</td><td>35</td><td>111</td><td>71</td></tr><tr><td>J Biol Chem</td><td>2025</td><td>9</td><td>128</td><td>117</td></tr><tr><td>J Cell Biol</td><td>2025</td><td>35</td><td>259</td><td>218</td></tr><tr><td>J Cell Sci</td><td>2025</td><td>13</td><td>168.5</td><td>155</td></tr><tr><td>Mol Cell</td><td>2025</td><td>27</td><td>258</td><td>231</td></tr><tr><td>Nat Cell Biol</td><td>2025</td><td>48</td><td>381.5</td><td>327</td></tr><tr><td>Nat Commun</td><td>2025</td><td>20</td><td>266</td><td>241</td></tr></tbody></table></figure>



<p>This is using the median time. Obviously, some papers whizz straight in, whereas others… don’t. Let’s have a look.</p>



<figure data-wp-context="{"imageId":"69d7ae27b0e23"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b0e23" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_scatter_scale-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3728" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_scatter_scale-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_scatter_scale-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_scatter_scale-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_scatter_scale-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/lag_rec_pub_scatter_scale-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p>You can see many examples of papers that have lag times of 1, 2 or 3 years. I scaled all the plots to a maximum lag time of 3 years. There were several examples of papers with lag times of up to 7 years that looked to be genuine, but they distorted the view.</p>



<p><strong>So what trends can we see?</strong></p>



<p>The lag times are creeping up at some journals, but not at others. It’s possible to see some very short lag times (in amongst the longer ones) recently at Dev Cell, Mol Cell and EMBO J. I assume these are transfers in to the journal, leading to rapid publication. Although Cell also has many of those too, so perhaps there are other explanations.</p>



<p>To click though in more detail, I made some graphics for each journal which use ridgelines to look at the profile of lag times for each year.</p>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure data-wp-context="{"imageId":"69d7ae27b1420"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b1420" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3729" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/BiochemJ_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3729" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/BiochemJ_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/BiochemJ_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/BiochemJ_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/BiochemJ_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/BiochemJ_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Biochem J</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b189e"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b189e" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3734" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/Cell_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3734" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/Cell_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/Cell_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/Cell_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/Cell_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/Cell_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Cell</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b1d82"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b1d82" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3731" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/CellDeathDiffer_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3731" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/CellDeathDiffer_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDiffer_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDiffer_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDiffer_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDiffer_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Cell Death Differ</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b222e"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b222e" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3730" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/CellDeathDis_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3730" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/CellDeathDis_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDis_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDis_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDis_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/CellDeathDis_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Cell Death Dis</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b26bb"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b26bb" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3735" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/CellRep_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3735" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/CellRep_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/CellRep_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/CellRep_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/CellRep_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/CellRep_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Cell Rep</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b2b0d"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b2b0d" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3732" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/CellRes_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3732" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/CellRes_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/CellRes_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/CellRes_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/CellRes_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/CellRes_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Cell Res</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b2fcb"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b2fcb" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3733" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/Cells_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3733" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/Cells_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/Cells_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/Cells_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/Cells_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/Cells_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Cells</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b3448"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b3448" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3736" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/DevCell_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3736" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/DevCell_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/DevCell_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/DevCell_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/DevCell_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/DevCell_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Dev Cell</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b38ef"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b38ef" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3737" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/EMBOJ_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3737" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/EMBOJ_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/EMBOJ_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/EMBOJ_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/EMBOJ_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/EMBOJ_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">EMBO J</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b3d5a"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b3d5a" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3738" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/FASEBJ_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3738" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/FASEBJ_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/FASEBJ_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/FASEBJ_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/FASEBJ_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/FASEBJ_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">FASEB J</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b4222"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b4222" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3739" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/FrontCellDevBiol_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3739" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/FrontCellDevBiol_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/FrontCellDevBiol_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/FrontCellDevBiol_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/FrontCellDevBiol_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/FrontCellDevBiol_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Front Cell Dev Biol</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b469f"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b469f" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3741" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/JBiolChem_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3741" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/JBiolChem_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/JBiolChem_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/JBiolChem_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/JBiolChem_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/JBiolChem_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">J Biol Chem</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b4aef"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b4aef" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3740" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/JCellBiol_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3740" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/JCellBiol_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/JCellBiol_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/JCellBiol_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/JCellBiol_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/JCellBiol_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">J Cell Biol</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b4f41"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b4f41" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3743" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/JCellSci_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3743" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/JCellSci_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/JCellSci_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/JCellSci_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/JCellSci_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/JCellSci_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">J Cell Sci</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b5446"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b5446" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3742" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/MolBiolCell_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3742" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/MolBiolCell_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/MolBiolCell_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/MolBiolCell_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/MolBiolCell_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/MolBiolCell_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Mol Biol Cell</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b5896"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b5896" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3744" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/MolCell_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3744" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/MolCell_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/MolCell_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/MolCell_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/MolCell_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/MolCell_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Mol Cell</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b5d7a"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b5d7a" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3745" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/NatCellBiol_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3745" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/NatCellBiol_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/NatCellBiol_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/NatCellBiol_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/NatCellBiol_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/NatCellBiol_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Nat Cell Biol</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b61f9"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b61f9" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3746" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/NatCommun_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3746" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/04/NatCommun_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/NatCommun_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/NatCommun_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/NatCommun_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/NatCommun_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Nat Commun</figcaption></figure>



<figure data-wp-context="{"imageId":"69d7ae27b66ae"}" data-wp-interactive="core/image" data-wp-key="69d7ae27b66ae" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" data-id="3747" src="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/SciAdv_lag_plots-1024x585.png?w=450&#038;ssl=1" alt="" class="wp-image-3747" srcset_temp="https://i0.wp.com/quantixed.org/wp-content/uploads/2026/04/SciAdv_lag_plots-1024x585.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/SciAdv_lag_plots-300x171.png 300w, https://quantixed.org/wp-content/uploads/2026/04/SciAdv_lag_plots-768x439.png 768w, https://quantixed.org/wp-content/uploads/2026/04/SciAdv_lag_plots-1536x878.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/SciAdv_lag_plots-2048x1170.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Sci Adv</figcaption></figure>
</figure>



<h2 class="wp-block-heading">And finally</h2>



<p>Incidentally, nine of the top ten papers with the longest lag times were published in Nature Communications. The longest was this one (3263 days). Almost nine years! All papers have their battle stories and I’m sure this one has a tale to tell.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/image-1024x699.png?w=450&#038;ssl=1" alt="" class="wp-image-3748" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/04/image-1024x699.png?w=450&#038;ssl=1 1024w, https://quantixed.org/wp-content/uploads/2026/04/image-300x205.png 300w, https://quantixed.org/wp-content/uploads/2026/04/image-768x525.png 768w, https://quantixed.org/wp-content/uploads/2026/04/image-1536x1049.png 1536w, https://quantixed.org/wp-content/uploads/2026/04/image.png 1546w" sizes="auto, (max-width: 1024px) 100vw, 1024px" data-recalc-dims="1" /></figure>



<p>—</p>



<p>The post title comes from “Hold On Hope” by Guided by Voices.</p>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://quantixed.org/2026/04/09/hold-on-hope-publication-lag-times-at-cell-biology-journals/"> Rstats – quantixed</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/hold-on-hope-publication-lag-times-at-cell-biology-journals/">Hold On Hope: publication lag times at cell biology journals</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400426</post-id>	</item>
		<item>
		<title>Developer Engagement and Bioconductor</title>
		<link>https://www.r-bloggers.com/2026/04/developer-engagement-and-bioconductor/</link>
		
		<dc:creator><![CDATA[Nicholas Cooley, PhD]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://blog.bioconductor.org/posts/2026-04-09-developer-engagement/</guid>

					<description><![CDATA[<p>Introduction<br />
During the Chan Zuckerberg Institute’s Essential Open Source Software for Science cycle 6 funding round, the Bioconductor Community Manager, Maria Doyle, secured a grant to fund a developer engagement position for Bioconductor, and...</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/developer-engagement-and-bioconductor/">Developer Engagement and Bioconductor</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://blog.bioconductor.org/posts/2026-04-09-developer-engagement/"> Bioconductor community blog</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>During the Chan Zuckerberg Institute’s <a href="https://blog.bioconductor.org/posts/2024-07-12-czi-eoss6-grants/" rel="nofollow" target="_blank">Essential Open Source Software for Science</a> cycle 6 funding round, the Bioconductor Community Manager, Maria Doyle, secured a grant to fund a developer engagement position for Bioconductor, and I was fortunate enough to be offered that role. I am Nick Cooley, and I’m excited to see what this role can bring to Bioconductor. My background is relatively diverse, I received my PhD in organic chemistry from the University of Missouri, and I worked on prokaryotic genomics and functional genomics at the University of Pittsburgh from 2017 to 2025.</p>
</section>
<section id="role-responsibilities" class="level2">
<h2 class="anchored" data-anchor-id="role-responsibilities">Role responsibilities</h2>
<p>The mandate of this role is somewhat broad. Bioconductor, and academic computing generally face a myriad of distinct and interrelated challenges as hardware, computing paradigms, and education environments change rapidly. Improving developer resources for tackling new and existing challenges, modernizing Bioconductor developer onboarding materials (particularly for early career researchers), and improving recognition mechanisms for community members who volunteer time and effort to the Bioconductor project are all general themes within the role scope.</p>
</section>
<section id="some-specific-efforts" class="level2">
<h2 class="anchored" data-anchor-id="some-specific-efforts">Some Specific Efforts</h2>
<p>A few of the specific efforts I’ll be working on in this role include:</p>
<section id="developer-forum" class="level3">
<h3 class="anchored" data-anchor-id="developer-forum">Developer Forum</h3>
<p>The <a href="https://bioconductor.org/developers/developers-forum/" rel="nofollow" target="_blank">Developer Forum</a> had previously been run on a volunteer basis, and served as a community resource for discussing technical and infrastructure issues, concerns, and opportunities. The creation of the Developer Engagement Lead allowed us include the Forum as direct responsibility of this role.</p>
</section>
<section id="developer-champions-program" class="level3">
<h3 class="anchored" data-anchor-id="developer-champions-program">Developer Champions Program</h3>
<p><a href="https://workinggroups.bioconductor.org/" rel="nofollow" target="_blank">Bioconductor working groups</a> have been a pillar of Bioconductor for a while, and represent a considerable amount of volunteer work towards the project. Improving the visibility of the working groups themselves, and the recognition that project contributors receive for their participation in the working groups can go a long way towards ensuring that that work is valued by contributors home institutions and funding mechanisms. The Champions Program aims to create a clear recognition mechanism for those volunteer efforts.</p>
</section>
<section id="bioconductor-hackathon-events" class="level3">
<h3 class="anchored" data-anchor-id="bioconductor-hackathon-events">Bioconductor hackathon events</h3>
<p>Community and collaboration are irreplaceable engines of strong research. Many Bioconductor contributors find community and collaboration within their own disciplines or institutions. Providing an avenue for collaborative and technical events within Bioconductor can fill persistent gaps in the the research tooling present in the project, and present networking opportunities for early career researchers. Part of this role is <a href="https://bioconductor.org/developers/bioccommits/" rel="nofollow" target="_blank">planning and running these events</a>.</p>
</section>
<section id="bioconductor-documentation-and-llms" class="level3">
<h3 class="anchored" data-anchor-id="bioconductor-documentation-and-llms">Bioconductor documentation and LLMs</h3>
<p>The ways that researchers search for information, tools, and workflow examples are changing with the rise of large language models and their interfaces. There are opportunities for improving how bioinformaticians, especially those outside of the Bioconductor community, find and familiarize themselves with research solutions within the Bioconductor project, including through improvements to website search and documentation discoverability. A long term goal of this role is to work on documentation templates and checking tools to improve their searchability by LLMs, and explore the feasibility of Bioconductor sanctioned and managed LLMs.</p>
</section>
</section>
<section id="how-to-get-in-touch" class="level2">
<h2 class="anchored" data-anchor-id="how-to-get-in-touch">How to get in touch</h2>
<p>For developer discussions and ideas, the <a href="https://chat.bioconductor.org/" rel="nofollow" target="_blank">Bioconductor Zulip</a> is the best place to connect.</p>


</section>

<p>
© 2026 Bioconductor. Content is published under <a href="https://creativecommons.org/licenses/by/4.0/" rel="nofollow" target="_blank">Creative Commons CC-BY-4.0 License</a> for the text and <a href="https://opensource.org/licenses/BSD-3-Clause" rel="nofollow" target="_blank">BSD 3-Clause License</a> for any code. | <a href="https://www.r-bloggers.com/" rel="nofollow" target="_blank">R-Bloggers</a>
</p> 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://blog.bioconductor.org/posts/2026-04-09-developer-engagement/"> Bioconductor community blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/developer-engagement-and-bioconductor/">Developer Engagement and Bioconductor</a>]]></content:encoded>
					
		
		<enclosure url="https://blog.bioconductor.org/posts/2026-04-09-developer-engagement/featured-image.jpeg" length="0" type="image/jpeg" />

		<post-id xmlns="com-wordpress:feed-additions:1">400428</post-id>	</item>
		<item>
		<title>Collaborating between Bioconductor and R-universe on Development of Common Infrastructure</title>
		<link>https://www.r-bloggers.com/2026/04/collaborating-between-bioconductor-and-r-universe-on-development-of-common-infrastructure-2/</link>
		
		<dc:creator><![CDATA[The rOpenSci Team]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://blog.bioconductor.org/posts/2026-04-08-r-universe-collaboration/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>This article is cross-posted on rOpenSci and R-Consortium blogs.<br />
For more than two decades, the Bioconductor project has been a cornerstone of the R ecosystem, providing high-quality, peer-reviewed tools for bioinformatics and computational biol...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/collaborating-between-bioconductor-and-r-universe-on-development-of-common-infrastructure-2/">Collaborating between Bioconductor and R-universe on Development of Common Infrastructure</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://blog.bioconductor.org/posts/2026-04-08-r-universe-collaboration/"> Bioconductor community blog</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 





<p><small><i>This article is cross-posted on <a href="https://ropensci.org/blog/" rel="nofollow" target="_blank">rOpenSci</a> and <a href="https://r-consortium.org/blog/" rel="nofollow" target="_blank">R-Consortium</a> blogs.</i></small></p>
<p>For more than two decades, the <a href="https://www.bioconductor.org/" rel="nofollow" target="_blank">Bioconductor project</a> has been a cornerstone of the R ecosystem, providing high-quality, peer-reviewed tools for bioinformatics and computational biology. Its curated repository model, rigorous review standards, and tightly coordinated release process have helped establish Bioconductor as one of the most trusted distribution channels in scientific computing.</p>
<p>However, the infrastructure that supports such a long-standing and large-scale project inevitably accumulates technical debt. Legacy build systems, bespoke tooling, and historically grown workflows add up to costly and unsustainable maintenance work. For this reason, Bioconductor is collaborating with <a href="https://r-universe.dev/" rel="nofollow" target="_blank">R-universe</a> to gradually modernize parts of its infrastructure, while accommodating the project’s scale, governance, and established processes. In turn, Bioconductor is helping R-universe expand and refine its features as we learn to serve the complex needs of the Bioconductor community.</p>
<p>This collaboration reflects a core principle of R-universe as an R Consortium <a href="https://r-consortium.org/all-projects/" rel="nofollow" target="_blank">Infrastructure Steering Committee (ISC)</a> top-level project: supporting reviewed package repositories such as rOpenSci and Bioconductor, and providing modern, open, and reusable infrastructure that strengthens the broader R ecosystem.</p>
<section id="a-shared-mission-tooling-for-managed-repositories" class="level2">
<h2 class="anchored" data-anchor-id="a-shared-mission-tooling-for-managed-repositories">A Shared Mission: Tooling for Managed Repositories</h2>
<p>R-universe was designed as a next-generation package distribution and build system for R. It provides:</p>
<ul>
<li>Continuous building and checking of R packages across platforms<br>
</li>
<li>Binary packages for Windows, macOS, Linux, and WebAssembly<br>
</li>
<li>Transparent and reproducible build environments managed via GitHub actions<br>
</li>
<li>Dashboards and metadata APIs for monitoring ecosystem health and activity<br>
</li>
<li>CRAN-like package repositories with discoverable metrics and documentation</li>
</ul>
<p>From the outset, a key objective has been to support curated and reviewed communities — such as rOpenSci and Bioconductor — by offering modern infrastructure without requiring them to redesign their governance model or review processes.</p>
<p>For Bioconductor, this means incrementally introducing piece-wise functionality, with consideration for established release cycles and quality control mechanisms:</p>
<ol type="1">
<li>Setting up independent build and dashboard tooling, replicating processes from the current Bioconductor build systems on R-universe infrastructure</li>
<li>Mirroring Windows and macOS binaries produced on R-universe to Bioconductor</li>
<li>Exploring further integration of results and metadata produced by R-universe for Bioconductor health/activity monitoring and aiding the curation processes</li>
<li>Potential future steps toward deeper automation and harmonization</li>
</ol>
<p>By taking small gradual steps towards adopting R-universe components, everyone gets the opportunity to experiment with new tooling and evaluate where adjustments may be needed in order to minimize disruption to existing practices.</p>
<p>An important milestone in this venture is that Bioconductor now uses R-universe to build the Windows and macOS binaries, which significantly reduces costs and the maintenance load on the Bioconductor team. Beyond binary distribution, we are currently exploring deeper integration of R-universe’s continuous check results into Bioconductor’s quality control and release processes.</p>
</section>
<section id="two-universes-release-and-development" class="level2">
<h2 class="anchored" data-anchor-id="two-universes-release-and-development">Two Universes: Release and Development</h2>
<p>Bioconductor maintains two distinct repositories:</p>
<ul>
<li>A <strong>release</strong> branch for stable packages<br>
</li>
<li>A <strong>devel</strong> branch for ongoing development and the next release cycle</li>
</ul>
<p>To mirror this structure, we currently operate two dedicated R-universe instances:</p>
<ul>
<li><strong>Development branch:</strong> <a href="https://bioc.r-universe.dev/" rel="nofollow" target="_blank">https://bioc.r-universe.dev</a><br>
</li>
<li><strong>Release branch:</strong> <a href="https://bioc-release.r-universe.dev/" rel="nofollow" target="_blank">https://bioc-release.r-universe.dev</a></li>
</ul>
<p>These universes integrate directly with Bioconductor’s existing Git infrastructure and provide continuous builds for packages in both branches.</p>
<p>Through the R-universe dashboard, package maintainers and users can:</p>
<ul>
<li>Inspect cross-platform check results<br>
</li>
<li>Review extended BiocCheck diagnostics<br>
</li>
<li>Monitor build logs and dependency graphs<br>
</li>
<li>Explore rich package metadata and metrics<br>
</li>
<li>Publish binary packages for Windows, macOS, and Linux</li>
</ul>
<p>This provides a familiar yet modern interface for Bioconductor contributors, aligned with what users increasingly expect from contemporary R package infrastructure.</p>
<p>Information about each package is available on <code>https://bioc.r-universe.dev/{pkgname}</code>. For example, <a href="https://bioc.r-universe.dev/DESeq2" rel="nofollow" target="_blank">https://bioc.r-universe.dev/DESeq2</a> provides details on the DESeq2 package as shown below:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="https://i0.wp.com/docs.r-universe.dev/img/bioc-pkg.png?ssl=1" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="screenshot of r-universe" rel="nofollow" target="_blank"><img src="https://i0.wp.com/docs.r-universe.dev/img/bioc-pkg.png?w=578&#038;ssl=1" class="img-fluid figure-img" alt="screenshot of r-universe" data-recalc-dims="1"></a></p>
<figcaption>screenshot of r-universe</figcaption>
</figure>
</div>
<p>If this is your first time visiting R-universe, we recommend clicking the “Website Tour” button which will walk you through the most important information in 1 or 2 minutes.</p>
</section>
<section id="technical-documentation-for-bioconductor-maintainers" class="level2">
<h2 class="anchored" data-anchor-id="technical-documentation-for-bioconductor-maintainers">Technical Documentation for Bioconductor Maintainers</h2>
<p>The R-universe project maintains comprehensive technical documentation at <a href="https://docs.r-universe.dev/" rel="nofollow" target="_blank">https://docs.r-universe.dev</a>. For Bioconductor specifically, we created a dedicated section summarizing the most relevant topics for developers to get started with R-universe: <a href="https://docs.r-universe.dev/bioconductor/" rel="nofollow" target="_blank">https://docs.r-universe.dev/bioconductor/</a></p>
<p>As the collaboration evolves and new components get introduced, the documentation will continue to be expanded. The goal is to provide Bioconductor maintainers with a clear reference point for understanding how R-universe fits into their development workflow, while maintaining compatibility with the established practices that have made Bioconductor a successful project within the R community.</p>
</section>
<section id="looking-ahead" class="level2">
<h2 class="anchored" data-anchor-id="looking-ahead">Looking Ahead</h2>
<p>Adopting new infrastructure inevitably involves adjustments. For Bioconductor developers, integrating with a new build and distribution system will likely require some changes to workflows, and time to become familiar with new or different package checks, build diagnostics, and binary distribution.</p>
<p>However, by gradually moving toward common infrastructure, the Bioconductor project will benefit from improvements that are being continuously developed and maintained for the broader R ecosystem. A system based on modern continuous integration (CI) will provide developers with improved tooling, and will give the core team more time to focus on community coordination and quality control, rather than on maintaining costly infrastructure. At the same time, the shared platform provided by R-universe can help to increase the visibility and accessibility of Bioconductor software to the greater R community.</p>
<p>We look forward to continuing this alliance and to working with the Bioconductor community to ensure that the next generation of infrastructure supports the project for many years to come.</p>


</section>

<p>
© 2025 Bioconductor. Content is published under <a href="https://creativecommons.org/licenses/by/4.0/" rel="nofollow" target="_blank">Creative Commons CC-BY-4.0 License</a> for the text and <a href="https://opensource.org/licenses/BSD-3-Clause" rel="nofollow" target="_blank">BSD 3-Clause License</a> for any code. | <a href="https://www.r-bloggers.com/" rel="nofollow" target="_blank">R-Bloggers</a>
</p> 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://blog.bioconductor.org/posts/2026-04-08-r-universe-collaboration/"> Bioconductor community blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/collaborating-between-bioconductor-and-r-universe-on-development-of-common-infrastructure-2/">Collaborating between Bioconductor and R-universe on Development of Common Infrastructure</a>]]></content:encoded>
					
		
		<enclosure url="https://docs.r-universe.dev/img/bioc-pkg.png" length="0" type="image/png" />

		<post-id xmlns="com-wordpress:feed-additions:1">400403</post-id>	</item>
		<item>
		<title>Collaborating between Bioconductor and R-universe on Development of Common Infrastructure</title>
		<link>https://www.r-bloggers.com/2026/04/collaborating-between-bioconductor-and-r-universe-on-development-of-common-infrastructure/</link>
		
		<dc:creator><![CDATA[rOpenSci]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://ropensci.org/blog/2026/04/08/r-universe-bioc/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
For more than two decades, the Bioconductor project has been a cornerstone of the R ecosystem, providing high-quality, peer-reviewed tools for bioinformatics and computational biology. Its curated repository model, rigorous review standards, and tight...</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/collaborating-between-bioconductor-and-r-universe-on-development-of-common-infrastructure/">Collaborating between Bioconductor and R-universe on Development of Common Infrastructure</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://ropensci.org/blog/2026/04/08/r-universe-bioc/"> rOpenSci - open tools for open science</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p>For more than two decades, the <a href="https://www.bioconductor.org/" rel="nofollow" target="_blank">Bioconductor project</a> has been a cornerstone of the R ecosystem, providing high-quality, peer-reviewed tools for bioinformatics and computational biology. Its curated repository model, rigorous review standards, and tightly coordinated release process have helped establish Bioconductor as one of the most trusted distribution channels in scientific computing.</p>
<p>However, the infrastructure that supports such a long-standing and large-scale project inevitably accumulates technical debt. Legacy build systems, bespoke tooling, and historically grown workflows add up to costly and unsustainable maintenance work. For this reason, Bioconductor is collaborating with <a href="https://r-universe.dev/" rel="nofollow" target="_blank">R-universe</a> to gradually modernize parts of its infrastructure, while accommodating the project’s scale, governance, and established processes. In turn, Bioconductor is helping R-universe expand and refine its features as we learn to serve the complex needs of the Bioconductor community.</p>
<p>This collaboration reflects a core principle of R-universe as an R Consortium <a href="https://r-consortium.org/all-projects/" rel="nofollow" target="_blank">Infrastructure Steering Committee (ISC)</a> top-level project: supporting reviewed package repositories such as rOpenSci and Bioconductor, and providing modern, open, and reusable infrastructure that strengthens the broader R ecosystem.</p>
<h2>
A shared mission: Tooling for managed repositories
</h2><p>R-universe was designed as a next-generation package distribution and build system for R. It provides:</p>
<ul>
<li>Continuous building and checking of R packages across platforms</li>
<li>Binary packages for Windows, macOS, Linux, and WebAssembly</li>
<li>Transparent and reproducible build environments managed via GitHub actions</li>
<li>Dashboards and metadata APIs for monitoring ecosystem health and activity</li>
<li>CRAN-like package repositories with discoverable metrics and documentation</li>
</ul>
<p>From the outset, a key objective has been to support curated and reviewed communities — such as rOpenSci and Bioconductor — by offering modern infrastructure without requiring them to redesign their governance model or review processes.</p>
<p>For Bioconductor, this means incrementally introducing piece-wise functionality, with consideration for established release cycles and quality control mechanisms:</p>
<ol>
<li>Setting up independent build and dashboard tooling, replicating processes from the current Bioconductor build systems on R-universe infrastructure</li>
<li>Mirroring Windows and macOS binaries produced on R-universe to Bioconductor</li>
<li>Exploring further integration of results and metadata produced by R-universe for Bioconductor health/activity monitoring and aiding the curation processes</li>
<li>Potential future steps toward deeper automation and harmonization</li>
</ol>
<p>By taking small gradual steps towards adopting R-universe components, everyone gets the opportunity to experiment with new tooling and evaluate where adjustments may be needed in order to minimize disruption to existing practices.</p>
<p>An important milestone in this venture is that Bioconductor now uses R-universe to build the Windows and macOS binaries, which significantly reduces costs and the maintenance load on the Bioconductor team. Beyond binary distribution, we are currently exploring deeper integration of R-universe’s continuous check results into Bioconductor’s quality control and release processes.</p>
<h2>
Two Universes: Release and Development
</h2><p>Bioconductor maintains two distinct repositories:</p>
<ul>
<li>A <strong>release</strong> branch for stable packages</li>
<li>A <strong>devel</strong> branch for ongoing development and the next release cycle</li>
</ul>
<p>To mirror this structure, we currently operate two dedicated R-universe instances:</p>
<ul>
<li><strong>Development branch:</strong> <a href="https://bioc.r-universe.dev/" rel="nofollow" target="_blank">https://bioc.r-universe.dev</a></li>
<li><strong>Release branch:</strong> <a href="https://bioc-release.r-universe.dev/" rel="nofollow" target="_blank">https://bioc-release.r-universe.dev</a></li>
</ul>
<p>These universes integrate directly with Bioconductor’s existing Git infrastructure and provide continuous builds for packages in both branches.</p>
<p>Through the R-universe dashboard, package maintainers and users can:</p>
<ul>
<li>Inspect cross-platform check results</li>
<li>Review extended BiocCheck diagnostics</li>
<li>Monitor build logs and dependency graphs</li>
<li>Explore rich package metadata and metrics</li>
<li>Publish binary packages for Windows, macOS, and Linux</li>
</ul>
<p>This provides a familiar yet modern interface for Bioconductor contributors, aligned with what users increasingly expect from contemporary R package infrastructure.</p>
<p>Information about each package is available on <code>https://bioc.r-universe.dev/{pkgname}</code>. For example, <a href="https://bioc.r-universe.dev/DESeq2" rel="nofollow" target="_blank">https://bioc.r-universe.dev/DESeq2</a> provides details on the DESeq2 package as shown below:</p>
<div class="box" >
<figure   >
<div class="img">
<img  src="https://i0.wp.com/docs.r-universe.dev/img/bioc-pkg.png?w=578&#038;ssl=1" alt="screenshot of r-universe package" data-recalc-dims="1"/>
</div>
<a href="https://docs.r-universe.dev/img/bioc-pkg.png"  aria-disabled="true" rel="nofollow" target="_blank"></a>
</figure>
</div>
<p>If this is your first time visiting R-universe, we recommend clicking the “Website Tour” button which will walk you through the most important information in 1 or 2 minutes.</p>
<h2>
Technical Documentation for Bioconductor Maintainers
</h2><p>The R-universe project maintains comprehensive technical documentation at <a href="https://docs.r-universe.dev/" rel="nofollow" target="_blank">https://docs.r-universe.dev</a>. For Bioconductor specifically, we created a dedicated section summarizing the most relevant topics for developers to get started with R-universe: <a href="https://docs.r-universe.dev/bioconductor/" rel="nofollow" target="_blank">https://docs.r-universe.dev/bioconductor/</a></p>
<p>As the collaboration evolves and new components get introduced, the documentation will continue to be expanded. The goal is to provide Bioconductor maintainers with a clear reference point for understanding how R-universe fits into their development workflow, while maintaining compatibility with the established practices that have made Bioconductor a successful project within the R community.</p>
<h2>
Looking Ahead
</h2><p>Adopting new infrastructure inevitably involves adjustments. For Bioconductor developers, integrating with a new build and distribution system will likely require some changes to workflows, and time to become familiar with new or different package checks, build diagnostics, and binary distribution.</p>
<p>However, by gradually moving toward common infrastructure, the Bioconductor project will benefit from improvements that are being continuously developed and maintained for the broader R ecosystem. A system based on modern continuous integration (CI) will provide developers with improved tooling, and will give the core team more time to focus on community coordination and quality control, rather than on maintaining costly infrastructure. At the same time, the shared platform provided by R-universe can help to increase the visibility and accessibility of Bioconductor software to the greater R community.</p>
<p>We look forward to continuing this alliance and to working with the Bioconductor community to ensure that the next generation of infrastructure supports the project for many years to come.</p>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://ropensci.org/blog/2026/04/08/r-universe-bioc/"> rOpenSci - open tools for open science</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/collaborating-between-bioconductor-and-r-universe-on-development-of-common-infrastructure/">Collaborating between Bioconductor and R-universe on Development of Common Infrastructure</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400401</post-id>	</item>
		<item>
		<title>EM-DAT, the world&#8217;s disaster memory, is at risk</title>
		<link>https://www.r-bloggers.com/2026/04/em-dat-the-worlds-disaster-memory-is-at-risk/</link>
		
		<dc:creator><![CDATA[R on Stats and R]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://statsandr.com/blog/em-dat-the-world-s-disaster-memory-is-at-risk/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>I do not usually write posts that are calls to action. But sometimes, something important enough comes along that it would feel wrong to stay silent. This is one of those times.</p>
<p>What is EM-DAT?<br />
EM-DAT, the Emergency Events Database, is the world’s...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/em-dat-the-worlds-disaster-memory-is-at-risk/">EM-DAT, the world’s disaster memory, is at risk</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://statsandr.com/blog/em-dat-the-world-s-disaster-memory-is-at-risk/"> R on Stats and R</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>



<p><img src="https://i1.wp.com/statsandr.com/blog/em-dat-the-world-s-disaster-memory-is-at-risk/images/em-dat-the-world-s-disaster-memory-is-at-risk.jpg?w=578&#038;ssl=1" style="width:100.0%" data-recalc-dims="1" /></p>
<p>I do not usually write posts that are calls to action. But sometimes, something important enough comes along that it would feel wrong to stay silent. This is one of those times.</p>
<div id="what-is-em-dat" class="section level2">
<h2>What is EM-DAT?</h2>
<p><a href="https://www.emdat.be/" rel="nofollow" target="_blank">EM-DAT</a>, the Emergency Events Database, is the world’s most widely used and trusted global database for tracking natural and technological disasters. It has been maintained since 1988 by the <strong>Centre for Research on the Epidemiology of Disasters (CRED)</strong>, which is part of UCLouvain.</p>
<p>The database currently contains data on the occurrence and impacts of <strong>over 27,000 mass disasters</strong> worldwide, from 1900 to the present day. It covers floods, storms, earthquakes, droughts, wildfires, extreme temperatures, landslides, volcanic activity, and technological accidents, across virtually every country on earth.</p>
<p>Crucially, it is:</p>
<ul>
<li><strong>Open access</strong> (for non-commercial use)</li>
<li><strong>Globally comparable</strong>, using transparent and consistent inclusion criteria</li>
<li><strong>Cross-verified</strong> across multiple sources (UN agencies, NGOs, reinsurance companies, research institutes, press agencies)</li>
<li>The <strong>reference dataset</strong> for thousands of peer-reviewed studies, national risk assessments, and international policy processes</li>
</ul>
<p>If you have ever read a paper or report about global disaster trends, the probability is high that EM-DAT was the data source behind it.</p>
</div>
<div id="why-is-it-at-risk" class="section level2">
<h2>Why is it at risk?</h2>
<p>For more than 25 years, EM-DAT was primarily funded by the <strong>United States Agency for International Development (USAID)</strong>. Following the recent dismantling of USAID, that funding is gone, and no sustainable alternative has been secured.</p>
<p>This is not a minor budget shortfall. Without a replacement funding mechanism, EM-DAT risks shutting down entirely.</p>
</div>
<div id="why-does-it-matter" class="section level2">
<h2>Why does it matter?</h2>
<p>The <a href="https://openletter.earth/the-worlds-collective-disaster-memory-must-be-preserved-66c88c44" rel="nofollow" target="_blank">open letter</a> drafted in support of EM-DAT puts it well: in an era of intensifying climate extremes, cascading risks, and compounding crises, reliable data are not a luxury. They are the infrastructure for informed decision-making.</p>
<p>Concretely, EM-DAT underpins:</p>
<ul>
<li><strong>Disaster risk reduction and prevention policies</strong>, used by governments to assess national risks and prioritise investments</li>
<li><strong>Humanitarian operations</strong>, relied upon by multilateral agencies and NGOs to plan and forecast needs</li>
<li><strong>Climate research</strong>, providing historical baselines for understanding trends in extreme weather events</li>
<li><strong>Monitoring of global commitments</strong>, such as the Sendai Framework for Disaster Risk Reduction, the SDGs, and the Paris Agreement</li>
<li><strong>Insurance and risk modelling</strong>, used by the private sector alongside other data to benchmark losses and refine exposure models</li>
</ul>
<p>EM-DAT’s value is not just in the quantity of records. It lies in the <strong>rigour and consistency</strong> of its methodology over time and across countries. That is exactly what makes it irreplaceable. In a world awash with data, curated and quality-controlled datasets of this kind are rare. If EM-DAT were to close, the result would not be a smooth substitution. It would be fragmentation, proprietary data silos, and reduced access, particularly for lower-income countries that are already under-represented in global evidence.</p>
</div>
<div id="a-personal-note" class="section level2">
<h2>A personal note</h2>
<p>I signed the open letter after being informed of the issue by my colleague Prof. Niko Speybroeck, a leading epidemiologist at UCLouvain and program director of the CRED.</p>
<p>I do not have direct expertise in disaster epidemiology. But I do care about open data, open science, and the integrity of global research infrastructure. And EM-DAT is exactly the kind of resource that the whole scientific community relies on, often without fully realising it.</p>
</div>
<div id="how-you-can-help" class="section level2">
<h2>How you can help</h2>
<p>If you share these values, I encourage you to <a href="https://openletter.earth/the-worlds-collective-disaster-memory-must-be-preserved-66c88c44" rel="nofollow" target="_blank">sign the open letter: “The World’s collective disaster memory must be preserved”</a>.</p>
<p>The letter calls on governments, multilateral development banks, philanthropic foundations, and international organisations to step forward with a coordinated and sustainable funding arrangement for EM-DAT. The cost of maintaining the world’s primary disaster database is modest set against the billions spent on disaster response and recovery each year. The cost of losing it would be profound.</p>
<p>Please also consider sharing this post or the open letter with your own network (researchers, policymakers, students, practitioners, or anyone who cares about data-driven approaches to global challenges).</p>
</div>
<div id="more-information" class="section level2">
<h2>More information</h2>
<ul>
<li>EM-DAT website: <a href="https://www.emdat.be/" class="uri" rel="nofollow" target="_blank">https://www.emdat.be/</a></li>
<li>Open letter: <a href="https://openletter.earth/the-worlds-collective-disaster-memory-must-be-preserved-66c88c44" class="uri" rel="nofollow" target="_blank">https://openletter.earth/the-worlds-collective-disaster-memory-must-be-preserved-66c88c44</a></li>
<li>CRED at UCLouvain: <a href="https://www.uclouvain.be/en/research-institutes/irss/cred-epidemiology-of-disasters" class="uri" rel="nofollow" target="_blank">https://www.uclouvain.be/en/research-institutes/irss/cred-epidemiology-of-disasters</a></li>
</ul>
<p>As always, if you have any thoughts or questions related to this post, feel free to leave a comment below.</p>
</div>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://statsandr.com/blog/em-dat-the-world-s-disaster-memory-is-at-risk/"> R on Stats and R</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/em-dat-the-worlds-disaster-memory-is-at-risk/">EM-DAT, the world’s disaster memory, is at risk</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400384</post-id>	</item>
		<item>
		<title>Marathon Man: how to pace a marathon</title>
		<link>https://www.r-bloggers.com/2026/04/marathon-man-how-to-pace-a-marathon/</link>
		
		<dc:creator><![CDATA[Stephen Royle]]></dc:creator>
		<pubDate>Mon, 06 Apr 2026 13:36:35 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://quantixed.org/?p=3654</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> How does the average marathoner pace their race? In this post, we’ll use R to have a look at a large dataset of marathon times to try to answer this question. The ideal strategy would be to “even split” the race. This is where you run continually at the ...</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/marathon-man-how-to-pace-a-marathon/">Marathon Man: how to pace a marathon</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://quantixed.org/2026/04/06/marathon-man-how-to-pace-a-marathon/"> Rstats – quantixed</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p><strong>How does the average marathoner pace their race?</strong> In this post, we’ll use R to have a look at a large dataset of marathon times to try to answer this question.</p>



<p>The ideal strategy would be to “even split” the race. This is where you run continually at the same pace from kilometre 0 to the finish. Let’s forget about “negative splitting”. This is where you speed up through the race, usually by running at a constant pace for the first half or three-quarters and then increasing the pace. Negative splits are for the pros not mere mortals! The difficulty with even-splitting the race is that it is very hard to know what pace you can maintain. The marathon gets hard for everyone after 30 km, so a slow down is almost inevitable. Certainly if you have started too fast you will <strong>fade</strong>. This situation is known as “positive splitting”.</p>



<p>Why is it so hard to know what pace you can maintain? Well, you can predict a pace based on existing races e.g. half marathon, and there are various ways to do this, but it is difficult to tell if you can hold that pace for the marathon. It’s such a brutal event that training up to run one takes time and it equally takes a while to recover, so experimentation is limited. Running a full marathon (at pace) in training, is not advised. So determining an ideal pace involves quite a bit of guesswork.</p>



<p>Let’s take a look at a big dataset of marathon times – we’ll use the New York City Marathon from 2025 – to see if we can understand how to pace a marathon. There’s an available dataset of chip times (meaning we don’t have to worry about dodgy GPS data) and the <a href="https://quantixed.org/2025/11/17/choose-your-fighter-data-driven-selection-of-the-best-marathon/" rel="nofollow" target="_blank">course</a> has similar first and second half profiles, allowing us to use these times to understand negative/even/positive splitting. Let’s dive in.</p>



<p>You can skip to <a href="https://quantixed.org/2026/04/06/marathon-man-how-to-pace-a-marathon/#the-code" rel="nofollow" target="_blank">the code</a> to play along or just see the analysis here.</p>



<figure data-wp-context="{"imageId":"69d40822e11a7"}" data-wp-interactive="core/image" data-wp-key="69d40822e11a7" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" fetchpriority="high" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_histogram-768x1024.png?w=450&#038;ssl=1" alt="" class="wp-image-3671" srcset_temp="https://i2.wp.com/quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_histogram-768x1024.png?w=450&#038;ssl=1 768w, https://quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_histogram-225x300.png 225w, https://quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_histogram.png 900w" sizes="(max-width: 768px) 100vw, 768px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p>First we can see using histograms of the difference between second half and first half of the marathon, that <strong>most runners positive split the marathon</strong>. There are very few runners who run a negative-split (blue bars, left of the dashed line). More runners even-split (yellow), but the majority run positive (red) split times.</p>



<p>For marathoners with finishing in times of below 3 h, the modal split is only +2 minutes. Over 21.1 km this is only a loss of 6 s per km. For marathoners with finishes of over three hours, this loss gets more severe. Those finishing outside of 5 h, ship 20 minutes or more in the second half.</p>



<p>At first glance this looks like better pace management by the faster runners, but these positive splits could be proportional to the paces being run. In other words, a slower runner should ship more time in the second half, because they’re running more slowly.</p>



<figure data-wp-context="{"imageId":"69d40822e17a2"}" data-wp-interactive="core/image" data-wp-key="69d40822e17a2" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_scatter.png?w=450&#038;ssl=1" alt="" class="wp-image-3672" srcset_temp="https://i1.wp.com/quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_scatter.png?w=450&#038;ssl=1 1000w, https://quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_scatter-300x240.png 300w, https://quantixed.org/wp-content/uploads/2026/01/nyc_marathon_2025_split_difference_scatter-768x614.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Enlarge"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p>We can look at this data a different way and directly compare the first and second half times for each runner. Again this highlights just how few runners negative- or even-split the marathon. Most are positive splitting and are in the upper left half of the plot. We can also see that the data veers away from the ideal even-split (dashed line) with the slower paces. This veering looks linear (straight line).</p>



<p>We can fit a line to this data, and constrain it to go through (1,1) i.e. a 2 h marathoner even-splitting the race. To do this in R we can use <code>lm(formula = I(y - 60) ~ I(x - 60) + 0, data = fitting)</code> and this gives the coefficient for I(x – 60) as <strong>1.24</strong>. This is essentially the <strong>fade co-efficient</strong> for the average runner in the 2025 edition of this race.</p>



<p>What does that mean? Well, for a runner achieving a 90 minute first half, their second half would most likely be: 60 + 1.239 * (90 – 60) = 97.17 minutes, so this would be a finish time of 3:07:10.</p>



<p>For anyone looking to run a 3 h New York Marathon, the average runner would therefore need to run 60 / 2.239 + 60 = <strong>86.8</strong> minutes for the first half to anticipate the fade. So 1:26:48 for the first half, and then 1:33:12 for the second half.</p>



<p>A more simple calculation is to take the mean of the ratio between the two half times for everyone in the dataset. This gives a fade coefficient of <strong>1.13</strong>. The difference between these two fade co-efficients is due to the lack of constraint used in the fit. The ratio predicts a positive split being inevitable for the fastest runners, which is probably not true. Anyhow, this puts the first half time at 88 minutes for folks looking to run 3 h. These fade co-efficients are good predictors for a range of times, and I suspect would be similar at other marathon events with a similar profile. <strong>You can use them to calculate your ideal pace for a target finish time.</strong></p>



<p>Finally, for the most accurate answer about sub-3 h pacing, we can look directly at runners finishing between 02:50:00 and 03:00:00 and see what they actually ran. The median first half time was 86.3 min (IQR = 84.4 – 87.87) and the second half was 89.62 (88.07 – 91.12). This gives a median finish time of 2:56:00. So running a 1:26:18 first half would give someone their best chance of finishing in under 3 h, allowing for the inevitable fade.</p>



<p><strong>The takeaway message is: to finish within a goal time, do not assume even splits. </strong>That is, if you want to run 3 hours 30 min and bank on 90 minutes per half (4:59/km), you will most likely fail to hit the target. Build in a buffer of time to allow for the inevitable fade. A pace of 4:45/km is a better target pace (see below).</p>



<p>Good luck!</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td>Finish Time</td><td>Even split pace</td><td>Target pace</td></tr><tr><td>03:00:00</td><td>00:04:16</td><td>00:04:07</td></tr><tr><td>03:30:00</td><td>00:04:59</td><td>00:04:45</td></tr><tr><td>04:00:00</td><td>00:05:41</td><td>00:05:23</td></tr><tr><td>04:30:00</td><td>00:06:24</td><td>00:06:01</td></tr><tr><td>05:00:00</td><td>00:07:07</td><td>00:06:39</td></tr><tr><td>06:00:00</td><td>00:08:32</td><td>00:07:55</td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="the-code">The code</h2>



<p>This analysis was possible thanks to the uploader for making the chip time data available. Also, a shoutout to Nicola Rennie for <a href="https://nrennie.rbind.io/blog/adding-social-media-icons-ggplot2/" rel="nofollow" target="_blank">sharing</a> how to style social media handles in <code>{ggplot2}</code> graphics. This part of my code requires my <code>{qBrand}</code> library and should be skipped if you are running the code yourself (remove the <code>caption = cap</code> argument in the ggplot calls).</p>


<pre>
library(ggplot2)
library(ggtext)

sysfonts::font_add_google(&quot;Roboto&quot;, &quot;roboto&quot;)
showtext::showtext_auto()

## data wrangling ----

# load csv file from url
url &lt;- paste0(&quot;https://huggingface.co/datasets/donaldye8812/&quot;,
              &quot;nyc-2025-marathon-splits/resolve/main/&quot;,
              &quot;nyrr_marathon_2025_summary_56480_runners_WITH_SPLITS.csv&quot;)
df &lt;- read.csv(url)

# the data frame is a long table
# we need to grab the time values where splitCode is &quot;HALF&quot; or &quot;MAR&quot;
df &lt;- df[df$splitCode %in% c(&quot;HALF&quot;, &quot;MAR&quot;), c(&quot;RunnerID&quot;, &quot;splitCode&quot;, &quot;time&quot;)]
# reshape to wide format, values are in time
df &lt;- reshape(df, idvar = &quot;RunnerID&quot;, timevar = &quot;splitCode&quot;, direction = &quot;wide&quot;)
# calculate the split times in minutes
df$split_HALF &lt;- as.numeric(
  as.difftime(df$time.HALF, format = &quot;%H:%M:%S&quot;, units = &quot;mins&quot;))
df$split_MAR &lt;- as.numeric(
  as.difftime(df$time.MAR, format = &quot;%H:%M:%S&quot;, units = &quot;mins&quot;))
# calculate the second half time
df$split_SECOND_HALF &lt;- df$split_MAR - df$split_HALF
# remove rows with NA values
df &lt;- df[!is.na(df$split_SECOND_HALF), ]
# calculate the difference
df$Difference &lt;- df$split_SECOND_HALF - df$split_HALF
# difference as a fraction of first half
df$Difference_Fraction &lt;- df$Difference / df$split_HALF * 100
# classify into sub 3 hr, sub 4 hr, sub 5 hr, sub 6 hr, over 6 hr
df$Category &lt;- cut(df$split_MAR,
                           breaks = c(0, 180, 210, 240, 300, Inf),
                           labels = c(&quot;Sub 3 h&quot;, &quot;3:00-3:30&quot;, &quot;3:30-4:00&quot;,
                                      &quot;4:00-5:00&quot;, &quot;Over 5 h&quot;))

## plot styling ----

social &lt;- qBrand::qSocial()
cap &lt;-  paste0(
  &quot;**Data:** New York City Marathon 2025 Results&lt;br&gt;**Graphic:** &quot;,social
)

my_palette &lt;- c(&quot;Sub 3 h&quot; = &quot;#cb2029&quot;,
                &quot;3:00-3:30&quot; = &quot;#147f77&quot;,
                &quot;3:30-4:00&quot; = &quot;#cf6d21&quot;,
                &quot;4:00-5:00&quot; = &quot;#28a91b&quot;,
                &quot;Over 5 h&quot; = &quot;#a31a6d&quot;)

## make the plots ----

ggplot(df, aes(x = Difference, fill = after_stat(x))) +
  # vertical line at x = 0
  geom_vline(xintercept = 0, linetype = &quot;dashed&quot;, color = &quot;black&quot;) +
  geom_histogram(breaks = seq(
    from = -59.5, to = 81.5, by = 1), color = &quot;black&quot;) +
  scale_colour_gradient2(
    low = &quot;#2b83ba&quot;,
    mid = &quot;#ffffbf&quot;,
    high = &quot;#d7191c&quot;,
    midpoint = 0,
    limits = c(-15,15),
    na.value = &quot;#ffffffff&quot;,
    guide = &quot;colourbar&quot;,
    aesthetics = &quot;fill&quot;,
    oob = scales::squish
  ) +
  scale_x_continuous(breaks = seq(-45,90,15), limits = c(-40, 80)) +
  facet_wrap(~ Category, ncol = 1, scales = &quot;free_y&quot;) +
  labs(caption = cap) +
  labs(title = &quot;Most runners positive split the marathon&quot;,
       x = &quot;Difference in minutes (Second Half - First Half)&quot;,
       y = &quot;Number of Runners&quot;,
       caption = cap) +
  theme_classic() +
  # hide legend
  theme(legend.position = &quot;none&quot;) +
  theme(
    plot.caption = element_textbox_simple(
      colour = &quot;grey25&quot;,
      hjust = 0,
      halign = 0,
      margin = margin(b = 0, t = 5),
      size = rel(0.9)
    ),
    text = element_text(family = &quot;roboto&quot;, size = 16),
    plot.title = element_text(size = rel(1.2),
                              face = &quot;bold&quot;)
  )

ggsave(&quot;Output/Plots/nyc_marathon_2025_split_difference_histogram.png&quot;,
       width = 900, height = 1200, dpi = 72, units = &quot;px&quot;, bg = &quot;white&quot;)

ggplot() +
  geom_abline(slope = 1, linetype = &quot;dashed&quot;, color = &quot;black&quot;) +
  geom_point(data = df,
             aes(x = split_HALF, y = split_SECOND_HALF, colour = Category),
             shape = 16, size = 1.5, alpha = 0.1) +
  scale_x_continuous(breaks = seq(from = 0, to = 12 * 30, by = 30),
                     labels = seq(from = 0, to = 6, by = 0.5),
                     limits = c(1 * 60, 5 * 60)) +
  scale_y_continuous(breaks = seq(from = 0, to = 12 * 30, by = 30),
                     labels = seq(from = 0, to = 6, by = 0.5),
                     limits = c(1 * 60, 5 * 60)) +
  scale_colour_manual(values = my_palette) +
  labs(x = &quot;First half time (h)&quot;,
       y = &quot;Second half time (h)&quot;,
       caption = cap) +
  theme_bw() +
  theme(
    plot.caption = element_textbox_simple(
      colour = &quot;grey25&quot;,
      hjust = 0,
      halign = 0,
      margin = margin(b = 0, t = 10),
      size = rel(0.9)
    ),
    text = element_text(family = &quot;roboto&quot;, size = 16)
  ) +
  guides(colour = guide_legend(override.aes = list(alpha = 1)))

ggsave(&quot;Output/Plots/nyc_marathon_2025_split_difference_scatter.png&quot;,
       width = 1000, height = 800, dpi = 72, units = &quot;px&quot;, bg = &quot;white&quot;)
</pre>


<p>From this data we can also make some calculations to understand…</p>


<pre>
## fitting ----

# to fit, we&#039;ll constrain the line to go through (60,60), i.e. a
# 2 h marathoner who runs even splits
fitting &lt;- data.frame(x = df$split_HALF,y = df$split_SECOND_HALF)
lm( I(y-60) ~ I(x-60) + 0, data = fitting)


# Call:
#   lm(formula = I(y - 60) ~ I(x - 60) + 0, data = fitting)
# 
# Coefficients:
#   I(x - 60)  
# 1.239  

# so for a 90 minute first half, second half would be:
# 60 + 1.239 * (90 - 60) = 97.17 minutes, a finish time of 3:07:10

# to run a 3 h New York Marathon, the average runner needs to run
# 60 / 2.239 + 60 = 86.8 minutes for the first half
# so 1:26:48 for the first half, and 1:33:12 for the second half

# a more simple approach is to calculate the mean of the ratios
mean_ratio &lt;- mean(df$split_SECOND_HALF / df$split_HALF)
mean_ratio
# [1] 1.127581

# filter the df for finish times between 170 and 180 minutes
target &lt;- df[df$split_MAR &gt; 170 & df$split_MAR &lt; 180,]
summary(target)


    RunnerID         time.HALF           time.MAR           split_HALF      split_MAR     split_SECOND_HALF   Difference     
 Min.   :48819892   Length:1289        Length:1289        Min.   :70.25   Min.   :170.0   Min.   : 82.70    Min.   :-7.6833  
 1st Qu.:48834548   Class :character   Class :character   1st Qu.:84.42   1st Qu.:173.6   1st Qu.: 88.07    1st Qu.: 0.7167  
 Median :48849752   Mode  :character   Mode  :character   Median :86.30   Median :176.0   Median : 89.62    Median : 3.0500  
 Mean   :48849498                                         Mean   :85.98   Mean   :175.7   Mean   : 89.73    Mean   : 3.7585  
 3rd Qu.:48864551                                         3rd Qu.:87.87   3rd Qu.:178.2   3rd Qu.: 91.12    3rd Qu.: 5.9000  
 Max.   :48878979                                         Max.   :92.87   Max.   :180.0   Max.   :106.02    Max.   :35.7667  
 Difference_Fraction      Category   
 Min.   :-8.5008     Sub 3 h  :1289  
 1st Qu.: 0.8051     3:00-3:30:   0  
 Median : 3.5390     3:30-4:00:   0  
 Mean   : 4.5178     4:00-5:00:   0  
 3rd Qu.: 7.0055     Over 5 h :   0  
 Max.   :50.9134   
</pre>


<p>—</p>



<p>The post title comes from “Marathon Man” by Ian Brown from his “My Way” album. He’s wearing a track suit on the cover but that’s not optimal wear for running a marathon.</p>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://quantixed.org/2026/04/06/marathon-man-how-to-pace-a-marathon/"> Rstats – quantixed</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/marathon-man-how-to-pace-a-marathon/">Marathon Man: how to pace a marathon</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400370</post-id>	</item>
		<item>
		<title>One interface, (Almost) Every Classifier: unifiedml v0.2.1</title>
		<link>https://www.r-bloggers.com/2026/04/one-interface-almost-every-classifier-unifiedml-v0-2-1/</link>
		
		<dc:creator><![CDATA[T. Moudiki]]></dc:creator>
		<pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://thierrymoudiki.github.io//blog/2026/04/04/r/more-unifiedml-classifiers</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> A new version of `unifiedml` is out; available on CRAN. `unifiedml` is an effort to offer a unified interface to R's machine learning models.</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/one-interface-almost-every-classifier-unifiedml-v0-2-1/">One interface, (Almost) Every Classifier: unifiedml v0.2.1</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://thierrymoudiki.github.io//blog/2026/04/04/r/more-unifiedml-classifiers"> T. Moudiki's Webpage - R</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p>A new version of <code>unifiedml</code> is out; available on CRAN. <code>unifiedml</code> is an effort to offer a unified interface to R’s machine learning models.</p>

<p>The main change in this version <code>0.2.1</code> is the removal of <code>type</code> (of prediction) from <code>predict</code>, and the use of<code>...</code> instead, which is more generic and flexible.</p>

<p><strong>This post contains advanced examples of use of <code>unifiedml</code> for classification</strong>, with <code>ranger</code> and <code>xgboost</code>. More examples have been added to <a href="https://cloud.r-project.org/web/packages/unifiedml/vignettes/unifiedml-vignette.html" rel="nofollow" target="_blank">the package vignettes</a> too.</p>

<pre>install.packages(&quot;unifiedml&quot;)

install.packages(c(&quot;ranger&quot;))

library(&quot;unifiedml&quot;)

Loading required package: doParallel

Loading required package: foreach

Loading required package: iterators

Loading required package: parallel

Loading required package: R6
</pre>

<h1 id="1---ranger-example">1 &#8211; <code>ranger</code> example</h1>

<pre>library(ranger)



# 2 - 'ranger' classification ---------------------------

# -------------------------------
# S3 wrapper for ranger
# -------------------------------

# Fit function remains the same
my_ranger &lt;- function(x, y, ...) {
  if (!is.data.frame(x)) x &lt;- as.data.frame(x)
  y &lt;- as.factor(y)
  colnames(x) &lt;- paste0(&quot;X&quot;, seq_len(ncol(x)))
  df &lt;- data.frame(y = y, x)
  fit &lt;- ranger::ranger(y ~ ., data = df, probability = TRUE, ...)
  structure(list(fit = fit), class = &quot;my_ranger&quot;)
}

# Predict only with newdata
predict.my_ranger &lt;- function(object, newdata = NULL, newx = NULL, ...) {
  if (!is.null(newx)) newdata &lt;- newx
  if (is.null(newdata)) stop(&quot;No data provided for prediction&quot;)
#  misc::debug_print(newx)
#  misc::debug_print(newdata)
  if (is.matrix(newdata)) newdata &lt;- as.data.frame(newdata)
#  misc::debug_print(newdata)
  # Unconditionally rename to match training
  colnames(newdata) &lt;- paste0(&quot;X&quot;, seq_len(ncol(newdata)))
#  misc::debug_print(newdata)
  preds &lt;- predict(object$fit, data = newdata)$predictions
#  misc::debug_print(newdata)
  if (is.matrix(preds) &#038;&#038; ncol(preds) == 2) {
    lvls &lt;- colnames(preds)
    return(ifelse(preds[, 2] &gt; 0.5, lvls[2], lvls[1]))
  }

  preds
}

# Print method
print.my_ranger &lt;- function(x, ...) {
  cat(&quot;my_ranger model\n&quot;)
  print(x$fit)
}

# -------------------------------
# Example: Iris binary classification
# -------------------------------

set.seed(123)
iris_binary &lt;- iris[iris$Species %in% c(&quot;setosa&quot;, &quot;versicolor&quot;), ]
X_binary &lt;- iris_binary[, 1:4]
y_binary &lt;- as.factor(as.character(iris_binary$Species))

# Train/test split
train_idx &lt;- sample(seq_len(nrow(X_binary)), size = 0.7 * nrow(X_binary))
X_train &lt;- X_binary[train_idx, ]
y_train &lt;- y_binary[train_idx]
X_test &lt;- X_binary[-train_idx, ]
y_test &lt;- y_binary[-train_idx]

# Initialize and fit model
# Initialize model
mod &lt;- Model$new(my_ranger)

# Fit on training data only
mod$fit(X_train, y_train, num.trees = 150L)

# Predict on test set
preds &lt;- mod$predict(X_test)

# Evaluate
table(Predicted = preds, True =y_test)
mean(preds == y_test)  # Accuracy



# 5-fold cross-validation on training set
cv_scores &lt;- cross_val_score(
  mod,
  X_train,
  y_train,
  num.trees = 150L,
  cv = 5L
)

cv_scores
mean(cv_scores)  # average CV accuracy


            True
Predicted    setosa versicolor
  setosa         15          0
  versicolor      0         15
</pre>

<p>1</p>

<pre>  |======================================================================| 100%
</pre>

<style>
.list-inline {list-style: none; margin:0; padding: 0}
.list-inline>li {display: inline-block}
.list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
</style>

<p><ol class=list-inline><li>1</li><li>1</li><li>1</li><li>1</li><li>1</li></ol></p>

<p>1</p>

<h1 id="2---xgboost-example">2 - <code>xgboost</code> example</h1>

<pre>library(xgboost)

my_xgboost &lt;- function(x, y, ...) {
  
  # Convert to matrix safely
  if (!is.matrix(x)) {
    x &lt;- as.matrix(x)
  }
  
  # Handle factors
  if (is.factor(y)) {
    y &lt;- as.numeric(y) - 1
  }
  
  fit &lt;- xgboost::xgboost(
    data = x,
    label = y,
    ...
  )
  
  structure(list(fit = fit), class = &quot;my_xgboost&quot;)
}

predict.my_xgboost &lt;- function(object, newdata, ...) {
  
  # Ensure matrix
  newdata &lt;- as.matrix(newdata)
  
  preds &lt;- predict(object$fit, newdata)
  
  # If binary classification → convert probs to class
  if (!is.null(object$fit$params$objective) &#038;&#038;
      grepl(&quot;binary&quot;, object$fit$params$objective)) {
    
    return(ifelse(preds &gt; 0.5, 1, 0))
  }
  
  preds
}

predict.my_xgboost &lt;- function(object, newdata = NULL, newx = NULL, ...) {
  
  # Accept both conventions
  if (!is.null(newx)) {
    newdata &lt;- newx
  }
  
  newdata &lt;- as.matrix(newdata)
  
  preds &lt;- predict(object$fit, newdata)
  
  # Binary classification → class labels
  if (!is.null(object$fit$params$objective) &#038;&#038;
      grepl(&quot;binary&quot;, object$fit$params$objective)) {
    
    return(ifelse(preds &gt; 0.5, 1, 0))
  }
  
  preds
}

print.my_xgboost &lt;- function(x, ...) {
  cat(&quot;my_xgboost model\n&quot;)
  print(x$fit)
}


set.seed(123)  # for reproducibility

# Binary subset
iris_binary &lt;- iris[iris$Species %in% c(&quot;setosa&quot;, &quot;versicolor&quot;), ]
X_binary &lt;- as.matrix(iris_binary[, 1:4])
y_binary &lt;- as.factor(as.character(iris_binary$Species))

# Split indices: 70% train, 30% test
train_idx &lt;- sample(seq_len(nrow(X_binary)), size = 0.7 * nrow(X_binary))
X_train &lt;- X_binary[train_idx, ]
y_train &lt;- y_binary[train_idx]
X_test &lt;- X_binary[-train_idx, ]
y_test &lt;- y_binary[-train_idx]

# Initialize model
mod &lt;- Model$new(my_xgboost)

# Fit on training data only
mod$fit(X_train, y_train, nrounds = 50, objective = &quot;binary:logistic&quot;)

# Predict on test set
preds &lt;- mod$predict(X_test)

# Evaluate
table(Predicted = preds, True =y_test)
mean(preds == y_test)  # Accuracy



# 5-fold cross-validation on training set
cv_scores &lt;- cross_val_score(
  mod, 
  X_train, 
  y_train, 
  nrounds = 50, 
  objective = &quot;binary:logistic&quot;, 
  cv = 5L
)

cv_scores
mean(cv_scores)  # average CV accuracy
</pre>

<p><img src="https://i1.wp.com/thierrymoudiki.github.io/images/2026-04-04/2026-04-04-image1.png?w=578&#038;ssl=1" alt="image-title-here" class="img-responsive" data-recalc-dims="1" /></p>


<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://thierrymoudiki.github.io//blog/2026/04/04/r/more-unifiedml-classifiers"> T. Moudiki's Webpage - R</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/one-interface-almost-every-classifier-unifiedml-v0-2-1/">One interface, (Almost) Every Classifier: unifiedml v0.2.1</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400351</post-id>	</item>
		<item>
		<title>You can just build your own programming language</title>
		<link>https://www.r-bloggers.com/2026/04/you-can-just-build-your-own-programming-language/</link>
		
		<dc:creator><![CDATA[Econometrics and Free Software]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://b-rodrigues.github.io/posts/2026-04-03-tproject.html</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>Last summer, while relaxing on the beaches of Berck, a French town known for treating tuberculosis in kids by exposing them to the fresh maritime air (back in 19th century, they have antibiotics these days), I found myself daydreaming abou...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/you-can-just-build-your-own-programming-language/">You can just build your own programming language</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://b-rodrigues.github.io/posts/2026-04-03-tproject.html"> Econometrics and Free Software</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 




<div style="text-align: center;">
<p>
<a> <img src="https://i0.wp.com/b-rodrigues.github.io/assets/img/tlogo.png?w=578&#038;ssl=1" style="width: 50%; height: auto;" data-recalc-dims="1"> </a>
</p>
</div>
<p>Last summer, while relaxing on the beaches of Berck, a French town known for treating tuberculosis in kids by exposing them to the fresh maritime air (back in 19th century, they have antibiotics these days), I found myself daydreaming about building my own programming language.</p>
<p>Spoiler alert: I don’t know how to build programming languages, but I have developed extremely strong opinions over the years about the features a modern data science language <em>should</em> have. So could I use them fancy LLMs to build one?</p>
<p>Also, let’s get one question answered straight away: why create a new language instead of contributing to existing ones? I certainly do contribute, I maintain several R packages like <code>{rix}</code>, <code>{rixpress}</code>, and <code>{chronicler}</code>, and even have two Python packages (<code>cronista</code> and <code>ryxpress</code>), but I wanted a clean slate to build a system centered around a few non-negotiable principles and features I’ve implemented over the years in R:</p>
<ul>
<li><strong>Reproducibility-First</strong>: A language where reproducibility isn’t a bolt-on afterthought managed by external tools, but the very foundation of the runtime.</li>
<li><strong>Aggressive Re-use</strong>: Instead of reinventing the wheel, this language would stand on the shoulders of giants. It’d use <strong>Nix</strong> for package management and environment isolation, and <strong>Apache Arrow</strong> as its high-performance backbone for data frames. R, Python, Julia and other languages would provide the algorithms and models.</li>
<li><strong>First-Class Pipelines</strong>: Scripts shouldn’t be a sequence of side-effects. In this language, pipelines would be mandatory and first-class citizens.</li>
<li><strong>Fail Early and Loudly</strong>: No silent type conversions or hidden NAs. If something is wrong, the language breaks immediately so you can fix it.</li>
<li><strong>Errors as Objects</strong>: Inspired by functional programming, errors are first-class values that can be inspected and handled gracefully.</li>
<li><strong>Two Pipes</strong>: I want two pipes, one for linear transformations, <code>|&gt;</code>, and a maybe-pipe, <code>?|&gt;</code> for error recovery. Unlike the standard pipe, <code>?|&gt;</code> always forwards its value, including Errors, to the next function, allowing you to write handlers that inspect and potentially recover from them. Since Errors are just values, this composes naturally with the rest of the language.</li>
<li><strong>Polyglot by Design</strong>: Rather than re-implementing every statistical algorithm, this language would be designed to orchestrate and bridge R, Python, and Julia seamlessly.</li>
</ul>
<p>Also, we’re in a post LLM world, and like them or not, they’re here to stay. They’re pretty useful to write boilerplate code and so any new language would be dead on arrival if it didn’t play nicely with LLMs. So such a new language would need to be written for LLMs primarily, because I don’t expect anyone to learn any new language. This is where the declarative nature of Nix is a huge advantage. Because environments are precisely described, it is much easier for LLMs to focus on generating code and not have to fight with environment setup. This is also the reason I took another radical decision: since Nix would be mandatory for setting up the environment, why bother building OS-specific binaries? I’d just build a Nix package for this language and let Nix handle the rest.</p>
<p>This architecture results in a DSL for orchestration, making it trivial to transfer data objects between different ecosystems without the usual FFI (Foreign Function Interface) friction.</p>
<p>With these ideas in mind, I started prompting Gemini to brainstorm and started by generating specification files. Very broad first, but as days went by, more and more focused. The way I went about it (and still go) is that I first brainstorm an idea with an LLM, then I ask it to generate a specification file, then I refine it, ask it to generate a new specification file, and so on. Once I’m happy with the spec, I ask an LLM to generate a minimal implementation of the spec. Usually writing the spec and a first implementation is a task shared between Claude and Gemini (through Antigravity). Then I open a pull request and ask GitHub Copilot to review it (usually with GPT-5.x). I repeat this process until I’m happy with the implementation. I always ask for documentation and unit tests (and golden tests when relevant, more on this later).</p>
<p>I started to really believe that I had something interesting, so I gave it a shot, and called it <strong>T</strong>. I had long joked that the natural successor to R should be called T (because R is the successor to S… and no, I’m not going to call it Q because that sounds like the word for ass in French).</p>
<p>Something else that made me confident I could succeed, besides my own hubris, was that I am pretty familiar with unit testing, test-driven development, trunk-based development and Nix. When you combine all these elements, it makes developing with LLMs quite safe.</p>
<p>So I just started prompting. And now I’m quite happy to announce that there is a beta version of T that you can use today!</p>
<p>By leveraging Nix as a build engine, T can treat complex data science workflows as buildable derivations. A typical T pipeline looks like this:</p>
<pre>p = pipeline {
  -- 1. Python node: read data with pandas
  mtcars_pl = pyn(
    command = &lt;{
import pandas as pd
pd.read_csv(&quot;data/mtcars.csv&quot;, sep=&quot;|&quot;)
    }&gt;,
    include = [&quot;data/mtcars.csv&quot;],
    serializer = ^csv
  )

  -- 2. Python node: filter and serialize as CSV
  mtcars_pl_am = pyn(
    command = &lt;{
mtcars_pl[mtcars_pl['am'] == 1]
    }&gt;,
    deserializer = ^csv,
    serializer = ^csv
  )

  -- 3. R node: read CSV and take head using functions.R
  mtcars_head = rn(
    command = &lt;{
my_head(mtcars_pl_am)
    }&gt;,
    functions = [&quot;src/functions.R&quot;],
    deserializer = ^csv,
    serializer = ^csv
  )

  -- 4. R node: select column with dplyr
  mtcars_mpg = rn(
    command = &lt;{
library(dplyr)
mtcars_head %&gt;% select(mpg)
    }&gt;,
    deserializer = ^csv,
    serializer = ^csv
  )

  -- Render Quarto report
  report = node(script = &quot;src/report.qmd&quot;, runtime = Quarto)
}

-- Materialize the pipeline
populate_pipeline(p, build = true)
pipeline_copy() -- Copy the outputs from the Nix store to your working directory</pre>
<p>As you can see, each node has a <code>command</code> argument where you can write literal R or Python code. It is also possible to provide the path to a script instead. If packages need to be loaded for the code to work, you can just write the calls to load the required packages in the <code>command</code> argument as well.</p>
<p>While T is heavily inspired by the <code>{targets}</code> package in R, it takes the concept a step further by making pipelines <strong>first-class objects</strong> within the language itself. This means you can:</p>
<ul>
<li><strong>Compose Pipelines</strong>: You can define small, modular pipelines and then merge them into larger ones using standard operators.</li>
<li><strong>Static Analysis</strong>: Because the DAG (Directed Acyclic Graph) is defined within the language, T can validate your entire workflow (checking for circular dependencies or missing data) before a single line of code even runs.</li>
<li><strong>Heterogeneous Execution</strong>: A single pipeline can effortlessly mix R, Python, and native T code. Data is passed between these nodes using built-in serializers like <code>^csv</code>, <code>^arrow</code>, or even specialized formats like <code>^pmml</code> for traditional models and <code>^onnx</code> for deep learning architectures. It is also possible to define your own serializers.</li>
<li><strong>Immutable State</strong>: Each node output is managed by Nix, meaning if you haven’t changed the code or the data for a specific node, T (via Nix) will simply pull the cached result from previous runs.</li>
</ul>
<p>But don’t let the “orchestrator” label fool you; T is also a capable language in its own right. It features a selection of built-in packages inspired by the <code>tidyverse</code> for data manipulation. Thanks to its Arrow backend, it is surprisingly fast. I even maintain a CI benchmark running on NYC Taxi data to ensure performance remains competitive.</p>
<p>I made sure that T is pretty easy to use with LLMs by providing a file called <code>summary.md</code> in the root of the GitHub repository. This file is meant to be used by LLMs to quickly learn the language’s syntax and generate code accordingly. You could also provide the whole help documentation to the LLM (found in the repository under <code>help/docs.json</code>), but I found that a summary is usually enough. There is also another experimental feature I’m thinking about, called <code>intent</code> blocks. These blocks would essentially be first-class structured comments that would be used to anchor LLM’s behaviour and make it more deterministic. These blocks would be parsed by T and used to generate code accordingly. I have some ideas how these could look like, something like this:</p>
<pre>intent {
  description: &quot;Customer churn prediction&quot;,
  assumptions: [&quot;Age &gt; 18&quot;, &quot;NA imputed with multiple imputation&quot;],
  requires: [&quot;dataset.csv&quot;]
}</pre>
<section id="is-this-slop" class="level2">
<h2 class="anchored" data-anchor-id="is-this-slop">Is this slop?</h2>
<p>There’s a lot of skepticism about building your own language using LLMs, and I get it. I was pretty skeptical myself. So let me tell you what actually gives me confidence in T’s correctness: as of writing, 1753 unit tests, 122 golden tests, 13 end-to-end tests, and 18 full project demos are executed on every push and PR, on both Linux and macOS via GitHub Actions. That’s the verification regime, and it has to be rigorous precisely because I can’t audit the OCaml implementation by eye. This is actually one of the more interesting lessons from this project: when you can’t rely on code review, you have to over-invest in tests and specifications. The spec files, the enriched changelog, the <code>summary.md</code>, all of that context makes the LLM’s output more predictable, and the test suite tells you immediately when it isn’t.</p>
<p>From personal experience, when I generate R or Python code, the output looks a lot like what I would have written myself. The main failure mode I’ve noticed is lack of context: the more you give the model, the better the result. Letting separate LLMs review PRs and iterating through several loops helps catch what any single model misses.</p>
<p>I’m also confident in T’s safety from a different angle: it’s ultimately orchestrating Python and R code you write yourself, and that you can test independently.</p>
</section>
<section id="interested" class="level2">
<h2 class="anchored" data-anchor-id="interested">Interested?</h2>
<p>If you’re interested in trying it out or contributing, check out the <a href="https://github.com/b-rodrigues/tlang" rel="nofollow" target="_blank">official repository</a> or the <a href="https://tstats-project.org/" rel="nofollow" target="_blank">website</a>, and don’t hesitate to open an issue or a PR or contact me on the dedicated Matrix (https://matrix.to/#/#tproject:matrix.org) channel.</p>
</section>
<section id="appendix" class="level1">
<h1>Appendix</h1>
<p>For the interested reader, here’s how to get started with T.</p>
<section id="how-to-get-started" class="level2">
<h2 class="anchored" data-anchor-id="how-to-get-started">How to get started</h2>
<p>If you have Nix installed, getting started with a new project is just a single command away:</p>
<pre># 1. Initialize a new project
nix run github:b-rodrigues/tlang -- init --project my_t_project
cd my_t_project</pre>
<p>There will be no other way to start a T project. As explained above, I don’t want to have to deal with providing OS-specific binaries, and since Nix is used by T as the build engine, you’ll need to have Nix installed on your system anyways. Might as well reuse it to manage the install T itself!</p>
<p>Inside the project’s folder, you’ll find a <code>tproject.toml</code> file. This is were you list R and Python packages you’ll need. For example:</p>
<pre>[project]
name = &quot;r_py_xgboost_t&quot;
description = &quot;A T data analysis project&quot;

[dependencies]
# T packages this project depends on
# Format: package = { git = &quot;repository-url&quot;, tag = &quot;version&quot; }
# Example:
# stats = { git = &quot;https://github.com/t-lang/stats&quot;, tag = &quot;v0.5.0&quot; }

[r-dependencies]
packages = [&quot;dplyr&quot;, &quot;yardstick&quot;]

[py-dependencies]
version = &quot;python313&quot;
packages = [&quot;numpy&quot;, &quot;pandas&quot;, &quot;scikit-learn&quot;, &quot;xgboost&quot;]

[additional-tools]
packages = [&quot;quarto&quot;]

[t]
# Minimum T language version required
min_version = &quot;0.51.2&quot;</pre>
<p>Under “additional tools” you can add any package that is available in <code>nixpkgs</code>. If you need LaTeX, you can also add this dedicated section:</p>
<pre>\(\)
packages = [&quot;amsmath&quot;, &quot;geometry&quot;, &quot;hyperref&quot;, &quot;biblatex&quot;]</pre>
<p>You may have noticed that there is also a section for T packages; that’s right, T supports user-defined packages. Instead of starting a project you’d start a package:</p>
<pre>nix run github:b-rodrigues/tlang -- init --package my_package
cd my_package</pre>
<p>Instead of a <code>tproject.toml</code> file, you’ll have to fill a <code>DESCRIPTION.toml</code> file:</p>
<pre>[package]
name = &quot;my_package&quot;
version = &quot;0.1.0&quot;
description = &quot;A brief description of what my_package does&quot;
authors = [&quot;brodriguesco&quot;]
license = &quot;EUPL-1.2&quot;
homepage = &quot;&quot;
repository = &quot;&quot;

[dependencies]
# T packages this package depends on
# Format: package = { git = &quot;repository-url&quot;, tag = &quot;version&quot; }

[t]
# Minimum T language version required
min_version = &quot;0.5.0&quot;</pre>
<p>Another important file is the <code>flake.nix</code> that will be automatically generated. You shouldn’t have to touch it, but this <code>flake.nix</code> is what provides the reproducible development environment for running your project. To do so, simply use:</p>
<pre>nix develop</pre>
<p>This will install T and activate the environment. If you’ve added stuff to the <code>tproject.toml</code> you’ll have to run <code>t update</code> to sync the packages to the flake, and then rebuild the environment (you’ll need to exit the development environment with <code>exit</code> and rebuild it using <code>nix develop</code> again). Oh and by the way, T requires a Linux-like environment so if you’re on Windows, you’ll have to run T within <strong>WSL2</strong> (Windows Subsystem for Linux).</p>
<p>Once inside the <code>nix develop</code> shell, everything you need, the T interpreter, your specific versions of R/Python, and all project tools, is ready to use. You don’t need to manage virtual environments or Docker containers manually; T handles the heavy lifting via Nix under the hood.</p>
<p>You can browse examples on this <a href="https://github.com/b-rodrigues/t_demos" rel="nofollow" target="_blank">repository</a>.</p>
</section>
<section id="tooling-and-editor-support" class="level2">
<h2 class="anchored" data-anchor-id="tooling-and-editor-support">Tooling and Editor Support</h2>
<p>A language is only as good as its developer experience. I politely asked LLMs to implement a full Language Server (<strong>LSP</strong>) for T, which provides autocompletion, real-time diagnostics, and “Go to Definition” support.</p>
<ul>
<li>For <strong>VS Code / Positron</strong>: A dedicated extension providing syntax highlighting and LSP integration.</li>
<li>For <strong>Vim / Emacs</strong>: Detailed configuration guides and syntax files are available.</li>
<li>For <strong>Quarto</strong>: T is fully compatible with Quarto for literate programming, allowing you to run executable <code>{t}</code> chunks directly in your documents.</li>
</ul>
<p>For detailed setup instructions, check out the <a href="https://github.com/b-rodrigues/tlang/blob/main/docs/editors.md" rel="nofollow" target="_blank">Editor Support guide</a> in the official documentation.</p>
<p>There’s much more I haven’t covered here, so <a href="https://github.com/b-rodrigues/tlang" rel="nofollow" target="_blank">check out the official repository</a> or the <a href="https://tstats-project.org/" rel="nofollow" target="_blank">website</a>.</p>


</section>
</section>

 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://b-rodrigues.github.io/posts/2026-04-03-tproject.html"> Econometrics and Free Software</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/you-can-just-build-your-own-programming-language/">You can just build your own programming language</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400328</post-id>	</item>
		<item>
		<title>AI agents can create convincing ecological models, but you still need to know what you’re doing</title>
		<link>https://www.r-bloggers.com/2026/04/ai-agents-can-create-convincing-ecological-models-but-you-still-need-to-know-what-youre-doing/</link>
		
		<dc:creator><![CDATA[Seascapemodels]]></dc:creator>
		<pubDate>Thu, 02 Apr 2026 13:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://www.seascapemodels.org/posts/2026-03-28-agentic-AI-ecological-modelling/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>Agentic AI tools like Claude Code can write and run code, fix its own errors, and produce a formatted report with figures. I wanted to know whether that translates into reliable ecological modelling, so we ran a test: three fisheries tasks, four...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/ai-agents-can-create-convincing-ecological-models-but-you-still-need-to-know-what-youre-doing/">AI agents can create convincing ecological models, but you still need to know what you’re doing</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://www.seascapemodels.org/posts/2026-03-28-agentic-AI-ecological-modelling/"> Seascapemodels</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 





<p>Agentic AI tools like Claude Code can write and run code, fix its own errors, and produce a formatted report with figures. I wanted to know whether that translates into reliable ecological modelling, so we ran a test: three fisheries tasks, four AI models, ten independent runs each, scored against a rubric. The results are published in <a href="https://doi.org/10.1111/faf.70079" rel="nofollow" target="_blank">Fish and Fisheries</a>.</p>
<p>We found agents can be genuinely useful, but only if you know how to use them well and only if you know enough about the analysis to catch what they miss.</p>
<section id="how-we-did-our-tests" class="level2">
<h2 class="anchored" data-anchor-id="how-we-did-our-tests">How we did our tests</h2>
<p>We used <a href="https://roo.cline.bot/" rel="nofollow" target="_blank">Roo Code</a>, an agentic AI that runs inside VS Code. Unlike a chatbot, it can write code, execute it, read error messages, and iterate autonomously. There are many popular software’s for agentic AI, Claude Code is the most popular right now. We chose Roo Code because it is open source and fully customisable.</p>
<p>We gave it detailed specification sheets and asked it to complete three tasks. One was a common ecological modelling task: fitting a generalized linear model (GLM) of fish abundance and coral habitat. The other two were tasks specialised to fisheries modelling: fitting a von Bertalanffy growth curve and running a yield per recruit analysis. We chose these because they are common in ecological sciences, but specalised enough that LLMs probably haven’t seen many examples in their training data.</p>
<p>We ran each task 10 times. LLM responses have some randomness, and this multiplies when doing long-running tasks. So consistency is as important to measure as their best performance. We scored every output against a rubric covering accuracy, code quality, and report quality.</p>
<p>We used four versions of LLMs. Two proprietary models: Claude Sonnet 4.0, Sonnet 4.5 (which came out during review so we added later). One open weight model: Kimi K2 and its ‘exacto’ variant.</p>
<p>During review, Kimi K2 ‘exacto’ became available on the <a href="https://openrouter.ai/" rel="nofollow" target="_blank">OpenRouter</a> platform, so we added that. The exacto routes requests to providers with the best performance. Some providers run it cheaply. Long story-short, exacto performed much better than just requesting any provider’s version of K2, this highlights the importance of running open weight models on quality hardware.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://i1.wp.com/www.seascapemodels.org/posts/2026-03-28-agentic-AI-ecological-modelling/AI-agent-workflows.png?w=578&#038;ssl=1" class="img-fluid figure-img" data-recalc-dims="1"></p>
<figcaption>Agentic workflows vs AI assisted coding</figcaption>
</figure>
</div>
</section>
<section id="how-to-use-agentic-ai-for-ecological-modelling" class="level2">
<h2 class="anchored" data-anchor-id="how-to-use-agentic-ai-for-ecological-modelling">How to use agentic AI for ecological modelling</h2>
<p>We learned several key lessons about how to get the best out of agentic AI for ecological modelling.</p>
<p><strong>Write a detailed specification sheet.</strong> Our sheets ran to multiple pages covering analysis aims, data structure, recommended R functions and packages, expected outputs, and file naming conventions. This takes time, but writing a specification forces you to think carefully about what you actually want. <a href="https://github.com/cbrown5/agentic-ai-fisheries/blob/main/Scripts/glm-test-case/glm-readme.md" rel="nofollow" target="_blank">Here’s an example</a>.</p>
<p><strong>Specify the algorithms explicitly.</strong> Agents default to the most common method in their training data, which may not be appropriate for your question. If you want bootstrapped confidence intervals via the <code>boot</code> package, say so.</p>
<p>Even then, they may not comply: both Claude models in our study repeatedly applied natural mortality to the first age class in the yield per recruit model despite explicit instructions not to. That’s a subtle error that affected catch estimates—the numbers that would inform fishery management. These quirks of agent behaviour highlight why expert supervision is essential.</p>
<p><strong>Run replicates and compare outputs.</strong> Accuracy scores varied substantially between runs. sometimes the agent nailed every parameter; sometimes it got some parts correct but made systematic errors in other parts of the analysis. Running multiple agents and comparing outputs is one way to identify the best solutions.</p>
<p><strong>Check the things the agent doesn’t know to check.</strong> None of our agents checked for collinearity between predictors in the GLM, even though it’s standard practice. We deliberately left it out of the specification to see if they’d do that. The GLMs ran fine, the results looked coherent, but there was in fact strong colinearity between the predictors. The lesson here is that the agents are good at coding, but their conceptual implementation may be misleading, incomplete or logically flawed.</p>
</section>
<section id="the-biggest-problem-with-agentic-ai-is-that-it-can-produce-professionally-formatted-output-that-contains-logical-errors" class="level2">
<h2 class="anchored" data-anchor-id="the-biggest-problem-with-agentic-ai-is-that-it-can-produce-professionally-formatted-output-that-contains-logical-errors">The biggest problem with agentic AI is that it can produce professionally formatted output that contains logical errors</h2>
<p>The error type that concerns me most is professionally formatted output containing logical errors.</p>
<p>In our results we saw growth curves that plotted beautifully but used the wrong confidence interval method, or a yield analysis that applies mortality in the wrong sequence. A coding syntax error is immediately obvious. A methodological shortcut embedded in otherwise clean output may be invisible unless you already know what the answer should look like.</p>
<p>There is a genuine risk that inexperienced researchers will use these tools to produce analyses they cannot evaluate. Experienced researchers may also get overconfident and not check results thoroughly enough. These flaws can then leak through to the applications, as we’ve seen where human errors in <a href="https://pnas.org/doi/10.1073/pnas.2426166122" rel="nofollow" target="_blank">ecological modelling impacts decisions on invasive species</a>.</p>
<p>For scientists with strong quantitative foundations, agents offer a real efficiency gain. The specification sheets and rubrics from our study are in the supplemental materials if you want to adapt them. All our code is available on github if you want to run your own tests (<a href="https://github.com/cbrown5/agentic-ai-fisheries/tree/main/Scripts" rel="nofollow" target="_blank">Check this folder, each modelling ‘test-case’ has the specification sheet and other files</a>)</p>
<p>The paper is open access: <a href="https://doi.org/10.1111/faf.70079" rel="nofollow" target="_blank">Brown et al. 2026, Fish and Fisheries</a>.</p>


</section>

 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.seascapemodels.org/posts/2026-03-28-agentic-AI-ecological-modelling/"> Seascapemodels</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/ai-agents-can-create-convincing-ecological-models-but-you-still-need-to-know-what-youre-doing/">AI agents can create convincing ecological models, but you still need to know what you’re doing</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400276</post-id>	</item>
		<item>
		<title>A Better R Programming Experience Thanks to Tree-sitter</title>
		<link>https://www.r-bloggers.com/2026/04/a-better-r-programming-experience-thanks-to-tree-sitter/</link>
		
		<dc:creator><![CDATA[rOpenSci]]></dc:creator>
		<pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://ropensci.org/blog/2026/04/02/tree-sitter-overview/</guid>

					<description><![CDATA[<p>A little bit less than two years ago, building on work by Jim Hester and Kevin Ushey, Davis Vaughan completed a very impactful JavaScript file for the R community: an R grammar for the Tree-sitter parsing generator. He even got a round of applause for...</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/a-better-r-programming-experience-thanks-to-tree-sitter/">A Better R Programming Experience Thanks to Tree-sitter</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/"> rOpenSci - open tools for open science</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p>A little bit less than two years ago, building on work by Jim Hester and Kevin Ushey, Davis Vaughan completed a very impactful JavaScript file for the R community: an R grammar for the Tree-sitter parsing generator. He even got a round of applause for it during a talk at the useR! 2024 conference! So, did he get cheered for… grammatical rules in a <a href="https://github.com/r-lib/tree-sitter-r/blob/next/grammar.js" rel="nofollow" target="_blank">JavaScript file</a>? <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f605.png" alt="😅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>No, the audience was excited about the <em>improved developer experience for R</em> that this file unlocked. R tooling around Tree-sitter is how you get</p>
<ul>
<li>reformatting through <a href="https://posit-dev.github.io/air/" rel="nofollow" target="_blank">Air</a> and linting through <a href="https://jarl.etiennebacher.com/" rel="nofollow" target="_blank">Jarl</a>;</li>
<li>auto-completion or help on hover in the <a href="https://lionel-.github.io/slidedecks/2024-07-11-ark" rel="nofollow" target="_blank">Positron IDE</a>;</li>
<li>better <a href="https://github.com/orgs/community/discussions/120397" rel="nofollow" target="_blank">search</a> for R on GitHub;</li>
<li>and more!</li>
</ul>
<p>In this post, we’ll explain what Tree-sitter is, and how tools built on Tree-sitter can benefit your R development workflow.</p>
<h2>
Code parsing: what is Tree-sitter?
</h2><p><a href="https://tree-sitter.github.io/tree-sitter/" rel="nofollow" target="_blank">Tree-sitter</a> is a code parsing generator written in C, with bindings existing in several languages including Rust (and R!).</p>
<p>Let’s rewind a little bit. What does it mean to parse code?</p>
<p>Basically, given a string of code like</p>
<pre>a &lt;- mean(x, na.rm = TRUE)
</pre><p>How do you know that <code>mean</code> is a function name, <code>na.rm</code> an argument name, <code>TRUE</code> a logical? You have to <em>parse</em> that code into what’s called a parse tree. You do that in your head when reading R code. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f638.png" alt="😸" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>R itself can obviously parse R code, thanks to its <a href="https://github.com/wch/r-source/blob/trunk/src/main/gram.y" rel="nofollow" target="_blank">grammar</a>. See for instance the <a href="https://github.com/wch/r-source/commit/a1425adea54bcc98eef86081522b5dbb3e149cdc#diff-ba804d7fa3fa053c1f57d46369f4432cb55c9c4f69f46ae6510d0d1fcc59f382" rel="nofollow" target="_blank">commit that introduced R’s native pipe</a>, which necessitated extending R’s syntax thus modifying its grammar.</p>
<p>You can use <a href="https://rdrr.io/r/base/parse.html" rel="nofollow" target="_blank"><code>parse()</code></a> and <a href="https://rdrr.io/r/utils/getParseData.html" rel="nofollow" target="_blank"><code>getParseData()</code></a> to parse R code.</p>
<div class="highlight">
<pre>parse(
 text = &quot;a &lt;- mean(x, na.rm = TRUE)&quot;,
 keep.source = TRUE
) |&gt;
 getParseData()
#&gt; line1 col1 line2 col2 id parent token terminal text
#&gt; 23 1 1 1 26 23 0 expr FALSE 
#&gt; 1 1 1 1 1 1 3 SYMBOL TRUE a
#&gt; 3 1 1 1 1 3 23 expr FALSE 
#&gt; 2 1 3 1 4 2 23 LEFT_ASSIGN TRUE &lt;-
#&gt; 21 1 6 1 26 21 23 expr FALSE 
#&gt; 4 1 6 1 9 4 6 SYMBOL_FUNCTION_CALL TRUE mean
#&gt; 6 1 6 1 9 6 21 expr FALSE 
#&gt; 5 1 10 1 10 5 21 '(' TRUE (
#&gt; 7 1 11 1 11 7 9 SYMBOL TRUE x
#&gt; 9 1 11 1 11 9 21 expr FALSE 
#&gt; 8 1 12 1 12 8 21 ',' TRUE ,
#&gt; 13 1 14 1 18 13 21 SYMBOL_SUB TRUE na.rm
#&gt; 14 1 20 1 20 14 21 EQ_SUB TRUE =
#&gt; 15 1 22 1 25 15 16 NUM_CONST TRUE TRUE
#&gt; 16 1 22 1 25 16 21 expr FALSE 
#&gt; 17 1 26 1 26 17 21 ')' TRUE )
</pre>
</div>
<p>Or you could transform that same data into XML using Gábor Csárdi’s <a href="https://r-lib.github.io/xmlparsedata/" rel="nofollow" target="_blank">{xmlparsedata}</a>:</p>
<div class="highlight">
<pre>parse(
 text = &quot;a &lt;- mean(x, na.rm = TRUE)&quot;,
 keep.source = TRUE
) |&gt;
 xmlparsedata::xml_parse_data(pretty = TRUE) |&gt;
 xml2::read_xml() |&gt;
 as.character() |&gt;
 cat()
#&gt; &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
#&gt; &lt;exprlist&gt;
#&gt; &lt;expr line1=&quot;1&quot; col1=&quot;1&quot; line2=&quot;1&quot; col2=&quot;26&quot; start=&quot;28&quot; end=&quot;53&quot;&gt;
#&gt; &lt;expr line1=&quot;1&quot; col1=&quot;1&quot; line2=&quot;1&quot; col2=&quot;1&quot; start=&quot;28&quot; end=&quot;28&quot;&gt;
#&gt; &lt;SYMBOL line1=&quot;1&quot; col1=&quot;1&quot; line2=&quot;1&quot; col2=&quot;1&quot; start=&quot;28&quot; end=&quot;28&quot;&gt;a&lt;/SYMBOL&gt;
#&gt; &lt;/expr&gt;
#&gt; &lt;LEFT_ASSIGN line1=&quot;1&quot; col1=&quot;3&quot; line2=&quot;1&quot; col2=&quot;4&quot; start=&quot;30&quot; end=&quot;31&quot;&gt;&lt;-&lt;/LEFT_ASSIGN&gt;
#&gt; &lt;expr line1=&quot;1&quot; col1=&quot;6&quot; line2=&quot;1&quot; col2=&quot;26&quot; start=&quot;33&quot; end=&quot;53&quot;&gt;
#&gt; &lt;expr line1=&quot;1&quot; col1=&quot;6&quot; line2=&quot;1&quot; col2=&quot;9&quot; start=&quot;33&quot; end=&quot;36&quot;&gt;
#&gt; &lt;SYMBOL_FUNCTION_CALL line1=&quot;1&quot; col1=&quot;6&quot; line2=&quot;1&quot; col2=&quot;9&quot; start=&quot;33&quot; end=&quot;36&quot;&gt;mean&lt;/SYMBOL_FUNCTION_CALL&gt;
#&gt; &lt;/expr&gt;
#&gt; &lt;OP-LEFT-PAREN line1=&quot;1&quot; col1=&quot;10&quot; line2=&quot;1&quot; col2=&quot;10&quot; start=&quot;37&quot; end=&quot;37&quot;&gt;(&lt;/OP-LEFT-PAREN&gt;
#&gt; &lt;expr line1=&quot;1&quot; col1=&quot;11&quot; line2=&quot;1&quot; col2=&quot;11&quot; start=&quot;38&quot; end=&quot;38&quot;&gt;
#&gt; &lt;SYMBOL line1=&quot;1&quot; col1=&quot;11&quot; line2=&quot;1&quot; col2=&quot;11&quot; start=&quot;38&quot; end=&quot;38&quot;&gt;x&lt;/SYMBOL&gt;
#&gt; &lt;/expr&gt;
#&gt; &lt;OP-COMMA line1=&quot;1&quot; col1=&quot;12&quot; line2=&quot;1&quot; col2=&quot;12&quot; start=&quot;39&quot; end=&quot;39&quot;&gt;,&lt;/OP-COMMA&gt;
#&gt; &lt;SYMBOL_SUB line1=&quot;1&quot; col1=&quot;14&quot; line2=&quot;1&quot; col2=&quot;18&quot; start=&quot;41&quot; end=&quot;45&quot;&gt;na.rm&lt;/SYMBOL_SUB&gt;
#&gt; &lt;EQ_SUB line1=&quot;1&quot; col1=&quot;20&quot; line2=&quot;1&quot; col2=&quot;20&quot; start=&quot;47&quot; end=&quot;47&quot;&gt;=&lt;/EQ_SUB&gt;
#&gt; &lt;expr line1=&quot;1&quot; col1=&quot;22&quot; line2=&quot;1&quot; col2=&quot;25&quot; start=&quot;49&quot; end=&quot;52&quot;&gt;
#&gt; &lt;NUM_CONST line1=&quot;1&quot; col1=&quot;22&quot; line2=&quot;1&quot; col2=&quot;25&quot; start=&quot;49&quot; end=&quot;52&quot;&gt;TRUE&lt;/NUM_CONST&gt;
#&gt; &lt;/expr&gt;
#&gt; &lt;OP-RIGHT-PAREN line1=&quot;1&quot; col1=&quot;26&quot; line2=&quot;1&quot; col2=&quot;26&quot; start=&quot;53&quot; end=&quot;53&quot;&gt;)&lt;/OP-RIGHT-PAREN&gt;
#&gt; &lt;/expr&gt;
#&gt; &lt;/expr&gt;
#&gt; &lt;/exprlist&gt;
</pre>
</div>
<p>In both cases, you recognize words such as <code>LEFT_ASSIGN</code> or <code>SYMBOL_FUNCTION_CALL</code>. Parsing is an essential step before the code is actually executed, but parsed code can also be used for other purposes, such as analyzing code without brittle regular expressions (does it call a particular <a href="https://nrennie.rbind.io/blog/how-to-make-your-own-rstats-wrapped/" rel="nofollow" target="_blank">function</a>?), navigating code (going from a function call to the definition of that function), or modifying code (replacing all occurrences of a function with another one).</p>
<p>Now, Tree-sitter performs this same code parsing but <strong>faster</strong> especially thanks to its support of incremental parsing – which is key to updating the syntax tree as you are typing in your editor for instance! Tree-sitter is agnostic in that it can parse any code as long as there is a grammar for it (think, Rosetta Stone plugins). It’s been used for many languages which means many tools have been built around it.</p>
<p>To have Tree-sitter “learn” a new language you need to give it a file containing the definition of the syntax of that language, what’s called a <em>grammar</em>. This is where the aforementioned JavaScript file by Davis Vaughan and collaborators comes into play! The <a href="https://github.com/r-lib/tree-sitter-r" rel="nofollow" target="_blank">treesitter-r repo</a>, which provides a translation of the R grammar in the format expected by Tree-sitter, is the base of all tools presented in this post which use R code as their input.</p>
<p>Here’s how to use the {treesitter} R package for the same code as earlier. The {treesitter} R package allows us to use Tree-sitter from R. To parse R code with it, we need the <code>language()</code> function from {treesitter.r}<sup id="fnref:1"><a href="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/#fn:1" class="footnote-ref" role="doc-noteref" rel="nofollow" target="_blank">1</a></sup>.</p>
<div class="highlight">
<pre>library(treesitter)
#&gt; 
#&gt; Attaching package: 'treesitter'
#&gt; The following object is masked from 'package:base':
#&gt; 
#&gt; range
language &lt;- treesitter.r::language()
parser &lt;- parser(language)
text &lt;- &quot;a &lt;- mean(x, na.rm = TRUE)&quot;
parser_parse(parser, text)
#&gt; &lt;tree_sitter_tree&gt;
#&gt; 
#&gt; ── Text ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
#&gt; a &lt;- mean(x, na.rm = TRUE)
#&gt; 
#&gt; ── S-Expression ────────────────────────────────────────────────────────────────────────────────────────────────────────────────
#&gt; (program [(0, 0), (0, 26)]
#&gt; (binary_operator [(0, 0), (0, 26)]
#&gt; lhs: (identifier [(0, 0), (0, 1)])
#&gt; operator: &quot;&lt;-&quot; [(0, 2), (0, 4)]
#&gt; rhs: (call [(0, 5), (0, 26)]
#&gt; function: (identifier [(0, 5), (0, 9)])
#&gt; arguments: (arguments [(0, 9), (0, 26)]
#&gt; open: &quot;(&quot; [(0, 9), (0, 10)]
#&gt; argument: (argument [(0, 10), (0, 11)]
#&gt; value: (identifier [(0, 10), (0, 11)])
#&gt; )
#&gt; (comma [(0, 11), (0, 12)])
#&gt; argument: (argument [(0, 13), (0, 25)]
#&gt; name: (identifier [(0, 13), (0, 18)])
#&gt; &quot;=&quot; [(0, 19), (0, 20)]
#&gt; value: (true [(0, 21), (0, 25)])
#&gt; )
#&gt; close: &quot;)&quot; [(0, 25), (0, 26)]
#&gt; )
#&gt; )
#&gt; )
#&gt; )
</pre>
</div>
<p>Tree-sitter is the workhorse of many tools, that are mentioned in the diagram below. All of them are dependent on tree-sitter and the R grammar provided to it. Some of them are command-line interfaces (CLIs), while others are R packages.</p>
<figure><img src="https://i0.wp.com/ropensci.org/blog/2026/04/02/tree-sitter-overview/tree-sitter.png?w=578&#038;ssl=1"
alt="Diagram of Tree-sitter tooling for R. At the center is Tree-sitter especially its Rust bindings and the R grammar for treesitter. At the top is the input, R scripts. At the bottom from treesitter is the treesitter R package,; ast-grep that is used by astgrepr which is used by flir and that is used by the CLAUDE.md instructions for parsing code; Air that is used by Jarl; Ark that is used by the Positron IDE; R code browsing on GitHub." data-recalc-dims="1">
</figure>
<h2>
Browsing code interactively: Positron IDE, GitHub
</h2><p>The real reason why the audience applauded Davis Vaughan is that he explained how the R grammar for Tree-sitter had been <a href="https://github.com/orgs/community/discussions/120397" rel="nofollow" target="_blank">deployed to GitHub</a> so that we get almost as good experience browsing R code on GitHub as browsing, say, JS code. If we search for a function name in a repository for instance, its definition will be indicated in the search results. See <a href="https://www.youtube.com/watch?v=Gm0ikRBAfwc" rel="nofollow" target="_blank">Davis’ slides</a> (also available in <a href="https://github.com/DavisVaughan/2024-07-09_useR-2024" rel="nofollow" target="_blank">PDF</a>), or refer to the video below showing how typing <code>vetiver_model</code> in the search bar from the R vetiver repo makes the function definition the first result, on which one can click to land into the definition.</p>
<video controls preload="auto" width="450" playsinline class="html-video">
<source src="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/searching-for-vetiver-model-r-new.mp4" type="video/mp4">
<span></span>
</video>
<p>Also very useful is the use of Tree-sitter by <a href="https://github.com/posit-dev/ark" rel="nofollow" target="_blank">Ark</a>, the R kernel <a href="https://lionel-.github.io/slidedecks/2024-07-11-ark/#/language-server-protocol-1" rel="nofollow" target="_blank">used in the Positron IDE</a>. Ark is how you get autocompletion and help on hover in Positron. The video below shows how you can extend the selection to further steps of a pipeline in Positron.</p>
<video controls preload="auto" width="450" playsinline class="html-video">
<source src="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/expand-selection-2.mp4" type="video/mp4">
<span></span>
</video>
<p>This use case of Tree-sitter is also featured in <a href="https://www.youtube.com/watch?v=Gm0ikRBAfwc" rel="nofollow" target="_blank">Davis’ slides</a>. See also Lionel Henry’s and Davis Vaughan’s talk about Ark at <a href="https://youtu.be/8uRcB34Hhsw?si=UeWqIi9PtEOWqRsp&#038;t=2109" rel="nofollow" target="_blank">posit conf 2024</a>, especially the part about <a href="https://youtu.be/8uRcB34Hhsw?si=GBqntC6tW7D2WhBN&#038;t=2455" rel="nofollow" target="_blank">code assistance</a>.</p>
<p>Other development environments such as <a href="https://lists.gnu.org/archive/html/emacs-devel/2022-11/msg01443.html" rel="nofollow" target="_blank">Emacs</a> also have support for Tree-sitter.</p>
<h2>
Searching/browsing code
</h2><p>You can parse and search R code using the {treesitter} R package and <a href="https://tree-sitter.github.io/tree-sitter/4-code-navigation.html" rel="nofollow" target="_blank">treesitter query syntax</a>. The {treesitter} R package is a dependency of the <a href="https://simonpcouch.github.io/gander/" rel="nofollow" target="_blank">{gander} package</a> by Simon Couch, that is meant to be used for a better experience with LLMs when writing R code. Another use case of the {treesitter} R package is the {igraph.r2cdocs} <a href="https://roxygen2.r-lib.org/dev/articles/extending.html" rel="nofollow" target="_blank">extension</a> to {roxygen2} for the {igraph} package, that <a href="https://github.com/igraph/igraph.r2cdocs/blob/6be2a327a18deb823302caeab8b60a916f6fac62/R/roxygen.R#L119" rel="nofollow" target="_blank">parses all of igraph R code</a> to then be able to identify, for each exported function, whether it (in)directly calls a function whose name ends with <code>_impl</code>, indicating a wrapper to a C igraph function whose docs can be then be linked from the manual of the R function.</p>
<p>The {pkgdepends} package calls Tree-sitter (<a href="https://github.com/r-lib/pkgdepends/blob/main/src/tree-sitter.c" rel="nofollow" target="_blank">C</a>) to detect <a href="https://github.com/r-lib/pkgdepends/blob/634661a7d91b41476fd1ab653fe3087a6e40b8a9/R/scan-deps.R#L340" rel="nofollow" target="_blank">dependencies in files</a>. Below we run it on the source of the <a href="https://docs.ropensci.org/saperlipopette/" rel="nofollow" target="_blank">saperlipopette R package</a>.</p>
<div class="highlight">
<pre>pkgdepends::scan_deps(
 &quot;../../../../../CHAMPIONS/saperlipopette&quot;,
 &quot;../../../../../CHAMPIONS&quot;
)
#&gt; 
#&gt; Dependencies:
#&gt; + brio  @ R/blame.R, R/check-editor.R, R/clean-dir.R, R/committed-to-main.R, R/committed-to-wrong-branch.R, R/conflict…
#&gt; + cli  @ inst/exo_bisect-Rprofile.en.R, inst/exo_bisect-Rprofile.es.R, inst/exo_bisect-Rprofile.fr.R, inst/exo_blame-…
#&gt; + devtools  @ saperlipopette.Rproj
#&gt; + fs  @ R/blame.R, R/check-editor.R, R/clean-dir.R, R/committed-to-main.R, R/committed-to-wrong-branch.R, R/conflict…
#&gt; + gert  @ inst/exo_check_editor-Rprofile.en.R, inst/exo_check_editor-Rprofile.es.R, inst/exo_check_editor-Rprofile.fr.…
#&gt; + knitr  @ README.Rmd
#&gt; + parsedate  @ R/utils-git.R
#&gt; + purrr  @ R/create-all.R, R/debug.R, R/log-deleted-file.R, R/log-deleted-line.R, R/revparse.R, R/roxygen2.R, R/worktre…
#&gt; + rlang  @ R/create-all.R, R/roxygen2.R, R/utils-fs.R, R/utils-usethis.R, R/zzz.R
#&gt; + rmarkdown  @ README.Rmd, vignettes/saperlipopette.qmd
#&gt; + roxygen2  @ R/roxygen2.R, saperlipopette.Rproj
#&gt; + saperlipopette @ README.Rmd, vignettes/saperlipopette.qmd
#&gt; + tibble  @ R/roxygen2.R
#&gt; + usethis  @ R/blame.R, R/check-editor.R, R/clean-dir.R, R/committed-to-main.R, R/committed-to-wrong-branch.R, R/conflict…
#&gt; + vctrs  @ R/roxygen2.R
#&gt; + withr  @ R/blame.R, R/check-editor.R, R/clean-dir.R, R/committed-to-main.R, R/committed-to-wrong-branch.R, R/conflict…
#&gt; 
#&gt; Test dependencies:
#&gt; + fs  @ tests/testthat/test-blame.R, tests/testthat/test-check-editor.R, tests/testthat/test-clean-dir.R, tests/test…
#&gt; + gert  @ tests/testthat/test-blame.R, tests/testthat/test-clean-dir.R, tests/testthat/test-committed-to-main.R, tests…
#&gt; + rlang  @ tests/testthat/test-blame.R, tests/testthat/test-check-editor.R, tests/testthat/test-clean-dir.R, tests/test…
#&gt; + saperlipopette @ tests/testthat.R
#&gt; + testthat  @ tests/testthat.R
#&gt; + withr  @ tests/testthat/test-blame.R, tests/testthat/test-check-editor.R, tests/testthat/test-clean-dir.R, tests/test…
</pre>
</div>
<p><a href="https://ast-grep.github.io/" rel="nofollow" target="_blank">ast-grep</a> is a useful tool built on Tree-sitter for searching and re-writing code, with a clearer query syntax than Tree-sitter’s. Its name is reminiscent of grep, but with ast-grep we do not need to write brittle regular expressions <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f638.png" alt="😸" class="wp-smiley" style="height: 1em; max-height: 1em;" />. <a href="https://astgrepr.etiennebacher.com/" rel="nofollow" target="_blank">{astgrepr}</a> by Etienne Bacher is an R wrapper to the Rust bindings of ast-grep, and is used in Etienne’s <a href="https://flir.etiennebacher.com/" rel="nofollow" target="_blank">{flir} package</a> for <a href="https://flir.etiennebacher.com/articles/adding_rules" rel="nofollow" target="_blank">refactoring</a> code.</p>
<p>The ast-grep command-line interface (CLI) itself is featured in a useful <a href="https://emilhvitfeldt.com/post/ast-grep-r-claude-code/" rel="nofollow" target="_blank">blog post by Emil Hvitfeldt</a> where he explains how to document the usage of ast-grep for Claude.</p>
<h2>
Formatting and linting: Air, Jarl
</h2><p>Speaking of CLIs…</p>
<figure><img src="https://i2.wp.com/ropensci.org/blog/2026/04/02/tree-sitter-overview/meme.png?w=578&#038;ssl=1"
alt="Cute kitten attacked by robots. The text says &#39;Everytime you use Claude for something a CLI can do, a kitten dies&#39;." data-recalc-dims="1">
</figure>
<p><a href="https://posit-dev.github.io/air/cli.html" rel="nofollow" target="_blank">Air</a>, by Davis Vaughan and Lionel Henry, is a CLI built on Tree-sitter, in Rust. It <em>reformats</em> code blazingly fast.</p>
<p><a href="https://jarl.etiennebacher.com/" rel="nofollow" target="_blank">Jarl</a>, by Etienne Bacher, is a CLI built on Air, therefore also on Tree-sitter, in Rust. It <em>lints</em> and <em>fixes</em> code, also blazingly fast. It can even detect <a href="https://jarl.etiennebacher.com/rules/unreachable_code" rel="nofollow" target="_blank">unreachable code</a>, <a href="https://jarl.etiennebacher.com/rules/unused_function" rel="nofollow" target="_blank">unused functions</a> and <a href="https://jarl.etiennebacher.com/rules/duplicated_function_definition" rel="nofollow" target="_blank">duplicated function definitions</a>.</p>
<p>In both of these examples, the creation of <em>CLIs</em> wrapping Rust bindings was more efficient than the creation of R packages wrapping the {treesitter} R package, for several reasons:</p>
<ul>
<li>Rust CLIs can edit code very fast<sup id="fnref:2"><a href="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/#fn:2" class="footnote-ref" role="doc-noteref" rel="nofollow" target="_blank">2</a></sup>;</li>
<li>CLIs are integrated in extensions for popular IDEs (for instance Positron);</li>
<li>a CLI is easier to install on CI than an R package that needs, well, an R installation.</li>
</ul>
<h2>
More tools
</h2><p>A brief mention of some other interesting tools we’ve explored a bit less.</p>
<h3>
Configuring: {ts} for parsing JSON and TOML (not R!)
</h3><p>The <a href="https://github.com/r-lib/ts" rel="nofollow" target="_blank">{ts}</a> package by Gábor Csárdi is the backbone of two R packages used for editing and manipulating:</p>
<ul>
<li>TOML <a href="https://gaborcsardi.github.io/tstoml/" rel="nofollow" target="_blank">{tstoml}</a>;</li>
<li>JSON <a href="https://gaborcsardi.github.io/tsjsonc/" rel="nofollow" target="_blank">{tsjson}</a>.</li>
</ul>
<p>Compared to existing parsers in R for those formats, these two packages preserve comments.</p>
<h3>
Testing code: {muttest}
</h3><p><a href="https://en.wikipedia.org/wiki/Mutation_testing" rel="nofollow" target="_blank">Mutation testing</a> is a kind of testing where you, say, randomly swap <code>+</code> with <code>-</code> in your code (you <em>mutate</em> it) and you run your tests to see whether they catch the mutant. The <a href="https://github.com/jakubsob/muttest" rel="nofollow" target="_blank">{muttest} package</a> by Jakub Sobolewski is an R package for mutation testing, that depends on the {treesitter} R package.</p>
<h3>
Diffing code: difftastic
</h3><p>The difftastic CLI by Wilfred Hughes is “a structural diff tool that understands syntax”. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> This means that difftastic doesn’t only compare line or “words” but actual syntax by looking at lines around the lines that changed (by default, 3). Even better, it understands R out of the box. See this <a href="https://masalmon.eu/2026/03/30/difftastic/" rel="nofollow" target="_blank">blog post with examples of R code diffing</a>.</p>
<h2>
Conclusion: more to come?
</h2><p>In this post, we’ve presented an overview of Tree-sitter based tooling for R or in R.</p>
<p>Note that this ecosystem of tools is very actively developed, so some tools might come and go. However, the idea that plugging the R grammar into a general parsing generator brings cool features to us R developers, will remain true. Maybe <em>you</em> will contribute to this ecosystem, either through an existing tool or by creating a new one?</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>We could also parse C code with it using <a href="https://sounkou-bioinfo.github.io/treesitter.c/" rel="nofollow" target="_blank">{treesitter.c}</a>. <a href="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/#fnref:1" class="footnote-backref" role="doc-backlink" rel="nofollow" target="_blank"><img src="https://s.w.org/images/core/emoji/13.0.0/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></p>
</li>
<li id="fn:2">
<p>Rust is a lower level language than R so has less overhead; furthermore this kind of Rust code can be easily parallelized. <a href="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/#fnref:2" class="footnote-backref" role="doc-backlink" rel="nofollow" target="_blank"><img src="https://s.w.org/images/core/emoji/13.0.0/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></p>
</li>
</ol>
</div>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://ropensci.org/blog/2026/04/02/tree-sitter-overview/"> rOpenSci - open tools for open science</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/04/a-better-r-programming-experience-thanks-to-tree-sitter/">A Better R Programming Experience Thanks to Tree-sitter</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400270</post-id>	</item>
		<item>
		<title>Techtonique dot net is down until further notice</title>
		<link>https://www.r-bloggers.com/2026/03/techtonique-dot-net-is-down-until-further-notice/</link>
		
		<dc:creator><![CDATA[T. Moudiki]]></dc:creator>
		<pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://thierrymoudiki.github.io//blog/2026/04/01/r/python/techtonique/techtonique-dot-net-down</guid>

					<description><![CDATA[<p>Techtonique dot net is down until further notice</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/techtonique-dot-net-is-down-until-further-notice/">Techtonique dot net is down until further notice</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://thierrymoudiki.github.io//blog/2026/04/01/r/python/techtonique/techtonique-dot-net-down"> T. Moudiki's Webpage - R</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p><strong>IMPORTANT: The website <a href="https://www.techtonique.net/" rel="nofollow" target="_blank">https://www.techtonique.net</a> is down until further notice.</strong></p>

<p><a href="https://www.techtonique.net/" rel="nofollow" target="_blank">https://www.techtonique.net</a> contained an language-agnostic API for machine learning tasks (classification, regression, survival analysis, forecasting etc.).</p>

<p>As a result, do not buy the Gumroad tutorial then.</p>

<p>You can still use the packages <a href="https://github.com/Techtonique" rel="nofollow" target="_blank">https://github.com/Techtonique</a> locally.</p>

<p>PS: It’s not an April’s fool joke.</p>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://thierrymoudiki.github.io//blog/2026/04/01/r/python/techtonique/techtonique-dot-net-down"> T. Moudiki's Webpage - R</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/techtonique-dot-net-is-down-until-further-notice/">Techtonique dot net is down until further notice</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400260</post-id>	</item>
		<item>
		<title>Transgender Day of Visibility</title>
		<link>https://www.r-bloggers.com/2026/03/transgender-day-of-visibility/</link>
		
		<dc:creator><![CDATA[Jerry Tuttle]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 04:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">http://www.r-bloggers.com/?guid=5ea12746cec1b25e0746ca21879d6565</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>     <br />
March 31 is Transgender Day of Visibility. I’m not transgender myself, but I have friends, acquaintances, and family members who are. Chances are you do too, whether you realize it or not.   </p>
<p>  &#038;nbs...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/transgender-day-of-visibility/">Transgender Day of Visibility</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://onlinecollegemathteacher.blogspot.com/2026/03/transgender-day-of-visibility.html"> Online College Math Teacher</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<font size = 3>

  
 <div class="separator" style="clear: both;"><a href="https://i1.wp.com/blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZfk2-sxWBT_tk6b5Aq5W_ZFTvUKWWBlbiDmUau8As6CakkBCcLnsYGrDEQpTekShVIbQFBUBWux9Kf7YcQ1LW6In9s8uh-vjliUKtDdpH5OzVs50JAeA9HTGG5gFrWy1eJqFub5puN3zIv5Pj0jji6KLwkmLFq1rKUx3KwIWOpmXhVcFRZCW-EY7iEqE/s1152/Transgender_Pride_Flag.jpeg?ssl=1" style="display: block; padding: 1em 0; text-align: center; " rel="nofollow" target="_blank"><img alt="" border="0" width="400" data-original-height="487" data-original-width="450" src="https://i0.wp.com/blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZfk2-sxWBT_tk6b5Aq5W_ZFTvUKWWBlbiDmUau8As6CakkBCcLnsYGrDEQpTekShVIbQFBUBWux9Kf7YcQ1LW6In9s8uh-vjliUKtDdpH5OzVs50JAeA9HTGG5gFrWy1eJqFub5puN3zIv5Pj0jji6KLwkmLFq1rKUx3KwIWOpmXhVcFRZCW-EY7iEqE/s400/Transgender_Pride_Flag.jpeg?resize=400%2C487&#038;ssl=1" data-recalc-dims="1"/></a></div>
  
     
March 31 is Transgender Day of Visibility. I’m not transgender myself, but I have friends, acquaintances, and family members who are. Chances are you do too, whether you realize it or not.   <p>
  
     
My understanding is that transgender is an umbrella term for people whose gender identity or expression differs from the sex they were assigned at birth. It reflects a deeply held internal sense of self—something not defined by appearance, clothing, or medical procedures. Being transgender is about identity, not sexual orientation.      <p>
  
     
What I’ve learned over time is that many transgender people face challenges most of us never have to think about. These include discrimination, gaps in legal protection, denial of medical care, and even physical violence. There are also everyday barriers that rarely make headlines, like difficulty obtaining accurate driver’s licenses or passports—documents most of us take for granted.      <p>
  
     
I found this resource helpful:
<a href = "https://www.hrc.org/resources/understanding-the-transgender-community">
  Understanding the Transgender Community</a> .  <p>
  
       
I wish every transgender person could live their life openly, safely, and without being hassled for who they are.      <p>
  
     
The five color Transgender Pride Flag was designed by Monica Helms in 1999. I made this flag in computer language R.  Here is the R code.<p>

########################

<pre>

library(ggplot2)

# Define the colors in order: Blue, Pink, White, Pink, Blue
trans_colors &lt;- c(&quot;#5BCEFA&quot;, &quot;#F5A9B8&quot;, &quot;#FFFFFF&quot;, &quot;#F5A9B8&quot;, &quot;#5BCEFA&quot;)

# Create a data frame for the 5 stripes
flag_data &lt;- data.frame(
  stripe = factor(1:5),
  height = rep(1, 5)
)

# Plot the flag
ggplot(flag_data, aes(x = 1, y = height, fill = stripe)) +
  geom_bar(stat = &quot;identity&quot;, width = 1, color = NA) +
  scale_fill_manual(values = rev(trans_colors)) + # Reverse to stack correctly
  theme_void() + # Remove axes and labels
  theme(legend.position = &quot;none&quot;) +
  coord_cartesian(expand = FALSE)


</pre>
End
</font>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://onlinecollegemathteacher.blogspot.com/2026/03/transgender-day-of-visibility.html"> Online College Math Teacher</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/transgender-day-of-visibility/">Transgender Day of Visibility</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400212</post-id>	</item>
		<item>
		<title>Meet dataviewR: The View() You Always Wanted</title>
		<link>https://www.r-bloggers.com/2026/03/meet-dataviewr-the-view-you-always-wanted/</link>
		
		<dc:creator><![CDATA[Siddhesh Pujari]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.html</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>Disclaimer: This blog contains opinions that are of the authors alone and do not necessarily reflect the strategy of their respective organizations.</p>
<p>The humble View() and its limits<br />
View() has served R programmers well for a long time — pass ...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/meet-dataviewr-the-view-you-always-wanted/">Meet dataviewR: The View() You Always Wanted</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.html"> pharmaverse blog</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 





<!--------------- typical setup ----------------->
<!--------------- post begins here ----------------->
<p>Disclaimer: This blog contains opinions that are of the authors alone and do not necessarily reflect the strategy of their respective organizations.</p>
<section id="the-humble-view-and-its-limits" class="level2">
<h2 class="anchored" data-anchor-id="the-humble-view-and-its-limits">The humble <code>View()</code> and its limits</h2>
<p><code>View()</code> has served R programmers well for a long time — pass it a data frame, get a spreadsheet-style window. It even has a basic search bar for checking whether a value exists in your data. But the moment you need something more precise — filter by a specific column or combine conditions — you are back in your script.</p>
<p>Add to that: no side-by-side dataset comparison, no metadata inspection, and no way to carry your exploration into reproducible code. For day-to-day clinical data work — reviewing your clinical datasets, let’s say <code>ADSL</code>, cross-checking subject demographics against lab data in <code>ADLB</code>, doing a QC pass before analysis — these gaps add up.</p>
</section>
<section id="what-is-dataviewr" class="level2">
<h2 class="anchored" data-anchor-id="what-is-dataviewr">What is dataviewR?</h2>
<p><a href="https://madhankumarnagaraji.github.io/dataviewR/" rel="nofollow" target="_blank"><code>dataviewR</code></a> is a Shiny-based interactive data viewer that works alongside <code>View()</code> as a companion — not a replacement. It launches directly in your RStudio Viewer pane, requires no Shiny code, and never modifies the datasets passed to it.</p>
<pre>install.packages(&quot;dataviewR&quot;)</pre>
</section>
<section id="features" class="level2">
<h2 class="anchored" data-anchor-id="features">Features</h2>
<p><code>dataviewR</code> offers the following capabilities:</p>
<ul>
<li><strong>Interactive Filtering</strong> — apply <code>dplyr</code>-style expressions directly in the app, no script changes needed. Supports <code>%in%</code>, <code>is.na()</code>, <code>grepl()</code>, and compound conditions — the same syntax you already write every day.</li>
</ul>
<pre>SEX == &quot;F&quot; & AGE &gt; 65 & TRT01P == &quot;Xanomeline High Dose&quot;</pre>
<ul>
<li><strong>Reproducible Code Generation</strong> — hit “Generate R Code” and walk away with ready-to-use <code>dplyr</code> code from your interactions. Your exploration session feeds directly into your scripted workflow.</li>
</ul>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://i1.wp.com/pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/dataview_codegen.png?w=578&#038;ssl=1" class="img-fluid figure-img" style="width:60.0%" data-recalc-dims="1"></p>
<figcaption>Auto-generated dplyr code from interactive filter and column selections.</figcaption>
</figure>
</div>
<ul>
<li><strong>Variable Metadata</strong> — inspect variable classes, labels and attributes without writing <code>str()</code> or <code>attr()</code> calls. Particularly useful for clinical datasets where CDISC-style labels are carried as R attributes.</li>
</ul>
<p>See all of this in action:</p>
<video width="450" controls="" playbackrate="2" onloadedmetadata="this.playbackRate = 2;">
<source src="dataview_explore.mp4" type="video/mp4">
</video>
</section>
<section id="cross-checking-multiple-datasets" class="level2">
<h2 class="anchored" data-anchor-id="cross-checking-multiple-datasets">Cross-Checking Multiple Datasets</h2>
<p>But what if you need to look at more than one dataset at the same time? <code>dataviewR</code> handles that too — pass multiple datasets in a single call and each opens in its own tab within the same session. Switch between them, filter independently, and track a specific subject across datasets — the kind of check that comes up in every safety review.</p>
<pre>library(dataviewR)
library(pharmaverseadam)

dataviewer(adsl, adlb)</pre>
<video width="450" controls="" onloadedmetadata="this.playbackRate = 1.5;">
<source src="dataview_multidata.mp4" type="video/mp4">
</video>
</section>
<section id="final-thoughts" class="level2">
<h2 class="anchored" data-anchor-id="final-thoughts">Final Thoughts</h2>
<p>That is dataviewR in a nutshell. Try it out and share your thoughts on <a href="https://github.com/madhankumarnagaraji/dataviewR" rel="nofollow" target="_blank">GitHub</a> or <a href="https://pharmaverse.slack.com/" rel="nofollow" target="_blank">pharmaverse Slack</a>!</p>
<p>Full documentation, vignettes, and clinical dataset examples are available at <a href="https://madhankumarnagaraji.github.io/dataviewR/" rel="nofollow" target="_blank">madhankumarnagaraji.github.io/dataviewR</a>.</p>
<!--------------- appendices go here ----------------->
</section>
<div class="cell">
<div class="cell-output-display">


</div>
</div>



<div id="quarto-appendix" class="default"><section id="last-updated" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Last updated</h2><div class="quarto-appendix-contents">

<p>2026-03-31 18:28:15.461796</p>
</div></section><section id="details" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Details</h2><div class="quarto-appendix-contents">

<p><a href="https://github.com/pharmaverse/blog/tree/main/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.qmd" rel="nofollow" target="_blank">Source</a>, <a href="https://pharmaverse.github.io/blog/session_info.html" rel="nofollow" target="_blank">Session info</a></p>
</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="nofollow" href="https://creativecommons.org/licenses/by/4.0/" target="_blank">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>@online{pujari2026,
  author = {Pujari, Siddhesh and Kumar N, Madhan and S, Gomathi and
    Haight, Mackenzie},
  title = {Meet {dataviewR:} {The} {View()} {You} {Always} {Wanted}},
  date = {2026-03-31},
  url = {https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.html},
  langid = {en}
}
</pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-pujari2026" class="csl-entry quarto-appendix-citeas">
Pujari, Siddhesh, Madhan Kumar N, Gomathi S, and Mackenzie Haight. 2026.
<span>“Meet dataviewR: The View() You Always Wanted.”</span> March 31,
2026. <a href="https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.html" rel="nofollow" target="_blank">https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.html</a>.
</div></div></section></div> 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/meet-dataviewr-the-view-you-always-wanted.html"> pharmaverse blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/meet-dataviewr-the-view-you-always-wanted/">Meet dataviewR: The View() You Always Wanted</a>]]></content:encoded>
					
		
		<enclosure url="https://pharmaverse.github.io/blog/posts/2026-03-29-meet-dataviewr-the/dataviewR-logo.png" length="0" type="image/png" />

		<post-id xmlns="com-wordpress:feed-additions:1">400225</post-id>	</item>
		<item>
		<title>AGENTS.md, {admiral}, and the AI-Assisted Programmer</title>
		<link>https://www.r-bloggers.com/2026/03/agents-md-admiral-and-the-ai-assisted-programmer/</link>
		
		<dc:creator><![CDATA[Jeff Dickinson]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://pharmaverse.github.io/blog/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.html</guid>

					<description><![CDATA[<p>Introduction<br />
AI coding assistants are becoming a natural part of how clinical R programmers work — autocompleting functions, suggesting test cases, drafting derivations. But out of the box, these agents know nothing about ADaM conventions, CD...</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/agents-md-admiral-and-the-ai-assisted-programmer/">AGENTS.md, {admiral}, and the AI-Assisted Programmer</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://pharmaverse.github.io/blog/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.html"> pharmaverse blog</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 





<!--------------- typical setup ----------------->
<!--------------- post begins here ----------------->
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>AI coding assistants are becoming a natural part of how clinical R programmers work — autocompleting functions, suggesting test cases, drafting derivations. But out of the box, these agents know nothing about ADaM conventions, CDISC standards, or how the pharmaverse ecosystem fits together. They don’t know that analysis flag variables such as <code>ANL01FL</code> typically take <code>&quot;Y&quot;</code> or <code>NA</code> and not <code>&quot;N&quot;</code> They don’t know that <code>{pharmaversesdtm}</code> is the canonical source of test SDTM data, or that <code>{xportr}</code> is waiting downstream to turn your dataset into a submission-ready XPT file. <code>AGENTS.md</code> is a simple, open standard that changes that — and the <code>{admiral}</code> ecosystem now has infrastructure to generate and maintain these files automatically across every package in the family.</p>
</section>
<section id="what-is-agents.md" class="level2">
<h2 class="anchored" data-anchor-id="what-is-agents.md">What Is AGENTS.md?</h2>
<p><code>AGENTS.md</code> is a plain markdown file you commit to your repository that gives AI coding agents the context they need to work correctly in your project. Think of it as a README for agents — while <code>README.md</code> tells a new developer what the project is, <code>AGENTS.md</code> tells an AI assistant how to work in it correctly.</p>
<p>The format is supported across the growing ecosystem of AI coding tools: OpenAI Codex, GitHub Copilot, Google’s Jules, Cursor, Aider, Gemini CLI, and more. One file, version-controlled alongside your code, works everywhere.</p>
</section>
<section id="why-this-matters-for-the-pharmaverse" class="level2">
<h2 class="anchored" data-anchor-id="why-this-matters-for-the-pharmaverse">Why This Matters for the pharmaverse</h2>
<p>ADaM derivations encode decades of CDISC regulatory expectations that don’t appear anywhere in the R syntax. The fact that <code>ANL01FL</code> is an analysis flag with specific derivation logic, that <code>DTYPE = &quot;LLOQ&quot;</code> imputation records follow specific rules — none of this is inferable from the code alone.</p>
<p>The <code>{admiral}</code> package also doesn’t exist in isolation. It operates in a pipeline that flows from <code>{pharmaversesdtm}</code> test data through admiral derivations, often guided by <code>{metacore}</code> specifications, and ultimately out through <code>{xportr}</code> to submission-ready XPT files. An agent writing admiral code without that context is like a new programmer who only knows the function they’re editing — not the system it belongs to.</p>
<p>An <code>AGENTS.md</code> in an admiral-family repository can communicate all of this before the agent writes a single line of code.</p>
</section>
<section id="a-first-step-in-the-pharmaverse-ai-strategy" class="level2">
<h2 class="anchored" data-anchor-id="a-first-step-in-the-pharmaverse-ai-strategy">A First Step in the pharmaverse AI Strategy</h2>
<p>The <code>{admiral}</code> team is actively discussing how to formalize its approach to AI-assisted development — what tools to encourage, what guardrails to put in place, and how to document AI’s role in the programming strategy. That conversation is still early, and deliberately so: the consensus is to gain real experience before locking in formal guidance.</p>
<p>The good news is that experience is already arriving, fast.</p>
<p><strong>March 7, 2026 — the question arrives.</strong> <a href="https://github.com/pharmaverse/admiral/pull/2996" rel="nofollow" target="_blank">PR #2996</a> landed from a new contributor, <code>maxthecat2024</code>, fixing poorly formatted warning messages in <code>derive_param_computed()</code>. The PR was thorough and well-structured — detailed before/after examples, snapshot test conversions, a fully completed checklist. It was also the kind of contribution that made the team wonder: was this an AI bot? We don’t know for certain, and ultimately it didn’t matter — the code was good and it got merged. But the question itself was telling.</p>
<p><strong>March 17, 2026 — the reality arrives.</strong> <a href="https://github.com/pharmaverse/admiral/pull/3010" rel="nofollow" target="_blank">PR #3010</a> was opened not by a human contributor, but by GitHub Copilot itself — the branch named <code>copilot/enhance-examples-derive-vars-merged-summary</code>, the author listed as <code>Copilot</code>. The PR enhanced documentation examples for <code>derive_vars_merged_summary()</code>, correctly picking up the admiral-specific <code>@examplesx</code> structured example pattern from the existing codebase — context that came directly from <code>AGENTS.md</code>.</p>
<p>But the PR also revealed an important limitation. Rather than running <code>devtools::document()</code> to regenerate the <code>.Rd</code> file, Copilot manually edited <code>man/derive_vars_merged_summary.Rd</code> directly — and its own PR description acknowledged this: <em>“Manually updated to match <code>roxygen2::roxygenize()</code> output.”</em> When a reviewer pointed this out, Copilot responded candidly: <em>“R is not available in my sandbox environment, so I can’t execute <code>devtools::document()</code> directly. For future sessions, I understand the correct workflow.”</em> A human reviewer ran <code>devtools::document()</code> outside the sandbox and pushed the correctly generated <code>.Rd</code> file in commit <code>c855860</code>.</p>
<p>This is an important nuance: the issue wasn’t that <code>AGENTS.md</code> was unclear — it was that Copilot’s execution environment simply didn’t have R available. No instruction, however well-written, can make an agent run a command it physically cannot execute. <code>AGENTS.md</code> can teach an agent the correct workflow; ensuring the environment supports that workflow is a separate, human-owned responsibility. That distinction matters as the community develops its AI strategy.</p>
<p>This two-week window tells the whole story. AI-assisted contributions are already arriving in the <code>{admiral}</code> repository. <code>AGENTS.md</code> is already helping agents understand project-specific conventions. And the gaps it exposes are already informing improvements. This is the feedback loop the community needs to build a thoughtful AI strategy — not speculation, but evidence.</p>
<p><code>AGENTS.md</code> represents the first tangible infrastructure to come out of that thinking. Whether a contributor is a human using an AI assistant, an autonomous agent, or something in between — the code still needs to follow ADaM conventions and pharmaverse standards. <code>AGENTS.md</code> helps ensure it does.</p>
<p>If you have thoughts on what the broader strategy should look like, the discussion is open — join the conversation at <a href="https://github.com/pharmaverse/admiraldev/issues/547" rel="nofollow" target="_blank">admiraldev issue #547</a>. The broader scientific open-source community is working through similar questions: rOpenSci recently published an <a href="https://ropensci.org/blog/2026/02/26/ropensci-ai-policy/" rel="nofollow" target="_blank">AI policy</a> that’s worth reading as a reference point for how these norms are taking shape. Notably, rOpenSci’s policy calls out <code>agents.md</code> directly in its software review submission template:</p>
<blockquote class="blockquote">
<p>“If your repository includes an ‘agents.md’ file or equivalent, please provide a link, and describe how this has been used in the development of your package.”</p>
</blockquote>
<p>That the broader open-source scientific community is already asking for <code>AGENTS.md</code> as part of peer review is a signal that this norm is catching on fast.</p>
</section>
<section id="the-admiral-ecosystem-implementation" class="level2">
<h2 class="anchored" data-anchor-id="the-admiral-ecosystem-implementation">The Admiral Ecosystem Implementation</h2>
<p>Rather than each package maintaining its own file by hand, the generation logic is centralized in <code>{admiralci}</code> and delivers a consistent, up-to-date file to every package that opts in. The workflow pulls together content from several sources:</p>
<ul>
<li><strong>Programming strategy and unit testing guidelines</strong> from <code>{admiraldev}</code></li>
<li><strong>Package-specific context</strong> from a YAML file in each repository (therapeutic area, related packages, relevant CDISC IGs)</li>
<li><strong>Ecosystem context</strong> describing how admiral-family packages fit into the broader pharmaverse pipeline</li>
<li><strong>ADaM fundamentals</strong> covering key variable conventions and controlled terminology patterns</li>
</ul>
<p>The <code>{admiral}</code> <code>AGENTS.md</code> is substantial — over 1,300 lines of auto-generated context pulled directly from the <code>{admiraldev}</code> programming strategy, git usage, and R CMD check vignettes. It even includes a built-in verification mechanism: agents are instructed to add the comment <code># admiral guidelines loaded</code> to the first line of every new R file they create, confirming the guidelines were actually read. It’s a small but clever way to make agent compliance observable during code review.</p>
<p>Here’s a simplified illustration of the kind of content the file contains:</p>
<pre># AGENTS.md — admiral

## Package Overview
{admiral} provides a toolbox for ADaM dataset construction in R,
following CDISC ADaM standards and pharmaverse conventions.

## ADaM Conventions
- Flag variables (ANL01FL, SAFFL, etc.) take values &quot;Y&quot; or NA
- PARAM/PARAMCD pairs must align with CDISC controlled terminology
- ASEQ must be derived as the last step before dataset finalization

## Ecosystem Context
- Test SDTM data: use {pharmaversesdtm} (CDISC pilot data)
- Downstream: datasets consumed by {xportr} for XPT transport files
- Metadata: {metacore}/{metatools} provide spec-driven variable control

## Unit Testing
- Use {testthat} with expect_dfs_equal() for dataset comparisons
- Every new function requires tests for typical use, edge cases, and errors

## Documentation
- Run devtools::document() to regenerate .Rd files — never edit man/ directly
- Update NEWS.md for any user-facing function changes</pre>
<p>One practical note: <code>AGENTS.md</code> at the repository root triggers a NOTE in R CMD check, so the file is added to <code>.Rbuildignore</code>. It also lives in <code>tests/testthat/</code> where testing-specific guidance is scoped closest to where it’s needed. Extension packages like <code>{admiralonco}</code>, <code>{admiralvaccine}</code>, and <code>{admiralpeds}</code> can layer their own context on top, adding therapeutic area-specific conventions without duplicating shared infrastructure content.</p>
</section>
<section id="how-to-adopt-this-in-your-package" class="level2">
<h2 class="anchored" data-anchor-id="how-to-adopt-this-in-your-package">How to Adopt This in Your Package</h2>
<p>If you maintain an admiral-family package, adoption is three steps:</p>
<ol type="1">
<li>Add a YAML configuration file to your repository with package-specific context (therapeutic area, related packages, relevant CDISC IGs)</li>
<li>Reference the reusable workflow from <code>{admiralci}</code> in your <code>.github/workflows/</code> directory</li>
<li>Add <code>^AGENTS\.md$</code> to your <code>.Rbuildignore</code></li>
</ol>
<p>The workflow then runs on a schedule, pulling the latest content from <code>{admiraldev}</code> and your package YAML and committing an updated <code>AGENTS.md</code> automatically.</p>
</section>
<section id="resources" class="level2">
<h2 class="anchored" data-anchor-id="resources">Resources</h2>
<ul>
<li><code>AGENTS.md</code> standard: <a href="https://agents.md/" class="uri" rel="nofollow" target="_blank">https://agents.md</a></li>
<li><code>{admiral}</code> <code>AGENTS.md</code> (live): <a href="https://github.com/pharmaverse/admiral/blob/main/AGENTS.md" class="uri" rel="nofollow" target="_blank">https://github.com/pharmaverse/admiral/blob/main/AGENTS.md</a></li>
<li><code>{admiral}</code> <code>sync-admiralci-agents</code> workflow (live): <a href="https://github.com/pharmaverse/admiral/blob/main/.github/workflows/sync-admiralci-agents.yml" class="uri" rel="nofollow" target="_blank">https://github.com/pharmaverse/admiral/blob/main/.github/workflows/sync-admiralci-agents.yml</a></li>
<li>pharmaverse AI strategy discussion: <a href="https://github.com/pharmaverse/admiraldev/issues/547" class="uri" rel="nofollow" target="_blank">https://github.com/pharmaverse/admiraldev/issues/547</a></li>
<li>pharmaverse examples site: <a href="https://pharmaverse.github.io/examples/" class="uri" rel="nofollow" target="_blank">https://pharmaverse.github.io/examples/</a></li>
<li>rOpenSci AI policy: <a href="https://ropensci.org/blog/2026/02/26/ropensci-ai-policy/" class="uri" rel="nofollow" target="_blank">https://ropensci.org/blog/2026/02/26/ropensci-ai-policy/</a></li>
</ul>
<!--------------- appendices go here ----------------->
</section>
<div class="cell">
<div class="cell-output-display">


</div>
</div>



<div id="quarto-appendix" class="default"><section id="last-updated" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Last updated</h2><div class="quarto-appendix-contents">

<p>2026-03-30 18:40:51.936093</p>
</div></section><section id="details" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Details</h2><div class="quarto-appendix-contents">

<p><a href="https://github.com/pharmaverse/blog/tree/main/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.qmd" rel="nofollow" target="_blank">Source</a>, <a href="https://pharmaverse.github.io/blog/session_info.html" rel="nofollow" target="_blank">Session info</a></p>
</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="nofollow" href="https://creativecommons.org/licenses/by/4.0/" target="_blank">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>@online{dickinson2026,
  author = {Dickinson, Jeff},
  title = {AGENTS.md, \{Admiral\}, and the {AI-Assisted} {Programmer}},
  date = {2026-03-31},
  url = {https://pharmaverse.github.io/blog/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.html},
  langid = {en}
}
</pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-dickinson2026" class="csl-entry quarto-appendix-citeas">
Dickinson, Jeff. 2026. <span>“AGENTS.md, {Admiral}, and the AI-Assisted
Programmer.”</span> March 31, 2026. <a href="https://pharmaverse.github.io/blog/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.html" rel="nofollow" target="_blank">https://pharmaverse.github.io/blog/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.html</a>.
</div></div></section></div> 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://pharmaverse.github.io/blog/posts/2026-03-31-agents-md-admiral-a/agents-md-admiral-and-the-ai-assisted-programmer.html"> pharmaverse blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/agents-md-admiral-and-the-ai-assisted-programmer/">AGENTS.md, {admiral}, and the AI-Assisted Programmer</a>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">400187</post-id>	</item>
		<item>
		<title>UK monarchs’ longevity against their people: a demographically correct reanalysis</title>
		<link>https://www.r-bloggers.com/2026/03/uk-monarchs-longevity-against-their-people-a-demographically-correct-reanalysis/</link>
		
		<dc:creator><![CDATA[Ilya Kashnitsky]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 22:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://ikashnitsky.phd/2026/royal-longevity/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>NoteEnd of March is the time when I remember with warm nostalgia the vivid memories of working alongside and learning from Jim Vaupel, who died untimely on 27th March 2022. He was a brilliant demographer and a vital person who radiated lov...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/uk-monarchs-longevity-against-their-people-a-demographically-correct-reanalysis/">UK monarchs’ longevity against their people: a demographically correct reanalysis</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://ikashnitsky.phd/2026/royal-longevity/"> Ilya Kashnitsky</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
 





<script src="https://cdn.counter.dev/script.js" data-id="daa70324-89c3-4b1c-8ea0-3588f29f41f5" data-utcoffset="1"></script><div class="callout callout-style-default callout-note callout-empty-content 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">Note</span>End of March is the time when I remember with warm nostalgia the vivid memories of working alongside and learning from Jim Vaupel, who died untimely on 27th March 2022. He was a brilliant demographer and a vital person who radiated love to demography and influenced generations of researchers in finding and shaping their academic paths. Please read more about Jim on our collective memorial webpage – <a href="https://remembering-james-vaupel.org/" class="uri" rel="nofollow" target="_blank">https://remembering-james-vaupel.org</a> <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f49a.png" alt="💚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> In this post, I’m revisiting one of the last projects that we worked on with Jim. Unlike all other posts in my blog, here I’m using plural voice since an earlier draft of the analysis was co-authored with Jim.
</div>
</div>
<div class="callout-body-container callout-body">

</div>
</div>
<section id="resonant-headlines-in-the-context-of-global-news" class="level1">
<h1>Resonant headlines in the context of global news</h1>
<p>Following the death of Prince Philip in April 2021, <em>The Conversation</em> published a <a href="https://theconversation.com/long-live-the-monarchy-british-royals-tend-to-survive-a-full-three-decades-longer-than-their-subjects-158766" rel="nofollow" target="_blank">piece by Jay Olshansky</a> titled <em>“Long live the monarchy! British royals tend to survive a full three decades longer than their subjects.”</em> In this, essentially, blog post routinely perceived by the media almost as a peer-reviewed article – the usual problem with The Conversation – the author compared the longevity of last six UK monarchs and their spouses with the longevity of their subjects. Employing a deeply flawed analysis, Olshansky arrived at sensational conclusions, which were, of course, elevated to the title of the piece and to the title of the only figure from the analysis, which <a href="https://www.altmetric.com/details/103817538" rel="nofollow" target="_blank">circulated widely in the media</a>.</p>
<p><img src="https://i1.wp.com/ikashnitsky.phd/2026/royal-longevity/olshansky-plot.jpg?w=578&#038;ssl=1" class="img-fluid" style="width:80.0%" data-recalc-dims="1"></p>
<p>Drawing far-reaching conclusions based on a handful of individuals’ lifespans is already very problematic, since longevity of humans fluctuates a lot by chance. Yet, apart from this obvious statistical limitation, there are at least two purely demographic methodological flaws in the analysis that make the conclusions completely wrong. Olshansky compared the lifespan of a UK monarch or spouse with the <strong>period life expectancy</strong> that prevailed in the <strong>year of their birth</strong>. This is demographically wrong, for at least two reasons.</p>
</section>
<section id="flawed-design-of-the-analysis" class="level1 page-columns page-full">
<h1>Flawed design of the analysis</h1>
<p><strong>Firstly</strong>, period life expectancy for a certain year is a poor predictor of the future lifespan of a child born in the year. <sup>1</sup> Despite the seemingly straightforward name, period life expectancy is <strong>not</strong> designed to forecast longevity, despite this being a way too often misinterpretation of the indicator. It is just a summary measure of current age-specific death rates in a population. In other words, life expectancy gives the average length of life for a cohort of newborns only in the unlikely (i.e. not registered in the observed human history) case when death rates remain unchanged throughout their lives. Mortality, however, has <a href="https://doi.org/10.1073/pnas.2019536118" rel="nofollow" target="_blank">decreased substantially</a> over the past two centuries in all countries, including the UK, and the actual longevity of people born in a specific year is usually <a href="https://doi.org/10.1080/00324720600895876" rel="nofollow" target="_blank">much higher</a> than the period life expectancy that was observed when they were born.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup> Have a look at my <a href="https://ikashnitsky.github.io/2021/what-is-life-expectancy/" rel="nofollow" target="_blank">previous post</a> about common misinterpretations of life expectancy.</p></div></div><p>Why is this error so important? Because life expectancy at birth in historical populations was massively skewed by staggering infant and child mortality rates. When we hear that medieval peasants had a life expectancy of 35, it wasn’t because a hard life in the fields meant dropping dead at 36; it was because a huge fraction of the population died of disease during childhood. A peasant who reached adulthood actually had pretty good odds of reaching 60. And this leads us to the <strong>second</strong> massive flaw in the design of the initial analysis.</p>
<p>A monarch, by definition, has already survived childhood to reach the age of their coronation. It makes little sense to compare the actual fulfilled lifespans of royal individuals who succeeded to become monarchs with life expectancy <strong>at birth</strong> in the year of their birth. What about all their siblings who were less lucky? <sup>2</sup> One simply cannot evaluate historical longevity without properly accounting for survival bias. It’s all about selection and the luck of surviving through the hazardous early years of life. Back in the days, infant, child and early-adult mortality <a href="https://ourworldindata.org/child-mortality-in-the-past" rel="nofollow" target="_blank">used to be so high</a> that it’s hard for us to imagine how society functioned when half of the lifeborn kids don’t reach teenage. For the purpose of this reanalysis, we need to factor in the – too obvious when you spell it out – truth: only those royalty who survived to the date of their coronation became monarchs. <sup>3</sup></p>
<div class="no-row-height column-margin column-container"><div id="fn2"><p><sup>2</sup> In data analysis this common fallacy is known as <a href="https://xkcd.com/1827" rel="nofollow" target="_blank"><em>survivorship bias</em></a>.</p></div><div id="fn3"><p><sup>3</sup> Interestingly, the age of UK monarchs’ coronation varied widely, from 9 years for Queen Victoria to 59 years for King Edward VII.</p></div></div></section>
<section id="a-demographically-correct-approach" class="level1 page-columns page-full">
<h1>A demographically correct approach</h1>
<p>So, what should a proper comparison look like if we still want to evaluate whether royals lived exceptionally long compared to their subjects? The methodological corrections are straightforward: 1) Instead of period life tables we should look at cohort life tables (also obtained from the <a href="https://www.mortality.org/" rel="nofollow" target="_blank">Human Mortality Database</a>); 2) As the comparison population, we need to look at the people who were born at the same year as the monarch in question and who survived at least until the age when this monarch was crowned. We compare monarch’s lifespan against the <strong>remaining cohort life expectancy</strong> of their birth cohort <em>at the exact age of the monarch’s coronation</em>. Correcting for these two errors, we obtained the demographically correct results below. <sup>4</sup></p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup> Let me re-iterate, just in case: we do not claim that this is a good way of researching the royal premium in survival. Our aim here is to correct the fundamental demographic flaws in the original widely circulated piece.</p></div></div><p><img src="https://i1.wp.com/ikashnitsky.phd/2026/royal-longevity/royal-survival.png?w=578&#038;ssl=1" class="img-fluid" data-recalc-dims="1"></p>
<p>The results? Yes, royals still enjoy a survival advantage over the general population. This is hardly a surprise – living in extreme privilege gives you access to the best diet, living environments, and medical care of your era. But the sensational headline from Olshansky’s piece no longer holds. Instead of the claimed 30 year advantage, we see a more modest 7.7 years of extra survival, on average across the 12 monarchs and their spouses.</p>
<p>And let’s highlight again that even this largely corrected figure does not convincingly claim that the royals live much longer than their subjects. We are still comparing a summary of 12 individual lifespans against population-level demographic averages. Human lifespans vary. <sup>5</sup></p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup> In a <a href="http://doi.org/10.4054/DemRes.2021.44.35" rel="nofollow" target="_blank">recent article</a> we introduced a new outsurvival measure to study differences in longevity between populations, taking into account lifespan inequality.</p></div></div><p>The longevity premium for royalty depends on the age of coronation – the younger the monarch begins to reign, the fewer of those born in his or her year of birth are dead. Thus, the biggest differences in longevity are for those monarchs who stepped in very young, such as Queen Victoria or Queen Elizabeth II. When Queen Elizabeth II was crowned at age 25, 88% of her birth cohort was still alive. In comparison, when King Edward VII was crowned at age 59, only 37% of his birth cohort was alive.</p>
<p>Another way to frame the comparison is to calculate the percentage of monarch’s birth cohort who were alive at the monarch’s coronation and who were subsequently outlived by this monarch. This is a sort of p-score for the monarch’s longevity – how “well” did he or she “perform” compared correctly with their birth cohort.</p>
<p><img src="https://i0.wp.com/ikashnitsky.phd/2026/royal-longevity/royal-survival-relative.png?w=578&#038;ssl=1" class="img-fluid" data-recalc-dims="1"></p>
<p>King Edward VII outlived only 30% of males his age alive at his coronation: 70% of his peers alive at his crowning were alive at his funeral. Prince Philip outlived 99.5% of those UK males born in 1921 who lived at least until 1952.</p>
</section>
<section id="bonus" class="level1">
<h1>Bonus</h1>
<p>For the dedicated readers we offer a third plot in which we combined all the data discussed in the text in one figure. We realise it may be slightly challenging to process, but we also believe it provides a unique opportunity to see the whole data-story “at a glance”.</p>
<p><img src="https://i2.wp.com/ikashnitsky.phd/2026/royal-longevity/royal-survival-combined.png?w=578&#038;ssl=1" class="preview-image img-fluid" data-recalc-dims="1"></p>
<p><em>In the plot</em>: The colored stripes start at the age of the monarch’s coronation, they fade out as the remaining birth cohort dies out; the average survival of the reference cohorts is marked with white vertical ticks; survival to the coronation is annotated in red labels.</p>
<hr>
<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>Replication
</div>
</div>
<div class="callout-body-container callout-body">
<p>You can find the data and the <code>R</code> code to reproduce this re-analysis in <a href="https://gist.github.com/ikashnitsky/bec6af5ac0d57129a406ee5b5a522ce2" rel="nofollow" target="_blank">this GitHub gist</a>. The post is based on my earlier <a href="https://x.com/ikashnitsky/status/1382595760756244481" rel="nofollow" target="_blank">Twitter thread</a>.</p>
</div>
</div>


<!-- -->

</section>


 
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://ikashnitsky.phd/2026/royal-longevity/"> Ilya Kashnitsky</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/uk-monarchs-longevity-against-their-people-a-demographically-correct-reanalysis/">UK monarchs’ longevity against their people: a demographically correct reanalysis</a>]]></content:encoded>
					
		
		<enclosure url="https://ikashnitsky.phd/2026/royal-longevity/teaser.jpg" length="0" type="image/jpeg" />

		<post-id xmlns="com-wordpress:feed-additions:1">400222</post-id>	</item>
		<item>
		<title>Same model, better shape: why centering improves MCMC</title>
		<link>https://www.r-bloggers.com/2026/03/same-model-better-shape-why-centering-improves-mcmc/</link>
		
		<dc:creator><![CDATA[ouR data generation]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> The Emergency departments leading the transformation of Alzheimer’s and dementia care (ED-LEAD) study, which I have written about in the past, is approaching the end of its third year. This multifactorial design evaluates three independent, yet potenti...</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/same-model-better-shape-why-centering-improves-mcmc/">Same model, better shape: why centering improves MCMC</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/"> ouR data generation</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p>The <em>Emergency departments leading the transformation of Alzheimer’s and dementia care</em> (ED-LEAD) study, which I have written about in the <a href="https://www.rdatagen.net/post/2024-02-20-ensuring-balance-with-a-cluster-randomized-factorial-design/" rel="nofollow" target="_blank">past</a>, is approaching the end of its third year. This multifactorial design evaluates three independent, yet potentially synergistic, interventions aimed at improving care for persons living with dementia (PLWD) and their caregivers.</p>
<p>To estimate intervention effects, we are using what I’ve <a href="https://onlinelibrary.wiley.com/doi/full/10.1002/sim.70264" rel="nofollow" target="_blank">called</a> the <em>HEx-factor model</em>, a Bayesian hierarchical exchangeable factorial model. The original plan was to conduct all analyses using <a href="https://mc-stan.org/" rel="nofollow" target="_blank"><code>Stan</code></a>. However, we’ve run into a bit of a snafu. I’ve been working through the problem, and thought I’d share here.</p>




<p>The challenge turns out to be a computational one. Because the <em>ED-LEAD</em> analyses must be conducted on National Institute on Aging (NIA) Data LINKAGE servers, we are working in a somewhat restricted software environment, at least with respect to Bayesian data analysis. In particular, we have not been able to install or run <code>Stan</code>, which was our analytic engine of choice. This forced us to consider alternatives, and we turned to <code>JAGS</code>, which <em>is</em> available in the Linkage environment and certainly is well-suited for Bayesian hierarchical modeling.</p>
<p>At first glance, this might seem like a straightforward substitution. Both <code>Stan</code> and <code>JAGS</code> allow us to specify the same likelihood and priors. However, I quickly noticed that the models were not performing as well in <code>JAGS</code> as they had in <code>Stan</code>. It turns out that the samplers used in <code>JAGS</code> are more sensitive to posterior dependence than the Hamiltonian Monte Carlo (HMC) methods implemented in <code>Stan</code>.</p>
<p>I set out to understand and fix the problem, and found that a simple reparameterization—re-coding the binary treatment indicators—made a substantial difference. With this change, the <code>JAGS</code> sampler was able to explore the posterior distribution much more efficiently, yielding results comparable to those obtained with <code>Stan</code>.</p>
<p>To understand why this happens, I ran a series of simple simulations comparing the original and reparameterized versions of a basic two-way factorial model. That is what I present here.</p>
<div id="the-setup" class="section level3">
<h3>The setup</h3>
<p>In models with binary predictors and interactions, it turns out that <em>centering</em> can have a surprisingly large impact on computation, even though it does not change the underlying model. To see this clearly, I’ll start with a simple two-factor logistic model:
<span class="math display">\[
\text{logit}\big[P(Y=1)\big] = \alpha+ \beta_a A + \beta_b B + \beta_{ab}AB
\]</span>
where <span class="math inline">\(A\)</span> and <span class="math inline">\(B\)</span> are binary treatment indicators. I’ll compare this to the algebraically equivalent centered version:
<span class="math display">\[
\text{logit}\big[P(Y=1)\big] = \alpha^*+ \gamma_a A^* + \gamma_b B^* + \gamma_{ab}A^*B^*
\]</span>
where</p>
<p><span class="math display">\[
A^* = A &#8211; 0.5, \ \ \ B^* = B &#8211; 0.5.
\]</span></p>
<p>The scientific model is unchanged. The question is whether the sampler behaves differently.</p>
<div id="log-odds-ratios-under-each-parameterization" class="section level4">
<h4>Log odds ratios under each parameterization</h4>
<p>With 0/1 coding, the log-odds ratio for <span class="math inline">\(A\)</span> alone (that is, when <span class="math inline">\(B=0\)</span>) is simply
<span class="math display">\[
\begin{align*}
\text{lOR}_a(B=0) &#038;= (\alpha + \beta_a \cdot 1 + \beta_b \cdot 0 + \beta_{ab} \cdot 0) -(\alpha + \beta_a \cdot 0 + \beta_b \cdot 0 + \beta_{ab} \cdot 0) \\
&#038; = \beta_a
\end{align*}
\]</span>
Analogously, the log-odds ratio for <span class="math inline">\(B\)</span> alone is <span class="math inline">\(\beta_b\)</span>. And if we want to compare the combination of both <span class="math inline">\(A=1\)</span> and <span class="math inline">\(B=1\)</span> to the case where neither is activated, then
<span class="math display">\[
\begin{align*}
\text{lOR}_{ab} &#038;= (\alpha + \beta_a \cdot 1 + \beta_b \cdot 1 + \beta_{ab} \cdot 1) \\
&#038;\quad &#8211;
(\alpha + \beta_a \cdot 0 + \beta_b \cdot 0 + \beta_{ab} \cdot 0) \\
&#038;= \beta_a + \beta_b + \beta_{ab}
\end{align*}
\]</span>
If instead we center the predictors, defining <span class="math inline">\(A^* = A &#8211; 0.5\)</span> and <span class="math inline">\(B^* = B &#8211; 0.5\)</span>, then the log-odds ratio of exposure to <span class="math inline">\(A\)</span> without exposure to <span class="math inline">\(B\)</span> relative to exposure to neither is
<span class="math display">\[
\begin{align*}
\text{lOR}_a(B=0)
&#038;=
(\alpha^* + \gamma_a(0.5) + \gamma_b(-0.5) + \gamma_{ab}(0.5)(-0.5)) \\
&#038;\quad &#8211;
(\alpha^* + \gamma_a(-0.5) + \gamma_b(-0.5) + \gamma_{ab}(-0.5)(-0.5)) \\
&#038;=
(\alpha^* + 0.5\gamma_a &#8211; 0.5\gamma_b &#8211; 0.25\gamma_{ab}) \\
&#038;\quad &#8211;
(\alpha^* &#8211; 0.5\gamma_a &#8211; 0.5\gamma_b + 0.25\gamma_{ab}) \\
&#038;=
\gamma_a &#8211; 0.5\gamma_{ab}.
\end{align*}
\]</span>
Using the same logic we can show that
<span class="math display">\[
\text{lOR}_{b} = \gamma_{b} &#8211; 0.5 \gamma_{ab}
\]</span>
and
<span class="math display">\[
\text{lOR}_{ab} = \gamma_a + \gamma_b.
\]</span>
<!-- $$ -->
<!-- \begin{align*} -->
<!-- \text{lOR}_{ab} &= (\alpha^* + \gamma_a(0.5) + \gamma_b(0.5) + \gamma_{ab}(0.5) (0.5)) -  (\alpha^* + \gamma_a(-0.5) + \gamma_b(-0.5) + \gamma_{ab}(-0.5)(-0.5))\\ -->
<!--  &= (\alpha^* + \gamma_a * 0.5 + \gamma_b * 0.5 + \gamma_{ab} * 0.25) -  (\alpha^* - \gamma_a * 0.5 - \gamma_b * 0.5 + \gamma_{ab} * 0.25)\\ -->
<!-- & = \gamma_a + \gamma_b -->
<!-- \end{align*} -->
<!-- $$ --></p>
</div>
</div>
<div id="bayesian-models-using-jags" class="section level3">
<h3>Bayesian models using JAGS</h3>
<p>The Bayesian model is a simple logistic regression with an interaction term:</p>
<p><span class="math display">\[
\begin{align*}
Y_i &#038;\sim \text{Bernoulli}(p_i), \\
\text{logit}(p_i)
&#038;= \alpha + \beta_a A_i + \beta_b B_i + \beta_{ab} A_i B_i,
\end{align*}
\]</span>
Here are the prior distribution assumptions, using variance-based notation to align with JAGS, which parameterizes normal distributions in terms of precision
<span class="math display">\[
\begin{align*}
\alpha &#038;\sim \mathcal{N}(0, 0.25^{-1}), \\
\beta_a &#038;\sim \mathcal{N}(0, 0.25^{-1}), \\
\beta_b &#038;\sim \mathcal{N}(0, 0.25^{-1}), \\
\beta_{ab} &#038;\sim \mathcal{N}(0, 25^{-1}).
\end{align*}
\]</span>
The centered model is similar, except that we replace the coefficients with <span class="math inline">\(\alpha^*\)</span> as well as <span class="math inline">\(\gamma_a\)</span>, <span class="math inline">\(\gamma_b\)</span>, <span class="math inline">\(\gamma_{ab}\)</span>, and define the predictors in terms of centered versions of <span class="math inline">\(A\)</span> and <span class="math inline">\(B\)</span>.</p>
</div>
<div id="simulations" class="section level3">
<h3>Simulations</h3>
<p>Before we get started on the simulations, we need to load the necessary libraries and set the seed in case you want to replicate these results:</p>
<pre>library(simstudy)
library(data.table)
library(ggplot2)
library(rjags)
library(coda)
library(posterior)
library(broom)
library(gt)

RNGkind(&quot;Mersenne-Twister&quot;, &quot;Inversion&quot;, &quot;Rejection&quot;)
set.seed(824)</pre>
<div id="creating-a-single-data-set" class="section level4">
<h4>Creating a single data set</h4>
<p>Here is the data generation process for a single data set. The outcome <span class="math inline">\(Y\)</span> is generated using the binary parameterization of <span class="math inline">\(A\)</span> and <span class="math inline">\(B\)</span>:</p>
<pre>s_gen &lt;- function(n = 2000,
                    alpha = -0.8,
                    beta_a = 0.5,
                    beta_b = 0.9,
                    beta_ab = -0.3) {
  
  def &lt;- 
    defData(varname = &quot;A&quot;, formula = 0.5, dist = &quot;binary&quot;) |&gt;
    defData(varname = &quot;B&quot;, formula = 0.5, dist = &quot;binary&quot;) |&gt;
    defData(varname = &quot;AB&quot;, formula = &quot;A*B&quot;, dist = &quot;nonrandom&quot;) |&gt;
    defData(varname = &quot;A_c&quot;, formula = &quot;A - 0.5&quot;, dist = &quot;nonrandom&quot;) |&gt;
    defData(varname = &quot;B_c&quot;, formula = &quot;B - 0.5&quot;, dist = &quot;nonrandom&quot;) |&gt;
    defData(varname = &quot;AB_c&quot;, formula = &quot;A_c * B_c&quot;, dist = &quot;nonrandom&quot;) |&gt;
    defData(
      varname = &quot;Y&quot;, 
      formula = &quot;..alpha + ..beta_a * A + ..beta_b * B + ..beta_ab * AB&quot;,
      dist = &quot;binary&quot;, link = &quot;logit&quot;
    )
    
  genData(n, def)
  
}

dd &lt;- s_gen()</pre>
</div>
<div id="the-two-parameterizations-fit-the-same-model" class="section level4">
<h4>The two parameterizations fit the same model</h4>
<p>First, here is the frequentist check of both models. The fitted probabilities are identical, even though the coefficients differ.</p>
<pre>fit_01 &lt;- glm(Y ~ A * B, data = dd, family = binomial)
fit_c  &lt;- glm(Y ~ A_c * B_c, data = dd, family = binomial)

tidy(fit_01)
## # A tibble: 4 × 5
##   term        estimate std.error statistic  p.value
##   &lt;chr&gt;          &lt;dbl&gt;     &lt;dbl&gt;     &lt;dbl&gt;    &lt;dbl&gt;
## 1 (Intercept)   -1.03     0.0995    -10.4  3.90e-25
## 2 A              0.835    0.135       6.18 6.34e-10
## 3 B              1.14     0.134       8.46 2.73e-17
## 4 A:B           -0.670    0.186      -3.61 3.11e- 4
tidy(fit_c)
## # A tibble: 4 × 5
##   term        estimate std.error statistic  p.value
##   &lt;chr&gt;          &lt;dbl&gt;     &lt;dbl&gt;     &lt;dbl&gt;    &lt;dbl&gt;
## 1 (Intercept)   -0.212    0.0464     -4.57 4.91e- 6
## 2 A_c            0.501    0.0929      5.39 7.05e- 8
## 3 B_c            0.802    0.0929      8.63 6.07e-18
## 4 A_c:B_c       -0.670    0.186      -3.61 3.11e- 4</pre>
<p>From the 0/1-coded model, <span class="math inline">\(\text{lOR}_a = 0.835\)</span>, <span class="math inline">\(\text{lOR}_b = 1.14\)</span>, and <span class="math inline">\(\text{lOR}_{ab} = 0.835 + 1.14 - 0.67 = 1.305.\)</span></p>
<p>From the centered model,
<span class="math display">\[
\text{lOR}_a = 0.501 + 0.5*0.670 = 0.836
\]</span>
<span class="math display">\[
\text{lOR}_b = 0.802 + 0.5*0.670 = 1.137
\]</span>
<span class="math display">\[
\text{lOR}_{ab} = 0.501 + 0.802 = 1.303
\]</span>
So the coefficients themselves change under centering, but the underlying treatment contrasts do not.</p>
</div>
<div id="specifying-the-bayesian-models-in-jags" class="section level4">
<h4>Specifying the Bayesian models in JAGS</h4>
<p>Now we see that we can recover the same treatment contrasts using two different Bayesian models, though computational performance will be improved with centering.</p>
<p>Here is the JAGS code for each model:</p>
<pre>model_01 &lt;- &quot;
model {
  for (i in 1:N) {
    Y[i] ~ dbern(p[i])
    logit(p[i]) &lt;- alpha + beta_a * A[i] + beta_b * B[i] + beta_ab * AB[i]
  }
  
  alpha   ~ dnorm(0, 0.25)
  beta_a  ~ dnorm(0, 0.25)
  beta_b  ~ dnorm(0, 0.25)
  beta_ab ~ dnorm(0, 25)
}
&quot;

model_c &lt;- &quot;
model {
  for (i in 1:N) {
    Y[i] ~ dbern(p[i])
    logit(p[i]) &lt;- alpha + gamma_a * A_c[i] + gamma_b * B_c[i] + gamma_ab * AB_c[i]
  }
  
  alpha   ~ dnorm(0, 0.25)
  gamma_a  ~ dnorm(0, 0.25)
  gamma_b  ~ dnorm(0, 0.25)
  gamma_ab ~ dnorm(0, 25)
}
&quot;</pre>
</div>
<div id="fitting-the-models" class="section level4">
<h4>Fitting the models</h4>
<p>The function <code>fit_jags</code> fits one of the two models just described:</p>
<pre>fit_jags &lt;- function(dat, model_string, centered = FALSE,
                     n_chains = 3, burn = 2000, n_iter = 5000) {
  
  # jdat &lt;- as.list(dat[, .(Y, A, B, AB, A_c, B_c, AB_c)])
  if (centered) {
    jdat &lt;- as.list(dat[, .(Y, A_c, B_c, AB_c)])
    vars &lt;- c(&quot;alpha&quot;, &quot;gamma_a&quot;, &quot;gamma_b&quot;, &quot;gamma_ab&quot;)
  } else {
    jdat &lt;- as.list(dat[, .(Y, A, B, AB)])
    vars &lt;- c(&quot;alpha&quot;, &quot;beta_a&quot;, &quot;beta_b&quot;, &quot;beta_ab&quot;)
  }
  jdat$N &lt;- nrow(dat)
  
  mod &lt;- jags.model(
    textConnection(model_string),
    data = jdat,
    n.chains = n_chains,
    quiet = TRUE
  )
  
  update(mod, burn, progress.bar = &quot;none&quot;)
  
  samp &lt;- coda.samples(
    mod,
    variable.names = vars,
    n.iter = n_iter,
    progress.bar = &quot;none&quot;
  )
  
  samp
}</pre>
<p>Now, we can fit the models, collect the diagnostic data, and take a look at the results:</p>
<pre>samp_01 &lt;- fit_jags(dd, model_01, centered = FALSE)
samp_c  &lt;- fit_jags(dd, model_c, centered = TRUE)

diag_tbl &lt;- function(samp, model_name) {
  post &lt;- as_draws_df(samp)
  summ &lt;- summarise_draws(post)
  out &lt;- as.data.table(summ)
  out[, model := model_name]
  out[]
}

diag_01 &lt;- diag_tbl(samp_01, &quot;0/1-coded&quot;)
diag_c  &lt;- diag_tbl(samp_c, &quot;centered&quot;)</pre>
<p>Here are the summary statistics of the posterior distribution as well as the computational diagnostics:</p>
<div id="bxfxwqtyqe" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#bxfxwqtyqe table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#bxfxwqtyqe thead, #bxfxwqtyqe tbody, #bxfxwqtyqe tfoot, #bxfxwqtyqe tr, #bxfxwqtyqe td, #bxfxwqtyqe th {
  border-style: none;
}

#bxfxwqtyqe p {
  margin: 0;
  padding: 0;
}

#bxfxwqtyqe .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 15px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: auto;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#bxfxwqtyqe .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#bxfxwqtyqe .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#bxfxwqtyqe .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#bxfxwqtyqe .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#bxfxwqtyqe .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#bxfxwqtyqe .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#bxfxwqtyqe .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#bxfxwqtyqe .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#bxfxwqtyqe .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#bxfxwqtyqe .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#bxfxwqtyqe .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#bxfxwqtyqe .gt_spanner_row {
  border-bottom-style: hidden;
}

#bxfxwqtyqe .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#bxfxwqtyqe .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#bxfxwqtyqe .gt_from_md > :first-child {
  margin-top: 0;
}

#bxfxwqtyqe .gt_from_md > :last-child {
  margin-bottom: 0;
}

#bxfxwqtyqe .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#bxfxwqtyqe .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#bxfxwqtyqe .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#bxfxwqtyqe .gt_row_group_first td {
  border-top-width: 2px;
}

#bxfxwqtyqe .gt_row_group_first th {
  border-top-width: 2px;
}

#bxfxwqtyqe .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#bxfxwqtyqe .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#bxfxwqtyqe .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#bxfxwqtyqe .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#bxfxwqtyqe .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#bxfxwqtyqe .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#bxfxwqtyqe .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#bxfxwqtyqe .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#bxfxwqtyqe .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#bxfxwqtyqe .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#bxfxwqtyqe .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#bxfxwqtyqe .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#bxfxwqtyqe .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#bxfxwqtyqe .gt_left {
  text-align: left;
}

#bxfxwqtyqe .gt_center {
  text-align: center;
}

#bxfxwqtyqe .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#bxfxwqtyqe .gt_font_normal {
  font-weight: normal;
}

#bxfxwqtyqe .gt_font_bold {
  font-weight: bold;
}

#bxfxwqtyqe .gt_font_italic {
  font-style: italic;
}

#bxfxwqtyqe .gt_super {
  font-size: 65%;
}

#bxfxwqtyqe .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#bxfxwqtyqe .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#bxfxwqtyqe .gt_indent_1 {
  text-indent: 5px;
}

#bxfxwqtyqe .gt_indent_2 {
  text-indent: 10px;
}

#bxfxwqtyqe .gt_indent_3 {
  text-indent: 15px;
}

#bxfxwqtyqe .gt_indent_4 {
  text-indent: 20px;
}

#bxfxwqtyqe .gt_indent_5 {
  text-indent: 25px;
}

#bxfxwqtyqe .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#bxfxwqtyqe div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="variable">Parameter</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="mean">Mean</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="median">Median</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="sd">SD</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="mad">MAD</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="q5">5th %tile</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="q95">95th %tile</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rhat">R-hat</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="ess_bulk">ESS (bulk)</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="ess_tail">ESS (tail)</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr class="gt_group_heading_row">
      <th colspan="10" class="gt_group_heading" style="font-weight: bold;" scope="colgroup" id="0/1-coded">0/1-coded</th>
    </tr>
    <tr class="gt_row_group_first"><td headers="0/1-coded  variable" class="gt_row gt_left">alpha</td>
<td headers="0/1-coded  mean" class="gt_row gt_right">-0.937</td>
<td headers="0/1-coded  median" class="gt_row gt_right">-0.937</td>
<td headers="0/1-coded  sd" class="gt_row gt_right">0.092</td>
<td headers="0/1-coded  mad" class="gt_row gt_right">0.093</td>
<td headers="0/1-coded  q5" class="gt_row gt_right">-1.088</td>
<td headers="0/1-coded  q95" class="gt_row gt_right">-0.786</td>
<td headers="0/1-coded  rhat" class="gt_row gt_right">1.001</td>
<td headers="0/1-coded  ess_bulk" class="gt_row gt_right">1359.836</td>
<td headers="0/1-coded  ess_tail" class="gt_row gt_right">2862.560</td></tr>
    <tr><td headers="0/1-coded  variable" class="gt_row gt_left">beta_a</td>
<td headers="0/1-coded  mean" class="gt_row gt_right">0.665</td>
<td headers="0/1-coded  median" class="gt_row gt_right">0.665</td>
<td headers="0/1-coded  sd" class="gt_row gt_right">0.117</td>
<td headers="0/1-coded  mad" class="gt_row gt_right">0.118</td>
<td headers="0/1-coded  q5" class="gt_row gt_right">0.472</td>
<td headers="0/1-coded  q95" class="gt_row gt_right">0.855</td>
<td headers="0/1-coded  rhat" class="gt_row gt_right">1.001</td>
<td headers="0/1-coded  ess_bulk" class="gt_row gt_right">1612.670</td>
<td headers="0/1-coded  ess_tail" class="gt_row gt_right">3084.048</td></tr>
    <tr><td headers="0/1-coded  variable" class="gt_row gt_left">beta_ab</td>
<td headers="0/1-coded  mean" class="gt_row gt_right">-0.352</td>
<td headers="0/1-coded  median" class="gt_row gt_right">-0.352</td>
<td headers="0/1-coded  sd" class="gt_row gt_right">0.137</td>
<td headers="0/1-coded  mad" class="gt_row gt_right">0.139</td>
<td headers="0/1-coded  q5" class="gt_row gt_right">-0.579</td>
<td headers="0/1-coded  q95" class="gt_row gt_right">-0.128</td>
<td headers="0/1-coded  rhat" class="gt_row gt_right">1.001</td>
<td headers="0/1-coded  ess_bulk" class="gt_row gt_right">1699.870</td>
<td headers="0/1-coded  ess_tail" class="gt_row gt_right">3617.854</td></tr>
    <tr><td headers="0/1-coded  variable" class="gt_row gt_left">beta_b</td>
<td headers="0/1-coded  mean" class="gt_row gt_right">0.969</td>
<td headers="0/1-coded  median" class="gt_row gt_right">0.968</td>
<td headers="0/1-coded  sd" class="gt_row gt_right">0.118</td>
<td headers="0/1-coded  mad" class="gt_row gt_right">0.119</td>
<td headers="0/1-coded  q5" class="gt_row gt_right">0.777</td>
<td headers="0/1-coded  q95" class="gt_row gt_right">1.164</td>
<td headers="0/1-coded  rhat" class="gt_row gt_right">1.001</td>
<td headers="0/1-coded  ess_bulk" class="gt_row gt_right">1430.007</td>
<td headers="0/1-coded  ess_tail" class="gt_row gt_right">3298.993</td></tr>
    <tr class="gt_group_heading_row">
      <th colspan="10" class="gt_group_heading" style="font-weight: bold;" scope="colgroup" id="centered">centered</th>
    </tr>
    <tr class="gt_row_group_first"><td headers="centered  variable" class="gt_row gt_left">alpha</td>
<td headers="centered  mean" class="gt_row gt_right">-0.210</td>
<td headers="centered  median" class="gt_row gt_right">-0.210</td>
<td headers="centered  sd" class="gt_row gt_right">0.047</td>
<td headers="centered  mad" class="gt_row gt_right">0.047</td>
<td headers="centered  q5" class="gt_row gt_right">-0.285</td>
<td headers="centered  q95" class="gt_row gt_right">-0.133</td>
<td headers="centered  rhat" class="gt_row gt_right">1.000</td>
<td headers="centered  ess_bulk" class="gt_row gt_right">9278.897</td>
<td headers="centered  ess_tail" class="gt_row gt_right">9114.590</td></tr>
    <tr><td headers="centered  variable" class="gt_row gt_left">gamma_a</td>
<td headers="centered  mean" class="gt_row gt_right">0.492</td>
<td headers="centered  median" class="gt_row gt_right">0.492</td>
<td headers="centered  sd" class="gt_row gt_right">0.094</td>
<td headers="centered  mad" class="gt_row gt_right">0.094</td>
<td headers="centered  q5" class="gt_row gt_right">0.337</td>
<td headers="centered  q95" class="gt_row gt_right">0.647</td>
<td headers="centered  rhat" class="gt_row gt_right">1.000</td>
<td headers="centered  ess_bulk" class="gt_row gt_right">9316.962</td>
<td headers="centered  ess_tail" class="gt_row gt_right">8853.810</td></tr>
    <tr><td headers="centered  variable" class="gt_row gt_left">gamma_ab</td>
<td headers="centered  mean" class="gt_row gt_right">-0.361</td>
<td headers="centered  median" class="gt_row gt_right">-0.362</td>
<td headers="centered  sd" class="gt_row gt_right">0.135</td>
<td headers="centered  mad" class="gt_row gt_right">0.134</td>
<td headers="centered  q5" class="gt_row gt_right">-0.582</td>
<td headers="centered  q95" class="gt_row gt_right">-0.140</td>
<td headers="centered  rhat" class="gt_row gt_right">1.000</td>
<td headers="centered  ess_bulk" class="gt_row gt_right">9167.199</td>
<td headers="centered  ess_tail" class="gt_row gt_right">9311.161</td></tr>
    <tr><td headers="centered  variable" class="gt_row gt_left">gamma_b</td>
<td headers="centered  mean" class="gt_row gt_right">0.795</td>
<td headers="centered  median" class="gt_row gt_right">0.795</td>
<td headers="centered  sd" class="gt_row gt_right">0.093</td>
<td headers="centered  mad" class="gt_row gt_right">0.095</td>
<td headers="centered  q5" class="gt_row gt_right">0.642</td>
<td headers="centered  q95" class="gt_row gt_right">0.946</td>
<td headers="centered  rhat" class="gt_row gt_right">1.001</td>
<td headers="centered  ess_bulk" class="gt_row gt_right">8969.964</td>
<td headers="centered  ess_tail" class="gt_row gt_right">8821.275</td></tr>
  </tbody>
  
</table>
</div>
<p>There are a few things to notice here. First, the Bayesian estimates for both the 0/1-coded and centered data are closer to zero than the GLM estimates above. The shrinkage is particularly large for the interaction term, because we placed much more restrictive priors on <span class="math inline">\(\beta_{ab}\)</span> and <span class="math inline">\(\gamma_{ab}\)</span>. This is what we would expect as the prior is pulling the interaction toward zero.</p>
<p>Second, if we compare the two parameterizations, we see that the R-hat—essentially a measure of whether the chains have converged to the same distribution—is slightly lower for the centered data. There isn’t much to make of the difference here (both are very close to 1), but it does suggest slightly more stable behavior for the centered parameterization.</p>
<p>The biggest impact is on the bulk effective sample size (ESS), which reflects how much independent information the chains contain after accounting for autocorrelation. Even though we ran the same number of iterations, the centered model yields far larger ESS values, indicating much better mixing. The sampler is exploring the posterior much more efficiently under the centered parameterization, and in this case the improvement is quite dramatic. Importantly, these differences have nothing to do with the models themselves since the likelihood is unchanged. Rather, it reflects how easy it is for the sampler to navigate the posterior surface when the data are centered.</p>
<p>A comparison of the trace plots reinforces the stability that centering the data provides. The traces. for the 0/1-coded data (on the left) are a bit more irregular, suggesting less efficient exploration of the posterior. In contrast, the centered parameterization produces tighter, more stable traces with less autocorrelation (on the right), indicating that the chains are mixing more effectively. This aligns with the much larger effective sample sizes observed for the centered model.</p>
<p><img src="https://i0.wp.com/www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/code_and_data/trace_plot.png?w=578&#038;ssl=1" data-recalc-dims="1" />
Finally, we compare the estimation of the log-odds ratios for the two models, just as we did before with the GLM models, and it is clear that the two Bayesian models also provide the same estimates of the contratsts:</p>
<pre>get_lor_summary &lt;- function(samp, model_name) {
  dt &lt;- as.data.table(as_draws_df(samp))
  
  if (model_name == &quot;0/1-coded&quot;) {
    dt[, lOR_A := beta_a]
    dt[, lOR_B := beta_b]
    dt[, lOR_AB := beta_a + beta_b + beta_ab]
  } else {
    dt[, lOR_A := gamma_a - 0.5 * gamma_ab]
    dt[, lOR_B := gamma_b - 0.5 * gamma_ab]
    dt[, lOR_AB := gamma_a + gamma_b]
  }
  
  dt[, .(
    mean_A = mean(lOR_A),
    mean_B = mean(lOR_B),
    mean_AB = mean(lOR_AB),
    sd_A = sd(lOR_A),
    sd_B = sd(lOR_B),
    sd_AB = sd(lOR_AB)
  )]
}

lor_01 &lt;- get_lor_summary(samp_01, &quot;0/1-coded&quot;)
lor_c  &lt;- get_lor_summary(samp_c,  &quot;centered&quot;)</pre>
<div id="xwzeufbwmd" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#xwzeufbwmd table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#xwzeufbwmd thead, #xwzeufbwmd tbody, #xwzeufbwmd tfoot, #xwzeufbwmd tr, #xwzeufbwmd td, #xwzeufbwmd th {
  border-style: none;
}

#xwzeufbwmd p {
  margin: 0;
  padding: 0;
}

#xwzeufbwmd .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: auto;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#xwzeufbwmd .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#xwzeufbwmd .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#xwzeufbwmd .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#xwzeufbwmd .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#xwzeufbwmd .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xwzeufbwmd .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#xwzeufbwmd .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#xwzeufbwmd .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#xwzeufbwmd .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#xwzeufbwmd .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#xwzeufbwmd .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#xwzeufbwmd .gt_spanner_row {
  border-bottom-style: hidden;
}

#xwzeufbwmd .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#xwzeufbwmd .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#xwzeufbwmd .gt_from_md > :first-child {
  margin-top: 0;
}

#xwzeufbwmd .gt_from_md > :last-child {
  margin-bottom: 0;
}

#xwzeufbwmd .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#xwzeufbwmd .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#xwzeufbwmd .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#xwzeufbwmd .gt_row_group_first td {
  border-top-width: 2px;
}

#xwzeufbwmd .gt_row_group_first th {
  border-top-width: 2px;
}

#xwzeufbwmd .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#xwzeufbwmd .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#xwzeufbwmd .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#xwzeufbwmd .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xwzeufbwmd .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#xwzeufbwmd .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#xwzeufbwmd .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#xwzeufbwmd .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#xwzeufbwmd .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xwzeufbwmd .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#xwzeufbwmd .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#xwzeufbwmd .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#xwzeufbwmd .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#xwzeufbwmd .gt_left {
  text-align: left;
}

#xwzeufbwmd .gt_center {
  text-align: center;
}

#xwzeufbwmd .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#xwzeufbwmd .gt_font_normal {
  font-weight: normal;
}

#xwzeufbwmd .gt_font_bold {
  font-weight: bold;
}

#xwzeufbwmd .gt_font_italic {
  font-style: italic;
}

#xwzeufbwmd .gt_super {
  font-size: 65%;
}

#xwzeufbwmd .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#xwzeufbwmd .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#xwzeufbwmd .gt_indent_1 {
  text-indent: 5px;
}

#xwzeufbwmd .gt_indent_2 {
  text-indent: 10px;
}

#xwzeufbwmd .gt_indent_3 {
  text-indent: 15px;
}

#xwzeufbwmd .gt_indent_4 {
  text-indent: 20px;
}

#xwzeufbwmd .gt_indent_5 {
  text-indent: 25px;
}

#xwzeufbwmd .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#xwzeufbwmd div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="model"></th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="A">log OR A</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="B">log OR B</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="AB">log OR AB</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr><td headers="model" class="gt_row gt_left">0/1-coded</td>
<td headers="A" class="gt_row gt_center">0.672 (0.115)</td>
<td headers="B" class="gt_row gt_center">0.973 (0.116)</td>
<td headers="AB" class="gt_row gt_center">1.286 (0.132)</td></tr>
    <tr><td headers="model" class="gt_row gt_left">centered</td>
<td headers="A" class="gt_row gt_center">0.672 (0.116)</td>
<td headers="B" class="gt_row gt_center">0.975 (0.117)</td>
<td headers="AB" class="gt_row gt_center">1.288 (0.134)</td></tr>
  </tbody>
  
</table>
</div>
</div>
</div>
<div id="a-larger-simulation-experiment" class="section level3">
<h3>A larger simulation experiment</h3>
<p>A single data set can be misleading. So next I’ll repeat this 500 times and compare the two parameterizations across simulations. Each iteration, I generate a data set with 2000 observations, I fit each model—the one with 0/1-coding and the other with centered coding—using <code>JAGS</code>, and collect summary data of the posteriors from each model <code>JAGS</code>: mean, median, standard deviation, median absolute deviation, 5th percentile, 95th percentile, R-hat, bulk ESS, and tail ESS.</p>
<pre>one_run &lt;- function(
  n = 2000,
  truth = c(alpha = -0.8, beta_a = 0.5, beta_b = 0.9, beta_ab = -0.3),
  n_chains = 3,
  burn = 1000,
  n_iter = 3000
) {
  
  dd &lt;- s_gen(
    n = n,
    alpha = truth[&quot;alpha&quot;],
    beta_a = truth[&quot;beta_a&quot;],
    beta_b = truth[&quot;beta_b&quot;],
    beta_ab = truth[&quot;beta_ab&quot;]
  )
  
  samp_01 &lt;- fit_jags(
    dd, model_01, centered = FALSE, 
    n_chains = n_chains, burn = burn, n_iter = n_iter
  )
  
  samp_c &lt;- fit_jags(
    dd, model_c, centered = TRUE, 
    n_chains = n_chains, burn = burn, n_iter = n_iter)
  
  get_metrics &lt;- function(samp, model_name) {
    post &lt;- as_draws_df(samp)
    summ &lt;- as.data.table(summarise_draws(post))
    summ[, model := model_name]
    summ[]
  }
  
  out &lt;- rbindlist(list(
    get_metrics(samp_01, &quot;0/1-coded&quot;),
    get_metrics(samp_c,  &quot;centered&quot;)
  ))
  
  out[]
}

nsim &lt;- 500

sim_res &lt;- rbindlist(mclapply(seq_len(nsim), function(i) {
  out &lt;- one_run()
  out[, sim := i]
  out[]
}, mc.cores = 5))</pre>
<p>Earlier we saw for a single data set, there was not much difference in R-hat (essentially a measure of whether the chains have converged to the same distribution) between the two models. However, over repeated data sets, a more interesting picture emerges. The figure below shows that while <em>R-hat</em> for the 0/1-coding model is quite low, <em>R-hat</em> for the centered-coding is lower still, and much more consistent, suggesting that mixing is stronger in the centered model.</p>
<p><img src="https://i0.wp.com/www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/code_and_data/plot_rhat_V1.png?w=75%25&#038;ssl=1" alt="" data-recalc-dims="1" /></p>
<p>The next figure also confirms what we saw earlier. This shows the distribution of ratios of <em>bulk ESS</em> in the centered model compared to the 0/1-coding model. If the two models had the same effective sample size, we would expect those ratios to cluster near one. However, they are all mostly greater than five, confirming what we saw for the individual data set.</p>
<p><img src="https://i0.wp.com/www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/code_and_data/plot_ess_V1.png?w=75%25&#038;ssl=1" alt="" data-recalc-dims="1" /></p>
<p>The key issue is posterior dependence among parameters: when parameters are highly correlated, the sampler will explore narrower regions in the posterior, which slows mixing.</p>
</div>
<div id="understanding-what-is-driving-the-performance" class="section level3">
<h3>Understanding what is driving the performance</h3>
<p>To better understand this, we can look directly at the dependence structure of the posterior draws. Correlation plots (where each point is a draw from the posterior) help explain what is driving these differences in performance. Under the 0/1-coded parameterization, the posterior exhibits strong dependence among parameters. Several pairs of coefficients show substantial correlations, reflecting the fact that different combinations of parameters can produce similar fitted values. In geometric terms, the joint posterior has an elongated, highly correlated structure. This is evident in the pairwise scatter plots, where draws fall along narrow, tilted bands rather than forming roughly circular clouds.</p>
<p><img src="https://i1.wp.com/www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/code_and_data/plot_cor_01_V2.png?w=75%25&#038;ssl=1" alt="" data-recalc-dims="1" /></p>
<p>This geometry makes life difficult for the sampler. Exploring a narrower region requires smaller, correlated steps, which leads to high autocorrelation and, ultimately, low effective sample sizes.</p>
<p>In contrast, the centered parameterization produces a posterior that is nearly uncorrelated. The coefficients capture more distinct aspects of the model, and the resulting posterior is much more spherical. This greatly simplifies the exploration of the parameter space, allowing the sampler to move more freely.</p>
<p><img src="https://i1.wp.com/www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/code_and_data/plot_cor_c_V3.png?w=75%25&#038;ssl=1" alt="" data-recalc-dims="1" /></p>
<p>The key point is that centering does not change the model or the scientific conclusions. It changes the geometry of the posterior distribution, and that change can have a dramatic impact on computational performance. In effect, centering makes the parameters closer to orthogonal in the posterior, reducing interference among them and improving both statistical and computational behavior.</p>
<p>In the ED-LEAD study, where we are fitting hierarchical factorial models with multiple intervention components, this shift in parameterization is critical. Centering the treatment indicators leads to more stable estimation and far more efficient sampling, which is particularly important given our reliance on <code>JAGS</code>. Unlike Hamiltonian Monte Carlo (as implemented in <code>Stan</code>), which can handle correlated posteriors more effectively, the Gibbs and Metropolis-based updates used by <code>JAGS</code> are much more sensitive to posterior dependence. Improving the geometry of the posterior seems to be critical for good performance in this setting.</p>
<p>
<p><small><font color="darkkhaki">
Support:</p>
This work was supported in part by the National Institute on Aging (NIA) of the National Institutes of Health under Award Number U19AG078105, which funds the <em>Emergency departments leading the transformation of Alzheimer’s and dementia care</em> (ED-LEAD) study. The author, the leader of the Statistics Analysis Core, was the sole writer of this blog post and has no conflicts. The content is solely the responsibility of the author and does not necessarily represent the official views of the National Institutes of Health.
</font></small>
</p>
</div>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.rdatagen.net/post/2026-03-31-centering-binary-predictors-can-improve-bayesian-computation/"> ouR data generation</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/same-model-better-shape-why-centering-improves-mcmc/">Same model, better shape: why centering improves MCMC</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400210</post-id>	</item>
		<item>
		<title>Better Git diff with difftastic</title>
		<link>https://www.r-bloggers.com/2026/03/better-git-diff-with-difftastic/</link>
		
		<dc:creator><![CDATA[Maëlle&#039;s R blog on Maëlle Salmon&#039;s personal website]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://masalmon.eu/2026/03/30/difftastic/</guid>

					<description><![CDATA[<p>I’m currently on a quest to better know and understand treesitter-based tooling for R.<br />
To make it short, treesitter is a tool for parsing code, for instance recognizing what is a function, an argument, a logical in a string of code.<br />
With tools bu...</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/better-git-diff-with-difftastic/">Better Git diff with difftastic</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://masalmon.eu/2026/03/30/difftastic/"> Maëlle&#039;s R blog on Maëlle Salmon&#039;s personal website</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p>I’m currently on a quest to better know and understand treesitter-based tooling for R.
To make it short, treesitter is a tool for parsing code, for instance recognizing what is a function, an argument, a logical in a string of code.
With tools built upon treesitter you can <a href="https://emilhvitfeldt.com/post/ast-grep-r-claude-code/" rel="nofollow" target="_blank">search</a>, <a href="https://posit-dev.github.io/air/" rel="nofollow" target="_blank">reformat</a>, <a href="https://jarl.etiennebacher.com/" rel="nofollow" target="_blank">lint and fix</a>, etc. your code.
Exciting stuff, running locally and deterministically on your machine.</p>
<p>Speaking of “etc.”, <a href="https://www.etiennebacher.com/" rel="nofollow" target="_blank">Etienne Bacher</a> helpfully suggested I also look at treesitter-based tooling for <em>other languages</em> to see what’s still missing in our ecosystem.
This is how I stumbled upon difftastic by Wilfred Hughes, “a structural diff tool that understands syntax”. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" />
This means that difftastic doesn’t only compare line or “words” but actual syntax by looking at lines around the lines that changed (by default, 3),
Even better, it understands R out of the box<sup id="fnref:1"><a href="https://masalmon.eu/2026/03/30/difftastic/#fn:1" class="footnote-ref" role="doc-noteref" rel="nofollow" target="_blank">1</a></sup>.</p>
<p><em>Many thanks to Etienne Bacher not only for making me discover difftastic but also for useful feedback on this post!</em></p>
<h2 id="installing-difftastic">Installing difftastic</h2>
<p>To install difftastic I downloaded a binary file for my system from the releases of the GitHub repository,
as <a href="https://difftastic.wilfred.me.uk/installation.html" rel="nofollow" target="_blank">documented in the manual</a>.</p>
<h2 id="difftastic-on-two-files">difftastic on two files</h2>
<p>You can run difftastic on two files, a bit like you would use the <a href="https://waldo.r-lib.org/" rel="nofollow" target="_blank">waldo</a> R package on two objects.</p>
<p>Let’s compare:</p>
<pre>a &lt;- gsub(&quot;bad&quot;, &quot;good&quot;, x)
</pre><p>to</p>
<pre>a &lt;- stringr::str_replace(x, &quot;bad&quot;, &quot;good&quot;)
</pre><p>respectedly saved in <code>old.R</code> and <code>new.R</code>.
The CLI is called difft not difftastic.
I use the “inline” display rather than the two columns default in order to save horizontal space.</p>
<pre>difft old.R new.R --display inline
</pre><p>We’d get to this nice looking diff:</p>
<figure>
    <img src="https://i2.wp.com/masalmon.eu/2026/03/30/difftastic/oldnew.png?w=578&#038;ssl=1"
         alt="diff of the two lines of code, where &#39;gsub&#39; and &#39;, x&#39; are in red then &#39;strinrr::str_replace&#39; and &#39;x&#39; in green" data-recalc-dims="1"/> 
</figure>

<p>The parentheses and <code>&quot;bad&quot;</code> and <code>&quot;good&quot;</code> arguments are ignored.</p>
<p>We can also get the JSON version of this diff, which is an unstable feature which usage requires setting an environment variable:</p>
<pre>export DFT_UNSTABLE=yes
difft old.R new.R --display json
</pre><p>This gets us</p>
<pre>{&quot;aligned_lines&quot;:[[0,0],[1,1]],&quot;chunks&quot;:[[{&quot;lhs&quot;:{&quot;line_number&quot;:0,&quot;changes&quot;:[{&quot;start&quot;:5,&quot;end&quot;:9,&quot;content&quot;:&quot;gsub&quot;,&quot;highlight&quot;:&quot;normal&quot;},{&quot;start&quot;:23,&quot;end&quot;:24,&quot;content&quot;:&quot;,&quot;,&quot;highlight&quot;:&quot;normal&quot;},{&quot;start&quot;:25,&quot;end&quot;:26,&quot;content&quot;:&quot;x&quot;,&quot;highlight&quot;:&quot;normal&quot;}]},&quot;rhs&quot;:{&quot;line_number&quot;:0,&quot;changes&quot;:[{&quot;start&quot;:5,&quot;end&quot;:12,&quot;content&quot;:&quot;stringr&quot;,&quot;highlight&quot;:&quot;normal&quot;},{&quot;start&quot;:12,&quot;end&quot;:14,&quot;content&quot;:&quot;::&quot;,&quot;highlight&quot;:&quot;keyword&quot;},{&quot;start&quot;:14,&quot;end&quot;:25,&quot;content&quot;:&quot;str_replace&quot;,&quot;highlight&quot;:&quot;normal&quot;},{&quot;start&quot;:26,&quot;end&quot;:27,&quot;content&quot;:&quot;x&quot;,&quot;highlight&quot;:&quot;normal&quot;},{&quot;start&quot;:27,&quot;end&quot;:28,&quot;content&quot;:&quot;,&quot;,&quot;highlight&quot;:&quot;normal&quot;}]}}]],&quot;language&quot;:&quot;R&quot;,&quot;path&quot;:&quot;content/post/2026-03-26-difftastic/new.R&quot;,&quot;status&quot;:&quot;changed&quot;}
</pre><p>Now, none of this isn’t very useful because I would never compare files in this way…
I use version control!</p>
<h2 id="difftastic-with-git">difftastic with Git</h2>
<p>We can set difftastic as the external diff tool for Git globally or for the current project.</p>
<p>For instance with the gert R package, to set it locally:</p>
<pre>gert::git_config_set(&quot;diff.external&quot;, &quot;difft&quot;)
</pre><p>If I want to use the inline display I’d set:</p>
<pre>gert::git_config_set(&quot;diff.external&quot;, &quot;difft --display inline&quot;)
</pre><p>Then <code>git diff</code> will by default use difftastic.
Most interestingly for me, <code>git show --ext-diff</code> will use difftastic.
I never use <code>git diff</code> directly but I do look at more or less recent commits a lot.</p>
<p>Say I am interested in the <a href="https://github.com/r-lib/roxygen2/commit/7a1dd39866699a2b0a034bb15244c07698a1e2e7" rel="nofollow" target="_blank">commit</a> that removed roxygen2’s dependency on stringi, I’ll run:</p>
<pre>git show 7a1dd39866699a2b0a034bb15244c07698a1e2e7 --ext-diff
</pre><p>and get:</p>
<figure>
    <img src="https://i0.wp.com/masalmon.eu/2026/03/30/difftastic/strwrap.png?w=578&#038;ssl=1"
         alt="diff where the parentheses of a nested call are nicely highlighted" data-recalc-dims="1"/> 
</figure>

<p>This isn’t spectacular because this is a small diff, but I enjoy the highlighting of the parentheses of the removed nested call, and of the logical.</p>
<h2 id="cool-features-of-difftastic">Cool features of difftastic</h2>
<p>Building on two examples of the <a href="https://difftastic.wilfred.me.uk/" rel="nofollow" target="_blank">difftastic homepage</a>…</p>
<h3 id="ignoring-formatting-changes">Ignoring formatting changes</h3>
<p>Since formatters can so helpfully apply your formatting preferences,
reviewing formatting changes in a patch that’s about something else entirely is useless and annoying.
Imagine having a function definition that fits on a single line, then adding one argument to it.</p>
<p>Going from</p>
<pre>f &lt;- function(myarg1 = foo, myarg2 = bar) {}
</pre><p>to</p>
<pre>f &lt;- function(
  myarg1 = foo,
  myarg2 = bar,
  myarg3 = baz
) {}
</pre><p>Because the definition is now longer than 80 characters, your formatter might switch the definition to be on multiple lines.
But the actually interesting change is the addition of one argument.</p>
<p>Native Git diff<sup id="fnref:2"><a href="https://masalmon.eu/2026/03/30/difftastic/#fn:2" class="footnote-ref" role="doc-noteref" rel="nofollow" target="_blank">2</a></sup> would show:</p>
<figure>
    <img src="https://i0.wp.com/masalmon.eu/2026/03/30/difftastic/args.png?w=578&#038;ssl=1"
         alt="diff where all lines are highlighted because the function was reformatted, not only complemented with one argument" data-recalc-dims="1"/> 
</figure>

<p>Git with difftastic would show:</p>
<figure>
    <img src="https://i2.wp.com/masalmon.eu/2026/03/30/difftastic/args-better.png?w=578&#038;ssl=1"
         alt="diff where only the comma after `bar` and the line with the new argument are highlighted" data-recalc-dims="1"/> 
</figure>

<p>The matching of delimiters is why I found the difftastic’s display of the roxygen2 commit more pleasing.</p>
<h3 id="matching-delimiters-in-wrappers">Matching delimiters in wrappers</h3>
<p>The Git diff can look a bit ugly when you simply move code from one function to the other.</p>
<p>Say we go from</p>
<pre>f &lt;- function() {
  1 + 1
}

</pre><p>to</p>
<pre>f &lt;- function() {
  g()
}

g &lt;- function() {
  1 + 1
}

</pre><p>Git diff would show:</p>
<figure>
    <img src="https://i1.wp.com/masalmon.eu/2026/03/30/difftastic/wrappers-bad.png?w=578&#038;ssl=1"
         alt="uncool diff that shows lines modified in both the wrapper and the function without matching delimiters" data-recalc-dims="1"/> 
</figure>

<p>Whereas Git with difftastic would show:</p>
<figure>
    <img src="https://i1.wp.com/masalmon.eu/2026/03/30/difftastic/wrappers-good.png?w=578&#038;ssl=1"
         alt="cool diff that shows `g` as a new function by highlighting its name and the left arrow, whereas the entire definiton of `f` is marked as changed." data-recalc-dims="1"/> 
</figure>

<h2 id="will-i-use-difftastic">Will I use difftastic?</h2>
<p>I really like the concept behind difftastic and the few Git commits I looked at with it rendered nicely.
Now, what’s <a href="https://github.com/Wilfred/difftastic#does-difftastic-integrate-with-my-favourite-tool" rel="nofollow" target="_blank">missing</a> for me to use difftastic a lot is its integration with the tools where I actually use Git:</p>
<ul>
<li>Positron including the GitLens extension;</li>
<li>GitHub Pull Request Files tab.</li>
</ul>
<p>In any case, I’ll continue learning about tools based on treesitter, some of which like <a href="https://posit-dev.github.io/air/" rel="nofollow" target="_blank">Air</a> and <a href="https://jarl.etiennebacher.com/" rel="nofollow" target="_blank">Jarl</a> I can already use directly from my IDE. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f638.png" alt="😸" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>It’s not every day we R developers look at the <a href="https://difftastic.wilfred.me.uk/" rel="nofollow" target="_blank">homepage</a> of a tool and see the R logo among the logos of other languages! <a href="https://masalmon.eu/2026/03/30/difftastic/#fnref:1" class="footnote-backref" role="doc-backlink" rel="nofollow" target="_blank"><img src="https://s.w.org/images/core/emoji/13.0.0/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>To get the diff that Git would show me I ran <code>git diff --no-index old-args.R new-args.R --no-ext-diff</code>, cool trick I didn’t know about! Very glad I didn’t have to create a fake Git repo just for this. (<code>--no-ext-diff</code> because my diff in this repo would use difftastic by default!) <a href="https://masalmon.eu/2026/03/30/difftastic/#fnref:2" class="footnote-backref" role="doc-backlink" rel="nofollow" target="_blank"><img src="https://s.w.org/images/core/emoji/13.0.0/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></p>
</li>
</ol>
</section>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://masalmon.eu/2026/03/30/difftastic/"> Maëlle&#039;s R blog on Maëlle Salmon&#039;s personal website</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/better-git-diff-with-difftastic/">Better Git diff with difftastic</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400178</post-id>	</item>
		<item>
		<title>rOpenSci News Digest, March 2026</title>
		<link>https://www.r-bloggers.com/2026/03/ropensci-news-digest-march-2026/</link>
		
		<dc:creator><![CDATA[rOpenSci]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://ropensci.org/blog/2026/03/30/news-mars-2026/</guid>

					<description><![CDATA[<p>Dear rOpenSci friends, it’s time for our monthly news roundup!  You can read this post on our blog. Now let’s dive into the activity at and around rOpenSci!</p>
<p>rOpenSci HQ</p>
<p>rOpenSci Dev Guide 1.0.0: Trilingual and Improved<br />
rOpenSci Software...</p>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/ropensci-news-digest-march-2026/">rOpenSci News Digest, March 2026</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://ropensci.org/blog/2026/03/30/news-mars-2026/"> rOpenSci - open tools for open science</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<!-- Before sending DELETE THE INDEX_CACHE and re-knit! -->
<p>Dear rOpenSci friends, it’s time for our monthly news roundup! <!-- blabla --> You can read this post <a href="https://ropensci.org/blog/2026/03/30/news-mars-2026" rel="nofollow" target="_blank">on our blog</a>. Now let’s dive into the activity at and around rOpenSci!</p>
<h2>
rOpenSci HQ
</h2><h3>
rOpenSci Dev Guide 1.0.0: Trilingual and Improved
</h3><p>rOpenSci Software Peer Review’s guidance is gathered in an online book that keeps improving! It is now available in <a href="https://devguide.ropensci.org/" rel="nofollow" target="_blank">English</a>, <a href="https://devguide.ropensci.org/es/index.es.html" rel="nofollow" target="_blank">Spanish</a> and <a href="https://devguide.ropensci.org/pt/index.pt.html" rel="nofollow" target="_blank">Portuguese</a>. Read more in the <a href="https://ropensci.org/blog/2026/03/02/devguide-1.0.0/" rel="nofollow" target="_blank">release announcement</a></p>
<h3>
Champions Program Update
</h3><p>We are still going through the Champions selection process, and we’re excited to share that the new group of mentors has already been selected and is now actively reviewing Champions applications.</p>
<p>This cohort brings together a wonderful mix of returning Champions stepping into mentorship roles, mentors continuing their contributions, and new members joining the program. The 2026 mentors are Andrea Gómez Vargas, Pablo Paccioretti, Alber Hamersson Sánchez Ipia, Erick Isaac Navarro Delgado, Francisco Cardozo, Luis Verde Arregoitia, Monika Ávila Márquez, Guadalupe Pascal, Pao Corrales, and Elio Campitelli. Together, they represent a diverse and vibrant community across Colombia, Mexico, Argentina, Brazil, and Bolivia, with some currently based in Switzerland, Canada, the United States, and Australia. We’re very happy to see this growing, interconnected network supporting the next cohort of Champions.</p>
<h3>
R-Universe update
</h3><p>You can now download artifacts and log files from R-Universe without being logged in with a GitHub account, for example <a href="https://ropensci.r-universe.dev/opencv#checktable" rel="nofollow" target="_blank">https://ropensci.r-universe.dev/opencv#checktable</a>.</p>
<h3>
Software review and usage of AI tools
</h3><p>Authors submitting new software for <a href="https://ropensci.org/software-review/" rel="nofollow" target="_blank">peer review</a> are now required to explain potential usage of generative AI tools in their package development. All submission templates now include a mandatory check-box:</p>
<pre>- [ ] Generative AI tools were used to produce some of the material in this submission.
If so, please describe usage, and include links to any relevant aspects of your repository.
</pre>
<p>This is the start of our updates to accommodate generative AI tools in package development, as described in our <a href="https://ropensci.org/blog/2026/02/26/ropensci-ai-policy/" rel="nofollow" target="_blank">recent blog post</a>. The next phase will involve updates to our <a href="https://devguide.ropensci.org/" rel="nofollow" target="_blank"><em>Dev Guide</em></a>, explaining requirements and recommendations for authors, reviewers, and editors. All updates are intended to permit generative AI tools to be used in any useful way, while minimising the burden on those who volunteer their own time to keep our software peer review service running.</p>
<h3>
Software review bot updates
</h3><p>The <code>ropensci-review-bot</code> now delivers an initial report to all new software pre-submissions and submissions, identifying the five most similar packages from both all rOpenSci packages, and all CRAN packages. The matches are generated by our <a href="https://docs.ropensci.org/pkgmatch" rel="nofollow" target="_blank">ropensci-review-tools/pkgmatch package</a> (itself reviewed in <a href="https://github.com/ropensci/software-review/issues/671" rel="nofollow" target="_blank">this review issue</a>). Matching is based on an <a href="https://en.wikipedia.org/wiki/Tf%E2%80%93idf" rel="nofollow" target="_blank">“term frequency-inverse document frequency” algorithm</a>, using inverse document frequencies from all rOpenSci and CRAN packages. Similar package reports can also be manually triggered (by editors only) with <code>@ropensci-review-bot similar packages</code>, like in <a href="https://github.com/ropensci/software-review/issues/671#issuecomment-4117805740" rel="nofollow" target="_blank">this example for the pkgmatch package itself</a>.</p>
<h3>
Coworking
</h3><p>Read <a href="https://ropensci.org/blog/2023/06/21/coworking/" rel="nofollow" target="_blank">all about coworking</a>!</p>
<ul>
<li>Tuesday April 7th 2026, 9:00 Americas Pacific (16:00 UTC) <a href="https://ropensci.org/events/coworking-2026-04/" rel="nofollow" target="_blank">“Getting to know the CSID Network”</a> with <a href="https://ropensci.org/author/steffi-lazerte/" rel="nofollow" target="_blank">Steffi LaZerte</a> and cohosts <a href="https://ropensci.org/author/irene-ramos/" rel="nofollow" target="_blank">Irene Ramos</a> and <a href="https://ropensci.org/author/adamu-saleh-saidu" rel="nofollow" target="_blank">Adamu Saleh Saidu</a>.
<ul>
<li>Learn more about the <a href="https://csidnet.org/" rel="nofollow" target="_blank">CSID Network</a></li>
<li>Meet cohosts, Irene Ramos and Adamu Saleh Saidu, and learn more about the CSID Network and how you might get involved.</li>
</ul>
</li>
<li>Tuesday May 5th 2026, 9:00 Australia Western (01:00 UTC) <a href="https://ropensci.org/events/coworking-2026-05/" rel="nofollow" target="_blank">“Code Review with rOpenSci”</a> with <a href="https://ropensci.org/author/steffi-lazerte/" rel="nofollow" target="_blank">Steffi LaZerte</a> and cohost <a href="https://ropensci.org/author/liz-hare/" rel="nofollow" target="_blank">Liz Hare</a>.
<ul>
<li>Explore resources for Code Review</li>
<li>Sign up to volunteer to do <a href="https://airtable.com/app8dssb6a7PG6Vwj/shrnfDI2S9uuyxtDw" rel="nofollow" target="_blank">software peer-review</a> at rOpenSci</li>
<li>Meet cohost, Liz Hare, and discuss resources for Code Review with rOpenSci.</li>
</ul>
</li>
</ul>
<p>And remember, you can always cowork independently on work related to R, work on packages that tend to be neglected, or work on what ever you need to get done!</p>
<h2>
Software <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f4e6.png" alt="📦" class="wp-smiley" style="height: 1em; max-height: 1em;" />
</h2><h3>
New packages
</h3><p>The following package recently became a part of our software suite:</p>
<ul>
<li><a href="https://docs.ropensci.org/suwo" rel="nofollow" target="_blank">suwo</a>, developed by Marcelo Araya-Salas together with Jorge Elizondo-Calvo and Alejandro Rico-Guevara: Streamline searching/downloading of nature media files (e.g. audios, photos) from online repositories. The package offers functions for obtaining media metadata from online repositories, downloading associated media files and updating data sets with new records. It has been <a href="https://github.com/ropensci/software-review/issues/729" rel="nofollow" target="_blank">reviewed</a> by Eric R. Scott and Hugo Gruson.</li>
</ul>
<p>Discover <a href="https://ropensci.org/packages" rel="nofollow" target="_blank">more packages</a>, read more about <a href="https://ropensci.org/software-review" rel="nofollow" target="_blank">Software Peer Review</a>.</p>
<h3>
New versions
</h3><p>The following eleven packages have had an update since the last newsletter: <a href="https://docs.ropensci.org/cffr" title="Generate Citation File Format (cff) Metadata for R Packages" rel="nofollow" target="_blank">cffr</a> (<a href="https://github.com/ropensci/cffr/releases/tag/v1.3.0" rel="nofollow" target="_blank"><code>v1.3.0</code></a>), <a href="https://docs.ropensci.org/pkgmatch" title="Find R Packages Matching Either Descriptions or Other R Packages" rel="nofollow" target="_blank">pkgmatch</a> (<a href="https://github.com/ropensci-review-tools/pkgmatch/releases/tag/v0.5.2" rel="nofollow" target="_blank"><code>v0.5.2</code></a>), <a href="https://docs.ropensci.org/tarchetypes" title="Archetypes for Targets" rel="nofollow" target="_blank">tarchetypes</a> (<a href="https://github.com/ropensci/tarchetypes/releases/tag/0.14.1" rel="nofollow" target="_blank"><code>0.14.1</code></a>), <a href="https://docs.ropensci.org/rgbif" title="Interface to the Global Biodiversity Information Facility API" rel="nofollow" target="_blank">rgbif</a> (<a href="https://github.com/ropensci/rgbif/releases/tag/v3.8.5" rel="nofollow" target="_blank"><code>v3.8.5</code></a>), <a href="https://docs.ropensci.org/saperlipopette" title="Create Example Git Messes" rel="nofollow" target="_blank">saperlipopette</a> (<a href="https://github.com/ropensci-training/saperlipopette/releases/tag/v0.1.1" rel="nofollow" target="_blank"><code>v0.1.1</code></a>), <a href="https://docs.ropensci.org/gutenbergr" title="Download and Process Public Domain Works from Project Gutenberg" rel="nofollow" target="_blank">gutenbergr</a> (<a href="https://github.com/ropensci/gutenbergr/releases/tag/v0.5.0" rel="nofollow" target="_blank"><code>v0.5.0</code></a>), <a href="https://docs.ropensci.org/trud" title="Query the NHS TRUD API" rel="nofollow" target="_blank">trud</a> (<a href="https://github.com/ropensci/trud/releases/tag/v0.2.1" rel="nofollow" target="_blank"><code>v0.2.1</code></a>), <a href="https://docs.ropensci.org/naijR" title="Operations to Ease Data Analyses Specific to Nigeria" rel="nofollow" target="_blank">naijR</a> (<a href="https://github.com/ropensci/naijR/releases/tag/v0.7.0" rel="nofollow" target="_blank"><code>v0.7.0</code></a>), <a href="https://docs.ropensci.org/sasquatch" title="Use SAS, R, and quarto Together" rel="nofollow" target="_blank">sasquatch</a> (<a href="https://github.com/ropensci/sasquatch/releases/tag/v0.1.3" rel="nofollow" target="_blank"><code>v0.1.3</code></a>), <a href="https://docs.ropensci.org/lingtypology" title="Linguistic Typology and Mapping" rel="nofollow" target="_blank">lingtypology</a> (<a href="https://github.com/ropensci/lingtypology/releases/tag/v1.1.25" rel="nofollow" target="_blank"><code>v1.1.25</code></a>), and <a href="https://docs.ropensci.org/rerddap" title="General Purpose Client for ERDDAP&#x2122; Servers" rel="nofollow" target="_blank">rerddap</a> (<a href="https://github.com/ropensci/rerddap/releases/tag/v1.2.3" rel="nofollow" target="_blank"><code>v1.2.3</code></a>).</p>
<p>Post on dfms release: <a href="https://sebkrantz.github.io/Rblog/2026/01/29/releasing-dfms-1-0-fast-and-feature-rich-estimation-of-dynamic-factor-models-in-r/" rel="nofollow" target="_blank">Releasing dfms 1.0: Fast and Feature-Rich Estimation of Dynamic Factor Models in R</a>.</p>
<h2>
Software Peer Review
</h2><p>There are fifteen recently closed and active submissions and 5 submissions on hold. Issues are at different stages:</p>
<ul>
<li>
<p>One at <a href="https://github.com/ropensci/software-review/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%226/approved%22" rel="nofollow" target="_blank">‘6/approved’</a>:</p>
<ul>
<li><a href="https://github.com/ropensci/software-review/issues/729" rel="nofollow" target="_blank">suwo</a>, Access Nature Media Repositories Through R. Submitted by <a href="https://marce10.github.io/" rel="nofollow" target="_blank">Marcelo Araya-Salas</a>.</li>
</ul>
</li>
<li>
<p>One at <a href="https://github.com/ropensci/software-review/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%225/awaiting-reviewer(s)-response%22" rel="nofollow" target="_blank">‘5/awaiting-reviewer(s)-response’</a>:</p>
<ul>
<li><a href="https://github.com/ropensci/software-review/issues/671" rel="nofollow" target="_blank">pkgmatch</a>, Find R Packages Matching Either Descriptions or Other R Packages. Submitted by <a href="https://mpadge.github.io/" rel="nofollow" target="_blank">mark padgham</a>.</li>
</ul>
</li>
<li>
<p>Two at <a href="https://github.com/ropensci/software-review/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%224/review(s)-in-awaiting-changes%22" rel="nofollow" target="_blank">‘4/review(s)-in-awaiting-changes’</a>:</p>
<ul>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/741" rel="nofollow" target="_blank">logolink</a>, An Interface for Running NetLogo Simulations. Submitted by <a href="http://danielvartan.com/" rel="nofollow" target="_blank">Daniel Vartanian</a>.</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/615" rel="nofollow" target="_blank">galamm</a>, Generalized Additive Latent and Mixed Models. Submitted by <a href="https://osorensen.github.io/" rel="nofollow" target="_blank">Øystein Sørensen</a>. (Stats).</p>
</li>
</ul>
</li>
<li>
<p>Six at <a href="https://github.com/ropensci/software-review/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%223/reviewer(s)-assigned%22" rel="nofollow" target="_blank">‘3/reviewer(s)-assigned’</a>:</p>
<ul>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/760" rel="nofollow" target="_blank">pvEBayes</a>, Empirical Bayes Methods for Pharmacovigilance. Submitted by <a href="https://github.com/YihaoTancn" rel="nofollow" target="_blank">Yihao Tan</a>. (Stats).</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/754" rel="nofollow" target="_blank">saperlipopette</a>, Create Example Git Messes. Submitted by <a href="https://masalmon.eu/" rel="nofollow" target="_blank">Maëlle Salmon</a>.</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/730" rel="nofollow" target="_blank">ernest</a>, A Toolkit for Nested Sampling. Submitted by <a href="https://github.com/kylesnap" rel="nofollow" target="_blank">Kyle Dewsnap</a>. (Stats).</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/718" rel="nofollow" target="_blank">rcrisp</a>, Automate the Delineation of Urban River Spaces. Submitted by <a href="https://github.com/cforgaci" rel="nofollow" target="_blank">Claudiu Forgaci</a>. (Stats).</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/709" rel="nofollow" target="_blank">reviser</a>, Tools for Studying Revision Properties in Real-Time Time Series Vintages. Submitted by <a href="https://marcburri.github.io/" rel="nofollow" target="_blank">Marc Burri</a>.</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/704" rel="nofollow" target="_blank">priorsense</a>, Prior Diagnostics and Sensitivity Analysis. Submitted by <a href="https://github.com/n-kall" rel="nofollow" target="_blank">Noa Kallioinen</a>. (Stats).</p>
</li>
</ul>
</li>
<li>
<p>Two at <a href="https://github.com/ropensci/software-review/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%222/seeking-reviewer(s)%22" rel="nofollow" target="_blank">‘2/seeking-reviewer(s)’</a>:</p>
<ul>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/750" rel="nofollow" target="_blank">nycOpenData</a>, Convenient Access to NYC Open Data API Endpoints. Submitted by <a href="https://github.com/martinezc1" rel="nofollow" target="_blank">Christian Martinez</a>.</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/743" rel="nofollow" target="_blank">RAMEN</a>, RAMEN: Regional Association of Methylome variability with the Exposome and geNome. Submitted by <a href="https://erick-navarrodelgado.netlify.app/" rel="nofollow" target="_blank">Erick Navarro-Delgado</a>.</p>
</li>
</ul>
</li>
<li>
<p>Three at <a href="https://github.com/ropensci/software-review/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%221/editor-checks%22" rel="nofollow" target="_blank">‘1/editor-checks’</a>:</p>
<ul>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/744" rel="nofollow" target="_blank">RAQSAPI</a>, A Simple Interface to the US EPA Air Quality System Data Mart API. Submitted by <a href="https://github.com/mccroweyclinton-EPA" rel="nofollow" target="_blank">mccroweyclinton-EPA</a>.</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/740" rel="nofollow" target="_blank">fcmconfr</a>, Fuzzy Cognitive Map Analysis in R. Submitted by <a href="https://github.com/bhroston" rel="nofollow" target="_blank">benroston</a>. (Stats).</p>
</li>
<li>
<p><a href="https://github.com/ropensci/software-review/issues/717" rel="nofollow" target="_blank">coevolve</a>, Fit Bayesian Generalized Dynamic Phylogenetic Models using Stan. Submitted by <a href="https://scottclaessens.github.io/" rel="nofollow" target="_blank">Scott Claessens</a>. (Stats).</p>
</li>
</ul>
</li>
</ul>
<p>Find out more about <a href="https://ropensci.org/software-review" rel="nofollow" target="_blank">Software Peer Review</a> and how to get involved.</p>
<h2>
On the blog
</h2><!-- Do not forget to rebase your branch! -->
<h3>
Software Review
</h3><ul>
<li>
<p><a href="https://ropensci.org/blog/2026/02/26/ropensci-ai-policy" rel="nofollow" target="_blank">Software Review in the Era of AI: What We Are Testing at rOpenSci</a> by Mark Padgham, Noam Ross, Maëlle Salmon, Yanina Bellini Saibene, Mauro Lepore, Emily Riederer, Jouni Helske, and Francisco Rodriguez-Sanchez. rOpenSci is testing preliminary policies on the use of generative AI tools, with proposed updates to documentation and procedures for authors submitting software for review, for editors, and for reviewers.</p>
</li>
<li>
<p><a href="https://ropensci.org/blog/2026/03/02/devguide-1.0.0" rel="nofollow" target="_blank">rOpenSci Dev Guide 1.0.0: Trilingual and Improved</a> by Maëlle Salmon, Mark Padgham, and Noam Ross. Updates in version 1.0.0 of the online book ‘rOpenSci Packages: Development, Maintenance, and Peer Review’. Other languages: <a href='https://ropensci.org/es/blog/2026/03/02/r_open_sci_dev_guide_1_0_0_triling%C3%BCe_y_mejorada' lang='es' rel="nofollow" target="_blank">rOpenSci Dev Guide 1.0.0: Trilingüe y mejorada (es)</a>, <a href='https://ropensci.org/pt/blog/2026/03/02/guia_de_desenvolvimento_da_r_open_sci_1_0_0_tril%C3%ADngue_e_aprimorado' lang='pt' rel="nofollow" target="_blank">Guia de desenvolvimento da rOpenSci 1.0.0: trilíngue e aprimorado (pt)</a>.</p>
</li>
</ul>
<figure class="center"><img src="https://i2.wp.com/ropensci.org/blog/2026/03/30/news-mars-2026/cover.png?w=400&#038;ssl=1"
alt="cover of rOpenSci dev guide, showing a package production line with small humans discussing, examining and promoting packages"  data-recalc-dims="1">
</figure>
<ul>
<li><a href="https://ropensci.org/blog/2026/03/10/patentsview-breaking-release" rel="nofollow" target="_blank">Breaking Release of the patentsview R Package</a> by Russ Allen and Chris Baker. Breaking Release of the patentsview R Package.</li>
</ul>
<h2>
Calls for contributions
</h2><h3>
Calls for maintainers
</h3><p>If you’re interested in maintaining any of the R packages below, you might enjoy reading our blog post <a href="https://ropensci.org/blog/2023/02/07/what-does-it-mean-to-maintain-a-package/" rel="nofollow" target="_blank">What Does It Mean to Maintain a Package?</a>.</p>
<ul>
<li>
<p><a href="https://docs.ropensci.org/NLMR" rel="nofollow" target="_blank">NLMR</a>, R package to simulate neutral landscape models. <a href="https://github.com/ropensci/NLMR/issues/116" rel="nofollow" target="_blank">Issue for volunteering</a>.</p>
</li>
<li>
<p><a href="https://docs.ropensci.org/landscapetools" rel="nofollow" target="_blank">landscapetools</a>, R package for some of the less-glamorous tasks involved in landscape analysis. <a href="https://github.com/ropensci/landscapetools/issues/48" rel="nofollow" target="_blank">Issue for volunteering</a>.</p>
</li>
<li>
<p><a href="https://docs.ropensci.org/hddtools" rel="nofollow" target="_blank">hddtools</a>, Tools to discover hydrological data, accessing catalogues and databases from various data providers. <a href="https://github.com/ropensci/hddtools/issues/36" rel="nofollow" target="_blank">Issue for volunteering</a>.</p>
</li>
<li>
<p><a href="https://docs.ropensci.org/qualtRics/" rel="nofollow" target="_blank">qualtRics</a>, download Qualtrics survey data. <a href="https://github.com/ropensci/qualtRics/issues/383" rel="nofollow" target="_blank">Issue for volunteering</a>.</p>
</li>
</ul>
<h3>
Calls for contributions
</h3><p>Refer to our <a href="https://ropensci.org/help-wanted/" rel="nofollow" target="_blank">help wanted page</a> – before opening a PR, we recommend asking in the issue whether help is still needed.</p>
<h2>
Package development corner
</h2><p>Some useful tips for R package developers. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f440.png" alt="👀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h3>
A new R core member!
</h3><p>The R Foundation announced that <a href="https://uk.linkedin.com/in/heathrturnr" rel="nofollow" target="_blank">Heather Turner</a> has joined the <a href="https://www.r-project.org/contributors.html" rel="nofollow" target="_blank">R Core Team</a>! <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f389.png" alt="🎉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h3>
How to browse the R mailing lists
</h3><p>The <a href="https://www.r-project.org/mail.html" rel="nofollow" target="_blank">official mailing lists of the R project</a> like <a href="https://blog.r-hub.io/2019/04/11/r-package-devel/" rel="nofollow" target="_blank">R-package-devel</a> are full of important and useful information. How to browse them, given that the default website is not easy to search? You can use the <a href="https://mail-archive.com/r-devel@r-project.org/" rel="nofollow" target="_blank">mail-archive</a> website (thanks to Hugo Gruson for the reminder!) or a new project by James Balamuta: the <a href="https://r-mailing-lists.thecoatlessprofessor.com/" rel="nofollow" target="_blank">R Mailing Lists Archive</a>!</p>
<h3>
“Claude Code: Setting up ast-grep with R support”
</h3><p>Thanks to Mauro Lepore for sharing this blog post by Emil Hvitfeldt: <a href="https://emilhvitfeldt.com/post/ast-grep-r-claude-code/" rel="nofollow" target="_blank">“Claude Code: Setting up ast-grep with R support”</a>. ast-grep is a tool for querying code by syntax rather than brittle regular expressions. The blog post describes how to add R support to this tool, and how to take advantage of it when using Claude.</p>
<h3>
On muffling messages from packages
</h3><p>A follow-up on our post <a href="https://ropensci.org/blog/2024/02/06/verbosity-control-packages/" rel="nofollow" target="_blank">“Please Shut Up! Verbosity Control in Packages”</a>.</p>
<ul>
<li>With the {cli} R package you can change the default handler for messages. See the <a href="https://cli.r-lib.org/articles/semantic-cli.html#cli-messages" rel="nofollow" target="_blank">docs</a>. It seems mostly used to muffle messages, e.g. in <a href="https://github.com/etiennebacher/flir/blob/9254cd01d258d0bafcee41a44e5caa7104fed832/R/lint.R#L104" rel="nofollow" target="_blank">flir</a>.</li>
<li>Here’s how the usethis R package <a href="https://github.com/r-lib/usethis/commit/f0f3f91494a1b15c1b08ee78dc73ab7d1cf8b6a8" rel="nofollow" target="_blank">muffles gert message selectively</a>.</li>
</ul>
<h2>
Last words
</h2><p>Thanks for reading! If you want to get involved with rOpenSci, check out our <a href="https://contributing.ropensci.org/" rel="nofollow" target="_blank">Contributing Guide</a> that can help direct you to the right place, whether you want to make code contributions, non-code contributions, or contribute in other ways like sharing use cases. You can also support our work through <a href="https://ropensci.org/donate" rel="nofollow" target="_blank">donations</a>.</p>
<p>If you haven’t subscribed to our newsletter yet, you can <a href="https://ropensci.org/news/" rel="nofollow" target="_blank">do so via a form</a>. Until it’s time for our next newsletter, you can keep in touch with us via our <a href="https://ropensci.org/" rel="nofollow" target="_blank">website</a> and <a href="https://hachyderm.io/@rOpenSci" rel="nofollow" target="_blank">Mastodon account</a>.</p>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://ropensci.org/blog/2026/03/30/news-mars-2026/"> rOpenSci - open tools for open science</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/ropensci-news-digest-march-2026/">rOpenSci News Digest, March 2026</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400176</post-id>	</item>
		<item>
		<title>Pacific island energy supply by @ellis2013nz</title>
		<link>https://www.r-bloggers.com/2026/03/pacific-island-energy-supply-by-ellis2013nz/</link>
		
		<dc:creator><![CDATA[free range statistics - R]]></dc:creator>
		<pubDate>Sun, 29 Mar 2026 13:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://freerangestats.info/blog/2026/03/30/pacific-energy</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> With the conflict in Iran causing worldwide disruption to energy markets, I have both a work and personal interest in energy supply in Pacific islands, which led me to this blog post. Here I look at just two aspects of energy: electricity generation, a...</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/pacific-island-energy-supply-by-ellis2013nz/">Pacific island energy supply by @ellis2013nz</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://freerangestats.info/blog/2026/03/30/pacific-energy"> free range statistics - R</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p>With the conflict in Iran causing worldwide disruption to energy markets, I have both a work and personal interest in energy supply in Pacific islands, which led me to this blog post. Here I look at just two aspects of energy: electricity generation, and household cooking. Nothing fancy here, just accessing some data and drawing a couple of plots.</p>

<h2 id="electricity-generation">Electricity generation</h2>

<p>Here is the <em>source</em> of electricity for Pacific island countries, plus Australia and New Zealand, collated by Our World In Data from Energy Institute data that ultimately comes from government estimates:</p>

<object type="image/svg+xml" data="https://freerangestats.info/img/0320-pict-electricity-mix.svg" width="450"><img src="https://i0.wp.com/freerangestats.info/img/0320-pict-electricity-mix.png?w=450&#038;ssl=1" data-recalc-dims="1" /></object>

<p>There’s a pretty obvious story here: most of the Pacific is <strong>very</strong> dependent on “oil” (in the form of diesel) for generation of most of its electricity. There are some small steps towards renewables happening in recent years, but the vulnerability to a price or availability shock for diesel is pretty obvious.</p>

<p>Here’s the code for producing that, using the valuable <code>owidapi</code> R package to access the Our World in Data API.</p>

<figure class="highlight"><pre>#---------------Set up-----------------
library(owidapi)
library(tidyverse)
library(countrycode)
library(WDI)
library(jsonlite)
library(janitor)
library(httr2)


pic_codes &lt;- 
  c(
    &quot;ASM&quot;, &quot;COK&quot;, &quot;FSM&quot;, &quot;FJI&quot;, &quot;PYF&quot;, &quot;GUM&quot;, &quot;KIR&quot;, &quot;MHL&quot;, &quot;NRU&quot;, &quot;NCL&quot;,
    &quot;NIU&quot;, &quot;MNP&quot;, &quot;PLW&quot;, &quot;PNG&quot;, &quot;PCN&quot;, &quot;WSM&quot;, &quot;SLB&quot;, &quot;TKL&quot;, &quot;TON&quot;, &quot;TUV&quot;,
    &quot;VUT&quot;, &quot;WLF&quot;, &quot;AUS&quot;, &quot;NZL&quot;
  )
stopifnot(length(pic_codes) == 24)

# visual check we've got the right country codes for the Pacific:
countrycode::countrycode(pic_codes, origin = &quot;iso3c&quot;, destination = &quot;country.name.en&quot;)

#=======================electricity source===================

palette &lt;- c(
  coal = &quot;brown&quot;,
  gas = &quot;magenta&quot;,
  oil = &quot;red&quot;,
  kerosene = &quot;red&quot;,
  electricity = &quot;purple&quot;,
  solar = &quot;yellow&quot;,
  wind = &quot;steelblue&quot;,
  hydro = &quot;darkblue&quot;,
  bioenergy = &quot;lightgreen&quot;,
  charcoal = &quot;grey&quot;,
  biomass = &quot;darkgreen&quot;,
  'other renewables' = &quot;darkgreen&quot;
)

#-------------------electricity mix-----------------
elec_mix &lt;- owid_get(
  chart_id = &quot;share-elec-by-source&quot;,
  entities  = pic_codes
)

elec_data &lt;- elec_mix |&gt; 
   rename(country = entity_name) |&gt; 
   select(-entity_id) |&gt; 
   gather(variable, value, -country, -year) |&gt;
   filter(value != 0) |&gt; 
   filter(year &gt; 2001) |&gt; 
   mutate(variable = gsub(&quot;_share_of_electricity__pct&quot;, &quot;&quot;, variable, fixed = TRUE),
          variable =gsub(&quot;_&quot;, &quot; &quot;, variable),
          variable =gsub(&quot; excluding bioenergy&quot;, &quot;&quot;, variable),
          variable = fct_drop(variable)) |&gt; 
   mutate(variable = fct_relevel(variable, c(&quot;bioenergy&quot;, &quot;hydro&quot;, &quot;other renewables&quot;), after = Inf)) |&gt; 
   mutate(country = fct_relevel(country, c(&quot;Australia&quot;, &quot;New Zealand&quot;), after = Inf)) |&gt; 
  group_by(country) |&gt; 
  mutate(prop_pc= sum(value[variable %in% c(&quot;oil&quot;, &quot;gas&quot;) & year == max(year)]) 
         / sum(value[year == max(year)])) |&gt; 
  ungroup() |&gt; 
  mutate(country = fct_reorder(country, prop_pc))

# Draw chart
elec_data |&gt; 
  ggplot(aes(x = year, y = value, fill = variable)) +
 facet_wrap(~country, ncol = 5) +
  geom_col() +
  scale_fill_manual(values = palette) +
  scale_y_continuous(label = percent_format(scale = 1)) +
   labs(y = &quot;Percentage of electricity&quot;,
        fill = &quot;Source:&quot;,
        title = &quot;Share of electricity by source&quot;,
        subtitle = &quot;Countries shown in increasing order of vulnerability of electricity to a petrochemicals price or availability crisis.&quot;,
        x = &quot;&quot;,
        caption = &quot;Source: Ember (2026); Energy Institute - Statistical Review of World Energy (2025). Data processed by Our World In Data.&quot;) +
   theme(axis.text.x = element_text(angle = 45, hjust = 1))</pre></figure>

<h2 id="cooking-fuel">Cooking fuel</h2>

<p>OK, so electricity generation could be threatened by a lack of diesel. What about household cooking? This next chart draws on the definitive World Health Organization Household Energy Database, which models (based on what household survey data that is available) what households are using to cook:</p>

<object type="image/svg+xml" data="https://freerangestats.info/img/0320-pict-cooking-fuel.svg" width="450"><img src="https://i1.wp.com/freerangestats.info/img/0320-pict-cooking-fuel.png?w=450&#038;ssl=1" data-recalc-dims="1" /></object>

<p>Again, we see a lot of reliance on petrochemical products, particularly kerosene and liquid natural gas. The latter has been promoted as a relatively clean and healthy fuel to cook with compared to burning biomass (e.g. wood, coconuts, etc).</p>

<p>The larger Melanesian countries, with high rural populations, are those with the greatest use still of biomass for cooking. Most Pacific island countries do most of their cooking with oil or gas derived energy (remembering from the first chart, that ‘electricity’ often means diesel, ultimately).</p>

<p>Here’s the code to produce that chart. I used an LLM (I forget which) for the code to access the API itself, but I tested it and tweaked it to match my style, and the chart of course is all my own code.</p>

<figure class="highlight"><pre>#--------------------cooking-------------------
# The definitive source is the WHO  WHO Household Energy Database 
# which draws on various household surveys
# See https://www.who.int/data/gho/data/themes/air-pollution/cooking-fuel-and-technology-database-by-fuel-category

# next half dozen lines of code were supplied by Co-pilot and minimally
# tweaked by me for my style
indicator_code &lt;- &quot;PHE_HHAIR_PROP_POP_CATEGORY_FUELS&quot;  # % by fuel type [3](https://millenniumindicators.un.org/wiki/spaces/SDGeHandbook/pages/35291272/Indicator+7.1.2)
url &lt;- paste0(&quot;https://ghoapi.azureedge.net/api/&quot;, indicator_code)

resp &lt;- request(url) |&gt; 
  req_headers(`Accept` = &quot;application/json&quot;)  |&gt; 
  req_perform()

cooking_data &lt;- fromJSON(resp_body_string(resp), flatten = TRUE)$value |&gt;
  as_tibble() |&gt; 
  clean_names()


pic_cooking_data &lt;-cooking_data |&gt; 
  filter(spatial_dim %in% pic_codes) |&gt; 
  filter(dim1 == &quot;RESIDENCEAREATYPE_TOTL&quot;) |&gt; 
  mutate(fuel_type = tolower(gsub(&quot;HOUSEHOLDCOOKINGFUEL_FUEL_&quot;, &quot;&quot;, dim2))) |&gt; 
  mutate(year = as.numeric(time_dimension_value)) |&gt; 
   select(value = numeric_value, 
          iso3_code = spatial_dim,
          value = numeric_value,
          year,
          fuel_type) |&gt; 
  mutate(country = countrycode(iso3_code, origin = &quot;iso3c&quot;, destination = &quot;country.name.en&quot;),
         country = gsub(&quot;Federated States&quot;, &quot;Fed St&quot;, country)) |&gt;
  group_by(country) |&gt; 
  mutate(prop_gke = sum(value[fuel_type %in% c(&quot;gas&quot;, &quot;kerosene&quot;, &quot;electricity&quot;) & year == max(year)]) 
         / sum(value[year == max(year)])) |&gt; 
  ungroup() |&gt; 
  mutate(country = fct_reorder(country, prop_gke))

# Draw chart
pic_cooking_data |&gt; 
  ggplot(aes(y = value, x = year, fill = fuel_type)) +
  facet_wrap(~country, ncol = 5) +
  # the numbers don't add up to 100 always, due to being modelled estimates
  #, not fully MECE, not counting dual fuels, etc. Good practice advice
  # is to not force them to add to 100%
  geom_area() +
  scale_fill_manual(values = palette) +
  scale_y_continuous(label = percent_format(scale = 1)) +
  labs(title = &quot;Household primary fuel used for cooking&quot;,
       subtitle = &quot;Estimates are modelled by WHO, and not adding up to 100% is a known limitation.
Countries shown in increasing order of vulnerability of cooking to a petrochemicals price or availability crisis.&quot;,
       x = &quot;&quot;,
       fill = &quot;Fuel type:&quot;,
       y =&quot;Proportion of households&quot;,
       caption = &quot;Source: WHO Household Energy Database&quot;)</pre></figure>

<p>That’s all, just a quick one today.</p>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://freerangestats.info/blog/2026/03/30/pacific-energy"> free range statistics - R</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/pacific-island-energy-supply-by-ellis2013nz/">Pacific island energy supply by @ellis2013nz</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400172</post-id>	</item>
		<item>
		<title>Navigating Financial Statement And The Story It Tells Us &#8211; A Note To Myself</title>
		<link>https://www.r-bloggers.com/2026/03/navigating-financial-statement-and-the-story-it-tells-us-a-note-to-myself/</link>
		
		<dc:creator><![CDATA[r on Everyday Is A School Day]]></dc:creator>
		<pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://www.kenkoonwong.com/blog/financial-statement/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
📊 Dipping my toes into financial statements — income, balance sheet &#038; cash flow. Still don’t fully get it, but slowly piecing together the story these numbers tell. Warren Buffett makes it look easy 😅 Baby steps! 🌱</p>
<p>Motivations</p>
<p>      ...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/navigating-financial-statement-and-the-story-it-tells-us-a-note-to-myself/">Navigating Financial Statement And The Story It Tells Us – A Note To Myself</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://www.kenkoonwong.com/blog/financial-statement/"> r on Everyday Is A School Day</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<blockquote>
<p><img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Dipping my toes into financial statements — income, balance sheet &#038; cash flow. Still don’t fully get it, but slowly piecing together the story these numbers tell. Warren Buffett makes it look easy <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f605.png" alt="😅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Baby steps! <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f331.png" alt="🌱" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
</blockquote>




<h2 id="motivations">Motivations
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#motivations" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<p>I’ve always wanted to learn financial statement, what it means, what it tells us, what Warren Buffett sees in them. Following the book 
<a href="https://www.amazon.com/Warren-Buffett-Interpretation-Financial-Statements/dp/1849833192" rel="nofollow" target="_blank">Warren Buffett and the Interpretation of Financial Statements: The Search for the Company with a Durable Competitive Advantage</a> and 
<a href="https://datacamp.pxf.io/15bPYD" rel="nofollow" target="_blank">Datacamp: Analyzing Financial Statement in Python</a>, I’ve made some notes for myself and also create the metrics functions, so that I can use and view them easily in the future. I’ll be honest, I still don’t fully understand it, but at least I can refer back to this as I look at these statements more frequently.</p>




<h4 id="disclaimer">Disclaimer:
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#disclaimer" rel="nofollow" target="_blank"></a>
</h4>
<p><em>This is purely for educational purposes. This is not a financial advice, nor am I a financial advisor. This is a note to myself. If you find any mistakes or error, please let me know. Thanks! Also, there are a lot of information on each section, I won’t be covering all of them, just mostly the metrics from the book and also points I found interesting.</em></p>




<h2 id="objectives">Objectives:
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#objectives" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<ul>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#skeleton" rel="nofollow" target="_blank">The Skeleton of Financial Statements</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#example" rel="nofollow" target="_blank">Let’s Take An Example</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#income" rel="nofollow" target="_blank">Income Statement</a>
<ul>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#gpm" rel="nofollow" target="_blank">Gross Profit Margin</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#depreciation" rel="nofollow" target="_blank">Depreciation</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#interest" rel="nofollow" target="_blank">Interest Payment to Operating Income</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#incomebeforetax" rel="nofollow" target="_blank">Income Before Tax</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#incomeaftertax" rel="nofollow" target="_blank">Income After Tax</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#netearnings" rel="nofollow" target="_blank">Net Earnings</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#share" rel="nofollow" target="_blank">Per Share Earning</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#operatingmargin" rel="nofollow" target="_blank">Operating Margin</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#metric1" rel="nofollow" target="_blank">Metrics</a></li>
</ul>
</li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#balance" rel="nofollow" target="_blank">Balance Sheet</a>
<ul>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#asset" rel="nofollow" target="_blank">Current Assets</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#receivables" rel="nofollow" target="_blank">Net Receivables To Gross Sale Ratio</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#currentratio" rel="nofollow" target="_blank">The Current Ratio</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#ppe" rel="nofollow" target="_blank">Property, Plant, and Equipment</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#short" rel="nofollow" target="_blank">Short Term Debt</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#long" rel="nofollow" target="_blank">Long Term Debt</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#retained" rel="nofollow" target="_blank">Retained Earnings</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#treasury" rel="nofollow" target="_blank">Treasury Stock</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#ROSE" rel="nofollow" target="_blank">Return On Shareholders’ Equity</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#metric2" rel="nofollow" target="_blank">Metrics</a></li>
</ul>
</li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#cashflow" rel="nofollow" target="_blank">Cash Flow</a>
<ul>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#operating" rel="nofollow" target="_blank">Operating Income</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#capex" rel="nofollow" target="_blank">Capital Expenditure</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#buyback" rel="nofollow" target="_blank">Stock Buyback</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#metric3" rel="nofollow" target="_blank">Metrics</a></li>
</ul>
</li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#combine" rel="nofollow" target="_blank">Combine All Metrics</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#another" rel="nofollow" target="_blank">Let’s Look At Another Examples</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#opportunities" rel="nofollow" target="_blank">Oppotunities For Improvement</a></li>
<li>
<a href="https://www.kenkoonwong.com/blog/financial-statement/#lessons" rel="nofollow" target="_blank">Lessons Learnt</a></li>
</ul>




<h2 id="skeleton">The Skeleton of Financial Statements
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#skeleton" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<p>A financial statement is a formal record that shows a company’s financial activities and position, typically consisting of three core components: the <code>income statement</code> (which shows revenues earned and expenses incurred to calculate profit or loss over a period), the <code>balance sheet</code> (which presents what the company owns as assets, what it owes as liabilities, and the difference between them as equity at a specific point in time), and the <code>cash flow</code> statement (which tracks the actual movement of cash in and out of the business through operating activities, investing activities, and financing activities). The <code>income statement reveals profitability</code>, and the <code>cash flow statement shows liquidity</code> and how money actually moves through the business.</p>
<p>If we were to think of a kid’s lemonaid shop, the <code>income statement</code> would show how much money the shop made from selling lemon tea and how much it spent on ingredients, paying Johnny hourly to sell (salary) to calculate the profit. The <code>balance sheet</code> would list the shop’s assets (like cash in the register, inventory of lemons, sugar, and any equipment) and liabilities (like loans or unpaid bills &#8211; money your parent you borrowed from to buy all of the above) to show the net worth of the business at a given moment. The <code>cash flow statement</code> would track the actual cash coming in from customers and going out for expenses, giving insight into whether the shop has enough liquidity to cover its day-to-day operations.</p>
<p>It sounds simple, in the big picture, but these are just the basic skeleton of financial statements. There are many nuances and details that we need to understand to really grasp the story that these statements are telling us.Each section has its own items and some of these items are good at forming different metrics to tell the story of how the lemonaid business is doing. Below is just a snapshot of Apple’s financial statement.</p>




<h4 id="income-statement">Income Statement
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#income-statement" rel="nofollow" target="_blank"></a>
</h4>
<p align="center">
  <img loading="lazy" src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/income1.png?w=450&#038;ssl=1" alt="image" height="auto" data-recalc-dims="1">
</p>
<p align="center">
  <img loading="lazy" src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/income2.png?w=450&#038;ssl=1" alt="image" height="auto" data-recalc-dims="1">
</p>




<h4 id="balance-sheet">Balance Sheet
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#balance-sheet" rel="nofollow" target="_blank"></a>
</h4>
<p align="center">
  <img loading="lazy" src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/balance1.png?w=450&#038;ssl=1" alt="image" height="auto" data-recalc-dims="1">
</p>
<p align="center">
  <img loading="lazy" src="https://i1.wp.com/www.kenkoonwong.com/blog/financial-statement/balance2.png?w=450&#038;ssl=1" alt="image" height="auto" data-recalc-dims="1">
</p>




<h4 id="cash-flow">Cash Flow
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#cash-flow" rel="nofollow" target="_blank"></a>
</h4>
<p align="center">
  <img loading="lazy" src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/cash.png?w=450&#038;ssl=1" alt="image" height="auto" data-recalc-dims="1">
</p>




<h2 id="example">Let’s Take An Example
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#example" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<p>Let’s go to 
<a href="https://www.alphavantage.co/" rel="nofollow" target="_blank">Alpha Vantage</a> and create a free api key and then pull Apple’s 10 year financial statement and go through as an exercise.</p>
<p>
<a href="https://www.sec.gov/Archives/edgar/data/320193/000032019325000079/aapl-20250927.htm#i719388195b384d85a4e238ad88eba90a_181" rel="nofollow" target="_blank">https://www.sec.gov/Archives/edgar/data/320193/000032019325000079/aapl-20250927.htm#i719388195b384d85a4e238ad88eba90a_181</a></p>
<pre>library(httr)
library(jsonlite)
library(tidyverse)

api_key &lt;- &quot;your_api_key_here&quot; # Use .Renviron to be safer like below combine_all code

## Create a function to pull data
get_data &lt;- function(fx,ticker) {
  raw &lt;- GET(paste0(
    &quot;https://www.alphavantage.co/query?function=&quot;,fx,
    &quot;&#038;symbol=&quot;,ticker,&quot;&#038;apikey=&quot;, api_key
  )) %&gt;%
    content(as = &quot;text&quot;, encoding = &quot;UTF-8&quot;) %&gt;%
    fromJSON()
  
  df &lt;- raw$annualReports |&gt; 
    as_tibble() |&gt; 
    mutate(across(-c(fiscalDateEnding, reportedCurrency), as.numeric)) |&gt;
    mutate(fiscalDateEnding = as.Date(fiscalDateEnding)) |&gt;
    arrange(fiscalDateEnding)

  return(df)
}

## financial statement
income &lt;- get_data(&quot;INCOME_STATEMENT&quot;,&quot;AAPL&quot;)
balance &lt;- get_data(&quot;BALANCE_SHEET&quot;,&quot;AAPL&quot;)
cashflow &lt;- get_data(&quot;CASH_FLOW&quot;,&quot;AAPL&quot;)
</pre><p>Let’s visualize the income statement</p>
<img src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-2-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />




<h2 id="income">Income Statement
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#income" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<p>Alright, here we go! Income statement tells the story of how the goods and services are doing in the market, how much it costs to produce and sell them, and how much profit is left after all expenses are accounted for. It is a dynamic statement that shows the flow of money over a period of time, typically a quarter or a year. It is like a movie that tells the story of the company’s operations and profitability. Below are some ratios and heuristics of which companies have a durable competitive advantage, according to Warren Buffett.</p>




<h3 id="gpm">Gross Profit Margin
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#gpm" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Gross Profit Margin = Gross Profit / Total Revenue\)</code></p>
<p>In the book, we are looking for consistent, as a general rule, <code>above 40%</code> to consider a company to have a durable competitive advantage. Gross profit here is basically <code>Total Revenue - Cost of Revenue</code>, does not take into account of R&D, admin etc. Gross profit margin is a measure of how much profit a company makes from its core operations, before accounting for other expenses. A higher gross profit margin indicates that the company has a strong competitive position in the market and is able to generate more profit from its sales.</p>
<p>So on Apple, you can see that in the sales section, there is product and service. I assume product is the hardware and service is like the cloud storage etc. The cost of revenue section has the same sections, that depicts how much cost to make these products/services. Again, remember this is all just about the goods, does not take into account of the R&D, office that manages these, administrative etc, I think. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f914.png" alt="🤔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>




<h3 id="depreciation">Depreciation
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#depreciation" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Apparently this is a non-cash expense that reflects the reduction in value of a company’s assets over time. It is an accounting method used to allocate the cost of tangible assets (like machinery, equipment, buildings) and intangible assets (like patents, copyrights) over their useful lives. Depreciation allows companies to spread out the expense of an asset over several years, rather than recognizing the entire cost in the year it was purchased.</p>
<p>A quick ratio in the book is</p>
<p><code>\(Depreciation / Gross Profit\)</code></p>
<p>which should be low <code>~5-7%</code> which indicates that the company is not heavily reliant on physical assets that may lose value over time. Warren stated that EBITDA (Earnings Before Depreciation, Taxes, and Amortization) is something Wall Street loves, but in Warren’s eyes, depreciation is a real expanse. Why is it that he said EBITDA is something Wall Street love? Because it shows a higher profit by excluding non-cash expenses like depreciation, which can make a company look more profitable than it actually is… interesting. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f914.png" alt="🤔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>




<h3 id="interest">Interest Payment to Operating Income
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#interest" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Interest Payment / Operating Income\)</code></p>
<p>should be <code>less than 15%</code>. This ratio indicates that the company is not overly burdened by debt and has a healthy balance between its operating income and interest expenses. A lower ratio suggests that the company is generating sufficient operating income to cover its interest payments, which is a positive sign of financial stability.</p>
<p><code>Operating Income = Total Revenue - Cost of Revenue - Operating Expenses</code>. And <code>Operating Expenses = R&D + Selling, General and Administrative Expenses</code>. Wow, so many terminologies and I still don’t fully understand them, but at least I can refer back to this when I look at these statements.</p>




<h3 id="incomebeforetax">Income Before Tax
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#incomebeforetax" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>This is a value that Warren uses when he calculates the return that he is getting when he a whole business.</p>




<h3 id="incomeaftertax">Income After Tax
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#incomeaftertax" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>This is a value is the truth test of a business. What is reported with SEC should reflect the pre-tax income reported on the income statement. Apparently some companies like to report higher values than the the truth? was what the book said <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f914.png" alt="🤔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>




<h3 id="netearnings">Net Earnings
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#netearnings" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Net Earning / Total Revenue\)</code></p>
<p>The heuristic for this is we should look for <code>more than 20%</code> which indicates that the company is able to generate a significant amount of profit from its total revenue, hence a long term competitive advantage.</p>
<p><code>Net Earnings = Operating Income - Interest Expense - Taxes</code>. This is the bottom line of the income statement, which represents the company’s total profit after all expenses have been deducted from total revenue. It is a key indicator of a company’s profitability and financial performance. A higher net earnings figure indicates that the company is generating more profit from its operations, which can be a sign of a strong competitive position in the market.Interest Expense - Taxes`.</p>




<h3 id="share">Per Share Earning
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#share" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>This is something Warren wants to see consistent increment over time.</p>
<p>This is calculated by:
<code>\(EPS = Net Income/Outstanding Share\)</code></p>
<p>Does that mean if net income is negative, we’ll have negative share? <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f914.png" alt="🤔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>




<h3 id="operatingmargin">Operating Margin
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#operatingmargin" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Operating Margin = Operating Income / Total Revenue\)</code></p>
<p>This is a measure of a company’s profitability that indicates how much profit it generates from its operations relative to its total revenue. A higher operating margin suggests that the company is more efficient at converting revenue into profit, which can be a sign of a strong competitive position in the market. Warren looks for <code>more than 10%</code> which indicates that the company has a durable competitive advantage. ?????</p>




<h4 id="metric1">Metrics
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#metric1" rel="nofollow" target="_blank"></a>
</h4>
<pre>income_metric &lt;- function(df) {
  df_i &lt;- df |&gt;
    mutate(grossProfitMargin = grossProfit / totalRevenue,
           depreciationToGrossProfit = depreciationAndAmortization / grossProfit,
           interestExpenseToOperatingIncome = interestExpense / operatingIncome,
           netEarningMargin = netIncome / totalRevenue,
           operatingMargin = operatingIncome / totalRevenue)
  
  hline &lt;- tribble(
    ~param, ~hline_value, ~color2,
    &quot;grossProfitMargin&quot;, 0.4, &quot;red&quot;, 
    &quot;depreciationToGrossProfit&quot;, 0.07, &quot;blue&quot;,
    &quot;interestExpenseToOperatingIncome&quot;, 0.15, &quot;blue&quot;,
    &quot;netEarningMargin&quot;, 0.2, &quot;red&quot;,
    &quot;operatingMargin&quot;, 0.1, &quot;red&quot;
  ) |&gt;
    mutate(
      param = factor(param),
      ymin = ifelse(color2 == &quot;red&quot;, -Inf, hline_value),
      ymax = ifelse(color2 == &quot;red&quot;, hline_value, Inf)
    )
  
  columns &lt;- hline$param
  
  plot &lt;- df_i |&gt;
    select(fiscalDateEnding, grossProfitMargin:operatingMargin) |&gt;
    pivot_longer(cols = c(grossProfitMargin:operatingMargin), 
                 names_to = &quot;param&quot;, values_to = &quot;values&quot;) |&gt;
    mutate(param = factor(param, levels = columns)) |&gt; 
    ggplot(aes(x = fiscalDateEnding, y = values)) +
    geom_rect(
      data = hline,
      aes(ymin = ymin, ymax = ymax, fill = color2),
      xmin = -Inf, xmax = Inf,
      alpha = 0.15,
      inherit.aes = FALSE
    ) +
    geom_line() +
    facet_wrap(. ~ param, scale = &quot;free_y&quot;) +
    scale_fill_identity() +
    theme_bw()
  
  return(plot)
}

income_metric(income) 
</pre><img src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-3-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Net margin</p>
<p>What is EBTDA? It stands for <code>Earnings Before Depreciation, Taxes, and Amortization</code>. It is a measure of a company’s operating performance that excludes non-operating expenses such as depreciation, taxes, and amortization. It is often used as a proxy for cash flow from operations, as it focuses on the core profitability of the business before accounting for non-cash expenses and tax obligations.</p>




<h2 id="balance">Balance Sheet
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#balance" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<p><code>\(Asset = Liability + Shareholder Equity\)</code></p>
<p>Reminded me of Full Metal Alchemist famous phrase “tōka kōkan”, equivalent exchange.</p>
<p align="center">
<img loading="lazy" src="https://i2.wp.com/images5.alphacoders.com/840/840678.jpg?w=50%25&#038;ssl=1" alt="image" height="auto" data-recalc-dims="1">
</p>




<h3 id="asset">Current Assets
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#asset" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Current asset is any asset that can be reasonably expected to be converted into cash within one year. This includes cash and cash equivalents, accounts receivable, inventory, and other short-term assets. Current assets are important because they provide insight into a company’s liquidity and ability to meet its short-term obligations.</p>




<h3 id="receivables">Net Receivables To Gross Sale Ratio
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#receivables" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Net Receivables / Gross Sale\)</code></p>
<p>If a company consistently has a lower ratio (? <code>5%</code> or less), it may indicate that the company is efficient in collecting payments from customers and has a lower risk of bad debts. A higher ratio may suggest that the company is having difficulty collecting payments, which could lead to cash flow issues and potential losses from uncollected receivables.</p>




<h3 id="currentratio">The Current Ratio
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#currentratio" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Current Ratio = Total Assets / Total Liabilities\)</code></p>
<p>The current ratio is a liquidity ratio that measures a company’s ability to pay off its short-term liabilities with its short-term assets. A current ratio of <code>1 or higher</code> is generally considered good, indicating that the company has enough assets to cover its liabilities. A current ratio below <code>1</code> may indicate that the company may have difficulty meeting its short-term obligations. This makes sense.</p>




<h3 id="ppe">Property, Plant, and Equipment
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#ppe" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>This is the value of a company’s physical assets, such as land, buildings, machinery, and equipment. It is important to consider the value of PPE when evaluating a company’s financial health and potential for growth. A company with a significant amount of PPE may have a competitive advantage in its industry, as it may be able to produce goods or services more efficiently than its competitors. However, it is also important to consider the age and condition of the PPE, as well as any potential liabilities associated with it. In the title of this chapter, it says <code>For Warren Not Having Them Is A Good Thing</code> <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f923.png" alt="🤣" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>




<h3 id="short">Short Term Debt
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#short" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>From Warren’s perspective, when it comes to investing in financial institutions, he’s always shied away from companies who are bigger borrowers in short-term than long-term.</p>
<p><code>\(Short Term Debt/ Long Term Debt\)</code></p>
<p>Not really sure what the heuristic threshold is, but let’s use <code>less than 1</code> as a good indicator?</p>




<h3 id="long">Long Term Debt
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#long" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>As a general rule, a company with durable competitve edge, will have no or little long term debt to maintain their business operation. Let’s ensure this is not an uptrend on visualization</p>




<h3 id="retained">Retained Earnings
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#retained" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Retained earnings is the portion of a company’s net income that is retained and not distributed as dividends to shareholders. It represents the accumulated profits that a company has reinvested in its business over time. Retained earnings can be used for various purposes, such as funding research and development, expanding operations, paying off debt, or acquiring other companies. It is an important metric for investors to consider when evaluating a company’s financial health and growth potential, as it indicates how much profit the company has generated and how it has been utilized to support its long-term success.</p>
<p><code>\(Growth Rate = (Ending Retained Earnings/Beginning Retained Earnings)^{1/years}-1\)</code></p>




<h3 id="treasury">Treasury Stock
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#treasury" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Treasury stock refers to shares that a company has repurchased from its shareholders. These shares are held in the company’s treasury and are not considered outstanding shares. Treasury stock can be used for various purposes, such as to increase shareholder value, to have shares available for employee compensation plans, or to prevent hostile takeovers. When a company repurchases its own shares, it reduces the number of outstanding shares in the market, which can increase the value of the remaining shares and potentially boost earnings per share (EPS). However, it is important for investors to consider the reasons behind a company’s decision to buy back its own stock and how it may impact the company’s financial health and long-term growth prospects.</p>




<h3 id="ROSE">Return On Shareholders’ Equity
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#ROSE" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p><code>\(Return On Shareholders' Equity = Net Income / Shareholders' Equity\)</code></p>
<p>According to the book, <code>high ROSE means come play</code> <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f923.png" alt="🤣" class="wp-smiley" style="height: 1em; max-height: 1em;" /> How about stop and smell the rose? <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f339.png" alt="🌹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The book did not tell us exactly what the threshold is, but the companies of choice has about <code>~30-35%</code></p>




<h4 id="metrics">Metrics
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#metrics" rel="nofollow" target="_blank"></a>
</h4>
<pre>balance_metric &lt;- function(df, income) {
  df_b &lt;- df |&gt;
    mutate(currentRatio = totalCurrentAssets / totalCurrentLiabilities,
           netReceivablesToGrossSale = currentNetReceivables / income$grossProfit,
           shortToLongTermDebt = shortTermDebt / longTermDebt,
           growthRateRetainedEarnings = (retainedEarnings / lag(retainedEarnings))^(1/n()) - 1,
           returnOnShareholdersEquity = income$netIncome / totalShareholderEquity)
  
  hline &lt;- tribble(
    ~param, ~hline_value, ~color2,
    &quot;currentRatio&quot;, 1, &quot;red&quot;, 
    &quot;netReceivablesToGrossSale&quot;, 0.05, &quot;blue&quot;,
    &quot;shortToLongTermDebt&quot;, 1, &quot;blue&quot;,
    &quot;growthRateRetainedEarnings&quot;, 0.05, &quot;red&quot;,
    &quot;returnOnShareholdersEquity&quot;, 0.3, &quot;red&quot;
  ) |&gt;
    mutate(
      param = factor(param),
      ymin = ifelse(color2 == &quot;red&quot;, -Inf, hline_value),
      ymax = ifelse(color2 == &quot;red&quot;, hline_value, Inf)
    )
  
  columns &lt;- hline$param
  
  plot &lt;- df_b |&gt;
    select(fiscalDateEnding, currentRatio:returnOnShareholdersEquity) |&gt;
    pivot_longer(cols = c(currentRatio:returnOnShareholdersEquity), 
                 names_to = &quot;param&quot;, values_to = &quot;values&quot;) |&gt;
    mutate(param = factor(param, levels = columns)) |&gt; 
    ggplot(aes(x = fiscalDateEnding, y = values)) +
    geom_rect(
      data = hline,
      aes(ymin = ymin, ymax = ymax, fill = color2),
      xmin = -Inf, xmax = Inf,
      alpha = 0.15,
      inherit.aes = FALSE
    ) +
    geom_line() +
    facet_wrap(. ~ param, scale = &quot;free_y&quot;) +
    scale_fill_identity() +
    theme_bw()
  
  return(plot)
}

balance_metric(balance, income)
</pre><img src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-4-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />




<h2 id="cashflow">Cash Flow
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#cashflow" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>




<h3 id="operating">Operating Income
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#operating" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Cash flow from operating income starts with net income and then add back depreciation and amortization. This is because depreciation and amortization are non-cash expenses that reduce net income but do not actually involve a cash outflow. By adding them back, we can get a better picture of the actual cash generated by the company’s operations.</p>




<h3 id="capex">Capital Expenditure
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#capex" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Also known as CapEx, refers to the funds that a company uses to acquire, upgrade, and maintain physical assets such as property, buildings, technology, equipment, or machinery. CapEx is an important metric for investors to consider when evaluating a company’s financial health and growth potential, as it indicates how much the company is investing in its long-term success.</p>
<p>If we were to look at Apple’s cash flow statement, CapEx is payments for acquisition of proptery, plant, and equipment.</p>
<p><code>\(Capital Expenditure/Net Earning\)</code></p>
<p>And the heuristic is <code>~50% or less</code>.</p>




<h3 id="buyback">Stock Buyback
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#buyback" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<p>Stock buyback, also known as share repurchase, refers to a company’s practice of buying back its own shares from the open market. This can be done for various reasons, such as to increase shareholder value, to have shares available for employee compensation plans, or to prevent hostile takeovers. When a company repurchases its own shares, it reduces the number of outstanding shares in the market, which can increase the value of the remaining shares and potentially boost earnings per share (EPS).</p>
<p>On the Apple cash flow statement, stock buyback is listed as repurchase of common stocks. Others might use issuance of (retirement) stocks.</p>




<h4 id="metrics-1">Metrics
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#metrics-1" rel="nofollow" target="_blank"></a>
</h4>
<pre>cashflow_metric &lt;- function(df) {
  df_c &lt;- df |&gt;
    mutate(operatingCashFlow = netIncome + depreciationDepletionAndAmortization,
           capitalExpenditureToNetEarning = capitalExpenditures / netIncome,
           stockBuybackToNetEarning = abs(proceedsFromRepurchaseOfEquity / netIncome))
  
  hline &lt;- tribble(
    ~param, ~hline_value, ~color2,
    &quot;operatingCashFlow&quot;, 0, &quot;red&quot;, 
    &quot;capitalExpenditureToNetEarning&quot;, 0.5, &quot;blue&quot;,
    &quot;stockBuybackToNetEarning&quot;, 0.5, &quot;red&quot;
  ) |&gt;
    mutate(
      param = factor(param),
      ymin = ifelse(color2 == &quot;red&quot;, -Inf, hline_value),
      ymax = ifelse(color2 == &quot;red&quot;, hline_value, Inf)
    )
  
  columns &lt;- hline$param
  
  plot &lt;- df_c |&gt;
    select(fiscalDateEnding, operatingCashFlow, capitalExpenditureToNetEarning, stockBuybackToNetEarning) |&gt;
    pivot_longer(cols = c(operatingCashFlow, capitalExpenditureToNetEarning, stockBuybackToNetEarning), 
                 names_to = &quot;param&quot;, values_to = &quot;values&quot;) |&gt;
    mutate(param = factor(param, levels = columns)) |&gt; 
    ggplot(aes(x = fiscalDateEnding, y = values)) +
    geom_rect(
      data = hline,
      aes(ymin = ymin, ymax = ymax, fill = color2),
      xmin = -Inf, xmax = Inf,
      alpha = 0.15,
      inherit.aes = FALSE
    ) +
    geom_line() +
    facet_wrap(. ~ param, scale = &quot;free_y&quot;) +
    scale_fill_identity() +
    theme_bw()
  
  return(plot)
}

cashflow_metric(cashflow)
</pre><img src="https://i1.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-5-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Use key valuation metrics (P/E, EV/EBITDA, P/B, P/S, etc) to determine how cheap or expensive a stock is.</p>




<h2 id="combine">Combine All Metrics
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#combine" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<details>
<summary>code</summary>
<pre>library(httr)
library(jsonlite)
library(tidyverse)
library(ggpubr)

api_key &lt;- Sys.getenv(&quot;avkey&quot;)

## Create a function to pull data
get_data &lt;- function(fx,ticker,share=F) {
  raw &lt;- GET(paste0(
    &quot;https://www.alphavantage.co/query?function=&quot;,fx,
    &quot;&#038;symbol=&quot;,ticker,&quot;&#038;apikey=&quot;, api_key
  )) %&gt;%
    content(as = &quot;text&quot;, encoding = &quot;UTF-8&quot;) %&gt;%
    fromJSON()
  
  if (share==T) {
    df &lt;- raw$annualEarnings |&gt;
      select(fiscalDateEnding, reportedEPS) |&gt;
      mutate(fiscalDateEnding = ymd(fiscalDateEnding))
  } else {
  df &lt;- raw$annualReports |&gt; 
    as_tibble() |&gt;
    mutate(fiscalDateEnding = as.Date(fiscalDateEnding)) |&gt;   
    mutate(across(where(is.character), as.numeric)) |&gt;        
    arrange(fiscalDateEnding)
  }

  return(df)
}

income_metric &lt;- function(df) {
  df_i &lt;- df |&gt;
    mutate(grossProfitMargin = grossProfit / totalRevenue,
           depreciationToGrossProfit = depreciationAndAmortization / grossProfit,
           interestExpenseToOperatingIncome = interestExpense / operatingIncome,
           netEarningMargin = netIncome / totalRevenue,
           operatingMargin = operatingIncome / totalRevenue)
  
  hline &lt;- tribble(
    ~param, ~hline_value, ~color2,
    &quot;grossProfitMargin&quot;, 0.4, &quot;red&quot;, 
    &quot;depreciationToGrossProfit&quot;, 0.07, &quot;blue&quot;,
    &quot;interestExpenseToOperatingIncome&quot;, 0.15, &quot;blue&quot;,
    &quot;netEarningMargin&quot;, 0.2, &quot;red&quot;,
    &quot;operatingMargin&quot;, 0.1, &quot;red&quot;
  ) |&gt;
    mutate(
      param = factor(param),
      ymin = ifelse(color2 == &quot;red&quot;, -Inf, hline_value),
      ymax = ifelse(color2 == &quot;red&quot;, hline_value, Inf)
    )
  
  columns &lt;- hline$param
  
  plot &lt;- df_i |&gt;
    select(fiscalDateEnding, grossProfitMargin:operatingMargin) |&gt;
    pivot_longer(cols = c(grossProfitMargin:operatingMargin), 
                 names_to = &quot;param&quot;, values_to = &quot;values&quot;) |&gt;
    mutate(param = factor(param, levels = columns)) |&gt; 
    ggplot(aes(x = fiscalDateEnding, y = values)) +
    geom_rect(
      data = hline,
      aes(ymin = ymin, ymax = ymax, fill = color2),
      xmin = -Inf, xmax = Inf,
      alpha = 0.15,
      inherit.aes = FALSE
    ) +
    geom_line() +
    facet_wrap(. ~ param, scale = &quot;free_y&quot;) +
    scale_fill_identity() +
    theme_bw() +
    ggtitle(&quot;Income Statement Metrics&quot;)
  
  return(plot)
}

share_metric &lt;- function(df) {
    plot &lt;- df |&gt;
      mutate(reportedEPS = as.numeric(reportedEPS)) |&gt;
      ggplot(aes(x = fiscalDateEnding, y = reportedEPS)) +
      geom_line() +
      geom_smooth() +
      theme_bw() +
      ggtitle(&quot;Share Metrics&quot;)
    return(plot)
}

balance_metric &lt;- function(df, income) {
  df_b &lt;- df |&gt;
    mutate(currentRatio = totalCurrentAssets / totalCurrentLiabilities,
           netReceivablesToGrossSale = currentNetReceivables / income$grossProfit,
           shortToLongTermDebt = shortTermDebt / longTermDebt,
           growthRateRetainedEarnings = (retainedEarnings / lag(retainedEarnings))^(1/n()) - 1,
           returnOnShareholdersEquity = income$netIncome / totalShareholderEquity)
  
  hline &lt;- tribble(
    ~param, ~hline_value, ~color2,
    &quot;currentRatio&quot;, 1, &quot;red&quot;, 
    &quot;netReceivablesToGrossSale&quot;, 0.3, &quot;blue&quot;,
    &quot;shortToLongTermDebt&quot;, 1, &quot;blue&quot;,
    &quot;growthRateRetainedEarnings&quot;, 0.05, &quot;red&quot;,
    &quot;returnOnShareholdersEquity&quot;, 0.3, &quot;red&quot;
  ) |&gt;
    mutate(
      param = factor(param),
      ymin = ifelse(color2 == &quot;red&quot;, -Inf, hline_value),
      ymax = ifelse(color2 == &quot;red&quot;, hline_value, Inf)
    )
  
  columns &lt;- hline$param
  
  plot &lt;- df_b |&gt;
    select(fiscalDateEnding, currentRatio:returnOnShareholdersEquity) |&gt;
    pivot_longer(cols = c(currentRatio:returnOnShareholdersEquity), 
                 names_to = &quot;param&quot;, values_to = &quot;values&quot;) |&gt;
    mutate(param = factor(param, levels = columns)) |&gt;
    ggplot(aes(x = fiscalDateEnding, y = values)) +
    geom_rect(
      data = hline,
      aes(ymin = ymin, ymax = ymax, fill = color2),
      xmin = -Inf, xmax = Inf,
      alpha = 0.15,
      inherit.aes = FALSE
    ) +
    geom_line() +
    facet_wrap(. ~ param, scale = &quot;free_y&quot;) +
    scale_fill_identity() +
    theme_bw() +
    ggtitle(&quot;Balance Sheet Metrics&quot;)
  
  return(plot)
}

cashflow_metric &lt;- function(df, income) {
  df_c &lt;- df |&gt;
    mutate(operatingCashFlow = netIncome + depreciationDepletionAndAmortization,
           capitalExpenditureToNetEarning = capitalExpenditures / netIncome,
           stockBuybackToNetEarning = case_when(
             proceedsFromRepurchaseOfEquity &lt; 0 ~ -proceedsFromRepurchaseOfEquity / income$netIncome,
             income$netIncome &lt; 0 &#038; proceedsFromRepurchaseOfEquity &gt; 0 ~ NA_real_,
             income$netIncome &lt; 0 &#038; proceedsFromRepurchaseOfEquity &lt; 0 ~-proceedsFromRepurchaseOfEquity / income$netIncome))
  
  hline &lt;- tribble(
    ~param, ~hline_value, ~color2,
    &quot;operatingCashFlow&quot;, 0, &quot;red&quot;, 
    &quot;capitalExpenditureToNetEarning&quot;, 0.5, &quot;blue&quot;,
    &quot;stockBuybackToNetEarning&quot;, 0.5, &quot;red&quot;
  ) |&gt;
    mutate(
      param = factor(param),
      ymin = ifelse(color2 == &quot;red&quot;, -Inf, hline_value),
      ymax = ifelse(color2 == &quot;red&quot;, hline_value, Inf)
    )
  
  columns &lt;- hline$param
  
  plot &lt;- df_c |&gt;
    select(fiscalDateEnding, operatingCashFlow, capitalExpenditureToNetEarning, stockBuybackToNetEarning) |&gt;
    pivot_longer(cols = c(operatingCashFlow, capitalExpenditureToNetEarning, stockBuybackToNetEarning), 
                 names_to = &quot;param&quot;, values_to = &quot;values&quot;) |&gt;
    mutate(param = factor(param, levels = columns)) |&gt; 
    ggplot(aes(x = fiscalDateEnding, y = values)) +
    geom_rect(
      data = hline,
      aes(ymin = ymin, ymax = ymax, fill = color2),
      xmin = -Inf, xmax = Inf,
      alpha = 0.15,
      inherit.aes = FALSE
    ) +
    geom_line() +
    facet_wrap(. ~ param, scale = &quot;free_y&quot;) +
    scale_fill_identity() +
    theme_bw() +
    ggtitle(&quot;Cash Flow Metrics&quot;)
  
  return(plot)
}

show_all &lt;- function(name) {
  income &lt;- get_data(&quot;INCOME_STATEMENT&quot;,name)
  share &lt;- get_data(&quot;EARNINGS&quot;,name,share=T)
  balance &lt;- get_data(&quot;BALANCE_SHEET&quot;,name)
  cashflow &lt;- get_data(&quot;CASH_FLOW&quot;,name)
  plot1 &lt;- income_metric(income) 
  plot2 &lt;- share_metric(share)
  plot3 &lt;- balance_metric(balance, income)
  plot4 &lt;- cashflow_metric(cashflow, income)
  stacked_plot &lt;- ggarrange(plot1,plot3,nrow=2)
  squished_plot &lt;- ggarrange(plot4,plot2,ncol=2, widths = c(2,1))
  combineplot &lt;- ggarrange(plotlist = list(stacked_plot,squished_plot), nrow = 2, heights = c(2,1))
  return(combineplot)
}
</pre></details>




<h2 id="another">Let’s Look At Another Example
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#another" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<p>As a heuristics, we’ve made our dataviz where <code>red is like lava</code>, you want to stay above it. <code>Blue is like the sky</code>, you want to stay below it. The sweet zone is in between. <img src="https://s.w.org/images/core/emoji/13.0.0/72x72/1f923.png" alt="🤣" class="wp-smiley" style="height: 1em; max-height: 1em;" /> When there is a loess curve, we are trying to see if the share is consistently increasing.</p>




<h4 id="apple">Apple
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#apple" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;AAPL&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-7-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Looking the income metrics, Apple seems to be doing pretty good. Gross profit margin, net earning margin, operating income margin are all above thresholds. Depreciation to gross profit ratio is appropriately below the threshold, which means there is no recent purchase of property, plants, machines, etc where these are the ones that will add to depreciation. There is also a low to no interest expense, which is good! No debt? Next we move on to balance sheet metrics, current ratio is not great, liquidity is not great, net receivable is ?OK, I guess it make sense, if your products are popular and provide some sort of finance option, you might have some receivables. Short term debt is much lower than long term debt, which is good. The ROSE is smelling pretty good there too! In terms of cash flow metrics, it’s looking really good, it has high cash flowing in, low CapEx, and consistently buying its own share from 2020 onwards.</p>




<h4 id="microsoft">Microsoft
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#microsoft" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;MSFT&quot;)
</pre><img src="https://i2.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-8-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>As for Microsoft, now that we’re a bit more familiar with the sections, let’s just string our read instead of separating them. Good consistent profit for all profit, operating and net income. Interestingly, depreciation is high along with CapEx, did they buy property, plants or machine? 
<a href="https://www.ciodive.com/news/microsoft-azure-capacity-constraints-datacenter-buildouts-cloud-ai/722912/" rel="nofollow" target="_blank">Ah, they built data center?</a> Interest expense is low, which is good. Good liquidity factor with current ratio above threshold, net receivables is OK same as Apple (a competitor), short/long debt is good as well. ROSE is close to the threshold (worth watching). Cash is flowing, not much stock buyback, but overall EPS is consistently increasing. With its investment in data centers for Azure, next few years we should be seeing a persistent depreciation to gross profit ratio, along with CapEx, right? I read somewhere where you can’t place all depreciation in a single year.</p>




<h4 id="nvidia">NVIDIA
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#nvidia" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;NVDA&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-9-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Now let’s take a look at NVIDIA. Wow, gross profit, operating income, and net earning margin all really good, better than Apple and Microsoft! Well, make sense with all these data centers, they need GPUs from NVIDIA. Look at that depreciation and CapEx, barely any! That’s great, less to maintain and the current plants they have are adequate to supply the demand. Low interest expense too, not much debt interest. Liquidity is great with high current ratio! Net receivables is good too, these big companies are paying NVIDIA back! ROSE is also very fragrant! Cash is flowing through the roof. Not much stock buyback. Also exponential EPS! You know, Warren did say that be mindful of companies with R&D cost.</p>




<h4 id="intel">Intel
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#intel" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;INTC&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-10-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Wow, first glance with the profits, we’re seeing lava red. We then see high rise in depreciation and CapEx. Did they buy more property, plants, or machines? 
<a href="https://newsroom.intel.com/press-kit/intel-invests-ohio" rel="nofollow" target="_blank">Intel announces plans for an investment of more than $28 billion for two new chip factories in Licking County, Ohio</a>. And maybe Germany and Arizona too? Interesting. Notice that the interest expense towards the end of 2025 was in 2 digit but negative? It’s because the the operating income was negative and a high interest expense. I wonder if I should make this absolute as opposed to keeping the negative. Anyway, this means that not only was Intel in the red but also paying quite a bit of interest from the debt, I assume. The current ratio looks pretty good, same goes with the net receivables. Short term debt is also much lower compared to long term. ROSE not so good. As for the cash flow, when we add depreciation and demortization back to net income, it brought the red back up. Notice how the EPS dropped significantly lately, and notice that the buyback of share is missing? We code it where if it’s a positive value of buyback, which means it’s issuing stock instead of repurchasing, hence NA. Wow, what do you think? Will they be able to turn this around? Do data centers use Intel chips or AMD’s threadripper?</p>




<h4 id="amd">AMD
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#amd" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;AMD&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-11-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Interesting income statement metric results. Good gross profit margin, but the net earning is barely. Interesting depreciation trend, what happened in 2024, where CapEx didn’t budge? Great liquidity, pretty high net receivables. Wow, very high short-to-long term debt in ?2021-2022. ROSE is essentially 0. With cash flowing good towards 2025, and also high buybacks 2022 ish. Finally, uptrending EPS! This is an odd one. Pasting my observation onto Claude and wow, these findings are due to Xilinx acquisition. That makes sense! Didn’t build new plants, old property, plants, machines have already been amortized, hence low depreciation. The acquisition is funded by debt, hence high short-to-long term debt ratio. Very interesting, indeed! So, it could be true that data centers prefer AMD over Intel given the good profit?</p>




<h4 id="google">Google
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#google" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;GOOG&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-12-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Very good profit of all 3 metrics. After 2020, depreciation downtrended which is good and so did CapEx. Not much debt. Downtrending current ratio but still good. Very good net receivables! ROSE is coming up. Great cash flow. There is buyback of equity. Rising EPS. All great signs for Google! Being an all-service (no hardware?) company, this is quite good and healthy!</p>




<h4 id="3m">3M
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#3m" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;MMM&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-13-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Now on to 3M, not a tech company, but let’s see if our workflow of looking at financial statement will help us tell a story. Profit is not as great as other tech companies we looked at, though gross profit is above threshold, but the net earnings is in the lava. Notice both net earnings and operating margins dipped quite low in 2024? And then a pretty high interest expense to operating income ratio in 2025? I wonder if because of losing money, they borrowed long term, hence short-to-long term debt is not too high? Current ratio is acceptable, but why is net receivables so high for 3M? Clients were not able to pay 3M? ROSE is pretty good in 2024 and 2025 even when profits weren’t. But why? Cash flow with high variance last 3 years. There is stock buyback in 2025. And even though EPS downtrended past 2 years but still remained high. This is a very interesting one as well. 3M should be a company where there’s competitive advantage because they make lots of daily usables which doesn’t need a whole lot of R&D. But why the anomaly in 2024 requiring debt? What do you think?</p>




<h4 id="disney">Disney
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#disney" rel="nofollow" target="_blank"></a>
</h4>
<pre>show_all(&quot;DIS&quot;)
</pre><img src="https://i0.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-14-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Alright, what about Disney? Profit doesn’t seem as good as I expected. Both gross profit and net earning margins were below threshold, except for operating income margin. Interesting, in 2021, there is increase in depreciation, CapEx, and interest expense with low short-to-long debt ratio. It almost looked like they borrowed some money to purchase something new? Did they rebuild a park or something? In terms of liquidity, it’s on the lava zone in 2025 and seemed like it downtrended for the past 3 years as well. Net receivables is OK? Though I would think it should be lower? ROSE is red. Cash flow looks good, this is interesting because whatever that caused the depreciation when added back now they have cash. Also interesting to note that from 2020 to 2024 they were issuing stock rather than buying back. Their EPS appear to be quite volatile for the pat 3 years.</p>




<h3 id="boeing">Boeing
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#boeing" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h3>
<pre>show_all(&quot;BA&quot;)
</pre><img src="https://i1.wp.com/www.kenkoonwong.com/blog/financial-statement/index_files/figure-html/unnamed-chunk-15-1.png?w=450&#038;ssl=1" data-recalc-dims="1" />
<p>Last but not least, let’s look at Boeing. Three profit margin metrics in the lava zone. Spike of interest expense in 2021 along with depreciation. Something physical was bought with borrowed money that’s paid long term. Current ratio is good. Essentially no net receivables. Consistent floating ROSE on the red sea. Operating cash flow in the red for a few years then positive in 2025. CapEx spiked in 2025, ?what was spent in capital where it doesn’t really depreciate? Buyback stock is interesting, missing several past few years, essentially issuing stocks when we have NA data. EPS downtrend to the negatives.</p>




<h2 id="opportunities">Opportunities For Improvement
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#opportunities" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<ul>
<li>We need to recheck growth rate again, not sure if the code is correct</li>
<li>perhaps build this into an R package, and develop further</li>
<li>Learn about valuation metrics such as P/E, EV/EBITDA, P/B, P/S</li>
<li>Not really sure if short-to-long term debt ratio of 1 is a good threshold, seems too high.</li>
<li>include actual numbers on geom_label with ggrepel and reduce font size</li>
</ul>




<h2 id="lessons">Lessons learnt
  <a href="https://www.kenkoonwong.com/blog/financial-statement/#lessons" rel="nofollow" target="_blank"><svg class="anchor-symbol" aria-hidden="true" height="26" width="26" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="currentColor"></path>
      <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path>
    </svg></a>
</h2>
<ul>
<li>Depreciation and CapEx seem to have strong correlation, which makes sense.</li>
<li>learnt Alpha Vantage API, quite straight forward</li>
<li>learnt to look at financial statement and its metrics</li>
</ul>
<p>If you like this article:</p>
<ul>
<li>please feel free to send me a 
<a href="https://www.kenkoonwong.com/blog/" rel="nofollow" target="_blank">comment or visit my other blogs</a></li>
<li>please feel free to follow me on 
<a href="https://bsky.app/profile/kenkoonwong.bsky.social" rel="nofollow" target="_blank">BlueSky</a>, 
<a href="https://twitter.com/kenkoonwong/" rel="nofollow" target="_blank">twitter</a>, 
<a href="https://github.com/kenkoonwong/" rel="nofollow" target="_blank">GitHub</a> or 
<a href="https://rstats.me/@kenkoonwong" rel="nofollow" target="_blank">Mastodon</a></li>
<li>if you would like collaborate please feel free to 
<a href="https://www.kenkoonwong.com/contact/" rel="nofollow" target="_blank">contact me</a></li>
</ul>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.kenkoonwong.com/blog/financial-statement/"> r on Everyday Is A School Day</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/navigating-financial-statement-and-the-story-it-tells-us-a-note-to-myself/">Navigating Financial Statement And The Story It Tells Us – A Note To Myself</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400170</post-id>	</item>
		<item>
		<title>Explaining Time-Series Forecasts with Sensitivity Analysis (ahead::dynrmf and external regressors)</title>
		<link>https://www.r-bloggers.com/2026/03/explaining-time-series-forecasts-with-sensitivity-analysis-aheaddynrmf-and-external-regressors/</link>
		
		<dc:creator><![CDATA[T. Moudiki]]></dc:creator>
		<pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://thierrymoudiki.github.io//blog/2026/03/29/r/sensi-dynrmf</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> Explaining Time-Series Forecasts with Sensitivity Analysis (ahead::dynrmf and external regressors)</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/explaining-time-series-forecasts-with-sensitivity-analysis-aheaddynrmf-and-external-regressors/">Explaining Time-Series Forecasts with Sensitivity Analysis (ahead::dynrmf and external regressors)</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://thierrymoudiki.github.io//blog/2026/03/29/r/sensi-dynrmf"> T. Moudiki's Webpage - R</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>
<p>Following <a href="https://thierrymoudiki.github.io/blog/2026/03/08/r/exact-shapley-dynrmf" rel="nofollow" target="_blank">the post on exact Shapley values</a> for time series explainability, this post illustrates an example of how to use sensitivity analysis  to explain time-series forecasts, based on the <code>ahead::dynrmf</code> model and external regressors. What is <strong>sensitivity analysis</strong> in this context? It’s about evaluating the impact of changes in the external regressors on the time-series forecast.</p>

<p>The post uses the <a href="https://docs.techtonique.net/ahead/reference/dynrmf_sensi.html" rel="nofollow" target="_blank"><code>ahead::dynrmf_sensi</code></a> function to compute the sensitivities, and the <a href="https://docs.techtonique.net/ahead/reference/plot_dynrmf_sensitivity.html" rel="nofollow" target="_blank"><code>ahead::plot_dynrmf_sensitivity</code></a> function to plot the results.</p>

<p>First, install the package:</p>

<pre>devtools::install_github(&quot;Techtonique/ahead&quot;)
</pre>

<p>Then, run the following code:</p>

<pre># devtools::install_github(&quot;Techtonique/ahead&quot;)
# install.packages(c(&quot;fpp2&quot;, &quot;e1071&quot;, &quot;patchwork&quot;))

library(ahead)
library(fpp2)
library(patchwork)
library(e1071)

#' # Example 1: US Consumption vs Income
sensitivity_results_auto &lt;- ahead::dynrmf_sensi(
y = fpp2::uschange[, &quot;Consumption&quot;],
xreg = fpp2::uschange[, &quot;Income&quot;],
h = 10
)

plot1 &lt;- ahead::plot_dynrmf_sensitivity(sensitivity_results_auto, 
                           title = &quot;Sensitivity of Consumption to Income (Ridge)&quot;,
                           y_label = &quot;Effect (ΔConsumption / ΔIncome)&quot;)

#' # Example 1: US Consumption vs Income
sensitivity_results_auto_svm &lt;- ahead::dynrmf_sensi(
  y = fpp2::uschange[, &quot;Consumption&quot;],
  xreg = fpp2::uschange[, &quot;Income&quot;],
  h = 10, 
  fit_func = e1071::svm # additional parameter passed to ahead::dynrmf
)

plot2 &lt;- ahead::plot_dynrmf_sensitivity(sensitivity_results_auto_svm, 
                                        title = &quot;Sensitivity of Consumption to Income (SVM)&quot;,
                                        y_label = &quot;Effect (ΔConsumption / ΔIncome)&quot;)

 
# Example 2: TV Advertising vs Insurance Quotes
sensitivity_results_tv &lt;- ahead::dynrmf_sensi(
 y = fpp2::insurance[, &quot;Quotes&quot;],
   xreg = fpp2::insurance[, &quot;TV.advert&quot;],
   h = 8
 )

plot3 &lt;- ahead::plot_dynrmf_sensitivity(sensitivity_results_tv,
                           title = &quot;Sensitivity of Insurance Quotes to TV Advertising (Ridge)&quot;,
                           y_label = &quot;Effect (ΔQuotes / ΔTV.advert)&quot;)

sensitivity_results_tv_svm &lt;- ahead::dynrmf_sensi(
  y = fpp2::insurance[, &quot;Quotes&quot;],
  xreg = fpp2::insurance[, &quot;TV.advert&quot;],
  h = 8, 
  fit_func = e1071::svm # additional parameter passed to ahead::dynrmf
)

plot4 &lt;- ahead::plot_dynrmf_sensitivity(sensitivity_results_tv_svm,
                                        title = &quot;Sensitivity of Insurance Quotes to TV Advertising (SVM)&quot;,
                                        y_label = &quot;Effect (ΔQuotes / ΔTV.advert)&quot;)

(plot1+plot2)

(plot3+plot4)
</pre>

<p><img src="https://i0.wp.com/thierrymoudiki.github.io/images/2026-03-29/2026-03-29-image1.png?w=578&#038;ssl=1" alt="image-title-here" class="img-responsive" data-recalc-dims="1" />
<img src="https://i1.wp.com/thierrymoudiki.github.io/images/2026-03-29/2026-03-29-image2.png?w=578&#038;ssl=1" alt="image-title-here" class="img-responsive" data-recalc-dims="1" /></p>


<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://thierrymoudiki.github.io//blog/2026/03/29/r/sensi-dynrmf"> T. Moudiki's Webpage - R</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/explaining-time-series-forecasts-with-sensitivity-analysis-aheaddynrmf-and-external-regressors/">Explaining Time-Series Forecasts with Sensitivity Analysis (ahead::dynrmf and external regressors)</a>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400155</post-id>	</item>
		<item>
		<title>Momentum Investing Enhanced by Microsoft Foundry-Hosted Large Language Model</title>
		<link>https://www.r-bloggers.com/2026/03/momentum-investing-enhanced-by-microsoft-foundry-hosted-large-language-model/</link>
		
		<dc:creator><![CDATA[Selcuk Disci]]></dc:creator>
		<pubDate>Sat, 28 Mar 2026 12:48:37 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">http://datageeek.com/?p=11857</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; "> LLM-enhanced momentum investing combines traditional momentum signals with real-time news interpretation by large language models (LLMs). The idea is straightforward: stocks with strong past returns are candidates for momentum portfolios, but their inclusion and weight are refined by LLM-generated sentiment scores derived from firm-specific news. This hybrid approach improves risk-adjusted ...</div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/momentum-investing-enhanced-by-microsoft-foundry-hosted-large-language-model/">Momentum Investing Enhanced by Microsoft Foundry-Hosted Large Language Model</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://datageeek.com/2026/03/28/momentum-investing-enhanced-by-microsoft-foundry-hosted-large-language-model/"> DataGeeek</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p class="wp-block-paragraph"><strong><a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5680782" rel="nofollow" target="_blank"><em>LLM-enhanced momentum investing</em></a></strong> combines traditional momentum signals with real-time news interpretation by large language models (LLMs). The idea is straightforward: stocks with strong past returns are candidates for momentum portfolios, but their inclusion and weight are refined by LLM-generated sentiment scores derived from firm-specific news. This hybrid approach improves <strong>risk-adjusted returns</strong> (Sharpe, Sortino) and is particularly effective in concentrated, high-conviction portfolios.</p>



<p class="wp-block-paragraph"><strong>Key Parameters</strong></p>



<p class="wp-block-paragraph">1. <strong>Lookback Window (k)</strong></p>



<ul class="wp-block-list">
<li><strong>Definition:</strong> The number of past days of news considered for sentiment analysis.</li>



<li><strong>Role:</strong> Determines how much recent information the LLM uses to judge momentum continuation.</li>



<li><strong>Example:</strong> If k = 5, the model analyzes the last 5 business days of headlines and summaries for each stock. </li>
</ul>



<p class="wp-block-paragraph">2. <strong>Forecast Horizon (l)</strong></p>



<ul class="wp-block-list">
<li><strong>Definition:</strong> The period over which momentum continuation is predicted.</li>



<li><strong>Role:</strong> Sets the “target” for the LLM’s forecast — how far into the future the model should judge momentum persistence.</li>



<li><strong>Example:</strong> If <code>l = </code>5, the LLM predicts whether momentum will continue for the next 5 trading days.</li>



<li><strong>Connection to Rebalancing:</strong> The forecast horizon typically aligns with the rebalancing cycle. For weekly rebalancing, the horizon is 5 days; for monthly rebalancing, it’s ~21 days.</li>
</ul>



<p class="wp-block-paragraph">3. <strong>Portfolio Size (m)</strong></p>



<ul class="wp-block-list">
<li><strong>Definition:</strong> The number of stocks selected after LLM scoring.</li>



<li><strong>Role:</strong> Controls how concentrated or diversified the portfolio is.</li>



<li><strong>Example:</strong> From the top 20 YTD performers, you might select the top 10 after sentiment scoring.</li>
</ul>



<p class="wp-block-paragraph">4. <strong>Rebalancing Frequency (T)</strong></p>



<ul class="wp-block-list">
<li><strong>Definition:</strong> How often the portfolio is updated with new signals.</li>



<li><strong>Role:</strong> Sets the rhythm of portfolio refresh — weekly, monthly, or quarterly.</li>



<li><strong>Example:</strong> Weekly rebalancing means recalculating momentum and sentiment scores every 5 trading days.</li>
</ul>



<p class="wp-block-paragraph"><strong>Concept</strong></p>



<p class="wp-block-paragraph">The strategy begins with a <strong>classic momentum screen</strong>: select the <strong>top 20 S&#038;P 500 companies by year-to-date (YTD) performance</strong>. Instead of stopping there, the approach integrates <strong>large language model (LLM) sentiment analysis</strong> of firm-specific news. By analyzing the <strong>last 5 business days of headlines and summaries</strong>, the LLM produces a score indicating whether momentum is likely to continue.</p>



<p class="wp-block-paragraph">These scores are then used to <strong>re-weight the portfolio</strong>, tilting allocations toward companies with stronger news sentiment. Finally, the portfolio is narrowed to the <strong>top 10 conviction stocks</strong>.</p>



<p class="wp-block-paragraph"><strong>Selected Parameters</strong></p>



<ul class="wp-block-list">
<li><strong>Lookback Window:</strong> 5 days of firm-specific news.</li>



<li><strong>Rebalancing Frequency:</strong> Weekly updates of the portfolio.</li>



<li><strong>Forecast Horizon:</strong> 5 trading days (aligned with the rebalancing cycle).</li>
</ul>



<p class="wp-block-paragraph">This setup ensures that the LLM is asked to judge whether momentum will persist until the next rebalance, making the signals both <strong>short-term and actionable</strong>.</p>



<p class="wp-block-paragraph"><strong>What the Code Does Step by Step</strong></p>



<ol class="wp-block-list">
<li><strong>Fetching the Data</strong>
<ul class="wp-block-list">
<li>The <strong>R </strong>script first pulls all S&#038;P 500 tickers.</li>



<li>It calculates <strong>YTD returns</strong> for each stock.</li>



<li>The <strong>top 20 stocks</strong> by performance are selected as momentum candidates.</li>
</ul>
</li>



<li><strong>News Sentiment Analysis with LLM</strong>
<ul class="wp-block-list">
<li>For each of these 20 stocks, the code queries Bing News for recent headlines with <a href="https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/data-science-and-machine-learning#ai-services-in-azure" rel="nofollow" target="_blank"><em><strong>Azure AI Services</strong></em></a>.</li>



<li>The last <strong>5 business days of news</strong> are collected.</li>



<li>These headlines and summaries are sent to a <a href="https://learn.microsoft.com/en-us/azure/foundry/what-is-foundry" rel="nofollow" target="_blank"><strong><em>Microsoft Foundry</em></strong></a>-hosted LLM.</li>



<li>The LLM outputs a <strong>score (0–1)</strong> indicating whether sentiment supports momentum continuation or signals reversal.</li>
</ul>
</li>



<li><strong>Portfolio Tilting</strong>
<ul class="wp-block-list">
<li>LLM scores are normalized to [-1, +1].</li>



<li>Baseline equal weights are tilted according to these scores.</li>



<li>The <strong>top 10 stocks</strong> by adjusted weight form the final portfolio</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">4. <strong>Visualization</strong></p>



<ul class="wp-block-list">
<li>A styled table is created using the <a href="https://gt.rstudio.com/" rel="nofollow" target="_blank"><em><strong><code>gt</code> package</strong></em></a>.</li>



<li>Adjusted weights are color-coded (red–green gradient).</li>



<li>The final portfolio is saved as an image (<code>top10.png</code>).</li>
</ul>



<p class="wp-block-paragraph"><strong>Strategic Insight</strong></p>



<p class="wp-block-paragraph">This approach mirrors the methodology in the <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5680782" rel="nofollow" target="_blank"><em><strong>Swiss Finance Institute paper</strong></em></a>:</p>



<ul class="wp-block-list">
<li><strong>Momentum ranking</strong> provides the baseline.</li>



<li><strong>LLM sentiment scoring</strong> refines stock selection and weighting.</li>



<li><strong>Portfolio tilting</strong> integrates qualitative news signals into quantitative allocation.</li>
</ul>


<pre>
library(httr)
library(jsonlite)
library(tidyquant)
library(tidyverse)
library(lubridate)
library(gt)
library(gtExtras)
library(scales)
library(showtext)
library(webshot2)

# 1. Environment & Auth Setup
sysfonts::font_add_google(&quot;Roboto Slab&quot;, &quot;roboto_slab&quot;)
showtext_auto()

# Azure & Bing Credentials
bing_key           &lt;- &quot;&lt;your-bing-key&gt;&quot;
bing_endpoint      &lt;- &quot;&lt;your-bing-endpoint&gt;&quot; 
azure_llm_key      &lt;- &quot;&lt;your-llm-key&gt;&quot;
azure_llm_endpoint &lt;- &quot;&lt;your-llm-endpoint&gt;&quot;

# R Part (first): S&P 500 Screening with Monthly Returns
sp500_tickers &lt;- 
  tq_index(&quot;SP500&quot;) %&gt;% 
  select(symbol, company)

# Calculate YTD change
momentum_df &lt;- 
  sp500_tickers %&gt;%
  tq_get(get = &quot;stock.prices&quot;, from = floor_date(today(), &quot;year&quot;)) %&gt;%
  group_by(symbol) %&gt;%
  arrange(date) %&gt;% # Ensure chronological order for first/last functions
  summarize(
    total_return = (last(adjusted) / first(adjusted)) - 1, 
    .groups = &quot;drop&quot;
  ) %&gt;%
  inner_join(sp500_tickers, by = &quot;symbol&quot;) %&gt;%
  slice_max(total_return, n = 20) %&gt;%
  select(symbol, company)

# R Part (second): News Search and LLM Analysis
analyze_momentum_continuation &lt;- function(ticker, company_name) {
  
  # Construct the Bing News Search query: ticker + &#039; stock&#039;
  query_str &lt;- paste0(ticker, &quot; stock&quot;)
  news_url &lt;- paste0(bing_endpoint, &quot;v7.0/news/search&quot;)
  
  # Call Bing News Search API
  news_res &lt;- GET(news_url, add_headers(`Ocp-Apim-Subscription-Key` = bing_key), 
                  query = list(q = query_str, count = 5, freshness = &quot;Day&quot;))
  
  # Short pause to throttle calls and avoid rate limit errors
  Sys.sleep(1)
  
  news_text &lt;- &quot;&quot;
  if (status_code(news_res) == 200) {
    content &lt;- fromJSON(content(news_res, &quot;text&quot;, encoding = &quot;UTF-8&quot;))
    if (length(content$value) &gt; 0) {
      news_text &lt;- paste(content$value$name, content$value$description, collapse = &quot; | &quot;)
    }
  }
  
  # Construct the LLM payload for Azure AI Foundry
  prompt_payload &lt;- list(
    messages = list(
      list(role = &quot;system&quot;, content = &quot;You are an LLM Enhanced Momentum Investing Agent.&quot;),
      list(role = &quot;user&quot;, content = paste0(
        &quot;Headlines + Summaries for &quot;, company_name, &quot; (&quot;, ticker, &quot;): &quot;, news_text,
        &quot;\nPerform sentiment analysis based on the last 5 days of news (lookback=5, horizon=5). &quot;,
        &quot;Infer whether sentiment supports momentum continuation or signals reversal. &quot;,
        &quot;Return a JSON object with two fields: &#039;subsector&#039; (string) and &#039;llm_score&#039; (string: probability 0-1).&quot;))
    ),
    temperature = 0.1
  )
  
  llm_res &lt;- POST(url = azure_llm_endpoint, 
                  add_headers(`api-key` = azure_llm_key, `Content-Type` = &quot;application/json&quot;),
                  body = prompt_payload, encode = &quot;json&quot;)
  
  if (status_code(llm_res) == 200) {
    llm_out &lt;- fromJSON(content(llm_res, &quot;text&quot;, encoding = &quot;UTF-8&quot;))
    # Parse JSON response without using regex
    llm_json_data &lt;- fromJSON(llm_out$choices$message$content)
    return(as.data.frame(llm_json_data))
  } else {
    return(data.frame(subsector = &quot;N/A&quot;, llm_score = &quot;0.5&quot;))
  }
}

# Execute Analysis: Merge top 20 tickers with LLM scores
news_scores_df &lt;- momentum_df %&gt;%
  mutate(analysis = map2(symbol, company, analyze_momentum_continuation)) %&gt;%
  unnest(analysis) %&gt;%
  mutate(llm_score = as.numeric(llm_score))

# R Part (final): Portfolio Tilting and Visualization
# Normalize scores to [-1, +1] and tilt weights
tilted_portfolio &lt;- news_scores_df %&gt;%
  mutate(
    norm_score = rescale(llm_score, to = c(-1, 1), from = c(0, 1)),
    base_weight = 1 / n(),
    adj_weight = base_weight * (1 + norm_score)
  ) %&gt;%
  mutate(adj_weight = adj_weight / sum(adj_weight)) %&gt;%
  slice_max(adj_weight, n = 10)

# Create gt visualization using original column names
final_table &lt;- tilted_portfolio %&gt;%
  select(company, subsector, adj_weight) %&gt;%
  gt() %&gt;%
  tab_header(title = &quot;Top 10 Tilted S&P 500 Momentum Stocks&quot;) %&gt;%
  # Use cols_label for human-readable labels without renaming underlying columns
  cols_label(
    company = &quot;Company&quot;, 
    subsector = &quot;Subsector&quot;, 
    adj_weight = &quot;Adjusted Weight &quot;
  ) %&gt;%
  # Apply color intensity with scales::col_numeric
  data_color(
    columns = adj_weight, 
    colors = col_numeric(palette = c(&quot;red&quot;, &quot;green&quot;), domain = NULL)
  ) %&gt;%
  fmt_percent(
    columns = contains(&quot;adj_weight&quot;), 
    decimals = 2,
    locale = &quot;en&quot; 
  ) %&gt;% 
  cols_align(align = &quot;center&quot;) %&gt;%
  opt_table_font(font = google_font(&quot;Roboto Slab&quot;))

# Save the visualization as top10.png using webshot
gtsave(final_table, &quot;top10.png&quot;)
</pre>


<figure data-wp-context="{"imageId":"69c7da09160ee"}" data-wp-interactive="core/image" data-wp-key="69c7da09160ee" class="wp-block-image size-large wp-lightbox-container"><img loading="lazy" data-attachment-id="11859" data-permalink="https://datageeek.com/2026/03/28/momentum-investing-enhanced-by-microsoft-foundry-hosted-large-language-model/top10/" data-orig-file="https://datageeek.com/wp-content/uploads/2026/03/top10.png" data-orig-size="1500,1530" data-comments-opened="1" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0","alt":""}" data-image-title="top10" data-image-description="" data-image-caption="" data-medium-file="https://datageeek.com/wp-content/uploads/2026/03/top10.png?w=294" data-large-file="https://i1.wp.com/datageeek.com/wp-content/uploads/2026/03/top10.png?w=450&#038;ssl=1" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://i1.wp.com/datageeek.com/wp-content/uploads/2026/03/top10.png?w=450&#038;ssl=1" alt="" class="wp-image-11859" srcset_temp="https://i1.wp.com/datageeek.com/wp-content/uploads/2026/03/top10.png?w=450&#038;ssl=1 1004w, https://datageeek.com/wp-content/uploads/2026/03/top10.png?w=147 147w, https://datageeek.com/wp-content/uploads/2026/03/top10.png?w=294 294w, https://datageeek.com/wp-content/uploads/2026/03/top10.png?w=768 768w, https://datageeek.com/wp-content/uploads/2026/03/top10.png?w=1440 1440w, https://datageeek.com/wp-content/uploads/2026/03/top10.png 1500w" sizes="(max-width: 1004px) 100vw, 1004px" data-recalc-dims="1" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p class="wp-block-paragraph"><strong>Final Observation</strong></p>



<p class="wp-block-paragraph">Looking at the resulting portfolio, one striking feature is the <strong>dominance of energy and petroleum companies</strong>. Firms such as <strong>ConocoPhillips, EOG Resources, ExxonMobil, Occidental Petroleum, Marathon Petroleum, Valero, Phillips 66, Chevron, and Baker Hughes</strong> all appear prominently.</p>



<p class="wp-block-paragraph">This heavy tilt toward energy is not random—it reflects how <strong>geopolitical tensions (Iran and U.S.–Israel war dynamics)</strong> have amplified the importance of oil and gas in global markets. News sentiment around these companies has been strongly supportive of continued momentum, pushing them into the top allocation slots.</p>

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://datageeek.com/2026/03/28/momentum-investing-enhanced-by-microsoft-foundry-hosted-large-language-model/"> DataGeeek</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/momentum-investing-enhanced-by-microsoft-foundry-hosted-large-language-model/">Momentum Investing Enhanced by Microsoft Foundry-Hosted Large Language Model</a>]]></content:encoded>
					
		
		<enclosure url="https://datageeek.com/wp-content/uploads/2026/03/image.png" length="0" type="" />
<enclosure url="https://1.gravatar.com/avatar/db5e3f9ef188ea98fe38ab05c5a3fad9fb52fe3472715a8fc02f7ea41731f77c?s=96&#038;d=identicon&#038;r=G" length="0" type="" />
<enclosure url="https://datageeek.com/wp-content/uploads/2026/03/top10.png?w=1004" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">400135</post-id>	</item>
		<item>
		<title>Why Learning R is a Good Career Move in 2026</title>
		<link>https://www.r-bloggers.com/2026/03/why-learning-r-is-a-good-career-move-in-2026/</link>
		
		<dc:creator><![CDATA[The Jumping Rivers Blog]]></dc:creator>
		<pubDate>Thu, 26 Mar 2026 23:59:00 +0000</pubDate>
				<category><![CDATA[R bloggers]]></category>
		<guid isPermaLink="false">https://www.jumpingrivers.com/blog/why-learning-r-is-a-good-career-move-in-2026/</guid>

					<description><![CDATA[<div style = "width:60%; display: inline-block; float:left; ">
<p>Over the course of my career as a Data Scientist, I’ve worked on projects ranging from simple code reviews, to large application builds. For the most part, I have used R to do this.<br />
If you’re getting into coding or data science, one q...</p></div>
<div style = "width: 40%; display: inline-block; float:right;"></div>
<div style="clear: both;"></div>
<strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/why-learning-r-is-a-good-career-move-in-2026/">Why Learning R is a Good Career Move in 2026</a>]]></description>
										<content:encoded><![CDATA[<!-- 
<div style="min-height: 30px;">
[social4i size="small" align="align-left"]
</div>
-->

<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 12px;">
[This article was first published on  <strong><a href="https://www.jumpingrivers.com/blog/why-learning-r-is-a-good-career-move-in-2026/"> The Jumping Rivers Blog</a></strong>, and kindly contributed to <a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers</a>].  (You can report issue about the content on this page <a href="https://www.r-bloggers.com/contact-us/">here</a>)
<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div>

<p>
<a href = "https://www.jumpingrivers.com/blog/why-learning-r-is-a-good-career-move-in-2026/">
<img src="https://i1.wp.com/www.jumpingrivers.com/blog/why-learning-r-is-a-good-career-move-in-2026/featured.png?w=400&#038;ssl=1" style="width:400px" class="image-center" style="display: block; margin: auto;" data-recalc-dims="1" />
</a>
</p>
<p>Over the course of my career as a Data Scientist, I’ve worked on projects ranging from simple code reviews, to large application builds. For the most part, I have used R to do this.</p>
<p>If you’re getting into coding or data science, one question you’re probably asking yourself is <em>“Which language should I learn?”</em></p>
<p>This blog aims to show you why R might be a good decision.</p>
<aside class="advert">
<p>
Join us for our AI in Production conference! For more details, check out our
<a href="https://ai-in-production.jumpingrivers.com/" rel="nofollow" target="_blank">conference website!</a>
</p>
</aside>
<hr>
<h2 id="r-was-built-for-data-not-just-programming">R was built for data (not just programming)</h2>
<p>Unlike general purpose languages (such as Python), R was designed specifically for statistics and data analysis.</p>
<p>That means:</p>
<ul>
<li>Built in statistical tools</li>
<li>Powerful visualisation capabilities</li>
<li>Research level methods available immediately</li>
</ul>
<p>With packages like the <strong>tidyverse</strong>, you can clean, analyse, and visualise data with surprisingly little code.</p>
<hr>
<h2 id="high-demand-in-analytics-research-and-healthcare">High demand in analytics, research, and healthcare</h2>
<p>R is especially popular in many sectors such as:</p>
<ul>
<li>Healthcare &#038; biostats</li>
<li>Academic research</li>
<li>Government departments</li>
<li>Finance &#038; risk modeling</li>
<li>Pharmaceutical companies</li>
</ul>
<p>Here are some examples of R in production use:</p>
<ul>
<li>The <a href="https://github.com/bbc/bbplot" rel="nofollow" target="_blank">{bbplot} R package</a>. Yes, the BBC use R to create graphics for their website!</li>
<li>Health and wellbeing profiling <a href="https://shiny.posit.co/r/gallery/government-public-sector/scotpho-profiles/" rel="nofollow" target="_blank">app</a> for the NHS</li>
<li>During the Covid-19 pandemic, the financial times had a <a href="https://www.ft.com/content/a2901ce8-5eb7-4633-b89c-cbdf5b386938" rel="nofollow" target="_blank">stats tracker</a> in which the graphs were built with R.</li>
</ul>
<p>Knowing some R will give you a competitive edge if you’re looking at working within these sectors.</p>
<hr>
<h2 id="open-source-with-the-backing-of-posit">Open source with the backing of Posit</h2>
<p>R is open source. This means that:</p>
<ul>
<li>It’s free, and always will be!</li>
<li>Anyone can view the source code the makes up R, there are.</li>
<li>Each R package (a folder containing code) has to live on <a href="https://github.com/" rel="nofollow" target="_blank">GitHub.com</a>, for everyone to see.</li>
<li>It has a large community of contributors. There are great forums to get help such as <a href="https://stackoverflow.com/questions/tagged/r?tab=Votes" rel="nofollow" target="_blank">Stack Overflow</a>, <a href="https://forum.posit.co/" rel="nofollow" target="_blank">Posit Community</a> and the <a href="https://rweekly.org/" rel="nofollow" target="_blank">R weekly newsletter</a> and tonnes more.</li>
<li>There are thousands more available functionalities compared to paid softwares such as SPSS, SAS or Excel.</li>
</ul>
<p><a href="https://posit.co/" rel="nofollow" target="_blank">Posit</a>, who maintain the free to use RStudio and Positron IDEs (integrated development environment), have many full time staff working solely on maintaining and creating new functionality within R. This means we get:</p>
<ul>
<li>Defined accountability</li>
<li>Predictable release cycles</li>
<li>Bugs can be solved quicker</li>
</ul>
<hr>
<h2 id="incredible-data-visualisation-possibilities">Incredible data visualisation possibilities</h2>
<p>Being able to communicate your findings with stakeholders is very important in data science, and one of R’s biggest strengths is visualisation and reporting.</p>
<p>With the <strong>{ggplot2}</strong> package, you can create publication ready charts with very little code. The <a href="https://r-graph-gallery.com/best-r-chart-examples.html" rel="nofollow" target="_blank">R Graph Gallery</a> has some amazing examples of what is possible with {ggplot2}.</p>
<p>With the <strong>{quarto}</strong> and <strong>{shiny}</strong> packages, you are able to build reproducible reports and interactive dashboards. All this without needing to know any HTML, CSS or JavaScript.</p>
<h2 id="beginner-friendly-learning-curve">Beginner friendly learning curve</h2>
<p>This is very much my own opinion. Compared to other languages, I think R is
fairly intuitive and feels rewarding much earlier on in the journey. It also has (in my opinion), the most beginner friendly programme to code in, called RStudio.</p>
<p>Most people attend only two days worth of training with Jumping Rivers, and say they feel ready to start tackling their own data problems.</p>
<hr>
<h2 id="so-is-r-worth-learning-in-2026">So… is R worth learning in 2026?</h2>
<p>I think so. If you want pure software engineering or large-scale production systems, you may need Python. But for becoming a <strong>strong data thinker</strong>, and giving you an edge in your analysis, R is one of the best starting points.</p>
<p>
For updates and revisions to this article, see the <a href = "https://www.jumpingrivers.com/blog/why-learning-r-is-a-good-career-move-in-2026/">original post</a>
</p>
<div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.jumpingrivers.com/blog/why-learning-r-is-a-good-career-move-in-2026/"> The Jumping Rivers Blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div><strong>Continue reading</strong>: <a href="https://www.r-bloggers.com/2026/03/why-learning-r-is-a-good-career-move-in-2026/">Why Learning R is a Good Career Move in 2026</a>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">400093</post-id>	</item>
	</channel>
</rss>
