<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Discindo</title>
<link>https://discindo.org/</link>
<atom:link href="https://discindo.org/index.xml" rel="self" type="application/rss+xml"/>
<description>Data science and data engineering solutions with R and Shiny in the cloud.</description>
<generator>quarto-1.8.27</generator>
<lastBuildDate>Mon, 16 Mar 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Software engineering enters its accounting era</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2026-03-16-software-engineering-accounting/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>If you have ever done accounting, you probably know it is not much fun. If not here is a brief summary. There are bunch of rules to follow, coded into local, national, and international standards, and many modern ERP systems have them at least partially implemented and automated. There is not really creativity in the work – well not unless you want to work in organised crime, and the profession is highly regulated. There is a lot of gate keeping about who can do the job, or who can do which part of the job, and what kind of certificates one must have, although the core of the accounting process is largely unchanged since it was codified sometime during the <a href="https://en.wikipedia.org/wiki/Luca_Pacioli">renaissance or thereabouts</a>.</p>
<p>No one has accounting as a hobby. There is no cool project in accounting you can share with your friends, and there aren’t any interesting or thought provoking conferences or meetups where the topic is accounting. Was there ever an accountant speaking at TED? I haven’t check, but if there was he/she was probably speaking about something else.</p>
<p><img src="https://discindo.org/posts/2026-03-16-software-engineering-accounting/images/career-venn-diagram.png" class="img-fluid" alt="The Career Venn Diagram by Don McMillan"> So what has this have to do with software engineering? To use Don McMillan’s funny diagram, we are now seeing a shift away from problem solving in software engineering. Instead of solving problems we are writing markdown documents that tell agents to solve a problem. And, even in these early days we see projects popping up with default <code>.md</code> files to do a certain tasks, or write in certain language. I think it is not before long we see a standard <code>.md</code> file to build an R package, or to build a FastAPI, or something else, with complexity of the problem being solved increasing over time.</p>
<p>There is a trajectory in which agent skill will become something akin to International Financial Reporting Standards. I think we are not far away from having the big companies producing “verified” skill (as I went to LinkedIn to post this I was greeted by a <a href="https://www.linkedin.com/posts/antonabyzov_ai-developertools-buildinpublic-share-7438679148476125184-8lnk">post by Anton Abyzov</a> that talks about a <a href="https://verified-skill.com/">verified skill tool</a> :) to do certain things in their ecosystem. Think for example “AWS verified skills for infrastructure”, and maybe these will start to come with a price tag on a tier level, or even on regional level around the world.</p>
<p>Then if you are a company working in software auditing, you will probably have a skill that will instruct your agent to audit the work of another agent. I would not be surprised if the Big 4 are already thinking about this.</p>
<p>Where does this leave software engineers? No more problem solving, more OCD? I think it is not difficult to imagine future work being mostly reading <code>.md</code> files and trying to catch inconsistencies that slip through spell checkers or similar tools. Think someone typing <code>cat</code> instead of <code>car</code> in some <code>.md</code> file, and someone else trying to figure out where is the error coming from. That to me sounds much closer to tracking the stray balance mismatch on the balance sheet, than to improving a poorly implemented function that sometimes crashes the user’s computer.</p>
<p>Is this good or bad? I guess it depends on being good or bad for whom or what. I think that even if this trajectory takes place, it will probably not affect the current generation of software engineers.</p>
<p>However, not thinking about the other issues being raised (such as overall environmental concerns, employment outlook, and the stock market bubble), I think over time we are very likely to witness <a href="https://en.wikipedia.org/wiki/Tragedy_of_the_commons">tragedy of the commons</a> unraveling in the free software world.</p>
<p>Then maybe a lot of the software becomes like the cheap umbrellas you buy on the street form ad-hoc sellers when it suddenly starts to rain, and then they break after the second use and you toss them away. And maybe a lot of the software becomes a problem similar to the plastic in the oceans and <a href="https://www.theguardian.com/world/2026/mar/15/cairo-fishers-catching-plastic-bottles">some engineers re-skill to deal with that</a>.</p>
<p>For the current generation I think it will put pressure on community building around software, hobby projects, and events. Think about it: why would I want to come to a meetup if we are to discuss your latest <code>.md</code> file? It is not meant for people anyway. Or why would I bother with reporting a bug or offering a pull request on a project that is largely build by a coding agent? The intrinsic motivation to help and be involved with people is simply gone. I would even say there is no motivation to send my agent subscription to do a pull request on your agent driven project. What would my lighting talk be at the next conference: how to format your <code>.md</code> file in 10 easy steps? There is a skill for that too. After all have you ever heard of an accounting community?</p>



 ]]></description>
  <category>software</category>
  <category>llm</category>
  <category>agents</category>
  <category>accounting</category>
  <guid>https://discindo.org/posts/2026-03-16-software-engineering-accounting/</guid>
  <pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2026-03-16-software-engineering-accounting/images/career-venn-diagram.png" medium="image" type="image/png" height="75" width="144"/>
</item>
<item>
  <title>R project template</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2026-02-24-r-project-template/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>Couple of weeks ago I <a href="../../posts/2026-02-06-next-gen-r-tools/">wrote about all these new tools</a> that showed up in the R ecosystem, that seemed to aim to fill the gap for modern tooling and better developer experience. Then I bumped in the <a href="https://github.com/gemmadanks/python-project-template">excellent Python project template</a> by Gemma Danks, and I thought to myself, why not make something similar for R? So here it is, an R project template with a focus on modularity and tooling.</p>
<p><img src="https://discindo.org/posts/2026-02-24-r-project-template/images/spice-rack.webp" class="img-fluid" alt="Homer Simpson's spice rack"></p>
<p>But why I am presenting this with Homer Simpson’s spice rack? Well, it is a project template, and it works, but it seems many things can be improved. For example:<br>
- Test coverage cannot be registered with codecov because it seems the R package <code>covr</code> does not work in this not-R-pacakage project structure. - <code>pkgdown</code> cannot be used for documentation for the same reason as above. - devtools::check() does not work because it expects a package structure with a DESCRIPTION file and an R/ directory for source code, which this template does not have.</p>
<p>Workarounds are of course possible, but these are kind of a goto tools for R projects, and I think many people would expect them to just work.</p>
<p>Even with these limitations, I think there is the learning curve for many to use <code>box</code> for writing modular R code, with <code>box</code> itself last time released in 2024.</p>
<p>But it works, and it is fun to see that it works. And it may be an alternative path for writing R code when we would like to avoid the classic package structure.</p>
<p>Code is here: <a href="https://github.com/novica/r-project-template">R project template</a>.</p>
<p>Let me know if you try it or just contribute on the repository.</p>



 ]]></description>
  <category>R</category>
  <category>template</category>
  <category>project</category>
  <category>module</category>
  <category>tools</category>
  <guid>https://discindo.org/posts/2026-02-24-r-project-template/</guid>
  <pubDate>Tue, 24 Feb 2026 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2026-02-24-r-project-template/images/spice-rack.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Next-Gen R Tooling</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2026-02-06-next-gen-r-tools/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>Whether it is a case of <a href="https://en.wikipedia.org/wiki/Carcinisation">Carcinisation</a> or not, it seems we are now in the age where different tools for making the R language ecosystem better, faster, or more consistent are being built, of course, in Rust. In the R-world it definitely feels like an effort to catch up with what <a href="https://github.com/astral-sh">Astral.sh</a> has done for python.</p>
<p>Interestingly, though, while Astral seem to be a doing a focused job on providing several tools for python, the R-world looks a bit fragmented with Posit doing some tools, and then some other companies and/or individual doing some other tools. And some have LLM help visible in the GitHub contributors list.</p>
<p>Overall I am not sure how serious, or long-term all of this projects will be, but for now it seems fun to track them and see how they develop. And for that reason, and of course to make it easier to install these, I made Arch Linux <a href="https://aur.archlinux.org/">AUR</a> packages for all tools that seem to fit in this bundle of next-gen R tooling.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Tool</th>
<th>Description</th>
<th>Source Package</th>
<th>Binary Package</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><a href="https://github.com/posit-dev/air">air</a></td>
<td>An R language server and formatter</td>
<td><a href="https://aur.archlinux.org/packages/r-air">r-air</a></td>
<td><a href="https://aur.archlinux.org/packages/r-air-bin">r-air-bin</a></td>
</tr>
<tr class="even">
<td><a href="https://github.com/eitsupi/arf">arf</a></td>
<td>A modern R console</td>
<td><a href="https://aur.archlinux.org/packages/arf">arf</a></td>
<td><a href="https://aur.archlinux.org/packages/arf-bin">arf-bin</a></td>
</tr>
<tr class="odd">
<td><a href="https://github.com/posit-dev/ark">ark</a></td>
<td>An R kernel</td>
<td><a href="https://aur.archlinux.org/packages/r-ark">r-ark</a></td>
<td><a href="https://aur.archlinux.org/packages/r-ark-bin">r-ark-bin</a></td>
</tr>
<tr class="even">
<td><a href="https://github.com/etiennebacher/jarl">jarl</a></td>
<td>Fast linter for the R language</td>
<td><a href="https://aur.archlinux.org/packages/jarl">jarl</a></td>
<td><a href="https://aur.archlinux.org/packages/jarl-bin">jarl-bin</a></td>
</tr>
<tr class="odd">
<td><a href="https://github.com/r-lib/rig">rig</a></td>
<td>The R Installation Manager</td>
<td><a href="https://aur.archlinux.org/packages/r-rig">r-rig</a></td>
<td><a href="https://aur.archlinux.org/packages/r-rig-bin">r-rig-bin</a></td>
</tr>
<tr class="even">
<td><a href="https://github.com/a2-ai/rv">rv</a></td>
<td>A declarative R package manager</td>
<td><a href="https://aur.archlinux.org/packages/rv">rv</a></td>
<td><a href="https://aur.archlinux.org/packages/rv-bin">rv-bin</a></td>
</tr>
</tbody>
</table>
<section id="some-notes-on-packaging" class="level2">
<h2 class="anchored" data-anchor-id="some-notes-on-packaging">Some notes on packaging</h2>
<p>Overall, providing an AUR package is a simple process. Using any existing <code>PKGBUILD</code> can serve as a template. However, I had to make changes to few <code>PKGBUILDS</code> because not all releases on GitHub follow the same directory structure. Also sometimes files were named differently then expected, for example having <code>LICENSE.md</code> instead of just <code>LICENSE</code> would promt changes to the packaging files.</p>
<p>Additionally, it seems the authors of these tools were not always too mindful of other tools that exist with the same name. This is the case with <code>air</code> (a Go package), <code>ark</code> (the KDE archiving tool), and <code>rig</code> (A random identity generator) where binaries for other purposes alreary exist in the Linux distribution, so renaming those to <code>r-air</code>, <code>r-ark</code>, and <code>r-rig</code> was necessary to avoid conflicts.</p>
<p>Anyway, hopefully people find these useful. And if you try them out please report any issues.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>tools</category>
  <category>rust</category>
  <category>archlinux</category>
  <guid>https://discindo.org/posts/2026-02-06-next-gen-r-tools/</guid>
  <pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2026-02-06-next-gen-r-tools/images/aur.png" medium="image" type="image/png" height="63" width="144"/>
</item>
<item>
  <title>dplyr comes to duckdb</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2026-01-29-duckdb-dplyr/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>Of course, we have all used <a href="https://duckplyr.tidyverse.org/">duckplyr</a> by now. But now we can use dplys syntax in duckdb thanks to an extension: <a href="https://duckdb.org/community_extensions/extensions/dplyr">dplyr</a>.</p>
<p>I would guess that the inspiration for this comes from the 2023 <a href="https://research.google/pubs/sql-has-problems-we-can-fix-them-pipe-syntax-in-sql/">Google paper pipe syntax in SQL</a>. Since then at least, as far as I know, Databricks adopted it in 2025: <a href="https://www.databricks.com/blog/sql-gets-easier-announcing-new-pipe-syntax">SQL Gets Easier: Announcing New Pipe Syntax</a>.</p>
<p><img src="https://discindo.org/posts/2026-01-29-duckdb-dplyr/images/google-paper.png" class="img-fluid" alt="Screenshot from the Google paper"></p>
<p>And now piping is avaiable in duckdb. Fun! But wait…</p>
<p><img src="https://media1.tenor.com/m/8EtIRErgJk4AAAAd/ugly-duckling-crying-ducks.gif" class="img-fluid" alt="Crying duck from tenor gifs"></p>
<p>If you want to try it out and like me install the latest duckdb (v1.4.4 (Andium) 6ddac802ff), the extension will not be avaiable:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">INSTALL dplyr FROM community;</span>
<span id="cb1-2">HTTP Error<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb1-3">Failed to download extension <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dplyr"</span> at URL <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"http://community-extensions.duckdb.org/v1.4.4/windows_amd64/dplyr.duckdb_extension.gz"</span> (HTTP <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">404</span>)</span></code></pre></div></div>
</div>
<p>Hopefull the maintainer will <a href="https://github.com/mrchypark/libdplyr/issues/5">fix this</a> soon.</p>



 ]]></description>
  <category>R</category>
  <category>duckdb</category>
  <category>dplyr</category>
  <guid>https://discindo.org/posts/2026-01-29-duckdb-dplyr/</guid>
  <pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2026-01-29-duckdb-dplyr/images/duckplyr.png" medium="image" type="image/png" height="83" width="144"/>
</item>
<item>
  <title>Jumping in the Ducklake with nothing but R on</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2025-09-20-r-ducklake/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>A week or so ago I was listening to a podcast about <a href="https://ducklake.select/">Ducklake</a>, the new table format by DuckDB, and started thinking if it can be used from R, specifically to mimic what would one do on cloud providers such as Databricks.</p>
<p><code>dplyr</code> and friends are mostly about cleaning and summarizing data, and the <a href="https://www.databricks.com/blog/2020/01/30/what-is-a-data-lakehouse.html">lake(house)</a> idea is mostly about the so called ‘medallion architecture’ where data moves from raw and messy, to clean and validated, to business ready. So it’s kind of like:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">data_raw <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(something) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group__by</span>(something) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(something)</span></code></pre></div></div>
</div>
<p>But why, you may ask? Well I think most data is not big data, but all data goes through this same process of cleaning and summarizing, so why not try and use some of the nice ideas to add to an R workflow.</p>
<p>Note: If you are thinking about following through this post this is a good time to do <code>install.packages('duckdb')</code> if there is not a <a href="https://r.duckdb.org/#installation-from-cran">binary distribution</a> for your system. It takes a while to compile it.</p>
<p>OK. This is what we will try to do next:</p>
<ol type="1">
<li><p>Set up a Ducklake;</p></li>
<li><p>Write some data to it;</p></li>
<li><p>Visualize relationships among tables.</p></li>
</ol>
<section id="setting-up-a-ducklake" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-a-ducklake">Setting up a Ducklake</h2>
<p>Assuming you have opened a new <code>Rstudio</code> project with <code>git</code> enabled, and the <code>duckdb</code> package is installed on your system setting up Ducklake is as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"duckdb"</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3">con <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbConnect</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">duckdb</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dbdir=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":memory:"</span>)</span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"INSTALL ducklake;"</span>)</span>
<span id="cb2-6"></span>
<span id="cb2-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATTACH 'ducklake:metadata.ducklake' AS r_ducklake;"</span>)</span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"USE r_ducklake;"</span>)</span></code></pre></div></div>
</div>
<p>This creates a in memory <code>duckdb</code> database, installs the <code>ducklake</code> extension and then creates the <code>ducklake</code> on disk. In your project you will see two files: <code>metadata.ducklake</code> and <code>metadata.ducklake.wal</code>. The first one is a <code>duckdb</code> database with a different extension and the second is the <code>write-ahead log</code> that <code>duckdb</code> uses to manage the metadata.</p>
<p>If we close this connection (but if you do this remember to run the above again before continuing below:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbDisconnect</span>(con)</span></code></pre></div></div>
</div>
<p>And then open the <code>ducklake</code> file with a database browser, for example the <code>duckdb</code> cli:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span> duckdb <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>ui metadata.ducklake </span></code></pre></div></div>
</div>
<p>you will see that it is a database with the tables as described on the <a href="https://ducklake.select/docs/stable/specification/tables/overview.html">specification overview</a> for the table format.</p>
</section>
<section id="writing-data-to-the-ducklake" class="level2">
<h2 class="anchored" data-anchor-id="writing-data-to-the-ducklake">Writing data to the ducklake</h2>
<p>Next I will pretend that the <code>mtcars</code> dataset needs to be cleaned and aggregated. There may be a better datasets to give this example, but it is simple to see the steps like this. I am also using <code>SQL</code> but same can be achieved with <code>dplyr</code> or anything handy in R:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Bronze: raw data</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbWriteTable</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bronze_mtcars"</span>, mtcars)</span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Silver: filtered / cleaned</span></span>
<span id="cb5-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb5-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  CREATE TABLE silver_mtcars AS</span></span>
<span id="cb5-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT *, (mpg/mean(mpg) OVER()) AS mpg_norm</span></span>
<span id="cb5-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM bronze_mtcars;</span></span>
<span id="cb5-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-10"></span>
<span id="cb5-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Gold: aggregated summary</span></span>
<span id="cb5-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb5-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  CREATE TABLE gold_mtcars AS</span></span>
<span id="cb5-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT cyl, AVG(mpg) AS avg_mpg, AVG(mpg_norm) AS avg_mpg_norm</span></span>
<span id="cb5-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM silver_mtcars</span></span>
<span id="cb5-16"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  GROUP BY cyl;</span></span>
<span id="cb5-17"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
<p>In the medallion architecture the first layer, the raw data, is called bronze, and in this case we just write the <code>mtcars</code> as is.</p>
<p>Then the second layer, the silver layer, we sort of clean these data. I have no idea if normalizing miles per gallon makes sense, but hey why not.</p>
<p>The final layer is about an aggregate summary, a gold layer, so group by and summarize is what is happening there.</p>
<p>If you run the above in your demo project you will notice new files created:</p>
<pre><code>[metadata.ducklake.files]$ tree
.
└── main
    ├── bronze_mtcars
    │   └── ducklake-01996884-c393-7134-bee0-cbffb31e19c7.parquet
    ├── gold_mtcars
    │   └── ducklake-01996884-c3cd-7ae6-bcaa-0b69196040cb.parquet
    └── silver_mtcars
        └── ducklake-01996884-c3b5-7d9d-b9f8-05e3c8377bee.parquet</code></pre>
<p>This is ducklake keeping track of your data in <code>parquet</code> format.</p>
<p>Next we need to make something to track the relationships between the tables. For now i think this is not supported in ducklake(v.0.0.3), but probably will be in the future.</p>
<p>Ideally the following should be executed as each table is written, but for sake of example it is below:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb7-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CREATE TABLE IF NOT EXISTS ducklake_lineage (</span></span>
<span id="cb7-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  parent_table VARCHAR,</span></span>
<span id="cb7-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  child_table  VARCHAR,</span></span>
<span id="cb7-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  created_at   TIMESTAMP,</span></span>
<span id="cb7-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  description  VARCHAR</span></span>
<span id="cb7-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb7-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb7-9"></span>
<span id="cb7-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># After creating a silver table from bronze</span></span>
<span id="cb7-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb7-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    INSERT INTO ducklake_lineage (parent_table, child_table, created_at, description)</span></span>
<span id="cb7-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    VALUES ('bronze_mtcars', 'silver_mtcars', NOW(), 'normalization / filtering');</span></span>
<span id="cb7-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb7-15"></span>
<span id="cb7-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># After creating gold table from silver</span></span>
<span id="cb7-17"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb7-18"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    INSERT INTO ducklake_lineage (parent_table, child_table, created_at, description)</span></span>
<span id="cb7-19"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    VALUES ('silver_mtcars', 'gold_mtcars', NOW(), 'aggregation');</span></span>
<span id="cb7-20"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
<p>Let’s imagine that we have done some more transformation and maybe created 2 more silver tables and one more gold table. Of course, the <code>decription</code> should be updated to make more sense:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb8-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    INSERT INTO ducklake_lineage (parent_table, child_table, created_at, description)</span></span>
<span id="cb8-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    VALUES ('bronze_mtcars', 'silver_mtcars_2', NOW(), 'normalization / filtering');</span></span>
<span id="cb8-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb8-5"></span>
<span id="cb8-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb8-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    INSERT INTO ducklake_lineage (parent_table, child_table, created_at, description)</span></span>
<span id="cb8-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    VALUES ('bronze_mtcars', 'silver_mtcars_3', NOW(), 'normalization / filtering');</span></span>
<span id="cb8-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb8-10"></span>
<span id="cb8-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbExecute</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb8-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    INSERT INTO ducklake_lineage (parent_table, child_table, created_at, description)</span></span>
<span id="cb8-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    VALUES ('silver_mtcars', 'gold_mtcars_2', NOW(), 'aggregation');</span></span>
<span id="cb8-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
</section>
<section id="visualize-relationships-among-tables" class="level2">
<h2 class="anchored" data-anchor-id="visualize-relationships-among-tables">Visualize relationships among tables</h2>
<p>Since digging trough the parquet files to see what the relationships between the tables are does not make much sense, we can use some of good old <code>ggplot2</code> and friend magic to visualize that.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(igraph)</span>
<span id="cb9-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggraph)</span>
<span id="cb9-3"></span>
<span id="cb9-4">edges <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbGetQuery</span>(con, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SELECT parent_table AS from_table, child_table AS to_table FROM ducklake_lineage"</span>)</span>
<span id="cb9-5">g <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">graph_from_data_frame</span>(edges, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">directed =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb9-6"></span>
<span id="cb9-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggraph</span>(g, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">layout =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tree"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_edge_diagonal</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">arrow =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrow</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mm'</span>)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">end_cap =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">circle</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mm'</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_node_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">shape =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"steelblue"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lightblue"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb9-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_node_text</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> name), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vjust =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>               </span>
<span id="cb9-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_flip</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_reverse</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>  </span>
<span id="cb9-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_void</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>       </span>
<span id="cb9-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggtitle</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DuckLake Medallion Lineage"</span>)</span></code></pre></div></div>
</div>
<p><img src="https://discindo.org/posts/2025-09-20-r-ducklake/images/plot.png" class="img-fluid"></p>
<p>This is the sort of a thing you get to see under the lineage in Databricks’ <a href="https://docs.databricks.com/aws/en/data-governance/unity-catalog/data-lineage">Unity Catalog</a>, although not as elaborate. However, a proper <code>ggplot2</code> wizard may succeed in making duplicating that view.</p>
<p>You can imagine having this plot as part of a Quarto report or a Shiny app with some interactivity to keep track of the transformations that happen to the data you are managing.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>As we set out in the beginning we set up a Ducklake with R, wrote some data to it and visualized relationships among tables. While the example is trivial, I think it is obvious that this could be a useful approach for managing local pipelines and for prototyping things that could run on the cloud.</p>
<p>For local pipelines in particular, I can see this approach been used with something like <a href="https://github.com/whipson/maestro">{maestro}</a> to orchestrate a data pipeline.</p>
<p>The code above is available as a <a href="https://gist.github.com/novica/ff55fc4d79c3007bb1acba40e74e9d25">gist</a>.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>ducklake</category>
  <category>duckdb</category>
  <guid>https://discindo.org/posts/2025-09-20-r-ducklake/</guid>
  <pubDate>Sat, 20 Sep 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-09-20-r-ducklake/images/image.png" medium="image" type="image/png" height="51" width="144"/>
</item>
<item>
  <title>Introducing bioinf-bloggers.com</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2025-09-05-bioinf-bloggers/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>(Image taken from <a href="https://www.uio.no/english/studies/programmes/computational-science-master/programme-options/bioinformatics/why-choose/compbioinfo.jpg">UiO</a>.)</p>
<p>About a year ago I started following <a href="https://www.reddit.com/r/bioinformatics/">r/bioinformatics</a>. I work at a research institute where bioinformatics plays a big role, but not being from that field I wanted to familiarize my self with the topics, problems, and solutions.</p>
<p>Then I bumped into this post: <a href="https://www.reddit.com/r/bioinformatics/comments/1go98kz/any_bioinformatics_blogs_out_there/">Any Bioinformatics blogs out there?</a></p>
<p>I started following the blogs in my RSS reader and that worked well. But then I thought it would be nice to have them all aggregated somehow. I remembered how convenient were the old <a href="https://en.wikipedia.org/wiki/Planet_(software)">planet</a> sites that followed blogs on a similar topic.</p>
<p>So I decided to build one: <a href="https://bioinf-bloggers.com/">bioinf-bloggers.com</a>.</p>
<p>It is a static html rendered on <code>gh-pages</code>. I considered using Wordpress or something like that but it seemed like to much complications.</p>
<p>The repository is on <a href="https://github.com/novica/bioinf-bloggers">GitHub</a>. And contributions in the blogs that it should aggregate are welcome. Just make a PR editing the <code>feeds.txt</code> file. Other suggestions are also welcome.</p>



 ]]></description>
  <category>bioinformatics</category>
  <category>blog</category>
  <guid>https://discindo.org/posts/2025-09-05-bioinf-bloggers/</guid>
  <pubDate>Fri, 05 Sep 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-09-05-bioinf-bloggers/images/compbioinfo.jpg" medium="image" type="image/jpeg"/>
</item>
<item>
  <title>An Arch Linux package for the Air R formatter</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2025-06-21-arch-r-air/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>After the Python world got so many new tools, thanks to the people at <a href="https://astral.sh/">Astral</a>, I was super exited to see that the R world is trying to catch up.</p>
<p>In particular, Posit made a Rust backed R language server and formatter called <a href="https://posit-dev.github.io/air/">Air</a>.</p>
<p>Then, for no other particular reason than to see how it is done, I created a package for AUR the Arch User Repository of contributed packages. You can find it here: <a href="https://aur.archlinux.org/packages/r-air-bin">r-air-bin</a>.</p>
<section id="why-is-it-named-r-air" class="level2">
<h2 class="anchored" data-anchor-id="why-is-it-named-r-air">Why is it named r-air?</h2>
<p>Because there is already a binary named <code>Air</code>: a Go library <a href="https://aur.archlinux.org/packages/air">Air</a>. In order not to overwite the user’s system that may have the Go binary, the name of the binary for the formatter is <code>r-air</code>.</p>
<p>See more at the github discussion with Posit <a href="https://github.com/posit-dev/air/issues/347">here</a>.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>arch</category>
  <guid>https://discindo.org/posts/2025-06-21-arch-r-air/</guid>
  <pubDate>Sat, 21 Jun 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-06-21-arch-r-air/images/air.png" medium="image" type="image/png" height="162" width="144"/>
</item>
<item>
  <title>A plumber API to filter and aggregate datasets</title>
  <dc:creator>teo </dc:creator>
  <link>https://discindo.org/posts/2025-02-13-plumber-snippet/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>Over the past couple of weeks, I’ve been sharing some code that I use for dynamic <a href="../../posts/2025-01-31-filter-snippet">filtering</a> and <a href="../../posts/2025-02-06-aggregate-snippet">aggregation</a> of data frames in <code>R</code>. The idea of these functions was to have single-step methods for complex filter or aggregate queries. Each of the functions worked with a list of instructions, specifically formatted for the task. I adopted this approach to make it easier to use these functions in web applications or APIs. If the filter or aggregate query request can be sent as a list, then it can be easily converted to JSON and used in API calls.</p>
<p>In this post, I am going to demo how we can integrate the functions from the previous two posts into a <code>{plumber}</code> API and, after deployment, have <code>/filter</code> and <code>/aggregate</code> endpoints available as a “service”.</p>
<section id="plumber-api-for-filter-and-aggregate" class="level3">
<h3 class="anchored" data-anchor-id="plumber-api-for-filter-and-aggregate">Plumber API for filter and aggregate</h3>
<p>The <code>{plumber}</code> API is organized in the form of an <code>R</code> package.</p>
<pre><code>├── DESCRIPTION
├── inst
│   └── plumber.r
├── man
│   ├── dot-aggregate.Rd
│   ├── dot-filter.Rd
│   └── run_api.Rd
├── NAMESPACE
├── plumb.ex.Rproj
├── R
│   ├── api.r
│   └── funs.r
└── test.r</code></pre>
<p>The <code>R</code> directory contains the script <code>funs.r</code> where I define the <code>.filter</code> and <code>.aggregate</code> functions I covered in the previous two posts. The <code>.api.r</code> script contains a single function that starts the <code>API</code> on our preferred host and port (defaults to localhost and 5000).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' start plumber api</span></span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param host the host address</span></span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param port the port to use</span></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @importFrom plumber pr pr_run pr_get</span></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @export</span></span>
<span id="cb2-6">run_api <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">port =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">host =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"127.0.0.1"</span>) {</span>
<span id="cb2-7">  path <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.file</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plumber.r"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plumb.ex"</span>)</span>
<span id="cb2-8">  path <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pr</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pr_run</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">port =</span> port, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">host =</span> host)</span>
<span id="cb2-11">}</span></code></pre></div></div>
</div>
<p>This is similar to <code>{golem}</code>’s <code>run_app()</code> function and it streamlines the development cycle. Whenever I make updates to the underlying code in <code>funs.r</code> or the <code>{plumber}</code> endpoints in <code>inst/plumber.r</code>, I can run:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">devtools<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">document</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># re-documents and loads all functions </span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">run_api</span>()</span></code></pre></div></div>
</div>
<p>and that would start the API making it accessible at <code>http://127.0.0.1:5000</code>, with the <code>{swagger}</code> interface for manual testing at <code>http://127.0.0.1:5000/__docs__/</code>. It is then ready for queries.</p>
</section>
<section id="endpoints" class="level3">
<h3 class="anchored" data-anchor-id="endpoints">Endpoints</h3>
<p>The package exports the <code>.filter</code> and <code>.aggregate</code> functions. Then the API uses these when defining the endpoints. In this example API we have three endpoints defined in <code>inst/plumber.r</code>:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plumber.R.</span></span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @plumber</span></span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @apiTitle Plumber filter or aggregate</span></span>
<span id="cb4-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @apiDescription Plumber example for dynamic filtering and aggregation</span></span>
<span id="cb4-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @apiVersion 1.0.0</span></span>
<span id="cb4-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(pr) {</span>
<span id="cb4-8">  pr <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-9">    plumber<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pr_set_serializer</span>(plumber<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">serializer_unboxed_json</span>())</span>
<span id="cb4-10">}</span>
<span id="cb4-11"></span>
<span id="cb4-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* Hello</span></span>
<span id="cb4-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @get /hello</span></span>
<span id="cb4-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>() {</span>
<span id="cb4-15">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hello, there!"</span></span>
<span id="cb4-16">}</span>
<span id="cb4-17"></span>
<span id="cb4-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* Filter</span></span>
<span id="cb4-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @param data the name of the data frame to filter, `"iris"` or `"mtcars"`</span></span>
<span id="cb4-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @param instructions_list a list of instructions for aggregation.</span></span>
<span id="cb4-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @post /filter</span></span>
<span id="cb4-22"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, instructions_list) {</span>
<span id="cb4-23">  d <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(data)</span>
<span id="cb4-24">  l <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fromJSON</span>(instructions_list, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simplifyVector =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span>
<span id="cb4-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.filter</span>(d, l)</span>
<span id="cb4-26">}</span>
<span id="cb4-27"></span>
<span id="cb4-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* Aggregate</span></span>
<span id="cb4-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @param data the name of the data frame to aggregate, `"iris"` or `"mtcars"`</span></span>
<span id="cb4-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @param instructions_list a list of instructions for aggregation.</span></span>
<span id="cb4-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#* @post /aggregate</span></span>
<span id="cb4-32"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, instructions_list) {</span>
<span id="cb4-33">  d <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(data)</span>
<span id="cb4-34">  l <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fromJSON</span>(instructions_list, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simplifyVector =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span>
<span id="cb4-35">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.aggregate</span>(d, l)</span>
<span id="cb4-36">}</span></code></pre></div></div>
</div>
<p>The first is <code>/hello</code> and is simply a health check endpoint. Using <code>httr2</code> we can make requests to it as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">r<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(jsonlite)</span>
<span id="cb5-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(httr2)</span>
<span id="cb5-3"> </span>
<span id="cb5-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">request</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"http://127.0.0.1:5000/hello"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-5">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_perform</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">resp_body_json</span>()</span>
<span id="cb5-7">[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hello, there!"</span></span></code></pre></div></div>
</div>
<p>The other two endpoints are simple wrappers around <code>.filter</code> and <code>.aggregate</code> to do two steps:</p>
<ol type="1">
<li><p>get the dataset requested by the user. For simplicity in this example, the dataset argument is passed on as a string, and then we user <code>get</code> to get that dataset, assuming its one of the ones prepackaged with <code>R</code>. But its easy to modify that and simply send JSON data to the endpoint.</p></li>
<li><p>convert the JSON received by the API into a list as required in <code>R</code>. This is needed because the instructions list for filtering or aggregation is sent with the request as JSON, and the validation within our functions expects a list. One could relax these requirement as well by allowing a JSON string in the <code>instructions_list</code> argument and parsing this internally.</p></li>
</ol>
</section>
<section id="interactive-demo" class="level3">
<h3 class="anchored" data-anchor-id="interactive-demo">Interactive demo</h3>
<section id="start-the-api" class="level4">
<h4 class="anchored" data-anchor-id="start-the-api">Start the API</h4>
<p>During development, we would run:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">devtools<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">document</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># re-documents and loads all functions </span></span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">run_api</span>()</span></code></pre></div></div>
</div>
<p>If the <code>plumb.ex</code> package is installed, we would instead run:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(plumb.ex) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># re-documents and loads all functions </span></span>
<span id="cb7-2">plumb.ex<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">run_api</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">port =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6000</span>)</span></code></pre></div></div>
</div>
<p>If its deployed, for one method see <a href="../../posts/2024-02-25-how-to-set-up-development-and-production-environments-using-aws-copilot-example-using-a-plumber-api">this post</a>, we follow the code below to make requests.</p>
</section>
<section id="filter" class="level4">
<h4 class="anchored" data-anchor-id="filter">Filter</h4>
<p>From <code>R</code> and <code>{shiny}</code> we can call the <code>/filter</code> endpoint using the following steps. First, we create our filter instructions, convert that to JSON, and finally use <code>httr</code> or <code>httr2</code> to make a request to the API:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(jsonlite)</span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(httr2)</span>
<span id="cb8-3"></span>
<span id="cb8-4">filter_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb8-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Length"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"between"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">min =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.9</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb8-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Species"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"in"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">val =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"setosa"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"versicolor"</span>))</span>
<span id="cb8-7">)</span>
<span id="cb8-8"></span>
<span id="cb8-9">filter_json <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toJSON</span>(filter_data, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">auto_unbox =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb8-10">jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prettify</span>(filter_json)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[
    {
        "col": "Sepal.Length",
        "fun": "between",
        "min": 4.9,
        "max": 5
    },
    {
        "col": "Species",
        "fun": "in",
        "val": [
            "setosa",
            "versicolor"
        ]
    }
]
 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">request</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"http://127.0.0.1:6000"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_url_path</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"filter"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_body_json</span>(</span>
<span id="cb10-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"iris"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">instructions_list =</span> filter_json),</span>
<span id="cb10-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">auto_unbox =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb10-6">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_perform</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">resp_body_json</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simplifyVector =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1           4.9         3.0          1.4         0.2     setosa
2           5.0         3.6          1.4         0.2     setosa
3           5.0         3.4          1.5         0.2     setosa
4           4.9         3.1          1.5         0.1     setosa
5           5.0         3.0          1.6         0.2     setosa
6           5.0         3.4          1.6         0.4     setosa
7           4.9         3.1          1.5         0.2     setosa
8           5.0         3.2          1.2         0.2     setosa
9           4.9         3.6          1.4         0.1     setosa
10          5.0         3.5          1.3         0.3     setosa
11          5.0         3.5          1.6         0.6     setosa
12          5.0         3.3          1.4         0.2     setosa
13          4.9         2.4          3.3         1.0 versicolor
14          5.0         2.0          3.5         1.0 versicolor
15          5.0         2.3          3.3         1.0 versicolor</code></pre>
</div>
</div>
</section>
<section id="aggregate" class="level4">
<h4 class="anchored" data-anchor-id="aggregate">Aggregate</h4>
<p>Similarly, for the <code>/aggregate</code> endpoint:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(jsonlite)</span>
<span id="cb12-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(httr2)</span>
<span id="cb12-3"></span>
<span id="cb12-4">aggregate_instructions <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb12-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groups =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Species"</span>),</span>
<span id="cb12-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">aggregates =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb12-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Length"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>),</span>
<span id="cb12-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Width"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>)</span>
<span id="cb12-9">  )</span>
<span id="cb12-10">)</span>
<span id="cb12-11"></span>
<span id="cb12-12">aggregate_json <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toJSON</span>(aggregate_instructions, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">auto_unbox =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb12-13">jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prettify</span>(aggregate_json)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>{
    "groups": {
        "col": "Species"
    },
    "aggregates": [
        {
            "col": "Sepal.Length",
            "fun": "mean"
        },
        {
            "col": "Sepal.Width",
            "fun": "mean"
        }
    ]
}
 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">request</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"http://127.0.0.1:5000"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_url_path</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"aggregate"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_body_json</span>(</span>
<span id="cb14-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"iris"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">instructions_list =</span> aggregate_json),</span>
<span id="cb14-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">auto_unbox =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb14-6">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">req_perform</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">resp_body_json</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simplifyVector =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>     Species Sepal.Length_mean Sepal.Width_mean
1     setosa              5.01             3.43
2 versicolor              5.94             2.77
3  virginica              6.59             2.97</code></pre>
</div>
</div>
</section>
</section>
<section id="how-is-this-useful" class="level3">
<h3 class="anchored" data-anchor-id="how-is-this-useful">How is this useful?</h3>
<p>I struggle with this sometimes my self. Isn’t this why we have databases to begin with? Of course, having an API that queries a database would be preferable in most applications requiring large amounts of data. However, sometimes we don’t have the expertise, bandwidth, or budget for a database setup, or we could be working with local files, in <code>arrow</code>, <code>parquet</code>, <code>qs</code> or some other format where it might make sense or is justifiable to run the queries in <code>R</code> it self.</p>
</section>
<section id="summary" class="level3">
<h3 class="anchored" data-anchor-id="summary">Summary</h3>
<p>In this post, we demonstrated how to create a <code>{plumber}</code> API that provides endpoints for dynamic filtering and aggregation of datasets in <code>R</code>. We structured the API as an <code>R</code> package, defined the necessary functions, and set up the endpoints to handle JSON requests. We also provided examples of how to interact with the API using <code>httr2</code> from <code>R</code>. This approach can be useful for scenarios where a database setup is not feasible, and we need to work with data files directly in <code>R</code>.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>plumber</category>
  <category>API</category>
  <category>filter</category>
  <category>aggregate</category>
  <category>httr2</category>
  <guid>https://discindo.org/posts/2025-02-13-plumber-snippet/</guid>
  <pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-02-13-plumber-snippet/images/image.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>How to dynamically aggregate any dataset in R with purrr and dplyr</title>
  <dc:creator>teo </dc:creator>
  <link>https://discindo.org/posts/2025-02-06-aggregate-snippet/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>This post continues what I started <a href="../../posts/2025-01-31-filter-snippet">last time</a>, when I described an approach for dynamic filtering of data frame in <code>R</code>. The motivation and approach are very similar. In short, we want to have a function that takes a list with instructions about how to aggregate a data frame. This is desirable in non-interactive or automated workflows as in these cases we usually don’t know what the user might request. Creating a flexible interface, where one can send a JSON with aggregation instructions therefore can be very helpful for various <code>{shiny}</code> and <code>{plumber}</code> tasks.</p>
<section id="dynamic-aggregation" class="level3">
<h3 class="anchored" data-anchor-id="dynamic-aggregation">Dynamic aggregation</h3>
<p>As with the dynamic filter, we want something of the form:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.aggregate</span>(my_data, my_list_of_instructions)</span></code></pre></div></div>
</div>
<p>For aggregation to work, we need to specify at least one grouping variable, and then the names and aggregation functions for the columns we would like to summarize. So the instructions list should have the form:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">aggr_list <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb2-2">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groups =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"group_var"</span>),</span>
<span id="cb2-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">aggregates =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb2-4">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"column 1"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>),</span>
<span id="cb2-5">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"column 2"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sd"</span>),</span>
<span id="cb2-6">        ...</span>
<span id="cb2-7">    )</span>
<span id="cb2-8">)</span></code></pre></div></div>
</div>
<p>To show an example, we could get the mean, median, and standard deviation of Sepal Length in species from the <code>iris</code> dataset:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">d <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> iris</span>
<span id="cb3-2">l <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb3-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groups =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Species"</span>),</span>
<span id="cb3-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">aggregates =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb3-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Length"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>),</span>
<span id="cb3-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Length"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"median"</span>),</span>
<span id="cb3-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Length"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sd"</span>)</span>
<span id="cb3-8">  )</span>
<span id="cb3-9">)</span>
<span id="cb3-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.aggregate</span>(d, l)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Joining with `by = join_by(Species)`
Joining with `by = join_by(Species)`</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>     Species Sepal.Length_mean Sepal.Length_median Sepal.Length_sd
1     setosa              5.01                 5.0            0.35
2 versicolor              5.94                 5.9            0.52
3  virginica              6.59                 6.5            0.64</code></pre>
</div>
</div>
<p>As we can tell, we in the <code>aggregates list</code>, we can specify the same column multiple times, and the resulting table will only contain the columns for which we’ve specified an aggregation.</p>
<p>A more complex example would be to group on more than variable and summarize multiple columns. For example, group by cylinder, gear and carburetor and find the mean of miles per gallon, the total horse power and the median weight of cars in the <code>mtcars</code> dataset:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">d <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> mtcars</span>
<span id="cb6-2">l <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb6-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groups =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cyl"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gear"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"carb"</span>)),</span>
<span id="cb6-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">aggregates =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb6-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>),</span>
<span id="cb6-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hp"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sum"</span>),</span>
<span id="cb6-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wt"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"median"</span>)</span>
<span id="cb6-8">  )</span>
<span id="cb6-9">)</span>
<span id="cb6-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.aggregate</span>(d, l)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Joining with `by = join_by(cyl, gear, carb)`
Joining with `by = join_by(cyl, gear, carb)`</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>   cyl gear carb mpg_mean hp_sum wt_median
1    6    4    4    19.75    466      3.16
2    4    4    1    29.10    290      2.07
3    6    3    1    19.75    215      3.34
4    8    3    2    17.15    650      3.48
5    8    3    4    12.62   1140      5.25
6    4    4    2    24.75    318      2.96
7    8    3    3    16.30    540      3.78
8    4    3    1    21.50     97      2.46
9    4    5    2    28.20    204      1.83
10   8    5    4    15.80    264      3.17
11   6    5    6    19.70    175      2.77
12   8    5    8    15.00    335      3.57</code></pre>
</div>
</div>
<p>Neat. Again, the motivation here is not to replace the sweet <code>{dplyr}</code> syntax, rather to come up with a mechanism to do complex aggregation in one step, by creating an instructions list (or JSON) which, again, in <code>{shiny}</code> or <code>{plumber}</code> context would most likely be constructed programmatically.</p>
</section>
<section id="how-does-it-work" class="level3">
<h3 class="anchored" data-anchor-id="how-does-it-work">How does it work?</h3>
<p>Similar to our filtering function, we have two sections. First is input validation, again using <code>{checkmate}</code> because it’s awesome. We can make sure that the inputs are of correct type, that they are named, and that the columns specified as grouping and aggregation variables are present in the dataset. Likewise, we ensure that the requested aggregation functions are supported.</p>
<p>In the second section, we first convert the string passed to <code>fun</code> to a function, so it can be used downstream in <code>dplyr::summarize</code>. We do this with a helper function that can be called at the time <code>summarize</code> executes.</p>
<p>Then, we loop over the contents of the <code>aggregates</code> sub-list and apply each aggregation independently resulting in a list of aggregated datasets. For example, if we specified the mean, median, and sd for Sepal Length by Species, at this stage we would have a list of three data frames with the grouping column and another column representing the aggregate.</p>
<p>Finally, to collate the tables we use <code>reduce</code> with <code>left_join</code>, essentially joining the three data frames by species.</p>
<p>Note the nice argument <code>.by</code> for <code>dplyr::summarize</code>. In this case we just send the string from the <code>groups$col</code> slot in our instructions list. i.e we don’t need to use <code>dplyr::group_by</code> and the NSE construct it would require (converting it to symbol, and <code>!!</code> it).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' Aggregate a dataset</span></span>
<span id="cb9-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param .data the data frame</span></span>
<span id="cb9-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param .arglist a list of column names to group by</span></span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @examples</span></span>
<span id="cb9-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' d &lt;- iris</span></span>
<span id="cb9-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' l &lt;- list(</span></span>
<span id="cb9-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'   groups = list(col = "Species"),</span></span>
<span id="cb9-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'   aggregates = list(</span></span>
<span id="cb9-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'     list(col = "Sepal.Length", fun = "mean"),</span></span>
<span id="cb9-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'     list(col = "Sepal.Width", fun = "mean")</span></span>
<span id="cb9-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'   )</span></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' )</span></span>
<span id="cb9-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' .aggregate(d, l)</span></span>
<span id="cb9-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @return a data frame with the columns aggregated</span></span>
<span id="cb9-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @export</span></span>
<span id="cb9-16">.aggregate <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(.data, .arglist) {</span>
<span id="cb9-17">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_data_frame</span>(.data)</span>
<span id="cb9-18">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_list</span>(.arglist, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">types =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"list"</span>)</span>
<span id="cb9-19">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_named</span>(.arglist)</span>
<span id="cb9-20">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_subset</span>(</span>
<span id="cb9-21">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(.arglist),</span>
<span id="cb9-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">choices =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"groups"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"aggregates"</span>)</span>
<span id="cb9-23">  )</span>
<span id="cb9-24">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_list</span>(.arglist<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>groups, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">len =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb9-25">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_subset</span>(</span>
<span id="cb9-26">    purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pluck</span>(.arglist, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"groups"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"col"</span>),</span>
<span id="cb9-27">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">choices =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(.data)</span>
<span id="cb9-28">  )</span>
<span id="cb9-29">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_subset</span>(</span>
<span id="cb9-30">    purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pluck</span>(.arglist, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"aggregates"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"col"</span>),</span>
<span id="cb9-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">choices =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(.data)</span>
<span id="cb9-32">  )</span>
<span id="cb9-33">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_subset</span>(</span>
<span id="cb9-34">    purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pluck</span>(.arglist, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"aggregates"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fun"</span>),</span>
<span id="cb9-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">choices =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb9-36">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"median"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sum"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"min"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sd"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"count"</span></span>
<span id="cb9-37">    )</span>
<span id="cb9-38">  )</span>
<span id="cb9-39"></span>
<span id="cb9-40">  .get_aggr_fun <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb9-41">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">switch</span>(x,</span>
<span id="cb9-42">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> mean,</span>
<span id="cb9-43">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"median"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> stats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>median,</span>
<span id="cb9-44">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sum"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> sum,</span>
<span id="cb9-45">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"min"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> min,</span>
<span id="cb9-46">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> max,</span>
<span id="cb9-47">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sd"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> sd,</span>
<span id="cb9-48">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> var,</span>
<span id="cb9-49">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"count"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> length</span>
<span id="cb9-50">    )</span>
<span id="cb9-51">  }</span>
<span id="cb9-52"></span>
<span id="cb9-53">  aggr_dataset <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(</span>
<span id="cb9-54">    .arglist<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>aggregates,</span>
<span id="cb9-55">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.f =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb9-56">      .data,</span>
<span id="cb9-57">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste</span>(.x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>col, .x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>fun, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sep =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb9-58">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.get_aggr_fun</span>(.x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>fun)(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!!</span>rlang<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sym</span>(.x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>col)),</span>
<span id="cb9-59">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> .arglist<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>groups<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>col</span>
<span id="cb9-60">    )</span>
<span id="cb9-61">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-62">    purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reduce</span>(dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>left_join) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-63">    dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate_if</span>(is.numeric, round, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb9-64"></span>
<span id="cb9-65">  aggr_dataset</span>
<span id="cb9-66">}</span></code></pre></div></div>
</div>
<p>In a <code>{shiny}</code> application, where we want to enable the user to select any column(s) to aggregate with some choices for aggregating function, it would require quite a bit of <code>if/else</code> logic to capture all the cases manually. Using this alternative, we simply harvest the user’s selections from the input and construct the list of instructions before plugging it into <code>.aggregate</code> to obtain our results.</p>
</section>
<section id="summary" class="level3">
<h3 class="anchored" data-anchor-id="summary">Summary</h3>
<p>In this post, we explored a method for dynamically aggregating datasets in R using <code>purrr</code> and <code>dplyr</code>. We created a function <code>.aggregate</code> that takes a data frame and a list of instructions specifying the grouping variables and the aggregation functions to apply. This approach is particularly useful in non-interactive or automated workflows, such as in <code>{shiny}</code> applications or <code>{plumber}</code> APIS, where the user might specify different aggregation requirements.</p>
<p>We demonstrated the usage of the <code>.aggregate</code> function with examples using the <code>iris</code> and <code>mtcars</code> datasets, showing how to group by one or more variables and apply various aggregation functions. The function ensures input validation using <code>{checkmate}</code> and dynamically applies the specified aggregation functions, collating the results into a single data frame.</p>
<p>This method provides a flexible and efficient way to perform complex aggregations programmatically, reducing the need for extensive <code>if/else</code> logic and making it easier to handle user-defined aggregation instructions.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>aggregate</category>
  <category>dynamic</category>
  <category>purrr</category>
  <category>dplyr</category>
  <guid>https://discindo.org/posts/2025-02-06-aggregate-snippet/</guid>
  <pubDate>Thu, 06 Feb 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-02-06-aggregate-snippet/images/image.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>How to dynamically filter any dataset in R with purrr and dplyr</title>
  <dc:creator>teo </dc:creator>
  <link>https://discindo.org/posts/2025-01-31-filter-snippet/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<section id="interactive-and-dynamic-filtering" class="level3">
<h3 class="anchored" data-anchor-id="interactive-and-dynamic-filtering">Interactive and dynamic filtering</h3>
<p>The <code>{tidyverse}</code>, and <code>{dplyr}</code> in particular, have made data manipulation in <code>R</code> a breeze. In an interactive setting, the pattern:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">my_data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-2">    dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(my_col <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> my_value) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-3">    ...</span></code></pre></div></div>
</div>
<p>gives a lot of power and joy to everyone, including beginner programmers.</p>
<p>However, we often run into hurdles when trying to translate our script written for interactive analysis into code that can be run automatically. Where we won’t know ahead of time what column to filter on, or what values we should retain.</p>
<p>In such cases, we often write <code>if</code> statements, along the lines of:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"my_col1"</span>) {</span>
<span id="cb2-2">    dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(my_col1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> my_val1)</span>
<span id="cb2-3">} <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> my_col2) {</span>
<span id="cb2-4">    dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(my_col2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> my_val2)</span>
<span id="cb2-5">} ...</span></code></pre></div></div>
</div>
<p>Its easy to see how such approaches become long-winded, error prone, slow, and result in untidy, less extensible and maintainable code.</p>
<p>This is common, for example if you have a <code>{plumber}</code> API and an arbitrary user attempts to filter an arbitrary table in a data base. Or if you have a <code>{shiny}</code> application where the user uploads a table, with columns unknown to the code and then select one or more of them to filter on.</p>
<p>I have faced this many times, and have always wanted a solution where I can send instructions for filtering in the form of a named list, and get the filtered table. For this to work, the named list would need specify the column, filtering function, and values to retain (min, max, val). Then a function would take each element of the list, filter the dataset based on it, and finally return a table that combines all the filters. Or, more accurately, return the <em>intersect</em> of the filtered datasets.</p>
<p>Below is a function that solves this problem that I developed recently to add flexible dynamic filtering to a <code>{shiny}</code> application where the user can upload an arbitrary dataset, then select arbitrary filter columns and values and obtain the joint filtered result.</p>
<p>To find the <code>iris</code> flowers with sepal length between 4.9 and 5 and from species <em>setosa</em> and <em>versicolor</em>, we would write the following:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb3-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(checkmate)</span>
<span id="cb3-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb3-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(purrr)</span>
<span id="cb3-5">})</span>
<span id="cb3-6">l <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb3-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal.Length"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"between"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">min =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.9</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb3-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Species"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"in"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">val =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"setosa"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"versicolor"</span>))</span>
<span id="cb3-9">)</span>
<span id="cb3-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.filter</span>(iris, l)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1           4.9         3.0          1.4         0.2     setosa
2           5.0         3.6          1.4         0.2     setosa
3           5.0         3.4          1.5         0.2     setosa
4           4.9         3.1          1.5         0.1     setosa
5           5.0         3.0          1.6         0.2     setosa
6           5.0         3.4          1.6         0.4     setosa
7           4.9         3.1          1.5         0.2     setosa
8           5.0         3.2          1.2         0.2     setosa
9           4.9         3.6          1.4         0.1     setosa
10          5.0         3.5          1.3         0.3     setosa
11          5.0         3.5          1.6         0.6     setosa
12          5.0         3.3          1.4         0.2     setosa
13          4.9         2.4          3.3         1.0 versicolor
14          5.0         2.0          3.5         1.0 versicolor
15          5.0         2.3          3.3         1.0 versicolor</code></pre>
</div>
</div>
</section>
<section id="how-does-it-work" class="level3">
<h3 class="anchored" data-anchor-id="how-does-it-work">How does it work</h3>
<p>The function below has two sections. First we do input validation using <code>{checkmate}</code>. In a non-interactive setting, we can’t rely on the inputs being always correct, so validating, and returning meaningful errors is essential. For this job, I prefer <code>checkmate</code> because it has a nice and consistent interface with many built-in checking, asserting, and testing functions, but any other approach, including base <code>R</code>’s <code>stopifnot</code> or <code>assertthat</code> would work.</p>
<p>The second part is the filtering bit, where we have <code>purrr::map</code> cycle over each element of the filter list, grab the required filter function and go into one of two paths. If the column is numeric (date, datetime, integer, double), we use <code>dplyr::between</code> to filter. If, the column is character (string), factor or logical, we go with <code>%in%</code>.</p>
<p>After cycling over all elements of the filter list, the output would be a list of filtered datasets. We must now combine these into a single table, i.e.&nbsp;the table that we would get if we applied all these filters in one call, or sequentially. To do this, we use a bit more functional programming magic with <code>purrr::reduce</code> with the <code>intersect</code> function from <code>dplyr</code>. This final step, reduces the list of data frames to a single table containing only the rows that are shared between the data frames.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' Filter a dataset</span></span>
<span id="cb5-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param .data the data frame</span></span>
<span id="cb5-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param .arglist a list of filter specifications</span></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @examples</span></span>
<span id="cb5-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' d &lt;- iris</span></span>
<span id="cb5-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' l &lt;- list(</span></span>
<span id="cb5-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'   list(col = "Sepal.Length", fun = "between", min = 4, max = 5),</span></span>
<span id="cb5-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'   list(col = "Species", fun = "in", val = c("setosa", "versicolor"))</span></span>
<span id="cb5-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' )</span></span>
<span id="cb5-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' .filter(d, l)</span></span>
<span id="cb5-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @import checkmate</span></span>
<span id="cb5-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @import purrr</span></span>
<span id="cb5-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @import dplyr</span></span>
<span id="cb5-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @export</span></span>
<span id="cb5-15">.filter <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(.data, .arglist) {</span>
<span id="cb5-16">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_data_frame</span>(.data)</span>
<span id="cb5-17">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_list</span>(.arglist, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">types =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"list"</span>)</span>
<span id="cb5-18">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_subset</span>(</span>
<span id="cb5-19">    purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map_chr</span>(.arglist, purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>pluck, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"col"</span>),</span>
<span id="cb5-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">choices =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(.data)</span>
<span id="cb5-21">  )</span>
<span id="cb5-22">  checkmate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assert_subset</span>(</span>
<span id="cb5-23">    purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map_chr</span>(.arglist, purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>pluck, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fun"</span>),</span>
<span id="cb5-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">choices =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"in"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"between"</span>)</span>
<span id="cb5-25">  )</span>
<span id="cb5-26"></span>
<span id="cb5-27">  purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(.arglist, <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb5-28">    col <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>col</span>
<span id="cb5-29">    fun <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>fun</span>
<span id="cb5-30">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (fun <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"between"</span>) {</span>
<span id="cb5-31">      min <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>min</span>
<span id="cb5-32">      max <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>max</span>
<span id="cb5-33">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(min) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(max)) {</span>
<span id="cb5-34">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(.data)</span>
<span id="cb5-35">      }</span>
<span id="cb5-36">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(</span>
<span id="cb5-37">        dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(.data, dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(</span>
<span id="cb5-38">          <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!!</span>rlang<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sym</span>(col), min, max</span>
<span id="cb5-39">        ))</span>
<span id="cb5-40">      )</span>
<span id="cb5-41">    }</span>
<span id="cb5-42">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (fun <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"in"</span>) {</span>
<span id="cb5-43">      val <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>val</span>
<span id="cb5-44">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(val)) {</span>
<span id="cb5-45">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(.data)</span>
<span id="cb5-46">      }</span>
<span id="cb5-47">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(.data, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">%in%</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>(</span>
<span id="cb5-48">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!!</span>rlang<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sym</span>(col)), val</span>
<span id="cb5-49">      )))</span>
<span id="cb5-50">    }</span>
<span id="cb5-51">  }) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reduce</span>(dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>intersect)</span>
<span id="cb5-52">}</span></code></pre></div></div>
</div>
<p>To show another example, filter cars with mpg between 15 and 20 and cyl in 4 or 6</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">l <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb6-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"between"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">min =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>),</span>
<span id="cb6-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cyl"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"in"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">val =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb6-4">)</span>
<span id="cb6-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.filter</span>(mtcars, l)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>              mpg cyl  disp  hp drat   wt  qsec vs am gear carb
Valiant      18.1   6 225.0 105 2.76 3.46 20.22  1  0    3    1
Merc 280     19.2   6 167.6 123 3.92 3.44 18.30  1  0    4    4
Merc 280C    17.8   6 167.6 123 3.92 3.44 18.90  1  0    4    4
Ferrari Dino 19.7   6 145.0 175 3.62 2.77 15.50  0  1    5    6</code></pre>
</div>
</div>
<p>Pretty neat. In future posts, I’ll show how I use this in <code>{shiny}</code> context, where the construction of the filter list should also be automated.</p>
</section>
<section id="summary" class="level3">
<h3 class="anchored" data-anchor-id="summary">Summary</h3>
<p>In this post, we explored a method to dynamically filter datasets in R using <code>purrr</code> and <code>dplyr</code>. We discussed the limitations of traditional filtering approaches and introduced a flexible function that accepts a list of filter specifications. This function validates inputs using <code>checkmate</code> and applies the filters using <code>purrr</code> and <code>dplyr</code>. We demonstrated its usage with examples on the <code>iris</code> and <code>mtcars</code> datasets. This approach is particularly useful in interactive applications like <code>shiny</code>, where users can upload arbitrary datasets and apply custom filters dynamically.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>filter</category>
  <category>dynamic</category>
  <category>purrr</category>
  <category>dplyr</category>
  <guid>https://discindo.org/posts/2025-01-31-filter-snippet/</guid>
  <pubDate>Fri, 31 Jan 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-01-31-filter-snippet/images/image.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Sharing data between pages in a multi-page Brochure Shiny application</title>
  <dc:creator>teo </dc:creator>
  <link>https://discindo.org/posts/shiny/2025-01-27-brochure-caching/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>During 2024 I had an opportunity to work on an R/Shiny project for a large pharmaceutical company. I was in charge of converting a set of complex Excel workbooks into a <code>{shiny}</code> application. The application had tight integration with two databases, one for data retrieval and another for storing user history, preferences, and results. One of the requirements was that the application works with web-browser buttons (forward, back) and as we know, that is not a feature of <code>{shiny}</code> out of the box.</p>
<p>A <code>{shiny}</code> application by default is single-page and single-session. Meaning when we navigate from one to another “page” in a typical shiny application, some parts of the UI are hidden and others displayed, giving the impression that we went somewhere else. But in fact all of our application’s UI is still loaded in the browser, and its only partially shown. This is why, by default, navigating with browser buttons does not work. There is simply no previous page to return to when we hit <code>Back</code>.</p>
<p>There are a few ways to enable this behavior for <code>{shiny}</code> applications. We can use the <a href="https://appsilon.github.io/shiny.router/index.html"><code>shiny.router</code></a> or <a href="https://github.com/nteetor/blaze"><code>blaze</code></a> packages to ‘simulate’ navigation by modifying the URL paths. There is also functionality within <code>{shiny}</code> it self to update and parse the URL query string, so one can devise with server logic to mimic page-navigation as shown <a href="https://stackoverflow.com/a/71807248">here</a>. These methods work fine, and I have used some of them before for production applications, but none of them <a href="https://colinfay.me/brochure-r-package/">implement true multi-page applications</a>.</p>
<p>The <a href="https://github.com/ColinFay/brochure"><code>{brochure}</code> package</a>, still <strong>“work in progress, use at your own risk”</strong>, is the only approach so far that enables true multi-page and multi-session <code>{shiny}</code> applications. Meaning, the URL “myapp/page1” runs in its own R session and shares no data with the URL “myapp/page2”. Therefore, variables input by the user or calculated on page 1 have to be somehow saved so page 2 can access them. The <code>{brochure}</code> package includes examples and functionality to do just this through either caching or browser cookies, with browser local storage and databases as additional possibilities. However, all of it has to be done manually, meaning, you as the developer have to know what variables to store and then retrieve in the server on another page. In a single-page <code>{shiny}</code> this is typically not something we worry about, as inputs from “tab 1” are still available in the session, even though we’ve navigated to “tab 2”.</p>
<p>Back to my large <code>{shiny}</code> project I started with. I decided to use <code>{brochure}</code> for the full multi-page experience, and even though the final product was an impressive application, I ran into a major hurdle with sharing data between pages. I used a local disk cache to store variables in one page and then retrieve them later on other pages. This method is very simple and effective, but I had to cache dozens of variables per page, often not single values, but lists, data frames, and even some <code>R6</code> objects. Commonly, a single variable might be updated in multiple places in the server or in different submodules, and in all these cases I had to remember to cache the object. This resulted in repetitive and complicated code, which I did not anticipate soon enough, so when things became too thick and the project was in a very advanced state, I had no choice but to keep going. There was no time and budget to go back and refactor the data sharing aspect of the code, to come up with a more streamlined solution.</p>
<p>So, now, after a few months, I came back to this problem and I think I have a minor improvement. In the next few examples I outline step-by-step how one can simplify, or at least reduce repetitiveness of page-level caching in <code>{brochure}</code> applications.</p>
<p>In all code below I use these options and load the following packages. The options set the browser and instruct <code>{shiny}</code> to run the application externally, as browser button navigation does not make sense in a viewer pane. Moreover, before each example, we clear the local disk cache and re-initialize it. This ensures that the new examples are not pulling values stored in a previous’ examples cache.</p>
<section id="prep-code" class="level3">
<h3 class="anchored" data-anchor-id="prep-code">Prep code</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">options</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">browser =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/usr/bin/firefox"</span>)</span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">options</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">launch.browser =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(shiny)</span>
<span id="cb1-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(brochure)</span>
<span id="cb1-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(cachem)</span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unlink</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"brochure_cache"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">recursive =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-9">brochure_cache <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> cachem<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cache_disk</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"brochure_cache"</span>)</span></code></pre></div></div>
</div>
</section>
<section id="variables-are-not-shared-among-brochure-pages" class="level3">
<h3 class="anchored" data-anchor-id="variables-are-not-shared-among-brochure-pages">Variables are not shared among <code>{brochure}</code> pages</h3>
<p>One of the features of <code>{brochure}</code> is that each page runs in its own session and is ignorant of variables, reactives, inputs, etc. from other pages. We can show this easily with this basic example. The variable <code>some_var</code> is created in the home page (<code>/</code>) and when we try to <code>renderPrint</code> it in <code>page2</code> we get an error that the object is not found.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brochureApp</span>(</span>
<span id="cb2-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First page</span></span>
<span id="cb2-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb2-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>,</span>
<span id="cb2-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb2-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my first page"</span>)</span>
<span id="cb2-7">    ),</span>
<span id="cb2-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb2-9">      some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb2-10">    }</span>
<span id="cb2-11">  ),</span>
<span id="cb2-12">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Second page</span></span>
<span id="cb2-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb2-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/page2"</span>,</span>
<span id="cb2-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb2-16">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my second page"</span>),</span>
<span id="cb2-17">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>)</span>
<span id="cb2-18">    ),</span>
<span id="cb2-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb2-20">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(some_var)</span>
<span id="cb2-21">    }</span>
<span id="cb2-22">  )</span>
<span id="cb2-23">)</span></code></pre></div></div>
</div>
</section>
<section id="sharing-variables-with-caching-to-disk" class="level3">
<h3 class="anchored" data-anchor-id="sharing-variables-with-caching-to-disk">Sharing variables with caching to disk</h3>
<p>As we said, we have to store <code>some_var</code> somewhere outside the session of the page where it was created so we can retrieve it in the server of another page. The chunk below does that, in <code>/</code> we set the cache value <code>some_var</code> and in <code>page2</code> we get it, and can print it in the UI.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brochureApp</span>(</span>
<span id="cb3-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First page</span></span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb3-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>,</span>
<span id="cb3-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb3-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my first page"</span>)</span>
<span id="cb3-7">    ),</span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb3-9">      some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb3-10">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>, some_var)</span>
<span id="cb3-11">    }</span>
<span id="cb3-12">  ),</span>
<span id="cb3-13">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Second page</span></span>
<span id="cb3-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb3-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/page2"</span>,</span>
<span id="cb3-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb3-17">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my second page"</span>),</span>
<span id="cb3-18">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>)</span>
<span id="cb3-19">    ),</span>
<span id="cb3-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb3-21">      some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>)</span>
<span id="cb3-22">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(some_var)</span>
<span id="cb3-23">    }</span>
<span id="cb3-24">  )</span>
<span id="cb3-25">)</span></code></pre></div></div>
</div>
<p>Now, this is all great, except if we have dozens of variables that we need to share between pages. In this case we’d have to individually cache each of them or update a list and then re-cache the list every time its updated. Or if we need to cache an input, we’d need an observer to monitor that input and cache it on each change, potentially adding unnecessary workload to the session. It becomes cumbersome quickly, and the code gets long and potentially complex, for a relatively basic operation.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brochureApp</span>(</span>
<span id="cb4-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First page</span></span>
<span id="cb4-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb4-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>,</span>
<span id="cb4-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb4-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my first page"</span>)</span>
<span id="cb4-7">    ),</span>
<span id="cb4-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb4-9">      var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb4-10">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var1"</span>, var1)</span>
<span id="cb4-11">      var2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span></span>
<span id="cb4-12">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var2"</span>, var2)</span>
<span id="cb4-13">      var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb4-14">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var3"</span>, var3)</span>
<span id="cb4-15">      var4 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span></span>
<span id="cb4-16">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var4"</span>, var4)</span>
<span id="cb4-17">      var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span></span>
<span id="cb4-18">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var5"</span>, var5)</span>
<span id="cb4-19">      var6 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span></span>
<span id="cb4-20">      brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var6"</span>, var6)</span>
<span id="cb4-21">    }</span>
<span id="cb4-22">  ),</span>
<span id="cb4-23">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Second page</span></span>
<span id="cb4-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb4-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/page2"</span>,</span>
<span id="cb4-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb4-27">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my second page"</span>),</span>
<span id="cb4-28">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>)</span>
<span id="cb4-29">    ),</span>
<span id="cb4-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb4-31">      vars <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sapply</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, \(i) brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var"</span>, i)))</span>
<span id="cb4-32">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(vars))</span>
<span id="cb4-33">    }</span>
<span id="cb4-34">  )</span>
<span id="cb4-35">)</span></code></pre></div></div>
</div>
</section>
<section id="simplifying-the-caching-of-several-variables" class="level3">
<h3 class="anchored" data-anchor-id="simplifying-the-caching-of-several-variables">Simplifying the caching of several variables</h3>
<p>What I was hoping for at the time is for a single-step caching of the state of the page session right before the user navigates to another page. It did not occur to me that a mechanism for this was already available in <code>{shiny}</code>. Simply use <code>onSessionEnded</code> to harvest and cache the variables you need to share with another page. So simple.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brochureApp</span>(</span>
<span id="cb5-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First page</span></span>
<span id="cb5-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb5-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>,</span>
<span id="cb5-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb5-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my first page"</span>)</span>
<span id="cb5-7">    ),</span>
<span id="cb5-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb5-9">      var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb5-10">      var2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb5-11">      var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb5-12">      var4 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb5-13">      var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span></span>
<span id="cb5-14">      var6 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb5-15"></span>
<span id="cb5-16">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">onSessionEnded</span>(<span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb5-17">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lapply</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, \(i) {</span>
<span id="cb5-18">          brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var"</span>, i), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var"</span>, i)))</span>
<span id="cb5-19">        })</span>
<span id="cb5-20">      })</span>
<span id="cb5-21">    }</span>
<span id="cb5-22">  ),</span>
<span id="cb5-23">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Second page</span></span>
<span id="cb5-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb5-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/page2"</span>,</span>
<span id="cb5-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb5-27">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my second page"</span>),</span>
<span id="cb5-28">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>)</span>
<span id="cb5-29">    ),</span>
<span id="cb5-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb5-31">      vars <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sapply</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, \(i) brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var"</span>, i)))</span>
<span id="cb5-32">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(vars))</span>
<span id="cb5-33">    }</span>
<span id="cb5-34">  )</span>
<span id="cb5-35">)</span></code></pre></div></div>
</div>
<p>Regardless of how many times <code>var1</code> is updated during the session, we don’t have to worry about caching it. It will get done when the session is closed, i.e.&nbsp;when the user navigates to another page or closes the web page.</p>
</section>
<section id="cleaner-approach.-a-list-to-store-variables-to-be-cached" class="level3">
<h3 class="anchored" data-anchor-id="cleaner-approach.-a-list-to-store-variables-to-be-cached">Cleaner approach. A list to store variables to be cached</h3>
<p>Thinking about this some more, it certainly makes sense to have a page-level list of variables that need to be cached. Then, when we cache on session end, we can cycle over the contents of that list, not dozens of individual variables. Along the lines of:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brochureApp</span>(</span>
<span id="cb6-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First page</span></span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb6-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>,</span>
<span id="cb6-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb6-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my first page"</span>)</span>
<span id="cb6-7">    ),</span>
<span id="cb6-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb6-9">      var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-10">      var2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb6-11">      var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb6-12">      var4 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb6-13">      var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span></span>
<span id="cb6-14">      var6 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb6-15"></span>
<span id="cb6-16">      to_cache_list <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>()</span>
<span id="cb6-17">      to_cache_list<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> var1</span>
<span id="cb6-18">      to_cache_list<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> var3</span>
<span id="cb6-19">      to_cache_list<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> var5</span>
<span id="cb6-20"></span>
<span id="cb6-21">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">onSessionEnded</span>(<span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>() {</span>
<span id="cb6-22">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lapply</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(to_cache_list), \(x) {</span>
<span id="cb6-23">          brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(x, to_cache_list[[x]])</span>
<span id="cb6-24">        })</span>
<span id="cb6-25">      })</span>
<span id="cb6-26">    }</span>
<span id="cb6-27">  ),</span>
<span id="cb6-28">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Second page</span></span>
<span id="cb6-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb6-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/page2"</span>,</span>
<span id="cb6-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb6-32">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my second page"</span>),</span>
<span id="cb6-33">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>)</span>
<span id="cb6-34">    ),</span>
<span id="cb6-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb6-36">      var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var1"</span>)</span>
<span id="cb6-37">      var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var3"</span>)</span>
<span id="cb6-38">      var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var5"</span>)</span>
<span id="cb6-39">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(var1, var3, var5))</span>
<span id="cb6-40">    }</span>
<span id="cb6-41">  )</span>
<span id="cb6-42">)</span></code></pre></div></div>
</div>
</section>
<section id="still-to-cumbersome-cache-the-kitchen-sink" class="level3">
<h3 class="anchored" data-anchor-id="still-to-cumbersome-cache-the-kitchen-sink">Still to cumbersome? Cache the kitchen sink</h3>
<p>Finally, we can take this a step further, perhaps unwisely, and store the entire environment. Within <code>onSessionEnded</code>, we define a callback function whose environment is a child of the server’s environment. So we can collect the contents of the parent environment, convert to a list for easier handling, and simply cache all of it as <code>pageX_data</code>. Then, when we need to retrieve a value from pageX, we load the cache and index it with the benefit of knowing that the cache’s structure is going to reflect the structure of the pageX environment.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brochureApp</span>(</span>
<span id="cb7-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First page</span></span>
<span id="cb7-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb7-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>,</span>
<span id="cb7-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb7-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my first page"</span>),</span>
<span id="cb7-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sliderInput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"slide"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Shared input"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-8">    ),</span>
<span id="cb7-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb7-10">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">observe</span>({</span>
<span id="cb7-11">        slide_value <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"page_1_data"</span>)[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"input"</span>]][[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"slide"</span>]]</span>
<span id="cb7-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(slide_value)) {</span>
<span id="cb7-13">          <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">updateSliderInput</span>(</span>
<span id="cb7-14">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">inputId =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"slide"</span>,</span>
<span id="cb7-15">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Shared input"</span>,</span>
<span id="cb7-16">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> slide_value</span>
<span id="cb7-17">          )</span>
<span id="cb7-18">        }</span>
<span id="cb7-19">      })</span>
<span id="cb7-20">      var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb7-21">      var2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span></span>
<span id="cb7-22">      var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb7-23">      var4 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb7-24">      var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb7-25">      var6 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb7-26"></span>
<span id="cb7-27">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">onSessionEnded</span>(<span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>() {</span>
<span id="cb7-28">        env <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">environment</span>()</span>
<span id="cb7-29">        page_env <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parent.env</span>(env))</span>
<span id="cb7-30">        page_env<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>output <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb7-31">        page_env<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>session <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb7-32">        brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"page_1_data"</span>, page_env)</span>
<span id="cb7-33">      })</span>
<span id="cb7-34">    }</span>
<span id="cb7-35">  ),</span>
<span id="cb7-36">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Second page</span></span>
<span id="cb7-37">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page</span>(</span>
<span id="cb7-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/page2"</span>,</span>
<span id="cb7-39">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ui =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fluidPage</span>(</span>
<span id="cb7-40">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h1</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"This is my second page"</span>),</span>
<span id="cb7-41">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h5</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sum of some variables"</span>),</span>
<span id="cb7-42">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"some_var"</span>),</span>
<span id="cb7-43">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h5</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Input from previous page"</span>),</span>
<span id="cb7-44">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">verbatimTextOutput</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"slide_input"</span>)</span>
<span id="cb7-45">    ),</span>
<span id="cb7-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">server =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb7-47">      var1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"page_1_data"</span>)[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var1"</span>]]</span>
<span id="cb7-48">      var3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"page_1_data"</span>)[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var3"</span>]]</span>
<span id="cb7-49">      var5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"page_1_data"</span>)[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"var5"</span>]]</span>
<span id="cb7-50">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>some_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(var1, var3, var5))</span>
<span id="cb7-51">      slide <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reactive</span>(brochure_cache<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"page_1_data"</span>)[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"input"</span>]][[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"slide"</span>]])</span>
<span id="cb7-52">      output<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>slide_input <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderPrint</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slide</span>())</span>
<span id="cb7-53">    }</span>
<span id="cb7-54">  )</span>
<span id="cb7-55">)</span></code></pre></div></div>
</div>
<p>The example above also covers caching the <code>input</code> R6 from the <code>{shiny}</code> session and removes the <code>output</code> and <code>session</code> object, although if needed those could be cached as well. Apart from some input value being needed in another page, caching the <code>input</code> makes sense so we can update the input widget when we return to pageX. Again, as each page is its own session, unlike base <code>{shiny}</code>, when we return to pageX the input will be re-initialized with the value set in the code, not with the value previously set by the user, so updating it is necessary.</p>
<p>This last approach comes with a caveat. Its almost never a good idea to cache everything. The <code>input</code> object, for example, is a large R6 object. There could be data frames, lists, model results, etc within the session that have a large footprint and are not used in other pages. This could inflate the size of the cache or cause slowdowns when navigating between pages if saving takes a bit.</p>
<p>Personally, I prefer the approach of a page-level list of objects to be cached. It is more explicit and can be curated to minimize the size of the cache and potentially save time.</p>
</section>
<section id="summary" class="level3">
<h3 class="anchored" data-anchor-id="summary">Summary</h3>
<p>In this post, we explored various methods for sharing data between pages in a multi-page <code>{brochure}</code> <code>{shiny}</code> application. We started with a basic example demonstrating the isolation of sessions in <code>{brochure}</code> and the need for caching to share data. We then showed how to use <code>cachem</code> to store and retrieve variables between pages. To simplify the process, we introduced the use of <code>onSessionEnded</code> to cache variables at the end of a session. Finally, we discussed caching the entire environment and the potential pitfalls of this approach. These methods can help streamline data sharing in multi-page <code>{brochure}</code> applications, reducing repetitive code and improving maintainability.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>Shiny</category>
  <category>Brochure</category>
  <category>Cache</category>
  <category>multi-page</category>
  <category>multi-session</category>
  <guid>https://discindo.org/posts/shiny/2025-01-27-brochure-caching/</guid>
  <pubDate>Mon, 27 Jan 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/shiny/2025-01-27-brochure-caching/images/logos.jpg" medium="image" type="image/jpeg"/>
</item>
<item>
  <title>How to configure your shiny app content from a remote JSON file</title>
  <dc:creator>teo </dc:creator>
  <link>https://discindo.org/posts/shiny/2025-01-19-shiny-golem-config-json/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>A common question when developing a Shiny application goes along the lines of “How can I configure this?”, “Can it show different data?”, “What if I have a new client with a new logo and color scheme?”. There are of course many ways to approach configuration questions like these. One way is to implement server logic tied to some data about the client that logged in, keeping all the configuration logic in one codebase and have one deployed instance. Another way is to simply copy the code, make modifications to accommodate the differences in the UI and required data and deploy twice. Either approach, and the myriad in-between solutions, have their merits and drawbacks (complexity of code, maintainability, scalability, budget, etc.). Below I write about an approach that is somewhere in the middle that I used recently to provide flexibility for a client without major refactoring of the code, while maintaining a single code repository. Keeping it relatively simple, in other words.</p>
<p>In this example, we assume that there are predefined units of code (modules) that process different datasets and display results. The code can accommodate several different dataset types, but not all users have or need to access all types of data. Or in a subscription setting, one could say not all users have the subscription for each unit.</p>
<p>Furthermore, lets assume that there is some substantive data processing that occurrs before the data arrives to our Shiny application. For example, an analyst, you are performing some extensive machine learning procedure for different clients, resulting in charts and tables that need to be displayed in the Shiny application. The end-user of the application, <em>is not</em> analyzing the data, but seeing the final results, perhaps on some schedule.</p>
<p>In this scenario, it would help if the analyst can just update a cloud storage bucket with some results and automatically update the content of the Shiny application. The Shiny code is of course pointed to the cloud storage bucket (or database), so on the next session start can display the new data. Then, each client would have a separate bucket, and a separate instance of the Shiny application, to allow for flexibility between clients and different datasets versions for the same client.</p>
<section id="config-json" class="level3">
<h3 class="anchored" data-anchor-id="config-json">Config JSON</h3>
<p>Nothing particularly novel here. We just create a JSON file with a simple structure. The “meta” section has general info about the application and the client (logo, homepage, etc.). The “general” section contains info on the title of the particular app instance, and path to the data object. Depending on the needs this can be a folder (bucket) with several files, or a single file (like in the simple example here). Finally, we have the “pages” section where add information specific to the different pages/tabs the application has.</p>
<p>Some of the configurability comes in here. We can have separate pages for different types of data or subscription levels and enable/disable pages from this section accordingly.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode json code-with-copy"><code class="sourceCode json"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"meta"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Shiny golem config"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"version"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.0.1"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-5">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"description"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"An example of an app configured by a config file in the cloud"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-6">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"author"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Discindo"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-7">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"email"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hello@discindodata.com"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-8">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"logo"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"www/logo.png"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-9">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"favicon"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"favicon.ico"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-10">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"theme"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"default"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-11">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"language"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"en"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-12">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"homepage"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"discindo.org"</span></span>
<span id="cb1-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb1-14">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"general"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-15">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"title"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Test Title"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-16">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"subtitle"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A little longer subtitle just to show it (disable with `null`)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-17">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"data_path"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://raw.githubusercontent.com/discindo/shiny-golem-json-config/refs/heads/main/iris.csv"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-18">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"data_format"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"csv"</span></span>
<span id="cb1-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb1-20">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"pages"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-21">   <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"home"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-22">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"title"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Home"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-23">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"icon"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"home"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-24">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"url"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-25">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"template"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"inst/html/home.html"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-26">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"ui"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-27">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"server"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span></span>
<span id="cb1-28">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb1-29">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"data"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-30">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"title"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-31">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"icon"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"table"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-32">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"url"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/data"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-33">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"template"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-34">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"ui"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mod_data_ui"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-35">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"server"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mod_data_server"</span></span>
<span id="cb1-36">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb1-37">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"about"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-38">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"title"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"About"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-39">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"icon"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"info"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-40">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"url"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/about"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-41">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"template"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"inst/html/about.html"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-42">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"ui"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-43">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"server"</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span></span>
<span id="cb1-44">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-46"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</div>
<p>The config can be placed in the <code>inst</code> folder of the R package (if <code>{golem}</code>) or some other folder that is in the resource path of the Shiny app. But it can also live in the remote cloud location. Of course the Shiny app should have the required permissions to access these files.</p>
<p>In the example here, to keep things simple, the ‘remote-data’ folder is a public folder in the GitHub repository for the code used in this post. No additional files or variables are needed to access the config JSON and the data files. But if the data are in a private bucket at a cloud provider, the app would need to have read permissions for that bucket. Either through AWS IAM credentials, or Google cloud token, etc..</p>
</section>
<section id="shiny-code" class="level3">
<h3 class="anchored" data-anchor-id="shiny-code">Shiny code</h3>
<p>The Shiny app will need to load the config JSON from the cloud or local location, and use the configurations set by the user to generate the right content. In the example, I am using the <code>{golem}</code> setup, so there are separate <code>app_ui.r</code> and <code>app_server.r</code> scripts. Each one loads the JSON config using <code>jsonlite</code> and accesses the slots in the resulting list for the values it needs. If there are some expensive or repeated steps performed in the ui and server functions, we could use golem options or some other mechanism to parse the config JSON only once and pass the list as an argument or option to the main ui and server functions. But it this, admittedly simplified example, we parse the config twice, as its quite small.</p>
<p>In the <code>{rhino}</code> framework, something similar can be achieved by loading the config in <code>app.R</code>, and then using it in functions from <code>/logic/</code>. And in a “base” Shiny app, a straightforward approach would be to parse the config in <code>global.r</code> which would make the variable available in the scope of the ui and server functions.</p>
<section id="ui" class="level4">
<h4 class="anchored" data-anchor-id="ui">UI</h4>
<p>In the ui function we:</p>
<ul>
<li>load the config,</li>
<li>generate the pages UIs using <code>nav_panel</code> from <code>bslib</code>,</li>
<li>generate some basic aspects of the UI (brand, title, subtitle),</li>
<li>and finally <code>splice</code> in the pages/tabs</li>
</ul>
<p>To generate the content of the pages, we use either HTML Templates or Shiny modules. Of course this is not necessary, we can use R to write the HTML for the Home and About pages, or can make modules for all the pages, even if those modules are not intended to be reused. In the <code>{golem}</code> approach it is convenient that the module’s functions are exported from the package and can be accessed with <code>getFunction</code>. Similar approaches would work for <code>{rhino}</code> and base shiny setups.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">app_ui <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(request) {</span>
<span id="cb2-2">  config <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_json</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://raw.githubusercontent.com/discindo/shiny-golem-json-config/refs/heads/main/remote-data/app-config.json"</span>)</span>
<span id="cb2-3">  pages <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(</span>
<span id="cb2-4">    config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pages, <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb2-5">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>template)) {</span>
<span id="cb2-6">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nav_panel</span>(</span>
<span id="cb2-7">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>title,</span>
<span id="cb2-8">          shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">htmlTemplate</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>template)</span>
<span id="cb2-9">        ))</span>
<span id="cb2-10">      } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ui)) {</span>
<span id="cb2-11">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nav_panel</span>(</span>
<span id="cb2-12">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>title,</span>
<span id="cb2-13">          <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getFunction</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ui)(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data_1"</span>)</span>
<span id="cb2-14">        ))</span>
<span id="cb2-15">      } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {</span>
<span id="cb2-16">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nav_panel</span>(</span>
<span id="cb2-17">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>title,</span>
<span id="cb2-18">          x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>title</span>
<span id="cb2-19">        ))</span>
<span id="cb2-20">      }</span>
<span id="cb2-21">    }</span>
<span id="cb2-22">  )</span>
<span id="cb2-23">  shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tagList</span>(</span>
<span id="cb2-24">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Leave this function for adding external resources</span></span>
<span id="cb2-25">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">golem_add_external_resources</span>(),</span>
<span id="cb2-26">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Your application UI logic</span></span>
<span id="cb2-27">    shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">div</span>(</span>
<span id="cb2-28">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"container"</span>,</span>
<span id="cb2-29">      bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page_navbar</span>(</span>
<span id="cb2-30">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">theme =</span> bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bs_theme</span>(</span>
<span id="cb2-31">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bootswatch =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"litera"</span>,</span>
<span id="cb2-32">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_font =</span> bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lato"</span>)</span>
<span id="cb2-33">        ),</span>
<span id="cb2-34">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">inverse =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb2-35">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">underline =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb2-36">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">a</span>(</span>
<span id="cb2-37">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">href =</span> config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>meta<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>homepage,</span>
<span id="cb2-38">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_blank"</span>,</span>
<span id="cb2-39">          shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">img</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">src =</span> config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>meta<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>logo, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">height =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"70px"</span>)</span>
<span id="cb2-40">        ),</span>
<span id="cb2-41">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">header =</span> shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">div</span>(</span>
<span id="cb2-42">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p-5 text-center"</span>,</span>
<span id="cb2-43">          shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h4</span>(config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>general<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>title),</span>
<span id="cb2-44">          shiny<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h6</span>(config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>general<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>subtitle)</span>
<span id="cb2-45">        ),</span>
<span id="cb2-46">        bslib<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nav_spacer</span>(),</span>
<span id="cb2-47">        rlang<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">splice</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unname</span>(pages))</span>
<span id="cb2-48">      )</span>
<span id="cb2-49">    )</span>
<span id="cb2-50">  )</span>
<span id="cb2-51">}</span></code></pre></div></div>
</div>
</section>
<section id="server" class="level4">
<h4 class="anchored" data-anchor-id="server">Server</h4>
<p>In this example, the server is even simpler. All we need to do here is cycle over the <code>$pages</code> slot of the config, find the pages that have a <code>server</code> slot, and call the module server (obviously using the same <code>id</code> as in the ui). The data is passed to the module server as an argument, although this is not strictly required, as we can use <code>session$userData</code> to share the object across modules, or use some other mechanism. Again, in this simple example, there is only one data object, and we don’t do much with it apart to render a table. But in a real application we might need multiple files and more involved server logic. If many server data objects are needed, it might make sense to pass the paths to these objects to the module’s server rather than the data it self.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">app_server <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(input, output, session) {</span>
<span id="cb3-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Your application server logic</span></span>
<span id="cb3-3">  config <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> jsonlite<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_json</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"inst/app-config.json"</span>)</span>
<span id="cb3-4">  data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read.csv</span>(config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>general<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>data_path)</span>
<span id="cb3-5">  purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(config<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pages, <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb3-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>server)) {</span>
<span id="cb3-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getFunction</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>server)(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data_1"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> data)</span>
<span id="cb3-8">    }</span>
<span id="cb3-9">  })</span>
<span id="cb3-10">}</span></code></pre></div></div>
</div>
<p>In the event that we need multiple modules per page, for example modules for table, chart 1, chart2, we could organize the code in one “page-level” module, that calls individual tables, charts, maps modules. This way, we don’t have to build functionality to specify and call multiple modules per page <em>from</em> the config file. i.e., we could keep the config and top-level code simple, and build complexity at a lower level.</p>
</section>
<section id="configurability" class="level4">
<h4 class="anchored" data-anchor-id="configurability">Configurability</h4>
<p>The configurability in this simple example comes from the <code>$general$data_path</code> entry in the config. We can toggle between <code>iris</code> and <code>mtcars</code>. What other ways can this config json be used to customize the shiny app:</p>
<ul>
<li>have multiple ‘data’ pages, with different datasets or outputs</li>
<li>use different data processing modules</li>
<li>use different homepage link, logo, title, subtitle, …</li>
<li>use different input data formats specified through the <code>$general$data_format</code> (this is not implemented in the example, but one could write <code>switch</code> logic to read csv, excel, parquet, qs, RDS, etc.)</li>
<li>the config can be modified to have <code>data_path</code> and <code>data_format</code> entries on a per page (module) level. For example to load csv data in one page and a map in another.</li>
</ul>
<p>Using this approach is very similar in to using <code>{golem}</code>’s <code>golem-config.yml</code>, with the main difference that the the location of the config JSON can be anywhere. Like the <code>golem-config.yml</code> we can use the above approach to deploy a staging vs production app instances (i.e.&nbsp;by pointing them to staging vs production data buckets).</p>
<p>The data bucket directory structure:</p>
<div class="cell">
<pre class="shell cell-code"><code>remote-data/
├── app-config.json
├── iris.csv
└── mtcars.csv</code></pre>
</div>
<p>Of course, each data bucket, with its own config and data objects should in this case correspond to a deployed instance of the application. In the event of multiple clients, this makes sense, but it would obviously backfire after 5-10 clients. Maintaining that many data buckets and instances would be best approached with a database.</p>
</section>
</section>
<section id="summary" class="level3">
<h3 class="anchored" data-anchor-id="summary">Summary</h3>
<p>In this post, we explored how to configure a Shiny application using a remote JSON file. This approach allows for flexible and dynamic updates to the app’s content and appearance without major code refactoring. We discussed the structure of the JSON configuration file, how to load it in the Shiny app, and how to use it to generate the UI and server logic dynamically. This method can be particularly useful for applications that need to display different data or configurations for different clients, enabling easy updates by simply modifying the JSON file in a cloud storage location.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>Shiny</category>
  <category>JSON</category>
  <category>shiny module</category>
  <category>configuration</category>
  <guid>https://discindo.org/posts/shiny/2025-01-19-shiny-golem-config-json/</guid>
  <pubDate>Sun, 19 Jan 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/shiny/2025-01-19-shiny-golem-config-json/images/logos.png" medium="image" type="image/png" height="86" width="144"/>
</item>
<item>
  <title>Automating building and ckecking of renv environments using GitHub Actions</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/pkg-env/2025-01-10-automating-renv-environments/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>One of the challenges facing when moving work from a local computer to a remote server (such as an RStudio Server) where one does not have administrative privileges is how to make sure that the system has all the necessary system libraries be able to install all the needed <code>R</code> packages for a given project.</p>
<p>Errors like:</p>
<pre><code>unable to load shared object something.so':
something.so: cannot open shared object file: No such file or directory</code></pre>
<p>Usually mean that the user has to ask the administrator to install the <code>something</code> on the system to be able to compile the package.</p>
<p>And when one library is missing that is not a big deal (probably). But multiple projects, multiple libraries, and multiple users, means that the administrator may be spammed with requests which may or may not be final: each time <code>install.packages()</code> is run a different library may be missing after a previous one was installed.</p>
<p>The obvious solution to this type of a problem is to have Posit Package Manager serving binary packages, but that may not be something that is available because of costs, or whatever.</p>
<p>So, here is a free and public option to track the need for system dependencies and to make sure the R environment will be working: GitHub Actions</p>
<section id="step-1-use-renv-for-your-projects." class="level2">
<h2 class="anchored" data-anchor-id="step-1-use-renv-for-your-projects.">Step 1: Use <code>renv</code> for your projects.</h2>
<p>I will not go into details here. I presume everyone is doing this? :)</p>
<p>When using <code>renv</code> you will notice the <code>renv.lock</code> that are being generated.</p>
</section>
<section id="step-2-create-a-github-repository-with-folder-for-each-renv.lock-file" class="level2">
<h2 class="anchored" data-anchor-id="step-2-create-a-github-repository-with-folder-for-each-renv.lock-file">Step 2: Create a Github repository with folder for each <code>renv.lock</code> file</h2>
<p>Assuming you have multiple projects/environments you need to check and build have a directory structure where each folder has a <code>renv.lock</code> file. For example:</p>
<pre><code>my-renv-files/
├── my-first-comlicated-env/
    └── renv.lock
└── my-second-complicated-env/
    └── renv.lock</code></pre>
<p>Maybe you would want to add a <code>README.md</code> there as well.</p>
</section>
<section id="step-3-add-a-requirements.txt-file-to-the-repository" class="level2">
<h2 class="anchored" data-anchor-id="step-3-add-a-requirements.txt-file-to-the-repository">Step 3: Add a <code>requirements.txt</code> file to the repository</h2>
<p>This will hold any system libraries that are needed - one per line. You probably know at least one at this point so just add it on the first line.</p>
</section>
<section id="step-4-add-a-github-action-yaml-file-to-the-repository." class="level2">
<h2 class="anchored" data-anchor-id="step-4-add-a-github-action-yaml-file-to-the-repository.">Step 4: Add a GitHub Action yaml file to the repository.</h2>
<p>Create a <code>.github/workflows</code> folder in the repository and add the following as <code>build_renv.yaml</code>:</p>
<pre><code>name: Build renv environments

on:
  pull_request:
    paths:
      - '**/renv.lock'
  workflow_dispatch: 

jobs:
  build-renv:
    runs-on: ubuntu-latest

    steps:
      # 1. Checkout the repository
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # 2. Set up R environment
      - name: Set up R
        uses: r-lib/actions/setup-r@v2
        with:
          r-version: '4.4.1' # Specify your desired R version

      # 3. Install system dependencies
      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y $(cat requirements.txt)

      # 4. Install renv package in R
      - name: Install renv
        run: |
          Rscript -e "install.packages('renv')"

      # 5. Rebuild the R environment for the changed renv.lock file
      - name: Rebuild R environment
        run: |
          # Extract the changed renv.lock file
          file=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} | grep 'renv.lock')
          dir=$(dirname "$file")

          echo "Restoring renv environment for $dir"
          cd "$dir"
          Rscript -e "renv::restore(prompt = FALSE)"
        env:
          RENV_PATHS_CACHE: ~/.cache/R/renv</code></pre>
<p>This will run automatically on any pull requests that have <code>renv.lock</code> files, and also can be manually triggered (good for testing!).</p>
<p>Then it will setup <code>R</code>, install the dependencies, and set up <code>renv</code>.</p>
<p>Then in the final step <code>5</code> it will try to build the environment for each folder and fail if system dependencies are missing. So then you can update the <code>requirements.txt</code> and have it run again until you have a green pass and a complete <code>requiremtenst.txt</code> that you can share with the administrator. :)</p>
<p>Now, this runs on <code>Ubuntu</code> and the server that runs the RStudio Server may be on a different <code>Linux</code> distribution. And while not ideal, you will still know what are the names of the missing libraries, though their names for the other distribution maybe slightly different.</p>
<p>Still, a nice way to keep track of <code>renv</code> environments, and especially convenient if you have a very specific one that you need to share with coworkers or with the public.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>renv</category>
  <category>GitHub Actions</category>
  <guid>https://discindo.org/posts/pkg-env/2025-01-10-automating-renv-environments/</guid>
  <pubDate>Fri, 10 Jan 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Happy New Year</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2025-01-06-happy-new-year/</link>
  <description><![CDATA[ 





<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://discindo.org/posts/2025-01-06-happy-new-year/images/tree.png" class="img-fluid figure-img"></p>
<figcaption>Tree</figcaption>
</figure>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Tree branches</span></span>
<span id="cb1-4">tree_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb1-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>), </span>
<span id="cb1-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>),</span>
<span id="cb1-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">each =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb1-8">)</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Tree trunk</span></span>
<span id="cb1-11">trunk_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb1-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>),</span>
<span id="cb1-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>)</span>
<span id="cb1-14">)</span>
<span id="cb1-15"></span>
<span id="cb1-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Star at the top</span></span>
<span id="cb1-17">star_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb1-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>),</span>
<span id="cb1-19">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.35</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.20</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.20</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>)</span>
<span id="cb1-20">)</span>
<span id="cb1-21"></span>
<span id="cb1-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Decorations </span></span>
<span id="cb1-23">decorations_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb1-24">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>),  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Random x positions within the tree</span></span>
<span id="cb1-25">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Random y positions within the tree</span></span>
<span id="cb1-26">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colors =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"darkblue"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"purple"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gold"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"deeppink"</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-27">)</span>
<span id="cb1-28"></span>
<span id="cb1-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Check if a point is inside a triangle</span></span>
<span id="cb1-30">point_in_triangle <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(px, py, x1, y1, x2, y2, x3, y3) {</span>
<span id="cb1-31">  denominator <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ((y2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y3)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x3) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (x3 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x2)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(y1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y3))</span>
<span id="cb1-32">  a <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ((y2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y3)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(px <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x3) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (x3 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x2)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(py <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y3)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> denominator</span>
<span id="cb1-33">  b <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ((y3 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y1)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(px <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x3) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x3)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(py <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y3)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> denominator</span>
<span id="cb1-34">  c <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> a <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b</span>
<span id="cb1-35">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(a <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> b <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> c <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-36">}</span>
<span id="cb1-37"></span>
<span id="cb1-38"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Filter decorations to fit in tree triangles</span></span>
<span id="cb1-39">valid_points <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">apply</span>(decorations_data, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(point) {</span>
<span id="cb1-40">  x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(point[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>])</span>
<span id="cb1-41">  y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(point[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>])</span>
<span id="cb1-42">  inside_triangle1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">point_in_triangle</span>(x, y, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-43">  inside_triangle2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">point_in_triangle</span>(x, y, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>)</span>
<span id="cb1-44">  inside_triangle3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">point_in_triangle</span>(x, y, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb1-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(inside_triangle1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> inside_triangle2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> inside_triangle3)</span>
<span id="cb1-46">})</span>
<span id="cb1-47"></span>
<span id="cb1-48">decorations_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> decorations_data[valid_points, ]</span>
<span id="cb1-49"></span>
<span id="cb1-50"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot the tree</span></span>
<span id="cb1-51"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-52">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_polygon</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> tree_data, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(x, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> group), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"forestgreen"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-53">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_polygon</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> trunk_data, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(x, y), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"saddlebrown"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-54">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_polygon</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> star_data, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(x, y), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gold"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-55">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> decorations_data, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(x, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> colors), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-56">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_color_identity</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-57">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_fixed</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-58">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggtitle</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"🎄 Happy New Year!"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-59">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_void</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-60">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-61">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.position=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) </span></code></pre></div></div>
</div>



 ]]></description>
  <category>R</category>
  <guid>https://discindo.org/posts/2025-01-06-happy-new-year/</guid>
  <pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2025-01-06-happy-new-year/images/tree.png" medium="image" type="image/png" height="62" width="144"/>
</item>
<item>
  <title>r2lambda update to support multi-file projects and renv projects</title>
  <dc:creator>teo </dc:creator>
  <link>https://discindo.org/posts/r2lambda/2024-10-17-r2lambda-renv/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<section id="deploy-a-project-with-multiple-r-scripts-and-renv-managed-environment-to-aws-lambda" class="level2">
<h2 class="anchored" data-anchor-id="deploy-a-project-with-multiple-r-scripts-and-renv-managed-environment-to-aws-lambda">Deploy a project with multiple R scripts and <code>{renv}</code>-managed environment to AWS Lambda</h2>
<p>It has been a while since I’ve had the chance to work on my <code>{r2lambda}</code> project. In particular, there were a couple of good points made by a user on GitHub about functionality that is missing from the package. The option to deploy multiple files, e.g., one runtime function that depends on helpers in the same project organized in different files. And another, to enable <code>{renv}</code> management of the <code>R</code> environment within the AWS Lambda docker image. Both excellent points that I wished I addressed earlier. But better late than never.</p>
<p>Both of these features required minor adjustments to the codebase. Copying additional supports scripts and restoring the <code>{renv}</code> environment should both happen when the AWS Lambda docker image is built, so the logic to create the Dockerfile needed to be updated. Accordinly, the <code>r2lambda::build_lambda</code> function now has two additional arguments:</p>
<pre><code>#' @param support_path path to the support files (if any). Either NULL 
#' (the default) if all needed code is in the same `runtime_path` script, or a 
#' character vector of paths to additional files needed by the runtime script.
#' @param renvlock_path path to the renv.lock file (if any). Default is NULL.
#' 
#' @details Use either `renvlock_path` or `dependencies` to install required
#' packages, not both. By default, both are `NULL`, so the Docker image will
#' have no additional packages installed.</code></pre>
<p>To include any support scripts, provide a character vector script paths to the <code>support_path</code> argument when building the Lambda docker image locally with <code>build_lamdba</code>.</p>
<p>[Note that, multi-file project was supported previously as well, although perhaps not explicitly. An approach that I like is to create an ‘R’ package that exports the runtime function needed for the Lambda. Then one just needs to make that custom <code>R</code> package a dependency of the project and either install in the AWS Lambda docker image it through <code>dependencies</code> or <code>renvlock_path</code>.]</p>
<p>To use an existing <code>renv.lock</code> for installation of dependencies, provide its path to the <code>renvlock_path</code> argument to <code>build_lambda</code>. This instructs the code to copy the <code>renv.lock</code> file to the image and run <code>renv::restore()</code> which will reconstruct the <code>R</code> environment inside the docker image. I really like this feature, as it minimizes the size of the Dockefile and removes some potential headaches with R package dependencies from different repositories (CRAN, BioConductor, GitHub, etc).</p>
</section>
<section id="demo-code" class="level2">
<h2 class="anchored" data-anchor-id="demo-code">Demo code</h2>
<p>Assuming we have a folder with the following structure:</p>
<pre><code>~/Desktop$ ls -1 iris-lambda/
renv/
renv.lock
runtime.r
support.r
test-code.r</code></pre>
<p>Where, <code>support.r</code> defines some function that <code>runtime.r</code> uses for the Lambda:</p>
<pre><code>get_iris_summary_by_species &lt;- function(species) {
    iris |&gt;
    dplyr::filter(Species == species) |&gt;
    dplyr::summarise(
      mean = mean(Sepal.Length),
      sd = sd(Sepal.Length)
    )
}</code></pre>
<p>Then <code>runtime.r</code>, sources the support script, and calls the function defined there:</p>
<pre><code>source("support.r")

iris_summary &lt;- function(species) {
  get_iris_summary_by_species(species)
}

lambdr::start_lambda()</code></pre>
<p>Then the following should work, passing the support script and renv.lock to r2lambda::build_lambda:</p>
<pre><code>dir("~/Desktop/iris-lambda")
runtime_function &lt;- "iris_summary"
runtime_path &lt;- "~/Desktop/iris-lambda/runtime.r"
support_path &lt;- "~/Desktop/iris-lambda/support.r"
renvlock_path &lt;- "~/Desktop/iris-lambda/renv.lock"
dependencies &lt;- NULL

# Might take a while, its building a docker image
build_lambda(
  tag = "my_iris_lambda",
  runtime_function = runtime_function,
  runtime_path = runtime_path,
  support_path = support_path,
  renvlock_path = renvlock_path,
  dependencies = dependencies
)

# test
payload &lt;- list(species = "setosa")
tag &lt;- "my_iris_lambda"
test_lambda(tag = tag, payload)


# deploy

# Might take a while, its pushing it to a remote repository
deploy_lambda(
  tag = "my_iris_lambda",
  Timeout = 30
)

invoke_lambda(
  function_name = "my_iris_lambda",
  invocation_type = "RequestResponse",
  payload = list(species = "versicolor"),
  include_logs = FALSE
)

invoke_lambda(
  function_name = "my_iris_lambda",
  invocation_type = "RequestResponse",
  payload = list(species = "setosa"),
  include_logs = FALSE
)</code></pre>


</section>

 ]]></description>
  <category>AWS</category>
  <category>R</category>
  <category>r2lambda</category>
  <category>AWS Lambda</category>
  <category>renv</category>
  <guid>https://discindo.org/posts/r2lambda/2024-10-17-r2lambda-renv/</guid>
  <pubDate>Thu, 17 Oct 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Noting the differences in deploying R vs Python apps on Posit Connect</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/pkg-env/2024-09-29-noting-the-differences-in-deploying-r-vs-python-apps-on-posit-connect/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>I ended my previous post <a href="posts/pkg-env/2024-09-21-using-uv-to-manage-the-environment-for-a-python-shiny-app-and-set-up-a-workflow-to-publish-it-to-posit-connect/">Using uv to manage the environment for a Python Shiny app and setting up a GitHub action to publish it to Posit Connect</a> with:</p>
<blockquote class="blockquote">
<p>Posit Connect can only listen to branches, so the idea is to have a deploy branch which Connect publishes, but which is managed by GitHub actions.</p>
</blockquote>
<p>It seems this is not correct.</p>
<section id="the-python-deployment" class="level2">
<h2 class="anchored" data-anchor-id="the-python-deployment">The Python deployment</h2>
<p>Initially I was looking to publish a Python Shiny app, and indeed the <code>rsconnect-python</code> package seems to be able only to deploy new content even when there are no changes to the <code>manifest.json</code> file.</p>
<p>Below you can see that there are two <code>pyshinywikidata</code> deployments, but it is the same app. It is just what happens when I run the pipeline twice.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://discindo.org/posts/pkg-env/2024-09-29-noting-the-differences-in-deploying-r-vs-python-apps-on-posit-connect/images/Screenshot_20240928_212347.png" class="img-fluid figure-img"></p>
<figcaption>Posit Connect content</figcaption>
</figure>
</div>
<p>In other words, it seems that the command:</p>
<pre><code>uvx --from rsconnect-python rsconnect deploy manifest --server=$CONNECT_SERVER --api-key=$CONNECT_API_KEY  manifest.json</code></pre>
<p>does not recognize that there is already an existing content with the same manifest file on the server.</p>
</section>
<section id="the-r-deployment" class="level2">
<h2 class="anchored" data-anchor-id="the-r-deployment">The R deployment</h2>
<p>However, this is not the case with deploying an R Shiny app. In particular, this seems not to be the case when deploying an R Shiny app using the <a href="https://solutions.posit.co/operations/deploy-methods/ci-cd/github-actions/">RStudio actions</a> provided by Posit. This one is focused on R and doesn’t show in Google searches when looking to deploy a Python app.</p>
<p>Using this action in a workflow makes it possible to update existing deployments, which is great.</p>
<p>However, the R way of doing things has some other strange quirks, most notably that the <code>renv.lock</code> file should be kept updated in the repository as well. This complicates things a bit when the app that needs to be deployed is written with <code>{golem}</code>.</p>
<p>In this case, <code>renv.init()</code> does not know that the app needs to be installed in the deployment too, in order to be loaded. And, that additional packages are required as well. Therefore, adding these dependencies has to happen manually with <code>renv::record()</code>. Besides the packaged app, four more packages need to be added with <code>renv.record()</code>: <code>pkgload</code>, <code>pkgbuild</code>, <code>desc</code>, and <code>procesx</code>.</p>
<p>This complicates matters a bit, because it is another manual step that can be easily forgotten, and in that case the deployment will fail.</p>
<p>This is because, as <a href="https://rstudio.github.io/renv/articles/faq.html">the renv FAQ explains</a>:</p>
<blockquote class="blockquote">
<p>For a package to be recorded in the lockfile, it must be both: 1. Installed your project library, and 2. Used by the project, as determined by renv::dependencies().</p>
</blockquote>
<p>Altering the <code>renv</code> settings may be the best approach as <a href="https://rstudio.github.io/renv/articles/faq.html#capturing-explicit-dependencies">described in the FAQ too</a>.</p>
</section>
<section id="the-python-deployment-again" class="level2">
<h2 class="anchored" data-anchor-id="the-python-deployment-again">The Python deployment, again</h2>
<p>But, if the action exists, can it be used for Python apps as well?</p>
<p>The answer to that is yes.</p>
<p>Digging through the repository for <a href="https://github.com/rstudio/actions">RStudio actions</a>, and the <a href="https://github.com/rstudio/rsconnect-ts">TypeScript client library for the Posit Connect API</a> I found out that the good people at Posit have written tests for deploying a Flask app (which is Python!). So if it works for Flask it will work for Shiny, and indeed it does.</p>
<p>It seems to me that <code>rsconnect-ts</code> offers a bit more flexibility than <code>rsconnect-python</code>. As far as I can tell, I cannot use <code>rsconnect-python</code> to check if content already exists. At the same time, it seems the <code>rsconnect-ts</code>, still being a beta-quality package, is not really being advertised, or maybe not even been work on actively.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>In this article I tried to clarify some of my confusion regarding using GitHub Actions to deploy R and Python Shiny apps, and probably I added a bit of new confusion as well. I will try to keep this series updated as I learn new things or better ways to achieve gh-actions deployments. I would also appreciate suggestions for other relevant content if anyone has found something I have missed.</p>


</section>

 ]]></description>
  <category>R</category>
  <category>Python</category>
  <category>Automation</category>
  <category>Shiny</category>
  <category>Posit Connect</category>
  <category>GitHub Actions</category>
  <guid>https://discindo.org/posts/pkg-env/2024-09-29-noting-the-differences-in-deploying-r-vs-python-apps-on-posit-connect/</guid>
  <pubDate>Sun, 29 Sep 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Using uv to manage the environment for a Python Shiny app and setting up a GitHub action to publish it to Posit Connect</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/pkg-env/2024-09-21-using-uv-to-manage-the-environment-for-a-python-shiny-app-and-set-up-a-workflow-to-publish-it-to-posit-connect/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<section id="it-all-starts-with-a-notification" class="level2">
<h2 class="anchored" data-anchor-id="it-all-starts-with-a-notification">It all starts with a notification</h2>
<p>A couple of weeks ago, I got a notification from LinkedIn. Unlike the usual notifications, this was not from an anonymous recruiter viewing my profile. It was a post by <a href="https://www.jumpingrivers.com/authors/russ-hyde/">Russ Hyde</a> who was looking for examples on how to organize the code in a Python Shiny app. He bumped into my repository on the <a href="https://github.com/novica/pyshinywikidata">topic</a>. For the curious, there is also an accompanying <a href="../../../posts/pkg-env/2022-11-18-packaging-a-python-shiny-app/index.html">blog post</a> where I describe a simple approach to package a Python Shiny app.</p>
<p>It was a great reminder that I should look into my previous work, as I was anyhow trying to figure out different ways to deploy Python Shiny apps to Posit Connect.</p>
<p>At the same time the relatively new Python packager and project manager called <a href="https://docs.astral.sh/uv/">uv</a> caught my attention with many internet resources about its features popping up, more or less, at the same time (for example: <a href="https://github.com/gdamjan/uv-getting-started">demo project by Damjan</a>, <a href="https://talkpython.fm/episodes/show/476/unified-python-packaging-with-uv">Unified Python packaging with uv</a>).</p>
<p>So I thought why not test how Shiny for Python would work with <code>uv</code> and whether this package manager can be used to in a setup for deployments to Posit Connect.</p>
</section>
<section id="step-1-start-a-new-uv-project-and-add-your-code" class="level2">
<h2 class="anchored" data-anchor-id="step-1-start-a-new-uv-project-and-add-your-code">Step 1: Start a new <code>uv</code> project and add your code</h2>
<p>Setting up a new <code>uv</code> project is pretty straightforward, and their <a href="https://docs.astral.sh/uv/guides/projects/">projects guide</a> make is even simpler.</p>
<p>I just ran:</p>
<p><code>$ uv init py-shiny-uv</code></p>
<p>and I get a new folder with the following contents:</p>
<pre><code>.
├── hello.py
├── pyproject.toml
└── README.md</code></pre>
<p>No surprises here.</p>
<p>Then, since I already had all the code organized in the repo above, I just copied everything (including the <code>.git</code> folder and <code>.gitignore</code> file) to the <code>uv</code> project folder, and removed the <code>hello.py</code>. Now the Shiny Python application is part of the <code>uv</code> directory.</p>
</section>
<section id="step-2-project-specific-python-version" class="level2">
<h2 class="anchored" data-anchor-id="step-2-project-specific-python-version">Step 2: Project-specific python version</h2>
<p>Next, I needed a specific version of Python (my Posit Connect instance runs on 3.11.5).</p>
<p>First, I updated my <code>pyproject.toml</code> to have the required Python version.</p>
<p>Then, adding a specific Python version to the project is also simple. After navigating to the project folder, I just ran:</p>
<pre><code>$ uv venv --python 3.11.5</code></pre>
<p>And it gets installed in seconds. I can activate the environment in the usual way:</p>
<pre><code>$ source .venv/bin/activate</code></pre>
<p>And check the version:</p>
<pre><code>(py-shiny-uv) $ python --version

3.11.5</code></pre>
<p>This is the environment in which further development of the app could happen.</p>
<p>At this point I checked the git status and I have one new untracked file <code>.python-version</code>, which, as expected, has the Python version written inside.</p>
</section>
<section id="step-3-install-shiny-and-other-dependencies-for-the-app" class="level2">
<h2 class="anchored" data-anchor-id="step-3-install-shiny-and-other-dependencies-for-the-app">Step 3: Install Shiny and other dependencies for the app</h2>
<p>The example application depends on three packages: <code>shiny</code>, <code>SPARQLWrapper</code>, and <code>pandas</code>, and I added those. Adding this to the <code>uv</code> environment can be done with <code>uv add</code>:</p>
<pre><code>(py-shiny-uv) $ uv add pandas shiny SPARQLWrapper</code></pre>
<p>Then I just verified that the packages load by running python and importing.</p>
</section>
<section id="step-4-create-the-requirements.txt-and-manifest.json-needed-for-deploying-to-posit-connect" class="level2">
<h2 class="anchored" data-anchor-id="step-4-create-the-requirements.txt-and-manifest.json-needed-for-deploying-to-posit-connect">Step 4: Create the <code>requirements.txt</code> and <code>manifest.json</code> needed for deploying to Posit Connect</h2>
<p>As you might know if you are working with Shiny app in Python, the <code>rsconnect-python</code> package is needed to generate the <code>manifest.json</code> file. The manifest is used by Posit Connect when publishing from a git repository (which is something that I want to do).</p>
<p>Usually the way to do it is to run in the app folder:</p>
<pre><code>$ rsconnect write-manifest shiny .</code></pre>
<p>But since the idea is to use <code>uv</code> I had to try, and fail multiple times, with it.</p>
<p>First, the problem with <code>rsconnect</code> is that it generates the files in the app directory, instead of the top level python project. Moving the files is a possibility, of course, but it seems it is an unnecessary complication.</p>
<p>The default way to get the requirements with <code>uv</code> is:</p>
<pre><code>$ uv export -o requirements.txt</code></pre>
<p>This, however, generates the dependencies with hashes, which then is a problem with the package environment not having a hash. To quote the error log:</p>
<blockquote class="blockquote">
<p>The editable requirement pyshinywikidata cannot be installed when requiring hashes, because there is no single file to hash.</p>
</blockquote>
<p>Omitting the package with:</p>
<pre><code>$ uv export --no-emit-project -o requirements.txt</code></pre>
<p>Fails because now the package containing the app is no longer in <code>requirements.txt</code>, and Posit Connect can’t find the module to run.</p>
<p>Finally, after a few more trial and errors, I found the solution in the <code>--no-hashes</code> option of the <code>uv export</code> command.</p>
<p>Then, I needed to use <code>uv</code> to generate the manifest too. And <code>uv</code> has this nice feature where a tool can be invoked without installing it, which is handy for the <code>rsconnect-python</code> package. Here, the <code>--entrypoint</code> needs to be set up so that Posit Connect knows that the app is in the installed package.</p>
<p>The full <code>uv</code> set of commands is:</p>
<pre><code># update the project environment
$ uv sync 

# generate the the requirements.txt file
$ uv export --no-hashes -o requirements.txt 

# generate the manifest.json file. note the entrypoint.
$ uvx --from rsconnect-python --python .venv/bin/python rsconnect write-manifest shiny .  --entrypoint pyshinywikidata.app:app </code></pre>
<p>At this point <code>git status</code> said I have new files in the repository, as expected. So then I just added them to the repository.</p>
</section>
<section id="step-5-generate-requirements.txt-and-manifest.json-with-github-actions" class="level2">
<h2 class="anchored" data-anchor-id="step-5-generate-requirements.txt-and-manifest.json-with-github-actions">Step 5: Generate <code>requirements.txt</code> and <code>manifest.json</code> with GitHub actions</h2>
<p>Whenever changes to the code are made, <code>requirements.txt</code> and <code>manifest.json</code> may need to be regenerated and committed to the repository so that Posit Connect knows how to update the app. But, forgetting to do this would not be strange. So why not automate it?</p>
<p>Posit Connect can only listen to branches, so the idea is to have a <code>deploy</code> branch which Connect publishes, but which is managed by GitHub actions.</p>
<p>With a little help from existing <code>yaml</code> files, I stitched together a <a href="https://github.com/novica/pyshinywikidata/blob/main/.github/workflows/update-requirements.yaml">workflow script</a> that creates the needed files on the <code>deploy</code> branch and then successfully deployed it to Posit Connect.</p>
<p>Amazing!</p>
<p>Additionally, I needed to allow workflow permission in my repository settings to be able to read and write. That’s under <code>Settings -&gt; Select Actions → General -&gt; Workflow -&gt; Read</code> and write permissions.</p>
<p>All the code and my trials and errors are under the repo at: <a href="https://github.com/novica/pyshinywikidata/">https://github.com/novica/pyshinywikidata/</a>.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>In this article, I reviewed the procedure of setting up a <code>uv</code> project manager environment for a Python Shiny application and integrating the project with GitHub Actions to enable automated deployment to Posit Connect.</p>


</section>

 ]]></description>
  <category>python</category>
  <category>Automation</category>
  <category>Shiny</category>
  <category>uv</category>
  <category>GitHub Actions</category>
  <guid>https://discindo.org/posts/pkg-env/2024-09-21-using-uv-to-manage-the-environment-for-a-python-shiny-app-and-set-up-a-workflow-to-publish-it-to-posit-connect/</guid>
  <pubDate>Sat, 21 Sep 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Shiny ducks: connecting to MotherDuck from Shiny</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2024-06-27-shiny-ducks-connecting-to-motherduck-from-shiny/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>In a previous post I wrote about how to <a href="../../posts/2024-06-21-joining-the-flock-from-r-working-with-data-on-mother-duck/">connect to MotherDuck from R</a>. However, the process described there, where you click in the browser to authenticate, wouldn’t really work with a Shiny app, or for that matter with any productionized setup. And R without Shiny is like pizza without pineapple. So let’s see how to set up a Shiny that will run some queries on <code>MotherDuck</code>.</p>
<p>If you recall, there is a token that is used to authenticate to <code>MotherDuck</code>. You can go back to the previous post to see how to obtain the token via R, or you can log into setting on your <code>MotherDuck</code> account and simply copy it from there.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://discindo.org/posts/2024-06-27-shiny-ducks-connecting-to-motherduck-from-shiny/images/Screenshot_20240627_135442.png" class="img-fluid figure-img"></p>
<figcaption>motherduck token</figcaption>
</figure>
</div>
<p>After that, store that in an environment variable. You could save it permanently in <code>.Renviron</code> or just use <code>Sys.setenv()</code> if you are trying out things. Anyway you should verify that the token is available when running <code>Sys.getenv('MD_TOKEN')</code>, where <code>MD_TOKEN</code> is what I decided to name this variable.</p>
<section id="connecting-to-motherduck-from-the-shiny-server" class="level3">
<h3 class="anchored" data-anchor-id="connecting-to-motherduck-from-the-shiny-server">Connecting to MotherDuck from the Shiny server</h3>
<p>The main part of the Shiny app (well, at least the demo Shiny, scroll down for the full code) is establishing a connection to <code>MotherDuck</code>. And since the <code>R</code> version of <code>duckdb</code> doesn’t automatically load the <code>motherduck</code> extension, we have to do that step by step:</p>
<pre><code>con &lt;- DBI::dbConnect(duckdb::duckdb(), ":memory:")
  
# Install and load the MotherDuck extenstion
DBI::dbExecute(con, "INSTALL 'motherduck';")
DBI::dbExecute(con, "LOAD 'motherduck';")
  
# Define the query to authenticate
auth_query &lt;- glue::glue_sql("SET motherduck_token= {`Sys.getenv('MD_TOKEN')`};", .con = con)
  
DBI::dbExecute(con, auth_query)
  
# Connect to MotherDuck
DBI::dbExecute(con, "PRAGMA MD_CONNECT")</code></pre>
<p>Here we create an in-memory duckdb and use that to install and load the extension. Then we authenticate with the token that is stored in an environment variable.</p>
<p>Note, the <code>PRAGMA</code> statement here is <a href="https://duckdb.org/docs/configuration/overview.html#configuration-reference">duckdb’s way</a> of “changing the behavior of the system” which is what we are doing with loading the extension.</p>
<p>If you run the above code in a normal R script you will still connect to <code>MotherDuck</code>, which is of course expected.</p>
<p>Then is just about adding the other pats of the shiny app together:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://discindo.org/posts/2024-06-27-shiny-ducks-connecting-to-motherduck-from-shiny/images/Screenshot_20240628_180326.png" class="img-fluid figure-img"></p>
<figcaption>app screenshot</figcaption>
</figure>
</div>
<p>And the whole code below:</p>
<pre><code>library(shiny)
library(duckdb)

ui &lt;- fluidPage(
  titlePanel("DuckDB and Shiny Integration"),
  sidebarLayout(sidebarPanel(
    helpText(
      "This app connects to MotherDuck and queries the sample WHO dataset."
    ),
    uiOutput("cities")
  ), mainPanel(tableOutput("data_table")))
)


server &lt;- function(input, output, session) {
  # Connect to an in-memory DuckDB database
  con &lt;- DBI::dbConnect(duckdb::duckdb(), ":memory:")
  
  # Install and load the MotherDuck extenstion
  DBI::dbExecute(con, "INSTALL 'motherduck';")
  DBI::dbExecute(con, "LOAD 'motherduck';")
  
  # Define the query to authenticate
  auth_query &lt;- glue::glue_sql("SET motherduck_token= {`Sys.getenv('MD_TOKEN')`};", .con = con)
  
  DBI::dbExecute(con, auth_query)
  
  # Connect to MotherDuck
  DBI::dbExecute(con, "PRAGMA MD_CONNECT")
  
  cities &lt;- DBI::dbGetQuery(con,
                            "SELECT DISTINCT(city) FROM sample_data.who.ambient_air_quality LIMIT 25;")
  
  output$cities &lt;- renderUI({
    tagList(selectInput(
      inputId = "city",
      label = "City",
      choices = cities
    ))
  })
  
  query_rct &lt;- reactive({
    req(input$city)
    city_name &lt;- input$city
    glue::glue_sql(
      "SELECT country_name, city, \"year\", pm10_concentration, pm25_concentration, no2_concentration, FROM sample_data.who.ambient_air_quality WHERE  city = '{`city_name`}';",
      .con = con
    )
  })
  
  
  data_rct &lt;- reactive({
    req(query_rct())
    message(query_rct())
    DBI::dbGetQuery(con, query_rct())
  })
  
  
  # Render the table output
  output$data_table &lt;- renderTable({
    data_rct()
  })
  
  onSessionEnded({function() {DBI::dbDisconnect(con)} })  
}

shinyApp(ui = ui, server = server)</code></pre>
</section>
<section id="closing-notes" class="level3">
<h3 class="anchored" data-anchor-id="closing-notes">Closing notes</h3>
<p>Since this is just a demo app I am limiting the cities output to 25 to avoid Shiny complaining about the long vector of city names (8000+). You could obviously modify that to get cities in Europe or something else.</p>
<p>The SQL statements can be rewritten in <code>duckplyr</code>, but for me it was convenient to test a query in <code>MotherDuck</code> and just paste it in the <code>R</code> code like this.</p>
<p>Of course, it would be better to have dashboard-ready tables (aggregations, summaries) that can be used in the Shiny app directly, and something like that can be achieved with <code>dbt</code> or <code>SQLMesh</code>, but maybe I will do that in another post.</p>
<p>Finally, I don’t recommend deploying this app on <a href="https://shinyapps.io">shinyapps.io</a>. I tried and it takes too much time to compile and install the <code>duckdb</code> package, that I got a timeout. But it works nicely when running it from <code>RStudio</code>.</p>
<p>Happy quacking!</p>


</section>

 ]]></description>
  <category>R</category>
  <category>Shiny</category>
  <category>duckdb</category>
  <category>motherduck</category>
  <guid>https://discindo.org/posts/2024-06-27-shiny-ducks-connecting-to-motherduck-from-shiny/</guid>
  <pubDate>Fri, 28 Jun 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Few notes on getting R package data from the local library</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/pkg-env/2024-06-23-few-notes-on-getting-r-package-data-from-the-local-library/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>I am involved in a <a href="https://posit.co/products/enterprise/team/">Posit Team</a> deployment, and one of the things that we are looking into is default R packages that should be made available to all users. We are looking to do this because we would like to avoid people installing, for example <code>tidyverse</code>, in their own local libraries in order to save on space and to make sure everyone is on the same version, at least for the packages that are considered to be a preferred default option for working with data in R.</p>
<p>In order to do this we wanted to collect all the packages that are currently used, their versions, source repository and similar information. That way we can see if anything else should be installed for all users, in addition to the best guess that we should have <code>tidyverse</code>, <code>tidymodels</code>, and <code>shiny</code>.</p>
<p>In order to do this we first have to get the list of installed packages, which is fairly simple to do:</p>
<pre><code>installed_packages &lt;- installed.packages()</code></pre>
<p>Then, <code>utils::packageDescription</code> can be used to get the packages<code>descriptions. For example for getting the package description for</code>dplyr` we can run:</p>
<pre><code>dplyr_pkg_desc &lt;- utils::packageDescription('dplyr')</code></pre>
<p>The result is a list, and it can be subsetted to see details, for example:</p>
<pre><code>&gt; dplyr_pkg_desc[1]
$Type
[1] "Package"

&gt; dplyr_pkg_desc[2]
$Package
[1] "dplyr"

&gt; dplyr_pkg_desc[3]
$Title
[1] "A Grammar of Data Manipulation"

&gt; dplyr_pkg_desc[4]
$Version
[1] "1.1.4"</code></pre>
<p>At this point, I am thinking that all these description files have the same structure. Therefore, if I want to get all packages’ version I need to <code>lapply</code> to get the fourth element and that’s that. It turns out this is not entirely true. Not all packages have the same structure of the description. See <code>tydir</code>:</p>
<pre><code>&gt; tidyr_pkg_desc[1]
$Package
[1] "tidyr"

&gt; tidyr_pkg_desc[2]
$Title
[1] "Tidy Messy Data"

&gt; tidyr_pkg_desc[3]
$Version
[1] "1.3.1"

&gt; tidyr_pkg_desc[4]
$`Authors@R`
[1] "c(\n    person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\")),\n    person(\"Davis\", \"Vaughan\", , \"davis@posit.co\", role = \"aut\"),\n    person(\"Maximilian\", \"Girlich\", role = \"aut\"),\n    person(\"Kevin\", \"Ushey\", , \"kevin@posit.co\", role = \"ctb\"),\n    person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"))\n  )"</code></pre>
<p>Number four is the authors, and version is three. And these are two packages that are ultimately from the same author. Look at <code>data.table</code>:</p>
<pre><code>&gt; data.table_pkg_desc[1]
$Package
[1] "data.table"

&gt; data.table_pkg_desc[2]
$Version
[1] "1.15.4"

&gt; data.table_pkg_desc[3]
$Title
[1] "Extension of `data.frame`"

&gt; data.table_pkg_desc[4]
$Depends
[1] "R (&gt;= 3.1.0)"</code></pre>
<p>Now, of course, subsetting works with using the name, instead of the position:</p>
<pre><code>&gt; dplyr_pkg_desc[["Version"]]
[1] "1.1.4"
&gt; tidyr_pkg_desc[["Version"]]
[1] "1.3.1"
&gt; data.table_pkg_desc[["Version"]]
[1] "1.15.4"</code></pre>
<p>However, to be honest, it rarely comes to my mind to subset lists like this.</p>
<pre><code>package_names &lt;- installed.packages()[, 1]

all_packages_data &lt;- lapply(package_names,  utils::packageDescription)

version_number &lt;-
  lapply(1:length(package_names), function (x) {
    all_packages_data[[x]][["Version"]]
  })</code></pre>
<p>The above is possible, and then to <code>cbind</code> all needed fields in a <code>data.frame</code>.</p>
<p>However, looking at the <code>packageDescription</code> documentation, it seems the best way is to use additional arguments the function. This is neat:</p>
<pre><code>package_data &lt;- lapply(
  package_names,
  utils::packageDescription,
  fields = c("Package", "Version", "Built", "Repository")
) </code></pre>
<p>And then there is another surprise. The results are with class <code>packageDescription</code> which makes getting to a <code>data.frame</code>, or <code>tibble</code> in this case, a bit complicated:</p>
<pre><code>package_data &lt;- purrr::map_df(
  package_names,
  utils::packageDescription,
  fields = c("Package", "Version", "Built", "Repository")
) 
Error in `as_tibble()`:
! All columns in a tibble must be vectors.
✖ Column `askpass` is a `packageDescription` object.</code></pre>
<p>The full solution involves a step of changing the class of the object using <code>as</code>, and then reassigning the names of each element, because the previous step removes them:</p>
<pre><code>package_data &lt;- lapply(
  package_names,
  utils::packageDescription,
  fields = c("Package", "Version", "Built", "Repository")
) |&gt; 
  lapply(as, Class = "list") |&gt; 
  lapply(setNames, c("Package", "Version", "Built", "Repository")) |&gt; 
  dplyr::bind_rows()</code></pre>
<section id="update-2024-06-23-1644-cest" class="level3">
<h3 class="anchored" data-anchor-id="update-2024-06-23-1644-cest">Update 2024-06-23, 16:44 CEST</h3>
<p>Many thanks to <a href="https://github.com/ibecav">Chuck Powell</a> for sending a message that all of this can be achieved with one simple command from the package <code>pak</code>:</p>
<pre><code>pak::pkg_list()</code></pre>
<p>Awesome. :)</p>


</section>

 ]]></description>
  <category>R</category>
  <category>package</category>
  <guid>https://discindo.org/posts/pkg-env/2024-06-23-few-notes-on-getting-r-package-data-from-the-local-library/</guid>
  <pubDate>Sun, 23 Jun 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Joining the flock from R: working with data on MotherDuck</title>
  <dc:creator>novica </dc:creator>
  <link>https://discindo.org/posts/2024-06-21-joining-the-flock-from-r-working-with-data-on-mother-duck/</link>
  <description><![CDATA[ 





<p><a href="https://ko-fi.com/J3J8133RYV"><img src="https://ko-fi.com/img/githubbutton_sm.svg" class="img-fluid"></a></p>
<p>With DuckDB <a href="https://duckdb.org/2024/06/03/announcing-duckdb-100.html">releasing</a> version 1.0.0 on June 3rd, and MotherDuck <a href="https://motherduck.com/blog/announcing-motherduck-general-availability-data-warehousing-with-duckdb/">following</a> with the general availability announcement on June 11th, it is a perfect opportunity to see how both can be used from <code>R</code>. I work for an organization where <code>R</code> is the default language for doing most of the analytics, so being able to do this is more than just simple curiosity.</p>
<blockquote class="blockquote">
<p>Update: 2024.12.07: The steps described below will not work on Windows. The <code>motherduck</code> extension is not supported (yet). People have also experienced issues with running it on Mac, but I cannot test that, so if someone makes it work, let me know.</p>
</blockquote>
<section id="my-setup" class="level3">
<h3 class="anchored" data-anchor-id="my-setup">My setup</h3>
<p>I am running <code>R</code> version 4.4.1 on Linux, with <code>duckdb</code> <a href="https://r.duckdb.org/">version</a> 1.0.0.</p>
<p>I have <code>python</code> version 3.12, and I am installing <code>duckb</code> 1.0.0 in a virtual environment.</p>
<p>I installed the <code>duckdb</code> version 1.0.0 binary as well, and <a href="https://duckdb.org/docs/extensions/overview.html">installed</a> the <code>motherduck</code> extension.</p>
<p>And, of course, I also have created an account on <a href="https://motherduck.com/">MotherDuck</a>.</p>
</section>
<section id="running-duckdb-in-r" class="level3">
<h3 class="anchored" data-anchor-id="running-duckdb-in-r">Running duckdb in R</h3>
<p>This has been probably <a href="https://duckdb.org/docs/api/r">covered</a> many times so far. Nevertheless, for completeness, running <code>duckdb</code> in <code>R</code> is fairly straight forward:</p>
<pre><code># Connect to an in-memory DuckDB database
con &lt;- dbConnect(duckdb::duckdb(), ":memory:")

# Write the Iris dataset to the DuckDB in-memory database
dbWriteTable(con, "iris", iris)

# Query data from the DuckDB database
data &lt;- dbGetQuery(con, "SELECT * FROM iris")
</code></pre>
<p>Of course, there is the possibility of doing things with <a href="https://duckdblabs.github.io/duckplyr/">duckplyr</a>, but we are not going to go into that.</p>
</section>
<section id="connecting-to-motherduck" class="level3">
<h3 class="anchored" data-anchor-id="connecting-to-motherduck">Connecting to MotherDuck</h3>
<p>MotherDuck documentation has details about <a href="https://motherduck.com/docs/getting-started/connect-query-from-python/installation-authentication">connecting</a> to MotherDuck using <code>python</code>, but not for connecting using <code>R</code>.</p>
<p>After asking a few questions on the discord, I learned that the process should be similar.</p>
<p>Let’s see how that looks.</p>
<section id="python" class="level4">
<h4 class="anchored" data-anchor-id="python">Python</h4>
<p>In a Python 3.12 virtual environment, that has <code>duckdb-1.0.0</code>, getting to MotherDuck is simple, in fact as the documentation says:</p>
<pre><code>import duckdb

# connect to MotherDuck using 'md:' or 'motherduck:'
con = duckdb.connect('md:')</code></pre>
<p>The above results in getting a notification on the terminal:</p>
<pre><code>Attempting to automatically open the SSO authorization page in your default browser.
1. Please open this link to login into your account: https://auth.motherduck.com/activate
2. Enter the following code: XXXX-XXXX</code></pre>
<p>Nothing else is required here. We click in the browser, establish a connection, get a token, etc.</p>
</section>
<section id="r" class="level4">
<h4 class="anchored" data-anchor-id="r">R</h4>
<p>However, doing the same with R doesn’t have the same outcome:</p>
<pre><code>con &lt;- DBI::dbConnect(duckdb::duckdb(), "md:")</code></pre>
<p>Creates a local database called <code>md:</code>:</p>
<pre><code>ls -lh md\: 
-rw-r--r-- 1 novica novica 12K jun 21 10:32 md:</code></pre>
<p>My best guess here is that the <code>duckdb</code> package for <code>R</code> does not automatically figure out that it should load the <code>motherduck</code> extension, as is probably the case in <code>python</code>.</p>
<p>The approach in R is then similar to what is suggested in the section <a href="https://motherduck.com/docs/getting-started/connect-query-from-python/installation-authentication#connecting-to-motherduck-after-opening-a-local-duckdb-database">Connecting to MotherDuck after opening a local DuckDB database</a>:</p>
<pre><code># Create a local database
con &lt;- DBI::dbConnect(duckdb::duckdb(), "local.duckdb")


# Note: Installing the extension is not nececsary here since 
# I already have it installed on my system. However, if you don't want
# to go to the trouble of installing the duckdb binary and then installing
# extensions, then it is possible to do the installation here before
# loading with:
# DBI::dbExecute(con, "INSTALL 'motherduck';")

# Load the Mother Duck extension
DBI::dbExecute(con, "LOAD 'motherduck';")


# Verify that the extension is loaded
DBI::dbGetQuery(
  con,
  "SELECT extension_name, loaded, installed FROM duckdb_extensions() WHERE
  extension_name = 'motherduck'"
)

# Connect to MotherDuck
DBI::dbExecute(con, "PRAGMA MD_CONNECT")</code></pre>
<p>At which point the message for authenticating in the browser shows up in the terminal.</p>
<p>After approving the connection, as the friendly message says, the token can be stored in an environment variable to avoid having to log in again.</p>
<p>Then it is a simple matter of querying things on MotherDuck:</p>
<pre><code># Query the sample data about air quality that is avaiable on MotherDuck
DBI::dbGetQuery(
  con,
  "SELECT country_name, city, \"year\", pm10_concentration, pm25_concentration, no2_concentration, FROM sample_data.who.ambient_air_quality WHERE  city = 'Skopje' OR city = 'Oslo';"
)</code></pre>
<p>Note that we have to specify the database name: <code>sample_data</code>, and the schema: <code>who</code> to query the data on MotherDuck.</p>
<p>The results can be assigned to an object in R, which I did. And since it is always fun to make a plot, here is how it looks for the two cities where I spend most of my time.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://discindo.org/posts/2024-06-21-joining-the-flock-from-r-working-with-data-on-mother-duck/images/particles.png" class="img-fluid figure-img"></p>
<figcaption>Particle concentration plot</figcaption>
</figure>
</div>
<p>And, that’s a wrap. I mean, a quack. :)</p>


</section>
</section>

 ]]></description>
  <category>R</category>
  <category>duckdb</category>
  <category>database</category>
  <guid>https://discindo.org/posts/2024-06-21-joining-the-flock-from-r-working-with-data-on-mother-duck/</guid>
  <pubDate>Fri, 21 Jun 2024 00:00:00 GMT</pubDate>
  <media:content url="https://discindo.org/posts/2024-06-21-joining-the-flock-from-r-working-with-data-on-mother-duck/images/particles.png" medium="image" type="image/png" height="80" width="144"/>
</item>
</channel>
</rss>
