<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>3 Minutes Wednesdays</title>
    <description>Weekly bite-sized tips on DataViz, Shiny and Stats/Machine Learning.</description>
    
    <link>https://3mw.albert-rapp.de/</link>
    <atom:link href="https://rss.beehiiv.com/feeds/Ma00qoTlsO.xml" rel="self"/>
    
    <lastBuildDate>Mon, 13 Apr 2026 17:25:23 +0000</lastBuildDate>
    <pubDate>Wed, 09 Jul 2025 17:00:00 +0000</pubDate>
    <atom:published>2025-07-09T17:00:00Z</atom:published>
    <atom:updated>2026-04-13T17:25:23Z</atom:updated>
    
      <category>Programming</category>
      <category>Education</category>
      <category>Technology</category>
    <copyright>Copyright 2026, 3 Minutes Wednesdays</copyright>
    
    <image>
      <url>https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/publication/logo/dcd4eaf2-0a16-4f6e-a277-324841b39e98/Twitter_header_-_6.png</url>
      <title>3 Minutes Wednesdays</title>
      <link>https://3mw.albert-rapp.de/</link>
    </image>
    
    <docs>https://www.rssboard.org/rss-specification</docs>
    <generator>beehiiv</generator>
    <language>en-us</language>
    <webMaster>support@beehiiv.com (Beehiiv Support)</webMaster>

      <item>
  <title>3MW (Using Database Transactions in R)</title>
  <description>Database transactions should be your default mode of writing data to a database. In this newsletter, I show you how these transactions work in R.</description>
  <link>https://3mw.albert-rapp.de/p/using-database-transactions-in-r</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/using-database-transactions-in-r</guid>
  <pubDate>Wed, 09 Jul 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-07-09T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter, I want to teach you about <b>database transactions</b>. Sounds simple, but it’s actually a very crucial concept that we haven’t covered before.</p><p class="paragraph" style="text-align:left;">You see, in many cases you’ll want to write to your database using transactions. Technically, you could just write to your database as-is. But this leaves you <b>without any safety precautions in case something goes wrong</b>.</p><p class="paragraph" style="text-align:left;">For example, you could lose your internet connection in the middle of uploading a large dataset. If that happens your database ends up with only part of the data, and then you’re stuck trying to figure out:</p><ul><li><p class="paragraph" style="text-align:left;">What was successfully transferred?</p></li><li><p class="paragraph" style="text-align:left;">What’s still only on your local machine?</p></li></ul><p class="paragraph" style="text-align:left;">These kinds of situations can easily leave your database in a broken or inconsistent state. And that’s really really frustrating to deal with.</p><p class="paragraph" style="text-align:left;">So that’s where <b>transactions</b> come in. Let’s dive in.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="what-are-transactions"><b>What Are Transactions?</b></h1><p class="paragraph" style="text-align:left;">Transactions allow you to tell your database ahead of time</p><p class="paragraph" style="text-align:left;"><i>“Hey, I’m going to write something. I’ll let you know when I’m done. Don’t finalize anything until I say so.”</i></p><p class="paragraph" style="text-align:left;">If everything works fine, you “commit” the transaction, and the data gets saved. If not, you “roll it back,” and it’s like nothing ever happened.</p><p class="paragraph" style="text-align:left;">Sounds simple, right? Well, it is. You just have to use this nifty little safety feature. Your database will thank you.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="how-to-use-transactions-in-r"><b>How to Use Transactions in R</b></h1><p class="paragraph" style="text-align:left;">It’s surprisingly easy to use transactions in R when working with databases. You start a transaction with:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/dae90a3a-f826-4c6f-8f2b-baa181fab88b/image.png?t=1750768790"/></div><p class="paragraph" style="text-align:left;">Then, you perform your usual data writing operations. Let’s assume we’re just going to add a few rows:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/59a8becd-5832-4634-a4b8-e116a209b118/image.png?t=1750768798"/></div><p class="paragraph" style="text-align:left;">If everything goes well, you finalize the changes with:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/79c6c9f9-2789-410e-8ef4-d8ce09e2d87b/image.png?t=1750768807"/></div><p class="paragraph" style="text-align:left;">Or if anything goes wrong, you can cancel the whole transaction, i.e. everything you did since you called <code>dbBegin()</code>:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9f53b816-3afa-4171-8431-ab512757482d/image.png?t=1750768815"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="why-is-this-helpful"><b>Why Is This Helpful?</b></h1><p class="paragraph" style="text-align:left;">This is especially useful when you’re working with <b>multiple tables</b>.</p><p class="paragraph" style="text-align:left;">Let’s say you need to insert data into one table and then into another table that references the first table. Let’s try this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/18fe6e87-c47c-4e97-be7e-b9b0e93281fc/image.png?t=1750768831"/></div><p class="paragraph" style="text-align:left;">Notice how the second call failed? That happened because I put restrictions on the second table whereas the first one doesn’t have them.</p><p class="paragraph" style="text-align:left;">Either way, that’s when we call <code>dbRollback()</code>. And in order for all of this to happen automatically, we can wrap the whole procedure into a <code>tryCatch()</code> statement.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/218ce6a2-21ab-4885-8e22-3473e4179bee/image.png?t=1750768872"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">And with that, you’ve got a new set of tools to interact with databases <b>safely and reliably</b>. Use transactions whenever you write to a database, especially when multiple related operations are involved. Your future self (and your data) will thank you!</p><p class="paragraph" style="text-align:left;">And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-database-transactions-in-r" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=e38e2d2a-383d-4986-b585-312f8c4a3ec7&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Writing SQL in R Efficiently)</title>
  <description>I show you how to assemble SQL code from within R using the glue_sql() function from the {glue} package. Much simpler and safer than using paste()!</description>
  <link>https://3mw.albert-rapp.de/p/writing-sql-in-r-efficiently</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/writing-sql-in-r-efficiently</guid>
  <pubDate>Wed, 02 Jul 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-07-02T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. The <code>glue_sql()</code> function helped us last week to make our database calls safer and avoid SQL injection.</p><p class="paragraph" style="text-align:left;">But there’s also a lot of convenience that <code>glue_sql()</code> offers for everyday development. So let’s check that out.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="use-curly-braces-for-r-variables"><b>Use Curly Braces for R Variables</b></h1><p class="paragraph" style="text-align:left;">The first thing that’s really convenient and that you already know from last week is this: You can use curly braces <code>&#123;&#125;</code> inside your SQL string to insert R variables. This works great when the variables are just simple strings or scalar values.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2b7a7785-ec4f-4b36-be0f-c8c64654a0a6/image.png?t=1750766863"/></div><p class="paragraph" style="text-align:left;">And as you can see, this gives you the results you probably want:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e62baad3-59ac-49f2-a903-9eac587304ea/image.png?t=1750766873"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="use-backticks-for-i-ds"><b>Use Backticks for IDs</b></h1><p class="paragraph" style="text-align:left;">Next, let’s try to not grab all columns but only a selected one:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/bd62319f-d77b-437e-92a9-6fe9c9f01487/image.png?t=1750766900"/></div><p class="paragraph" style="text-align:left;">Well, that didn’t crash but it didn’t go as expected either. The reason for that is that you will have to tell <code>glue_sql()</code> that <code>col_name</code> (and technically also <code>tbl_name</code>) is an ID. You can do that with backticks <b>inside</b> the curly brackets.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/f24145dc-3c28-40c7-be69-c9a7ce5dff21/image.png?t=1750766910"/></div><p class="paragraph" style="text-align:left;">Ahh this looks much better!</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="collapse-vectors-with-the-operator"><b>Collapse Vectors with the </b><code>*</code><b> Operator</b></h1><p class="paragraph" style="text-align:left;">If you pass a vector into a placeholder, <code>glue_sql()</code> by default tries to insert the whole vector resulting in multiple SQL fragments:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3ea4dedc-8c44-48ba-9b52-c652f4cb21f3/image.png?t=1750766920"/></div><p class="paragraph" style="text-align:left;">This is usually <b>not</b> what you want. Instead, you want to collapse a vector with <code>*</code>:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/67ef4f8c-a6c9-4078-a567-dccb7930f85f/image.png?t=1750766927"/></div><p class="paragraph" style="text-align:left;">Sweet! With that you can easily get data from multiple columns:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/bb030609-ed8b-4fb5-becc-9e9a21e7fdef/image.png?t=1750766936"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="use-i-ds-from-different-tables"><b>Use IDs from different tables</b></h1><p class="paragraph" style="text-align:left;">Let’s imagine that our database has another table:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/72d20d91-0833-4e9f-8fc1-bb88f42eb7d5/image.png?t=1750766947"/></div><p class="paragraph" style="text-align:left;">Then, we can make sure to reference to columns from different tables by including the table names. The <code>Id()</code> function helps with that:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/340e3bf6-e4b9-4d51-9e18-40c84e719eac/image.png?t=1750766958"/></div><p class="paragraph" style="text-align:left;">And because we need to identify the corrsponding species columns somehow, we have to reference to the corresponding table names as well.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c9116161-2a0a-48c8-befa-208b9a118efa/image.png?t=1750766972"/></div><p class="paragraph" style="text-align:left;">Now, we could easily wrap all of these IDs into backticks and everything works out nicely in assembled SQL code. Here’s an example from the <code>glue_sql()</code> docs for that:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/33c586d2-d9cb-4917-87fb-dc03520c6bdf/image.png?t=1750766986"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">And there you have it: <code>glue_sql()</code> will make your life as an R developer much easier. Beyond just protecting you from SQL injection, it helps you write cleaner, more flexible, and maintainable database queries from within R.</p><p class="paragraph" style="text-align:left;">And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-writing-sql-in-r-efficiently" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=a2dae720-5834-4abe-b1eb-21c6cf910e28&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Safer SQL in R)</title>
  <description>I show you how to use the glue_sql() function from the {glue} R package to save yourself from SQL injections. That way, your database calls are much safer.</description>
  <link>https://3mw.albert-rapp.de/p/safer-sql-in-r</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/safer-sql-in-r</guid>
  <pubDate>Wed, 25 Jun 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-06-25T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In the last couple of newsletters, we talked about SQL databases. And there’s no way we can talk about accessing SQL databases via R code without mentioning <b>SQL injection</b>.</p><p class="paragraph" style="text-align:left;">This is a nasty thing that can leak data or even destroy your database if you allow people to interact with it unsafely. And often, that’s exactly what you want (the interaction, not the unsafe part 😆). Here’s a common scenario for that:</p><ul><li><p class="paragraph" style="text-align:left;">Users interact with a Shiny dashboard to retrieve specific data from a database.</p></li><li><p class="paragraph" style="text-align:left;">Based on the inputs, you execute some SQL.</p></li><li><p class="paragraph" style="text-align:left;">Your dashboard displays the new data.</p></li></ul><p class="paragraph" style="text-align:left;">So letting users interact with a database is not bad in itself. It’s only bad when you do it uncontrolled. That’s when this bad SQL injection can occur.</p><p class="paragraph" style="text-align:left;">But here’s the good news: There’s an easy way to avoid damage. And even better: This method also makes it much easier to assemble SQL code in R.</p><p class="paragraph" style="text-align:left;">Let me show you how that works.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="sql-injection-via-r-variables"><b>SQL Injection via R Variables</b></h1><p class="paragraph" style="text-align:left;">Let’s talk about how you might encounter SQL injection in the first place.</p><p class="paragraph" style="text-align:left;">Let’s imagine that you want to retrieve data about a specific penguin species from a table in your database. One common (but <b>unsafe</b>) way to do this is to paste together SQL code manually with R variables:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b515d3a9-006c-41d9-b277-eb50118936b9/image.png?t=1750766589"/></div><p class="paragraph" style="text-align:left;">While this works, it’s insecure. If a user-supplied value like <code>species</code> contains malicious SQL code, it could complete your SQL snippet <i>and</i> do something dangerous (e.g. extracting all of your confidential data). This is <b>SQL injection</b>.</p><p class="paragraph" style="text-align:left;">And in this specific scenario, here’s what that would look like. Let’s first set up our data base from last time:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/5a37adb6-910b-422c-a1aa-401ae2d1fa78/image.png?t=1750766602"/></div><p class="paragraph" style="text-align:left;">And then we can stick in some malicious code into the <code>species</code> variable.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3b6474a8-81a3-4a1e-82b7-abb6462033f9/image.png?t=1750766614"/></div><p class="paragraph" style="text-align:left;">Here, a little trick was used to close the “WHERE” statement with a <code>&#39;</code> followed by an or-statement that is always true. That way, we will never actually filter the data.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="why-would-that-happen"><b>Why Would That Happen?</b></h1><p class="paragraph" style="text-align:left;">Now, you might wonder: <i>Why would my variable ever be filled with something malicious?</i></p><p class="paragraph" style="text-align:left;">Well, consider a Shiny app that allows users to filter database results. If you’re not careful, users can input harmful values into the fields that populate those SQL variables. If someone with bad intentions figures out you’re pasting user input into SQL strings, they could inject destructive SQL.</p><p class="paragraph" style="text-align:left;">And they don’t even have to do that manually. There are automated tools that try out loads of combinations in the hopes that at some point some SQL injection works.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="the-solution-glue-sql-from-glue"><b>The Solution: </b><code>glue_sql()</code><b> from </b><code>&#123;glue&#125;</code></h1><p class="paragraph" style="text-align:left;">Here’s where <code>&#123;glue&#125;</code> and its <code>glue_sql()</code> function come in. Using <code>glue_sql()</code> makes assembling SQL both easier and safer. You still write your SQL code in text form, but you use curly braces (<code>&#123;&#125;</code>) to insert variables.</p><p class="paragraph" style="text-align:left;">Most importantly, <code>glue_sql()</code> handles <b>SQL escaping</b> for you to prevent SQL injection. Here’s an example:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e5816cd0-6ac5-439e-8a89-8fff65740492/image.png?t=1750766626"/></div><p class="paragraph" style="text-align:left;">So in the standard case everything works like you’d expect. And in case there’s the same malicious code from before inside the <code>species</code> variable?</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9cd45c43-84b7-4fc1-be20-911f47850bb5/image.png?t=1750766641"/></div><p class="paragraph" style="text-align:left;">Here, <code>glue_sql()</code> will put <b>everything</b> into quotes. That way, a user cannot stick in something to close the initial quotation mark. And the resuls would be empty:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/254c77af-9423-4478-bfcb-7fd9bcbc5edb/image.png?t=1750766654"/></div><p class="paragraph" style="text-align:left;">Thus, this is easy to write <b>and</b> secure.</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Fantastic! We’ve just seen how <code>glue_sql()</code> helps you write safer SQL code. But there’s more! In the next newsletter, we’ll explore additional features of <code>glue_sql()</code> that make it even more powerful.</p><p class="paragraph" style="text-align:left;">And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-safer-sql-in-r" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=495cad43-5bb8-4c75-8342-ce29b6de820a&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW ({dbplyr} combines the best of R &amp; SQL)</title>
  <description>I show you how to avoid using pure SQL code and instead use dplyr functions to interact with databases from within R. </description>
  <link>https://3mw.albert-rapp.de/p/dbplyr-combines-the-best-of-r-sql</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/dbplyr-combines-the-best-of-r-sql</guid>
  <pubDate>Wed, 04 Jun 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-06-04T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Last week, I showed you how to connect to databases with R. And I also mentioned that it’s helpful to write a bit more SQL code than just grabbing all the data and processing it locally. This might sound like a lot of effort, though. So here’s the good news:</p><p class="paragraph" style="text-align:left;">If you’re already using <code>dplyr</code> for data wrangling, you can get the best of both worlds. You can write <code>dplyr</code> code and let R translate that into SQL so that time-saving and resource-efficient calculations happen in the database. Then, you only retrieve the results.</p><p class="paragraph" style="text-align:left;">So in today’s newsletter I’ll show you how that works. Let’s go!</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="getting-started-with-dbplyr"><b>Getting Started with </b><code>&#123;dbplyr&#125;</code></h1><p class="paragraph" style="text-align:left;">First things first: you’ll need to install the <code>&#123;dbplyr&#125;</code> package. This package extends <code>dplyr</code> so it can translate R code into SQL syntax for supported databases.</p><p class="paragraph" style="text-align:left;"><br>To get started, establish a connection to your database using <code>DBI::dbConnect()</code>, just like before. This part hasn’t changed.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3980cc03-a8c9-412e-be2b-3e758549ee9a/image.png?t=1749051952"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="working-with-tables-using-dbplyr"><b>Working with Tables Using </b><code>&#123;dbplyr&#125;</code></h1><p class="paragraph" style="text-align:left;">Now you can use <code>&#123;dbplyr&#125;</code> functions to interact with the database using familiar <code>dplyr</code> verbs. For example, in our example database, you can copy an R dataset like <code>palmerpenguins::penguins</code> into a database table using <code>copy_to()</code>:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/10e3cf6c-c437-47bd-b455-10234ba209f6/image.png?t=1749051966"/></div><p class="paragraph" style="text-align:left;">Fun fact: Notice that I never loaded {dbplyr} 😮 {dplyr} will detect when you want to use a {dbplyr} function.</p><p class="paragraph" style="text-align:left;">Once the data is in the database, you can reference it with <code>tbl()</code>. This will <b>connect</b> to the table in the database (which is why the <code>con</code> variable is needed.)</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/0c2288f1-a165-4727-9305-5261c22f15cf/image.png?t=1749051998"/></div><p class="paragraph" style="text-align:left;">Notice how the output almost looks like a regular tibble. The only difference is that it shows only a preview and not the full dataset. And in case you’re wondering: That’s a good thing. You never know how large the database is and often a preview will suffice.</p><hr class="content_break"><p class="paragraph" style="text-align:left;"></p><div class="section" style="background-color:#e4ebf0;margin:0.0px 40.0px 0.0px 40.0px;padding:0.0px 0.0px 0.0px 0.0px;"><h1 class="heading" style="text-align:left;">Click to Support 👇️ </h1><p class="paragraph" style="text-align:left;">Hey friends 👋 I’m experimenting with ads in my newsletter to finance all the free stuff I give away. If you enjoy this newsletter and want to support it, a click on the the ad below would be a super simple but effective way to do so. 🤗 </p><p class="paragraph" style="text-align:left;"><b>No need to sign up. A click is enough support</b> 🥳 </p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="youve-never-experienced-business-ne">You’ve never experienced business news like this.</h3><div class="image"><a class="image__link" href="https://www.morningbrew.com/subscribe?utm_campaign={{publication_alphanumeric_id}}&utm_medium=paid_newsletter&utm_source=beehiiv&_bhiiv=opp_ae05c30d-d159-458e-8091-a4602f0273c8_fbd824b6&bhcl_id=4a6f7506-4e23-4fcf-83bf-7d82b8824d3c_{{subscriber_id}}_{{email_address_id}}" rel="noopener" target="_blank"><img class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a8ec3269-6f0b-4531-b518-08f34409091a/Option_2.png?t=1748535894"/></a></div><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.morningbrew.com/subscribe?utm_campaign={{publication_alphanumeric_id}}&utm_medium=paid_newsletter&utm_source=beehiiv&_bhiiv=opp_ae05c30d-d159-458e-8091-a4602f0273c8_fbd824b6&bhcl_id=4a6f7506-4e23-4fcf-83bf-7d82b8824d3c_{{subscriber_id}}_{{email_address_id}}" target="_blank" rel="noopener noreferrer nofollow">Morning Brew</a> delivers business news the way busy professionals want it — quick, clear, and written like a human.</p><p class="paragraph" style="text-align:left;">No jargon. No endless paragraphs. Just the day’s most important stories, with a dash of personality that makes them surprisingly fun to read.</p><p class="paragraph" style="text-align:left;">No matter your industry, Morning Brew’s daily email keeps you up to speed on the news shaping your career and life—in a way you’ll actually enjoy.</p><p class="paragraph" style="text-align:left;">Best part? It’s 100% free. <a class="link" href="https://www.morningbrew.com/subscribe?utm_campaign={{publication_alphanumeric_id}}&utm_medium=paid_newsletter&utm_source=beehiiv&_bhiiv=opp_ae05c30d-d159-458e-8091-a4602f0273c8_fbd824b6&bhcl_id=4a6f7506-4e23-4fcf-83bf-7d82b8824d3c_{{subscriber_id}}_{{email_address_id}}" target="_blank" rel="noopener noreferrer nofollow">Sign up in 15 seconds</a>, and if you end up missing the long, drawn-out articles of traditional business media, you can always go back.</p><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.morningbrew.com/subscribe?utm_campaign={{publication_alphanumeric_id}}&utm_medium=paid_newsletter&utm_source=beehiiv&_bhiiv=opp_ae05c30d-d159-458e-8091-a4602f0273c8_fbd824b6&bhcl_id=4a6f7506-4e23-4fcf-83bf-7d82b8824d3c_{{subscriber_id}}_{{email_address_id}}" target="_blank" rel="noopener noreferrer nofollow">Check it out</a></p><hr class="content_break"><p class="paragraph" style="text-align:left;">Alright, now back to the good stuff. </p><p class="paragraph" style="text-align:left;"></p></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="writing-sql-through-dplyr-verbs"><b>Writing SQL Through </b><code>dplyr</code><b> Verbs</b></h1><p class="paragraph" style="text-align:left;">Now that you have a table-like object, you can use familiar <code>dplyr</code> verbs to generate SQL queries. For example:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2c523331-8fcf-4784-bc59-100006ce0c7c/image.png?t=1749052034"/></div><p class="paragraph" style="text-align:left;">Again, this only shows a preview. To pull the full result set from the database, use <code>collect().</code></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/217a53b4-8a46-4b38-81b9-2abf63ed9258/image.png?t=1749052044"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="seeing-the-generated-sql"><b>Seeing the Generated SQL</b></h1><p class="paragraph" style="text-align:left;">And if you’re ever wondering how <code>&#123;dbplyr&#125;</code> translated your <code>dplyr</code> code into SQL, you can inspect it using <code>show_query().</code></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3920df4c-5c98-4737-be61-e0db13374dfa/image.png?t=1749052055"/></div><p class="paragraph" style="text-align:left;">Also, this is a great way to learn more about SQL by seeing how familiar R code maps to SQL commands.</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Nice. We’ve learned a simple way to interact with databases using familiar syntax. However, using <code>&#123;dbplyr&#125;</code> doesn’t mean you’ll never need to write raw SQL again. </p><p class="paragraph" style="text-align:left;">It helps you get started quickly and efficiently, though. Next week, I’ll show you how to combine <code>&#123;dbplyr&#125;</code> with raw SQL for more advanced database workflows. </p><p class="paragraph" style="text-align:left;">And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-dbplyr-combines-the-best-of-r-sql" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=8c174980-994f-4b75-989f-05b9743f3655&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Database Connections With R)</title>
  <description>I&#39;ll show you how to connect your R session to a SQL database so that you can get the data in a structured way.</description>
  <link>https://3mw.albert-rapp.de/p/database-connections-with-r</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/database-connections-with-r</guid>
  <pubDate>Wed, 28 May 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-05-28T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. When you’re working in a company, chances are you won’t be handed a simple CSV file to work with. Instead, you’ll likely need to grab your data from a company-wide SQL database hosted in the cloud or on internal servers.</p><p class="paragraph" style="text-align:left;">So in today’s newsletter, I’ll show you how to connect to these databases using R.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="what-the-heck-is-a-driver"><b>What The Heck is a Driver?</b></h1><p class="paragraph" style="text-align:left;">First, we need a so-called driver. In simple terms, this is the tool that handles the connection between your computer and the database. Think of it as a translator that often comes in one of two flavors:</p><ul><li><p class="paragraph" style="text-align:left;"><b>ODBC drivers</b>: These drivers work with the open database connection format</p></li><li><p class="paragraph" style="text-align:left;"><b>JDBC drivers</b>: These drivers use Java (that’s what the “J” stands for in JDBC)</p></li></ul><p class="paragraph" style="text-align:left;">Here, we’ll use the <code>&#123;odbc&#125;</code> package to go down the ODBC route.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="which-driver-do-you-need"><b>Which Driver Do You Need?</b></h1><p class="paragraph" style="text-align:left;">So now that we know that we want ODBC drivers, we also need to decide which specific driver we need. You see, this kind of thing depends on the database your or your company uses. For example it could be an Oracle or PostgreSQL database that will need an Oracle or PostgreSQL driver</p><p class="paragraph" style="text-align:left;">Typically, your tech department will tell you what you need. Your job is only to understand the big picture that I’m trying to explain here.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="example-setting-up-an-sq-lite-datab"><b>Example: Setting Up an SQLite Database</b></h1><p class="paragraph" style="text-align:left;">For today’s example, we’ll simulate a database using <b>SQLite</b>, which supports in-memory databases. This means that we can simply spin up a temporary database locally on our computer.</p><p class="paragraph" style="text-align:left;">After having installed a SQLite driver for your computer, you can set up a connection from R to a temporary database using <code>&#123;DBI&#125;</code> and <code>&#123;odbc&#125;</code>:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/fe69436a-2556-4d15-9b1a-6abf54c5592f/image.png?t=1746469282"/></div><p class="paragraph" style="text-align:left;">Whooah. That’s a lot of function arguments. Once again, the connection details (like database name, user, password and port) is something that your tech department should have ready for you.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="creating-and-populating-a-table"><b>Creating and Populating a Table</b></h1><p class="paragraph" style="text-align:left;">So now that we have a database connection stored in a variable called <code>con</code>, we can create a table in our SQLite database. Here, we’ll use the famous Palmer Penguins dataset:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/0e4798d9-9cab-4d9a-90d3-ab4831391266/image.png?t=1746469294"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="querying-data-from-the-database"><b>Querying Data from the Database</b></h1><p class="paragraph" style="text-align:left;">To fetch data, you’ll use <code>dbGetQuery()</code> from the <code>&#123;DBI&#125;</code> package. Here’s how to select all rows using SQL code:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a1e2af9f-e02c-4af8-b996-02f441a0e463/image.png?t=1746469310"/></div><p class="paragraph" style="text-align:left;">Alternatively, you can (and probably should) use a bit more SQL to filter down the data that you actually want.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/96c32e8a-823f-45de-acbf-dfaf1af5c4f1/image.png?t=1746469321"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="why-use-sql-for-filtering"><b>Why Use SQL for Filtering?</b></h1><p class="paragraph" style="text-align:left;">And you may wonder: <i>“Why should I invest time into learning SQL when I can just grab the full data using the snippet you’ve just shown?“</i> And indeed, you could download the entire table and filter it inside of R. But filtering directly in the database is often <b>much faster</b> because:</p><ul><li><p class="paragraph" style="text-align:left;">SQL databases are optimized for these operations</p></li><li><p class="paragraph" style="text-align:left;">You avoid transferring large datasets over the network</p></li></ul><p class="paragraph" style="text-align:left;">Learning a few basic SQL keywords can go a long way in improving your data workflow.</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Nice! With that we covered:</p><ul><li><p class="paragraph" style="text-align:left;">The basics of database connections in R</p></li><li><p class="paragraph" style="text-align:left;">The difference between ODBC and JDBC</p></li><li><p class="paragraph" style="text-align:left;">How to set up and query a database using <code>&#123;DBI&#125;</code> and <code>&#123;odbc&#125;</code></p></li></ul><p class="paragraph" style="text-align:left;">Armed with these skills, you’ll hopefully be ready to connect to real company databases and work with large-scale data. As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-database-connections-with-r" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=59653b36-7f6d-47b1-a813-04e7a1104eb1&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Environment Variables in R)</title>
  <description>The three most common ways to set environment variables in R. This sounds super boring and it is. But it is not as tricky as lots of R users think at first.</description>
  <link>https://3mw.albert-rapp.de/p/environment-variables-in-r</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/environment-variables-in-r</guid>
  <pubDate>Wed, 21 May 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-05-21T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Environment variables control <b>system-wide</b> or <b>session-wide settings</b> inside your R session. This sounds incredibly boring. And, honestly, it kind of is. </p><p class="paragraph" style="text-align:left;">But it can <b>feel complicated</b> to R users who haven’t encountered them before. When you do bump into environment variables “in the wild,” they can seem unnecessarily tricky.</p><p class="paragraph" style="text-align:left;">That’s why, in today’s newsletter, I’ll cover a bit of the mundane stuff. That is, I’ll show you how to set and get environment variables in R. I know: Exciting! So let’s dive in.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="when-do-environment-variables-matte"><b>When Do Environment Variables Matter?</b></h1><p class="paragraph" style="text-align:left;">Let’s quickly look at a couple of <b>real-world examples</b> where environment variables show up in R workflows:</p><h3 class="heading" style="text-align:left;" id="using-ap-is-like-open-ai"><b>Using APIs (like OpenAI)</b></h3><p class="paragraph" style="text-align:left;">If you’re working with APIs, such as using the <code>&#123;ellmer&#125;</code> package to connect to ChatGPT or other AI services, you’ll need to store your <b>API keys</b> as environment variables.</p><p class="paragraph" style="text-align:left;">For example, to use OpenAI’s API, you need to specify the environment variable <code>OPENAI_API_KEY</code>. This keeps your credentials <b>secure</b> and avoids hard-coding sensitive infos into your scripts.</p><h3 class="heading" style="text-align:left;" id="deploying-shiny-apps"><b>Deploying Shiny Apps</b></h3><p class="paragraph" style="text-align:left;">If you’re deploying a Shiny app, you might want to keep <b>different settings</b> for:</p><ul><li><p class="paragraph" style="text-align:left;">Production (the live version of your app that your users see)</p></li><li><p class="paragraph" style="text-align:left;">Development (the version of the app that you as a developer see and use to test new features)</p></li></ul><p class="paragraph" style="text-align:left;">Environment variables let you <b>switch configurations</b> easily depending on your deployment stage (without editing the core code.)</p><p class="paragraph" style="text-align:left;">So with the examples out of the way, let’s dive into <b>three popular methods</b> for setting environment variables.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="method-1-rprofile-my-favorite"><b>Method 1: </b><code>.Rprofile</code><b> (My Favorite)</b></h1><p class="paragraph" style="text-align:left;">The <code>.Rprofile</code> file allows you to run <b>R code automatically at the start of each R session</b>. If your project doesn’t have such a file, just create a text file and name it <code>.Rprofile</code>. And to set an environment variable, you can use <code>Sys.setenv()</code> inside the <code>.Rprofile</code> file:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/dab6f1ad-833e-4ec6-889b-e17ca7945396/image.png?t=1746469368"/></div><p class="paragraph" style="text-align:left;">🚨 <b>NOTE</b>: Only use <code>Sys.setenv()</code> inside your <code>.Rprofile</code>. If you put it in a regular script, it might get saved to your R history file. And if that ever gets pushed to a public repo, your API key could be compromised.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="method-2-renviron"><b>Method 2: </b><code>.Renviron</code></h1><p class="paragraph" style="text-align:left;">The <code>.Renviron</code> file is <b>simpler</b>. Unlike <code>.Rprofile</code>, it <b>cannot execute R code</b> as it only holds <b>key-value pairs</b>. But just like <code>.RProfile</code>, these environment variables are always loaded at the start of an R session. </p><p class="paragraph" style="text-align:left;">The file itself always follows the syntax <code>key=value</code>. Here’s an example:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/cf631f3a-ef05-480b-9c34-1b7649018922/image.png?t=1746469377"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="method-3-env-via-dotenv"><b>Method 3: </b><code>.env</code><b> (via </b><code>&#123;dotenv&#125;</code><b>)</b></h1><p class="paragraph" style="text-align:left;">The <code>.env</code> file is popular in many programming languages (like Python). A <code>.env</code> file looks just like <code>.Renviron</code>. The difference is only that you load the <code>.env</code> file manually. In R, you can use the <code>&#123;dotenv&#125;</code> package to do that.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/12a6652c-8895-42fc-af8c-3dc16f7258ca/image.png?t=1746469400"/></div><p class="paragraph" style="text-align:left;"></p><p class="paragraph" style="text-align:left;">This method is especially handy if you want to share environment variables<b> across R and Python</b>.</p><hr class="content_break"><p class="paragraph" style="text-align:left;">There you have it. Three ways to work with environment variables in R:</p><p class="paragraph" style="text-align:left;">1️⃣ <code>.Rprofile</code> (using <code>Sys.setenv()</code>)<br>2️⃣ <code>.Renviron</code> (key-value only)<br>3️⃣ <code>.env</code> (loaded via <code>&#123;dotenv&#125;</code>)</p><p class="paragraph" style="text-align:left;">Sure, it’s not the flashiest topic but it’s super important once you move into production-like environments or need to store secrets. As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-environment-variables-in-r" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=7c22c1d6-0ff9-472b-ab7b-589552b753a2&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Parameterized Sections With Quarto)</title>
  <description>We use Quarto and parameterized reports to fill a single document with multiple similar sections that use the same code logic but different data.</description>
  <link>https://3mw.albert-rapp.de/p/parameterized-sections-with-quarto</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/parameterized-sections-with-quarto</guid>
  <pubDate>Wed, 14 May 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-05-14T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter, I’ll show you how to <b>integrate multiple parametric report sections into a single report</b>. You see, instead of generating <b>separate reports</b> for each dataset, you can include multiple sections where each sections uses different data.</p><p class="paragraph" style="text-align:left;">This could look something like this:</p><ul><li><p class="paragraph" style="text-align:left;">📄 General intro text (applies to all datasets)</p></li><li><p class="paragraph" style="text-align:left;">🐟 Section A (Dataset A)</p></li><li><p class="paragraph" style="text-align:left;">🐦 Section B (Dataset B)</p></li><li><p class="paragraph" style="text-align:left;">🦋 Section C (Dataset C)</p></li><li><p class="paragraph" style="text-align:left;">✅ General conclusion</p></li></ul><p class="paragraph" style="text-align:left;">So let’s see how to build this.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="step-1-start-with-a-parametric-repo"><b>Step 1: Start with a Parametric Report</b></h1><p class="paragraph" style="text-align:left;">Begin with a <b>standard parametric report</b>, just like you normally would.</p><p class="paragraph" style="text-align:left;">For example, let’s say you have the Quarto file from last time that generates a report for a <b>single species</b>. This was driven by a <code>species</code> and a <code>color</code> parameter in the YAML header:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/89543df1-8790-4a1e-8fcd-2f61d9d8246e/image.png?t=1746468441"/></div><p class="paragraph" style="text-align:left;">This report works fine on its own, but we want to reuse the code and text within the report <b>multiple times in a single document</b>.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="step-2-create-a-main-quarto-file"><b>Step 2: Create a Main Quarto File</b></h1><p class="paragraph" style="text-align:left;">Next, create a <b>new Quarto file</b> that will act as the main document. This file will include first some general intro text, followed by multiple <b>“includes”</b> of your parametric report. For example, the document could start like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9ae99a48-4920-4177-b4d1-dae090d0c2c4/image.png?t=1746468451"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="step-3-use-include-snippets"><b>Step 3: Use </b><code>include</code><b> Snippets</b></h1><p class="paragraph" style="text-align:left;">Quarto has a special feature that lets you include other Quarto files using the following syntax:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/ba60e3ff-b30c-4be3-9dd0-af76bfd48335/image.png?t=1746468465"/></div><p class="paragraph" style="text-align:left;">Here, this will include text and code chunks from the Quarto file <code>species_report.qmd</code>. That way, you could modify your main Quarto file like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b619b258-248f-4d91-9cf1-7b5564f195fa/image.png?t=1746468476"/></div><p class="paragraph" style="text-align:left;">But if you render this now, you’ll hit an error that will say that <code>params</code> is not defined. If you recall, <code>params</code> is the object that we use inside the species Quarto file.</p><p class="paragraph" style="text-align:left;">Normally, this object is created from the parameters that are specifies inside the YAML header. But here this doesn’t work because <b>includes don’t copy the YAML header</b> from the included file.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="step-4-define-params-in-the-master-"><b>Step 4: Define </b><code>params</code><b> in the Master File</b></h1><p class="paragraph" style="text-align:left;">To solve this, define the <code>params</code> object manually in a code chunk <b>before</b> each include. For example, your report could look like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c530fc87-351d-4501-8d07-7f41d65d5fb4/image.png?t=1746468488"/></div><p class="paragraph" style="text-align:left;">That way, the copied-and-pasted code from <code>species_report.qmd</code> will work because it is preceded by a code chunk that defines <code>params</code>.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="step-5-repeat-for-multiple-datasets"><b>Step 5: Repeat for Multiple Datasets</b></h1><p class="paragraph" style="text-align:left;">Now, you can repeat the same process to include multiple sections, each with a different dataset:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2a281bd7-8614-4927-8ad2-266eaceddbf6/image.png?t=1746468506"/></div><p class="paragraph" style="text-align:left;">This reuses the same species report over and over, but with different <code>params</code> each time. Super efficient, isn’t it?</p><hr class="content_break"><p class="paragraph" style="text-align:left;">This approach allows you to </p><ul><li><p class="paragraph" style="text-align:left;">reuse the same report structure,</p></li><li><p class="paragraph" style="text-align:left;">render multiple sections with different data, and</p></li><li><p class="paragraph" style="text-align:left;">produce a <b>single, polished document</b></p></li></ul><p class="paragraph" style="text-align:left;">It’s a powerful pattern when working with multiple datasets that need similar analysis! Pretty neat, right? As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-parameterized-sections-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=12f24c58-0396-4c4c-a29d-2dc808350477&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Custom Styles with Typst and Quarto)</title>
  <description>We add a bit of visual polish to a PDF file that was generated with Quarto and Typst. That way, we explore lots of possibilities of how to style PDFs with Typst.</description>
  <link>https://3mw.albert-rapp.de/p/creating-beautiful-pdf-reports-with-typst-and-quarto-170a</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/creating-beautiful-pdf-reports-with-typst-and-quarto-170a</guid>
  <pubDate>Wed, 07 May 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-05-07T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul><p class="paragraph" style="text-align:left;">Or use my affiliate code <b>“RAPP10” to get 10% off </b>the fantastic data science courses from Athlyticz:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://athlyticz.com/affiliate-courses?am_id=rapp10&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">State of the Art Data Science Training</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In this week’s newsletter, we’re continuing our journey with <b>Typst + Quarto</b>. As promised, we’re taking our PDF reports to the next level with some <b>visual polish</b>.</p><p class="paragraph" style="text-align:left;">Today, I want to show you how to:</p><ol start="1"><li><p class="paragraph" style="text-align:left;">Add a <b>vertical color bar</b> along the left margin of every page</p></li><li><p class="paragraph" style="text-align:left;">Wrap your <b>main title</b> in a colored box and shift it slightly to the left for a bold visual effect</p></li></ol><p class="paragraph" style="text-align:left;">These small touches can improve the look and feel of your report. And once you know how these things work, you can work out how to add more visual elements with Typst.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-a-vertical-color-bar-to-the-lef"><b>Add a Vertical Color Bar to the Left Margin</b></h1><p class="paragraph" style="text-align:left;">Let’s start by giving all pages a distinctive look using a colored stripe along the left-hand side. To do this, we modify the <code>set page()</code> section of our Typst template. You know, this part here:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/8cb3a5ec-4061-4924-9653-e325ec3c47ac/image.png?t=1743424235"/></div><p class="paragraph" style="text-align:left;">Here, we can use the <code>background</code> property with the <code>place()</code> function to overlay a rectangle:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2f063bd7-84e0-4b53-aa22-f1d605b48e13/image.png?t=1743424248"/></div><p class="paragraph" style="text-align:left;">And with this simple change, we’ve added a vertical splash of color to every page.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2fcb5b99-2ada-425d-9b8f-7ec34ef46701/ksnip_20250331-131726.png?t=1743424351"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="style-the-main-title-with-a-colored"><b>Style the Main Title with a Colored Box</b></h1><p class="paragraph" style="text-align:left;">Next, let us give our report title more visual weight. Instead of plain text, we’ll wrap it in a <b>colored box</b>. We do so by wrapping our <code>text()</code> function into a <code>box()</code> function. That way, our previous pages specification</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/ff8aea0f-2354-4677-b2a0-629cc6a60dc9/image.png?t=1743424263"/></div><p class="paragraph" style="text-align:left;">becomes</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/80878f39-52d5-463f-82c3-37647ed27708/image.png?t=1743424286"/></div><p class="paragraph" style="text-align:left;">Now, our document looks like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/4a7cc724-d0ee-4ca5-9001-b4a71f03333d/ksnip_20250331-131727.png?t=1743424365"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="shift-the-title-box"><b>Shift the title box</b></h1><p class="paragraph" style="text-align:left;">Finally, we can shift the title box slightly to the left by adding a bit of negative horizontal space.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/f113f9fa-b989-415b-8063-a020d0fe7e14/image.png?t=1743424303"/></div><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b8db477b-c7be-4fca-aacf-86a56e2e83ac/ksnip_20250331-131730.png?t=1743424375"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">With just a few small tweaks, we now have a PDF report that is not only <b>parameterized</b> with different inputs but it also <b>looks polished and professional</b>.</p><p class="paragraph" style="text-align:left;">And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-custom-styles-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=a2d79d79-f30e-4c4c-99fa-b4ee4ec73080&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Creating Beautiful PDF Reports with Typst and Quarto)</title>
  <description>I show you how to leverage the Typst framework with Quarto to customize the styling of your PDFs really easily.</description>
  <link>https://3mw.albert-rapp.de/p/creating-beautiful-pdf-reports-with-typst-and-quarto</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/creating-beautiful-pdf-reports-with-typst-and-quarto</guid>
  <pubDate>Wed, 30 Apr 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-04-30T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Have you ever heard of the <b>Typst</b> project? It is a lightweight, Markdown-inspired language designed for creating beautiful, customized PDF documents with minimal effort. </p><p class="paragraph" style="text-align:left;">Basically, it is supposed to be like LaTeX but muuuch easier. And the coolest part? You can use Typst <b>from within Quarto</b> to create stunning PDF reports.</p><p class="paragraph" style="text-align:left;">So in today’s newsletter, I’ll walk you through how to style our PDF document from last week. Let’s dive in</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="set-typst-as-your-pdf-format"><b>Set Typst as Your PDF Format</b></h1><p class="paragraph" style="text-align:left;">To start using Typst from Quarto, go into your <code>.qmd</code> file and specify <code>typst</code> as the output format in the YAML header:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/89edaa7c-32b9-4eb2-9363-4fc831165d2d/image.png?t=1743423454"/></div><p class="paragraph" style="text-align:left;">If you render this now, you’ll get a similar PDF output as before.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7cd2565a-a6a2-402a-9047-f10b18d23f75/image.png?t=1743423844"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-custom-styling-with-typst-templ"><b>Add Custom Styling with Typst Templates</b></h1><p class="paragraph" style="text-align:left;">To make our PDF look good, we’ll use <b>template partials</b> provided by Typst. There are two key files that we need to mention in the YAML header for that:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/4ba75c1a-4cc4-4670-a4b6-bd2040a82bea/image.png?t=1744011227"/></div><p class="paragraph" style="text-align:left;">Both are plain text files that you can create by just taking a <code>.txt</code> file and changing the extension to <code>.typ</code>. So the more important question is: <i>“How do we fill these files?”</i> Let’s go through both files.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="filling-typstshowtyp"><b>Filling </b><code>typst-show.typ</code></h1><p class="paragraph" style="text-align:left;">This file defines the variables that are passed into the layout, such as the title, author, and parameters from your Quarto YAML. You see, what you you define in the Quarto YAML header isn’t automatically known to Typst. That’s why you need to transfer it. For that you use the <code>#show</code> function from Typst.</p><p class="paragraph" style="text-align:left;">There, you specify that your “article” layout (that’s the default name of the used layout) is equipped with a set of variables.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9194ff9f-51f9-4c69-9d4e-013fd1ff6315/image.png?t=1743423479"/></div><p class="paragraph" style="text-align:left;">The syntax takes some getting used to. Basically, you always write</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/f3c3e186-5b39-4045-b260-2758c7be755f/image.png?t=1743423489"/></div><p class="paragraph" style="text-align:left;">Yeah, I know. As I said, it takes some getting used to. And for drilling down nested YAML structures, you can just use a dot symbol (<code>.</code>). With that we know enough Typst code to transfer <code>title</code>, <code>author</code> and <code>params.species</code> from our Quarto YAML header to Typst.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/573d7dc3-7a55-4666-a9db-5e4eaf6a70be/image.png?t=1743423500"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="filling-typsttemplatetyp"><b>Filling </b><code>typst-template.typ</code></h1><p class="paragraph" style="text-align:left;">Nice. One file down, one more to go.</p><p class="paragraph" style="text-align:left;">In the <code>typst-template.typ</code> file, we define the actual <b>article layout</b> of our PDF report. For that, we use the <code>#let</code> function.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/8d12f428-dd08-480b-9f14-7cd839787708/image.png?t=1743423521"/></div><p class="paragraph" style="text-align:left;">Inside the function body (indicated by <code>&#123;&#125;</code>), we can now set attributes of</p><ul><li><p class="paragraph" style="text-align:left;"><code>document</code> (contains metadata),</p></li><li><p class="paragraph" style="text-align:left;"><code>text</code> (defines text properties of the document), and</p></li><li><p class="paragraph" style="text-align:left;"><code>page</code> (defines the properties of every page in the document).</p></li></ul><p class="paragraph" style="text-align:left;">Have a look at the code and see if you can make out what it does. I like to think that it’s somewhat manageable to piece together what it does. But don’t worry. I’ll explain afterwards anyway.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/24595bbc-469d-45cb-a28e-7bd19fa3d461/image.png?t=1743423549"/></div><p class="paragraph" style="text-align:left;">So here, we have used the <code>set</code> statement to specify properties of the <code>document</code>, <code>text</code> and <code>page</code> objects. There, we’ve set some of the objects attributes (like <code>title</code>, <code>font</code> or <code>paper</code>) to values that were</p><ul><li><p class="paragraph" style="text-align:left;">either hard-coded (like <code>&quot;Source Sans Pro&quot;</code> or the margins) or</p></li><li><p class="paragraph" style="text-align:left;">filled using arguments of the <code>#let()</code> function (like <code>author</code> or <code>paper</code>).</p></li></ul><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-a-page"><b>Add a page</b></h1><p class="paragraph" style="text-align:left;">So far so good. We’ve set a couple of things. But we haven’t added any content to the layout yet. Let’s change that.</p><p class="paragraph" style="text-align:left;">Let’s insert a page using the <code>page()</code> function. In there, we can make sure that everything is left-aligned and starts at the top of the page using <code>align()</code>. The syntax for that is</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/34a2ad1d-adee-42ef-bef6-2ef60b6993de/image.png?t=1743423567"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-content"><b>Add content</b></h1><p class="paragraph" style="text-align:left;">See that line that says “page content goes” here? That’s where we can place the content of the page. Here, let’s just try to use the <code>body</code> variable from the <code>article()</code> function to insert everything that is inside our Quarto document.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/832592e1-4558-4e08-90ad-fbb16e8baf7f/image.png?t=1743423585"/></div><p class="paragraph" style="text-align:left;">That should be a valid layout. Let’s try to render this. Here’s what we’ll get:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c64bd559-aa7b-4799-b526-2ae15589dc24/ksnip_20250331-131721.png?t=1743423884"/></div><p class="paragraph" style="text-align:left;">Oh no. That’s a bit dumb. Instead of understanding <code>body</code> as variable, Typst things that we actually want to use a literal text. But we have used other variables just like that before, haven’t we? What’s going on?</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="markdown-vs-evaluation-context"><b>Markdown vs evaluation context</b></h1><p class="paragraph" style="text-align:left;">You see, we are currently filling the <code>align()</code> function inside the <code>page()</code> function with content. This content is inside brackets <code>[]</code> where it is evaluated as Markdown. Not in any functional kind of way. And the magical signal for Typst to switch to an evaluated context is <code>#</code>.</p><p class="paragraph" style="text-align:left;">That’s also why the <code>let()</code> function to define the article layout started with <code>#</code>. Otherwise, Typst would think that our file is just filled with plain text and won’t evaluate anything. And the same has do be done now that we are inside a Markdown content block inside the brackets of <code>align()</code>. So, let’s try this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/6ca9b5b2-7b2f-4368-8e11-3c3d61d4a08c/image.png?t=1743423620"/></div><p class="paragraph" style="text-align:left;">Ahh much better. There’s all of our content. And notice how everything fits on one page now.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e24e7ba0-4459-4bb8-af4c-a325e94f25cb/ksnip_20250331-131722.png?t=1743423894"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-our-parameters"><b>Add our parameters</b></h1><p class="paragraph" style="text-align:left;">Similarly, we can add our parameters using the <code>text()</code> function. The syntax is the same as with <code>align()</code>:</p><ul><li><p class="paragraph" style="text-align:left;">First, we fill <code>text()</code> with arguments like <code>text(size:1.6em)</code>.</p></li><li><p class="paragraph" style="text-align:left;">Then, we create actual content inside the <code>brackets</code> like `text(size: 1.6em)[content].</p></li><li><p class="paragraph" style="text-align:left;">And finally we have to use <code>#</code> inside the Markdown content blocks to use functions and variables.</p></li></ul><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/1d3dfabb-7b4f-48c3-9e7a-80b57ec41fca/image.png?t=1743423635"/></div><p class="paragraph" style="text-align:left;">This will give us this terrible look.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/0d545e15-ba20-4635-8221-657923031af2/image.png?t=1743423942"/></div><p class="paragraph" style="text-align:left;">Let’s add some vertical space with the <code>v()</code> function.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/24973ee3-d95d-4fa5-b16f-abfab43e2fc7/image.png?t=1743447147"/></div><p class="paragraph" style="text-align:left;">And then we have way more space:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/97e940fb-d637-4db4-9b23-5cf695b96e6c/image.png?t=1743423970"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">Ahh much better. Let that sink in for now. Next week, I’m showing you how to add colors to our designs.</p><p class="paragraph" style="text-align:left;">And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-creating-beautiful-pdf-reports-with-typst-and-quarto" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=1ebcc84d-0309-46c4-b83f-c638a9eccdaf&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Scalable Reporting with Quarto)</title>
  <description>I show you how generate lots of PDFs via Quarto by using parameterized reports that iterate through lots and lots of placeholders and modify the PDF accordingly</description>
  <link>https://3mw.albert-rapp.de/p/scalable-reporting-with-quarto</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/scalable-reporting-with-quarto</guid>
  <pubDate>Wed, 23 Apr 2025 18:46:00 +0000</pubDate>
  <atom:published>2025-04-23T18:46:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. <b>Parameterized reports</b> are a powerful but often underutilized strategy for communicating data to multiple stakeholders.</p><p class="paragraph" style="text-align:left;">Let’s say you have several departments in your organization. A common instinct is to build a dashboard where users can click around to see the data for their department.</p><p class="paragraph" style="text-align:left;">But what if, instead, you could <b>automatically generate one customized report per department</b> and send those out directly? In today’s newsletter, I’ll show you how to do just that using <b>Quarto</b>.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="create-a-basic-report-template"><b>Create a Basic Report Template</b></h1><p class="paragraph" style="text-align:left;">First, we need a sample report. We’ll use the <code>palmerpenguins</code> dataset to simulate a situation where each penguin species represents a department.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/1cf473b9-12d4-4257-848e-1fbf3a01ec8e/image.png?t=1743423074"/></div><p class="paragraph" style="text-align:left;"></p><p class="paragraph" style="text-align:left;">This will give us a PDF output like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/527e4926-fbaf-4ae4-b81b-a5dfe9830ced/image.png?t=1743446666"/></div><hr class="content_break"><h2 class="heading" style="text-align:left;" id="add-parameters-to-the-yaml-header"><b>Add Parameters to the YAML Header</b></h2><p class="paragraph" style="text-align:left;">Here, we’ve used the <code>&quot;Adelie&quot;</code> species to act a placeholder. Next, we have to make sure that we can easily replace the species in all instances of the text and code. To do that, we define a <code>params</code> section in the YAML header:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b657efe9-d884-40bc-b8e4-99e70f54a0ee/image.png?t=1743423105"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">Now, wherever we want to reference </span><code>species</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;"> in the document, we use </span><code>params$species</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">. This allows the content of the report to adapt to whatever value we plug into the parameter. It works in code chunks:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/041e7173-f27f-4467-88e6-e0acba3f7c63/image.png?t=1743423117"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">And it works in inline text as well:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/06b3ef71-f14d-4faf-8b6c-7bc9bb35d36b/image.png?t=1743423127"/></div><p class="paragraph" style="text-align:left;">Now we can try to change <code>&quot;Adelie&quot;</code> to <code>&quot;Gentoo&quot;</code> and re-render the report. You’ll see the whole report adjusts accordingly (most notably seen by the plot change.)</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e298df22-f84a-4768-8372-78afc5f78bb8/image.png?t=1743446578"/></div><hr class="content_break"><h2 class="heading" style="text-align:left;" id="automate-rendering-for-multiple-par"><b>Automate Rendering for Multiple Parameters</b></h2><p class="paragraph" style="text-align:left;">Now the real power kicks in. We want to render <b>one report per species</b>, or in your real-world scenario, <b>one report per department</b>. To do that, we have to create a separate R script that uses the <code>quarto_render()</code> function from the <code>&#123;quarto&#125;</code> package:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/dec7d556-27f0-481e-8ccd-3e896bb26ef9/image.png?t=1743423149"/></div><p class="paragraph" style="text-align:left;">This script loops over all species and renders a separate PDF report for each one.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/02892e85-dff7-44b7-9176-72bf45229a10/ksnip_20250331-131720.png?t=1743423182"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">With just a few lines of configuration and code, you now have a scalable way to generate <b>customized PDF reports for any number of stakeholders or categories</b>. Whether you’re reporting by department, product line, region, or team, <b>parameterized Quarto documents</b> make it simple and powerful. </p><p class="paragraph" style="text-align:left;">Next week, we’re going to make that report prettier using the Typst-PDF format. And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-scalable-reporting-with-quarto" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=27e79a2a-9c5d-4151-8aa3-ce13f5148055&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Brand.yml: One Theme to Style Them All ✨)</title>
  <description>How to use the brand.yml styling mechanism. It works for Quarto documents as well as R-Shiny &amp; Py-Shiny apps. Fantastic for keeping a consistent style.</description>
  <link>https://3mw.albert-rapp.de/p/brand-yml-one-theme-to-style-them-all</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/brand-yml-one-theme-to-style-them-all</guid>
  <pubDate>Wed, 16 Apr 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-04-16T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Have you heard about <code>brand.yml</code>? It’s one of Posit’s newest and most exciting additions to their product lineup. With <code>brand.yml</code>, you can define a <b>unified theme</b> that works seamlessly across</p><ul><li><p class="paragraph" style="text-align:left;">Quarto documents,</p></li><li><p class="paragraph" style="text-align:left;">Shiny for R apps, and</p></li><li><p class="paragraph" style="text-align:left;">Shiny for Python apps.</p></li></ul><p class="paragraph" style="text-align:left;">In today’s newsletter, I’ll walk you through what <code>brand.yml</code> is and how to use it to bring consistent styling to all your projects.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="whats-the-idea"><b>What’s the idea?</b></h1><p class="paragraph" style="text-align:left;">The idea behind <code>brand.yml</code> is simple but powerful:</p><ol start="1"><li><p class="paragraph" style="text-align:left;">You define your <b>primary color</b>, <b>secondary color</b>, <b>fonts</b>, <b>logo</b>, and other branding settings in a single <code>brand.yml</code> file.</p></li><li><p class="paragraph" style="text-align:left;">You can then reuse that same configuration across all your data products. No need to redefine styles in each individual project.</p></li></ol><p class="paragraph" style="text-align:left;">This makes it easier to</p><ul><li><p class="paragraph" style="text-align:left;">maintain consistent branding,</p></li><li><p class="paragraph" style="text-align:left;">reuse themes across projects, and</p></li><li><p class="paragraph" style="text-align:left;">share themes across teams.</p></li></ul><hr class="content_break"><h1 class="heading" style="text-align:left;" id="how-does-this-work"><b>How does this work?</b></h1><p class="paragraph" style="text-align:left;">You’re probably now wondering: What does a <code>brand.yml</code> file actually look like? Well, let me show you. It’s just a plain text YAML file. Here’s an example from <a class="link" href="https://posit-dev.github.io/brand-yml/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">the official docs</a>:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/709079cb-52bb-4d90-a641-f07a3c4d31e1/image.png?t=1743422732"/></div><p class="paragraph" style="text-align:left;">As you can see, it looks pretty simple. But this simple file becomes the central definition of your app or document’s look and feel.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="how-to-use-brandyml"><b>How to Use </b><code>brand.yml</code><b>?</b></h1><p class="paragraph" style="text-align:left;">The way you use this file depends on your toolchain. Here’s a breakdown for each use case:</p><h3 class="heading" style="text-align:left;" id="in-quarto">📄<b> In Quarto</b></h3><p class="paragraph" style="text-align:left;">First, you need to save the branding content into a file called <code>_brand.yml</code>. And to apply the brand in a Quarto document you just have to add the <code>brand</code> attribute to the YAML header and fill it with the path to your yml-file. This could look something like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/194cee5f-00fb-4fa9-b42e-4bbf0c58ead9/image.png?t=1743422777"/></div><p class="paragraph" style="text-align:left;">It doesn’t get any easier than that. And if you want to use the specified branding options (e.g. colors) in a particular setting (like Typst PDFs), then you can check out the dedicated <span style="text-decoration:underline;"><a class="link" href="https://quarto.org/docs/authoring/brand.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all#overview" target="_blank" rel="noopener noreferrer nofollow" style="color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1))">Quarto documentation</a></span> on that.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="in-shiny-for-r"><b>💻 In Shiny for R</b></h3><p class="paragraph" style="text-align:left;">In Shiny for R, <code>brand.yml</code> is integrated via the fantastic <code>&#123;bslib&#125;</code> package.<br>You can use it in your UI definition like so:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9cb6f7cc-76f0-4570-a5bc-4676dd020f01/image.png?t=1743422799"/></div><hr class="content_break"><h3 class="heading" style="text-align:left;" id="in-shiny-for-python">🐍<b> In Shiny for Python</b></h3><p class="paragraph" style="text-align:left;">You’ll need the latest version of <b>Py-Shiny</b> installed with the <code>theme</code> extra.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/77aeabcc-ff5a-4019-9645-2cabeff24e82/image.png?t=1743422813"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">Once you’ve got that, you can use </span><code>brand.yml</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;"> like this:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/801a9151-28cd-4548-8bf5-2bb2c9e9b15e/image.png?t=1743422820"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">And if you’re using </span><b>Py-Shiny Express</b><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">, the usage is slightly different. There, you’ll have to configure the </span><code>page_options</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;"> argument in the UI object.</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/55cae1e3-e57c-46e6-a12e-d1779586b714/image.png?t=1743422864"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">I think <code>brand.yml</code> is a fantastic idea. It simplifies theming, supports consistency, and works beautifully across multiple frameworks. If you’re building out a data product pipeline that includes reports and interactive apps, this tool will save you time and help keep everything looking polished and on-brand.</p><p class="paragraph" style="text-align:left;">Let me know what you think about <code>brand.yml</code>. And as always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-brand-yml-one-theme-to-style-them-all" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=887f3bae-bbf0-40a1-8684-3b24badff938&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Using the new Positron IDE)</title>
  <description>I show you how I&#39;ve set up the new Positron IDE for data science workflows with R and Python. Additionally, I share settings that work for me.</description>
  <link>https://3mw.albert-rapp.de/p/using-the-new-positron-ide</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/using-the-new-positron-ide</guid>
  <pubDate>Wed, 09 Apr 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-04-09T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Recently, I’ve been playing around with the new <b>Positron</b> IDE, and I must say: I really enjoy it. It still has some small bugs but overall it’s great. More importantly, it’s packed with features tailored for data science workflows.</p><p class="paragraph" style="text-align:left;">In this week’s newsletter, I want to share my favorite features, settings, and shortcuts in Positron. That way, you can get a sense of why it might be a better fit than VSCode for your R or Python work.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="fixed-console-for-r-and-python"><b>Fixed Console for R and Python</b></h1><p class="paragraph" style="text-align:left;">One of the standout features in Positron is the <b>fixed console</b> for R and Python that never goes away. Unlike VSCode, there’s always a R or Python console that you can use for quick iterations. Also, you can easily switch between languages and even between different versions of R and Python. </p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3a1dcc1b-489b-4a9a-8adb-6436fe38c1f6/image.png?t=1743422041"/></div><p class="paragraph" style="text-align:left;">And regardless of what you use, there’s a dedicated console that always receives your commands when you press <b>Ctrl + Enter</b> in the editor. This makes it far more reliable than what I experienced with VS Code, where the console sometimes wouldn’t respond or would detach from the current session. </p><p class="paragraph" style="text-align:left;">And to make it perfectly clear, just for this feature alone, I’d already recommend Positron over VS Code.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="integrated-help-pane-f-1-to-view-fu"><b>Integrated Help Pane (F1 to View Function Docs)</b></h1><p class="paragraph" style="text-align:left;">Just like in RStudio, Positron lets you press <b>F1</b> on any function in your script to open the Help page.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c7e39601-ce95-44ec-b78d-276cfa9bf5d0/image.png?t=1743422180"/></div><p class="paragraph" style="text-align:left;">No more switching to a browser or dealing with limited pop-ups like in VS Code. This feature is built-in and persistent. It’s especially handy when you have to refer to arguments or function references on the fly.</p><p class="paragraph" style="text-align:left;">The only issue that I have is that the formatting in the help windows isn’t always great. In particular, if you increase your editor font size. In that case, you will have a large code font and regular text font inside the help panel.</p><p class="paragraph" style="text-align:left;">That’s not particularly great but I hope the kind people behind Positron <a class="link" href="https://github.com/posit-dev/positron/issues/7039?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide#issuecomment-2761614670" target="_blank" rel="noopener noreferrer nofollow">are already on it</a>. For now a workaround is to increase the window size instead if you want to have larger fonts.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="sideby-side-layout-just-like-r-stud"><b>Side-by-Side Layout (Just Like RStudio)</b></h1><p class="paragraph" style="text-align:left;">I love Positron’s layout customization. When you download the newest version, there’s a button in the top-right corner to switch layouts. </p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/53cc2de0-d808-4283-918a-1a17a21de95f/image.png?t=1743422262"/></div><p class="paragraph" style="text-align:left;">I always go with the <b>side-by-side layout</b>, similar to what I used in RStudio:</p><ul><li><p class="paragraph" style="text-align:left;">Left: Script or Quarto file </p></li><li><p class="paragraph" style="text-align:left;">Right: Console, plots, and environment</p></li></ul><p class="paragraph" style="text-align:left;">This makes transitioning from my previous RStudio setup feel completely natural.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="zen-mode-for-maximum-focus"><b>Zen Mode for Maximum Focus</b></h1><p class="paragraph" style="text-align:left;">Positron has a fantastic <b>Zen mode</b> that lets you minimize distractions and maximize space. That way, only the essential UI things are maximized. Here’s how it looks as I’m writing this newsletter.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a9d500ed-9bd9-4931-9b52-ea31f6679734/ksnip_20250331-131716.png?t=1743422325"/></div><p class="paragraph" style="text-align:left;">Depending on what I need at the moment, I can toggle between:</p><ul><li><p class="paragraph" style="text-align:left;">Code only</p></li><li><p class="paragraph" style="text-align:left;">Code + Console</p></li><li><p class="paragraph" style="text-align:left;">Code + Console + File Explorer</p></li></ul><hr class="content_break"><h1 class="heading" style="text-align:left;" id="familiar-shortcuts-from-r-studio"><b>Familiar Shortcuts from RStudio</b></h1><p class="paragraph" style="text-align:left;">Positron supports many of your favorite RStudio shortcuts:</p><ul><li><p class="paragraph" style="text-align:left;"><b>Ctrl + Shift + M</b> → Insert pipe (<code>|&gt;</code>)</p></li><li><p class="paragraph" style="text-align:left;"><b>Ctrl + Shift + K</b> → Render Quarto document</p></li></ul><p class="paragraph" style="text-align:left;">I’ve also customized a few additional shortcuts to toggle the sidebars for Zen mode (like I’ve just described). Or to jump between console and editor.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/99a84fc6-af5d-4023-968f-73cf6f9c550a/image.png?t=1743421850"/></div><p class="paragraph" style="text-align:left;">And in case this feels intimidating, there’s also a UI that you can use to tweak these things. It’s just easier to share the settings with you this way.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="use-the-command-palette-ctrl-shift-"><b>Use the Command Palette (Ctrl + Shift + P)</b></h1><p class="paragraph" style="text-align:left;">The <b>Command Palette</b> is your best friend in Positron. Press <b>Ctrl + Shift + P</b> to access any command or setting.</p><p class="paragraph" style="text-align:left;">Want to enter Zen Mode? Type “Zen” and the relevant action will pop up. You’ll also see the keyboard shortcut for it, helping you memorize it over time</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a4f2575b-3365-4b17-bbe8-5af939e1a5d9/image.png?t=1743422405"/></div><p class="paragraph" style="text-align:left;"><b>Pro tip: </b>If you delete the arrow <code>&gt;</code> that shows up in the palette, it becomes a fuzzy finder for files and objects in your workspace.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/73a3a653-f88a-4251-a0d0-93ff54131cdb/image.png?t=1743422435"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="projects-nope-directories-instead"><b>Projects? Nope. Directories Instead.</b></h1><p class="paragraph" style="text-align:left;">Positron doesn’t use “projects” the way RStudio does. Instead, it uses <b>directories</b>. If you had an RStudio project before, just open the directory in Positron using: <code>Ctrl + K</code> followed by <code>Ctrl + O</code> </p><p class="paragraph" style="text-align:left;">That directory becomes your workspace root. And everything inside it is visible in the file explorer. Pretty much like RStudio projects.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="customize-everything-with-settingsj"><b>Customize Everything with </b><code>settings.json</code></h1><p class="paragraph" style="text-align:left;">Like VSCode, Positron is fully customizable via the <code>settings.json</code> file. Open it via the Command Palette and throw in any setting you want. Here are some of my favorites:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/781a2895-d986-42ee-83ac-d25ab472ce7e/image.png?t=1743421827"/></div><p class="paragraph" style="text-align:left;">And just like with the <code>keybindings.json</code>, there’s also a UI that you can use.</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Positron is a joy to use. It brings the best of VSCode’s extensibility and combines it with RStudio’s comfort, especially for data scientists. Let me know if you’re using it already and what your favorite tweaks are. I’d love to hear what’s working for you!</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-the-new-positron-ide" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=8cf44829-75e4-4bac-b0c2-abd3eac1f375&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Automatic Time Series Collection With {pins} &amp; GH Actions)</title>
  <description>I show you how to use GitHub Actions and the {pins} R package to easily collect time series and store that in an AWS S3 bucket.</description>
  <link>https://3mw.albert-rapp.de/p/automatic-time-series-collection-with-pins-gh-actions</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/automatic-time-series-collection-with-pins-gh-actions</guid>
  <pubDate>Wed, 02 Apr 2025 17:00:00 +0000</pubDate>
  <atom:published>2025-04-02T17:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 10.0px 10.0px 10.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter, I want to show you how you can combine the <code>&#123;pins&#125;</code> package with GitHub Actions. That way, you can automate the process of downloading data from the internet and saving it as a time series. </p><p class="paragraph" style="text-align:left;">The workflow is pretty similar to one of our previous newsletter on GitHub Actions. So if you’ve read <a class="link" href="https://3mw.albert-rapp.de/p/automate-anything-with-r-github-actions?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">that newsletter</a>, then you should have no problem following along.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="a-repo-for-our-project"><b>A repo for our project</b></h1><p class="paragraph" style="text-align:left;">The first thing we need is a new project for our data extraction endeavor. But let’s not start completely from scratch. Let’s use our <a class="link" href="https://github.com/AlbertRapp/gh_actions_test/blob/2b7e278ff43b684a6d13a290b8692f0da16701a7/.github/workflows/main.yml?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">“gh_actions_test” repo</a>. It already has an <code>&#123;renv&#125;</code> environment for version control set up. That way, we don’t have to worry about that.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a9956ccb-81b9-4d23-8a86-64007135cbce/image.png?t=1743421435"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-pins-to-renv"><b>Add pins to </b><code>&#123;renv&#125;</code></h1><p class="paragraph" style="text-align:left;">Now we can add <code>&#123;pins&#125;</code> to our <code>&#123;renv&#125;</code> environment. Simply call the <code>install()</code> command.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/515b03e4-f9de-49f7-a43d-ed48a130ff65/image.png?t=1743421474"/></div><p class="paragraph" style="text-align:left;">Then, we can create a new R-Script <code>pins-demo.R</code> in which we’ll actually use <code>&#123;pins&#125;</code>. For now, this should only contain this code:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/24d4f4b6-6ba5-4185-bb2f-335a1fbf7e38/image.png?t=1743421487"/></div><p class="paragraph" style="text-align:left;">That way, <code>&#123;renv&#125;</code> lets us write the <code>&#123;pins&#125;</code> package to its lock file. If you recall, this is the thing we have to restore at the beginning of every GH workflow. Now make sure that</p><ul><li><p class="paragraph" style="text-align:left;">you can execute this code in your project, i.e. you have AWS credentials set,</p></li><li><p class="paragraph" style="text-align:left;">that you have your <code>.Rprofile</code> file removed from the git repo and added it to <code>.gitignore</code> (because you don’t want to share your keys),</p></li><li><p class="paragraph" style="text-align:left;">and that you saved the packages to the lock file via <code>renv::snapshot()</code>.</p></li></ul><p class="paragraph" style="text-align:left;">Alright, cool. So with that we need a new GH actions workflow file.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="base-git-hub-actions-workflow"><b>Base GitHub Actions Workflow</b></h1><p class="paragraph" style="text-align:left;">Let’s start out with <code>.yml</code> workflow file from our last GitHub Actions tutorial. That’s a good place to start I’d say.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/f24ea933-cca5-4f74-8551-4c6551bb6976/image.png?t=1743421301"/></div><p class="paragraph" style="text-align:left;">In this project, we don’t need anything from Quarto and we also don’t need to commit to Github, so we can remove those steps.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b53a4993-adc4-4603-aa31-db0616da866c/image.png?t=1743421347"/></div><p class="paragraph" style="text-align:left;">Unfortunately, R isn’t contained in the <code>ubuntu-latest</code> machine from GitHub anymore. That’s why we have to add R ourselves. But that’s super easy to do. We only have to use one of the R containers provided from the<a class="link" href="https://rocker-project.org/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow"> Rocker Project</a>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/af6f9810-5ccf-4f74-bd4f-fbdde48e8224/image.png?t=1743421506"/></div><p class="paragraph" style="text-align:left;">And with that we are once again ready to use R automations.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="extract-data"><b>Extract Data</b></h1><p class="paragraph" style="text-align:left;">Next, we need an R function that fetches data from an external source. This could be via</p><ul><li><p class="paragraph" style="text-align:left;">API calls,</p></li><li><p class="paragraph" style="text-align:left;">web scrapings, or</p></li><li><p class="paragraph" style="text-align:left;">any other data retrieval method.</p></li></ul><p class="paragraph" style="text-align:left;">To keep things simple, we’ll simulate it with a function that just returns a random value:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a910a5f8-65a2-4376-81dd-a13f8b505eec/image.png?t=1743421516"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="check-if-pin-is-available"><b>Check if pin is available</b></h1><p class="paragraph" style="text-align:left;">In the next step, we want to write this data to a pin that is stored in our board in S3. For that, we first need to check if our pin is even available. If not, we simply write to that pin without doing anything else.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c8dfa588-7377-4fba-b179-9c122904b4f2/image.png?t=1743421528"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="grab-previous-data"><b>Grab previous data</b></h1><p class="paragraph" style="text-align:left;">If the pin is already available, then we should</p><ul><li><p class="paragraph" style="text-align:left;">grab the already saved data,</p></li><li><p class="paragraph" style="text-align:left;">append our new data to it, and</p></li><li><p class="paragraph" style="text-align:left;">write that new complete data to the same pin.</p></li></ul><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/70fd150e-ce3f-4df0-bdeb-ce4fcee6e3db/image.png?t=1743421544"/></div><p class="paragraph" style="text-align:left;">And that’s it. <code>&#123;pins&#125;</code> will do all the data versioning for us. So overall, our <code>pins-demo.R</code> script is only a short little file like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7536683e-acb7-4f43-bb35-4d547ec82b2f/image.png?t=1743421556"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="modify-gh-workflow"><b>Modify GH workflow</b></h1><p class="paragraph" style="text-align:left;">Sweet. Now, we only have to tell our GH Actions workflow to run that script. The easiest way is to add another step after all dependencies are installed.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d51c06e2-dae5-4d80-88cc-88c999c4b720/image.png?t=1743421586"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-aws-credentials-to-git-hub-secr"><b>Add AWS Credentials to GitHub Secrets</b></h1><p class="paragraph" style="text-align:left;">But if you think about it, this cannot work yet. The machine that is supposed to execute this code, doesn’t know our GitHub credentials. If this script works on the GH action, then you should seriously check if you’ve accidentally pushed your <code>.Rprofile</code> file (which you should absolutely not do.)</p><p class="paragraph" style="text-align:left;">So that’s why we have to tell our step about the environment variables it needs.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/bf5a672e-5112-44ab-a4c4-1d8fc67de878/image.png?t=1743421601"/></div><p class="paragraph" style="text-align:left;">And then in your GitHub repository, go to <b>Settings &gt; Secrets and variables &gt; Actions</b>, and add:</p><ul><li><p class="paragraph" style="text-align:left;"><code>AWS_ACCESS_KEY_ID</code></p></li><li><p class="paragraph" style="text-align:left;"><code>AWS_SECRET_ACCESS_KEY</code></p></li><li><p class="paragraph" style="text-align:left;"><code>AWS_DEFAULT_REGION</code></p></li></ul><hr class="content_break"><p class="paragraph" style="text-align:left;">And that’s it! Now every time the flow runs, we will have added a new row to our dataset.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/5954e6a6-22a4-478c-b9e0-6c01951cdc80/image.png?t=1743421623"/></div><p class="paragraph" style="text-align:left;">You now have a working automation that pulls data from anywhere you like and stores it in cloud storage securely and automatically.</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-automatic-time-series-collection-with-pins-gh-actions" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=a61728ea-5a53-497f-b403-4e626d58ff45&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Storing {pins} on GitHub and AWS S3)</title>
  <description>Pins are a fantastic tool to keep track of data versions. Here, I show you how to leverage online storages like GitHub repos or AWS S3 to save these pins.</description>
  <link>https://3mw.albert-rapp.de/p/storing-pins-on-github-and-aws-s3</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/storing-pins-on-github-and-aws-s3</guid>
  <pubDate>Wed, 26 Mar 2025 18:00:00 +0000</pubDate>
  <atom:published>2025-03-26T18:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Source Sans 3','Source Sans Pro',Roboto,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'700' !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 15.0px 0.0px 15.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In this week’s newsletter, I’ll show you how to use the <code>&#123;pins&#125;</code> package to store your data on different online platforms. Basically, this is a follow-up to <a class="link" href="https://3mw.albert-rapp.de/p/using-pins-for-data-storage?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">last week’s newsletter</a>.</p><p class="paragraph" style="text-align:left;">And there are many places where you can store pins. Here, we’ll walk through two particuclar examples. Namely, GitHub and AWS S3. But before I show you how they work, let me show you my usual announcements.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="interactive-documents-full-app">Interactive Documents &gt; Full App</h1><p class="paragraph" style="text-align:left;">Ever found yourself building a Shiny app that contains mostly text with just a few interactive parts? That’s a bit of a nuisance to set up because you’re mostly trying to make your text look nice inside your app’s big blank canvas. </p><p class="paragraph" style="text-align:left;">Now here’s a better way.</p><p class="paragraph" style="text-align:left;">Just create a Quarto document! This will immediately use formatting that is proper for text-heavy documents. </p><p class="paragraph" style="text-align:left;">And the interactive part? </p><p class="paragraph" style="text-align:left;">Well, in Quarto you can add them via Shiny server code chunks. And in my newest YT video I show you how that works. Check it out:</p><iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true" class="youtube_embed" frameborder="0" height="100%" src="https://youtube.com/embed/06H8k1nzZQ0" width="100%"></iframe><hr class="content_break"><h1 class="heading" style="text-align:left;" id="using-git-hub-as-a-pin-board">Using GitHub as a Pin Board</h1><p class="paragraph" style="text-align:left;">Let’s assume you have a public GitHub repository with pins stored in it. You can connect to it using the <code>board_url()</code> function. Here’s an example of that using pins from the public <code>&#123;pins&#125;</code> repo.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/93d05027-06b0-40db-841e-4541ff5deec2/grafik.png?t=1742837553"/></div><p class="paragraph" style="text-align:left;">Once you’ve created the board, you can read pins from it using the <code>pin_read()</code> function:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/6efe4a17-7756-4766-81bd-943efc7c6067/grafik.png?t=1742837570"/></div><p class="paragraph" style="text-align:left;">But this only works with pins that contain actual R data sets. For example the <code>raw</code> pin contains a <code>.txt</code> file. That’s why it can’t be opened in the R console.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7b2bb862-1774-406f-8966-863d8e971ed5/grafik.png?t=1742837589"/></div><p class="paragraph" style="text-align:left;">Instead, you have to download the file.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/fd081082-7410-47af-be2a-412754eeb45d/grafik.png?t=1742837603"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="using-git-hub-with-private-repos">Using GitHub with Private Repos</h1><p class="paragraph" style="text-align:left;">What if you want to use a <b>private</b> repository instead?</p><p class="paragraph" style="text-align:left;">In that case, you’ll need to include your <b>GitHub Personal Access Token</b> in the request. You do this by first creating a named vector with your token as the authorization header.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c6cfb06e-547f-497b-ad24-7dd283a786cb/grafik.png?t=1742837619"/></div><p class="paragraph" style="text-align:left;">And then you could pass it to the <code>headers</code> argument of <code>board_url()</code>. Here, I’ve just taken the example from the <code>&#123;pins&#125;</code><a class="link" href="https://pins.rstudio.com/reference/board_url.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3#authentication-for-board-url-" target="_blank" rel="noopener noreferrer nofollow"> docs</a>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/09872fb5-4775-4783-924b-e575e1e04ae6/grafik.png?t=1742837631"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="limitations-of-pins-with-git-hub">Limitations of Pins with GitHub</h1><p class="paragraph" style="text-align:left;">Note that using pins like that only allows reading from GitHub. It doesn’t let you modify the data. If you want to change pins from a GitHub repo, you’d have to:</p><ol start="1"><li><p class="paragraph" style="text-align:left;">Clone the repository</p></li><li><p class="paragraph" style="text-align:left;">Modify the pins locally</p></li><li><p class="paragraph" style="text-align:left;">Push the changes back to GitHub</p></li></ol><p class="paragraph" style="text-align:left;">This isn’t the most convenient workflow. That’s why I prefer other options like AWS S3.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="using-aws-s-3-as-a-pin-board">Using AWS S3 as a Pin Board</h1><p class="paragraph" style="text-align:left;">For a smoother experience, AWS S3 is a great option.<br>To use it, you need an existing <b>S3 bucket</b> to store your pins. If you don’t have one yet, check out the tutorial <a class="link" href="https://3mw.albert-rapp.de/p/save-data-at-aws-s3-with-paws?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">I wrote a few weeks back</a> on how to create an S3 bucket.</p><p class="paragraph" style="text-align:left;">Once you have your bucket and region ready, you can connect using the <code>board_s3()</code> function:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/94450fa6-76b3-416c-8864-746ea4628960/grafik.png?t=1742837654"/></div><p class="paragraph" style="text-align:left;">If you encounter an “Access Denied” error, it’s likely because your <b>AWS credentials</b> are not set up correctly. You need to have the following environment variables configured:</p><ul><li><p class="paragraph" style="text-align:left;"><code>AWS_ACCESS_KEY_ID</code></p></li><li><p class="paragraph" style="text-align:left;"><code>AWS_SECRET_ACCESS_KEY</code></p></li></ul><p class="paragraph" style="text-align:left;">You can set these in your <code>.Renviron</code> file or in your R session.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="writing-pins-to-aws-s-3">Writing Pins to AWS S3</h1><p class="paragraph" style="text-align:left;">Once your S3 board is set up and authenticated, you can read and write pins just like with a local board.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/43e59f89-f915-46c8-a2d7-2292f6753822/grafik.png?t=1742837671"/></div><p class="paragraph" style="text-align:left;">The key benefit here is that you don’t need to manually download or push data. <code>&#123;pins&#125;</code> handles it all automatically. In fact, if you take a look at your S3 bucket now, you’ll see that the data is already there.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e7c024b6-7b83-4382-9bf0-e6c28c03a9a4/grafik.png?t=1742837758"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">With that, you have two solid ways to store your pins online. Next week, I’ll show you how to set up an automation on GitHub Actions that automatically collects time series data and stores it using the <code>&#123;pins&#125;</code> package.</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p><p class="embed__link"> data-cleaning.albert-rapp.de </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p><p class="embed__link"> arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p><p class="embed__link"> rfortherestofus.com/courses/tables </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-storing-pins-on-github-and-aws-s3" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=cc496388-f119-4b1c-a189-3d90a42ebc28&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Using {pins} for data storage)</title>
  <description>The {pins} package is a fantastic tool that makes data versioning super simple. In this post, I show you how its versioning mechanism works.</description>
  <link>https://3mw.albert-rapp.de/p/using-pins-for-data-storage</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/using-pins-for-data-storage</guid>
  <pubDate>Wed, 19 Mar 2025 18:00:00 +0000</pubDate>
  <atom:published>2025-03-19T18:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 15.0px 0.0px 15.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter, we are talking about the <code>&#123;pins&#125;</code> package. This package is not very well known in the R sphere, but it is a fantastic tool for keeping track of different data versions.</p><p class="paragraph" style="text-align:left;">Basically, <code>&#123;pins&#125;</code> makes storing data and versioning dead-simple. You can think of it as Git for your data. But before we dive in, I have a short thing to ask you: ‘</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="whats-next">What‘s next?</h1><p class="paragraph" style="text-align:left;">Recently, I find myself covering more and more technical aspects of data science that are not necessarily R focused. This includes:</p><ul><li><p class="paragraph" style="text-align:left;">Building automations with GitHub Actions</p></li><li><p class="paragraph" style="text-align:left;">Setting up infrastructure on AWS or Azure</p></li><li><p class="paragraph" style="text-align:left;">Using JavaScript to handle AI responses in Shiny apps</p></li></ul><p class="paragraph" style="text-align:left;">I do this because I think data science doesn’t happen in any single tool or language. Thus, I want to continue writing in as broad a scope as I feel like at the moment (after all I get to do whatever I want on this newsletter 🤪) </p><p class="paragraph" style="text-align:left;">But I do want to see if I can make this as valuable for you as possible. So let me know what you’re interested in by filling out this small poll. </p><p class="paragraph" style="text-align:left;">Just click on your favorite choice and it will be recorded. After that, you’ll also have the chance to leave additional comments in case you want to suggest something I haven’t thought of.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="why-use-the-pins-package"><b>Why use the </b><code>&#123;pins&#125;</code><b> package?</b></h1><p class="paragraph" style="text-align:left;">Now, before I show you how <code>&#123;pins&#125;</code> works, let’s talk about why you should even use it</p><ul><li><p class="paragraph" style="text-align:left;"><b>Version control</b>: Prevents accidental overwriting of important datasets when re-running workflows.</p></li><li><p class="paragraph" style="text-align:left;"><b>Efficient workflows</b>: You can run a calculation or an API call once and store the data permanently in a <b>pin</b>.</p></li><li><p class="paragraph" style="text-align:left;"><b>Metadata storage</b>: <code>&#123;pins&#125;</code> keeps detailed information about your data so you can easily restore or revert to previous versions.</p></li><li><p class="paragraph" style="text-align:left;"><b>Seamless integration</b> : You can store data anywhere you like. GitHub, Google Drive, AWS S3, you name it. <code>&#123;pins&#125;</code> will work exactly the same.</p></li></ul><p class="paragraph" style="text-align:left;"><a class="link" href="https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExaGpzYnRxajVxaWg4eTF0MHVjY3ZmaGd5Njl6MXpzeTIzZWZieG9ueCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3oEjHLzm4BCF8zfPy0/giphy.gif?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">Surely</a>, you’re wondering how all of that is supposed to work. So let’s dive into the technical details.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="set-up-pins"><b>Set up </b><code>&#123;pins&#125;</code></h1><p class="paragraph" style="text-align:left;">First, you need to install the package. As always, you can do this with:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d80cb277-f995-4a8d-b72a-04360bb2e5c7/image.png?t=1742403244"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="set-up-a-board"><b>Set up a board</b></h1><p class="paragraph" style="text-align:left;">To store data, you need to place <b>“pins”</b> in a <b>“board”</b>. If you want to try <code>&#123;pins&#125;</code> locally first, create a board using:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a27db50c-f940-4148-9b5e-f63d4467ab20/image.png?t=1742403253"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="write-data-to-a-pin"><b>Write data to a pin</b></h1><p class="paragraph" style="text-align:left;">To write data to your board, simply use:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b7954fb9-e1b6-48eb-9788-8d3185dc95b5/image.png?t=1742403275"/></div><p class="paragraph" style="text-align:left;">This creates a new pin, and the best part is that previous data versions aren’t deleted.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="retrieving-a-specific-version"><b>Retrieving a specific version</b></h1><p class="paragraph" style="text-align:left;">To check how many data versions exist in your board, use:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/4656ec2b-4d68-416a-96e0-a33a32369ec6/image.png?t=1742403294"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">That’s currently pretty boring. So let’s modify our data and overwrite our pin multiple times.</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a3a8eab5-28c9-412b-ab4f-379bdac218be/image.png?t=1742403308"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">Now, check out the different versions:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7536471a-76ce-416a-90a8-ab57a406a170/image.png?t=1742403318"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">Once you decide which version you want to load, retrieve it using:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/5b655f16-3d38-4143-bee3-b7bf8b4967b8/image.png?t=1742403331"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">As you can see, setting up <code>&#123;pins&#125;</code> is simple and efficient for storing and retrieving data. And the best thing is that you cannot accidentally overwrite data. Next week, I’ll show you how to set up cloud storages for your pins.</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-using-pins-for-data-storage" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=a130d6f6-6360-4008-a699-bcb0791df4c5&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (User-Specific Authentication for Quarto Projects on Azure Static Web Apps)</title>
  <description>I show you how to add user-specific authentication for your Quarto project with Azure Static Web Apps and Azure Active Directory B2C.</description>
  <link>https://3mw.albert-rapp.de/p/user-specific-authentication-for-quarto-projects-on-azure-static-web-apps</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/user-specific-authentication-for-quarto-projects-on-azure-static-web-apps</guid>
  <pubDate>Wed, 12 Mar 2025 18:00:00 +0000</pubDate>
  <atom:published>2025-03-12T18:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 15.0px 0.0px 15.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter we change the authentication for our Quarto project so that we can decide which users get to access our content. This will be similar to out GitHub authentication from last week.</p><p class="paragraph" style="text-align:left;">But this time, we can restrict access to only a few selected persons (if we want that). And to do so, we’re going to use another service from Azure called “Azure Active Directory B2C”.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="create-a-new-tenant">Create a new tenant</h1><p class="paragraph" style="text-align:left;">The first thing that you have to do is to create a new tenant for Azure AD B2C. To do so, you create a new resource.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b9119a21-1f6e-4a35-a4ff-ca8fc72d1e4a/image.png?t=1741602926"/></div><p class="paragraph" style="text-align:left;">And then, you select Azure AD B2C:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/5e1d1e34-34e3-46f6-8555-f31b4c0c92ab/image.png?t=1741602963"/></div><p class="paragraph" style="text-align:left;">There you will have to specify the org name and domain name of your tenant. Just choose what you like (as long as Azure accepts the name.)</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9f3f6474-f444-4478-a8a6-85119bcfb8a2/00_create_aadb2c.png?t=1741602134"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="switch-tenant"><b>Switch tenant</b></h1><p class="paragraph" style="text-align:left;">Once you’ve created the tenant, you can switch to it via the settings icon at the top of the Azure portal.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9b54e5e5-8ec3-4a3e-bd8b-f090d04deb80/01_tenant_switch.png?t=1741602142"/></div><p class="paragraph" style="text-align:left;">Just remember that your Azure Static Web App now lives in a separate tenant. That’s why you’ll have to switch between tenants when you modify the app settings.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="register-an-application"><b>Register an application</b></h1><p class="paragraph" style="text-align:left;">In our new tenant, we can access the Azure AD B2C resource. There, we first have to register an application. This is like registering the OAuth app that we created last week on GitHub.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/122e1999-0ade-4fd3-883d-077766b53fca/02_register_app.png?t=1741602151"/></div><p class="paragraph" style="text-align:left;">In the settings of that registration, you will have to enable all accounts to be allowed to “authenticate via user flows”. Also, make sure that the redirect URI of that application points to our app.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e1fe4e4e-466b-4af4-b270-2f6ecab0b37c/03_registration_details.png?t=1741602189"/></div><p class="paragraph" style="text-align:left;"><b>Watch out:</b> The redirect URI now doesn’t contain <code>.auth/login/github</code> but instead contains <code>.auth/login/aadb2c</code>.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="client-id-secret"><b>Client ID & Secret</b></h1><p class="paragraph" style="text-align:left;">Now that we have an OAuth app, we need to get client ID and client secret. This is exactly like what we did last week. The client ID is immediately displayed in the app page and the secret can be generated via the “Certificates & secrets” page.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/51e97035-dccb-4c52-bc68-75dc3bec7b4a/04_client_id.png?t=1741602208"/></div><p class="paragraph" style="text-align:left;">There, you can generate a new secret.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/ba170a1f-0d2b-48fd-9fbf-e816accdcf27/05_new_secret.png?t=1741602215"/></div><p class="paragraph" style="text-align:left;">Just make sure that you copy the secret as soon as you’ve created it. Otherwise, it will be lost as the secret will only be displayed once.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/223e0171-395d-4580-a594-abf37d2e20d0/06_client_secret.png?t=1741602223"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="create-a-new-user-flow"><b>Create a new user flow</b></h1><p class="paragraph" style="text-align:left;">Remember how we had to enable “user flows”? You can think of this as the procedures that a user might want to go through. Common procedures are “sign in”, “sign up”, “reset password” or “edit profile”.</p><p class="paragraph" style="text-align:left;">And that’s also what we need to set up inside of our AD B2C resource. We can do so via the “Policies” page.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/5d66b178-1ca3-4b8d-8ee3-796cbf53198f/08_new_user_flows.png?t=1741602238"/></div><p class="paragraph" style="text-align:left;">There, we can create a new sign in flow so that users can sign in.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/1a49a2bf-ca18-491e-8b4f-16d9ee36880f/09_signin_flow.png?t=1741602245"/></div><p class="paragraph" style="text-align:left;">The rest is pretty straightforward: Pick a name and choose sign up methods.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7b5743b6-9553-4751-9bea-a27b4d4bf6f7/10a_user_flow.png?t=1741602253"/></div><p class="paragraph" style="text-align:left;">If you want, you can also turn off multi-factor authentication and determine what information are transmitted when a user signs in.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a63fdb7b-0479-4c0f-873a-22c9d9988ee1/10b_user_flow.png?t=1741602262"/></div><p class="paragraph" style="text-align:left;">Once you’re finished, you can see a new user flow in your Policies page. Notice that the name of the policy also includes “B2C_1_”. This little detail will become important in a sec.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/1ff0bbff-5687-4021-82a7-efd3429c9da4/11_policy_name.png?t=1741602300"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="modify-config-file"><b>Modify config file</b></h1><p class="paragraph" style="text-align:left;">Now that we have everything set up, we can change the auth settings of our web app. Once again, this only requires modifying the <code>staticwebapp.config.json</code> file. Luckily for us, the <span style="text-decoration:underline;"><a class="link" href="https://learn.microsoft.com/en-us/azure/active-directory-b2c/configure-authentication-in-azure-static-app?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps#31-add-an-openid-connect-identity-provider" target="_blank" rel="noopener noreferrer nofollow" style="color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1))">Azure docs</a></span> also have the perfect auth code snippet for us:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/16c31560-d8bc-488d-84b6-996bad2ed7d4/ksnip_20250310-113058.png?t=1741602700"/></div><p class="paragraph" style="text-align:left;">Here, we need to replace</p><ul><li><p class="paragraph" style="text-align:left;"><code>&lt;TENANT_NAME&gt;</code> with the domain name of our tenant, and</p></li><li><p class="paragraph" style="text-align:left;"><code>&lt;POLICY_NAME&gt;</code> with the user flow name that we have created earlier. Remember to use the name that includes “B2C_1_”.</p></li></ul><p class="paragraph" style="text-align:left;">Also, we can modify the requested scopes a bit. All in all, this should look something like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/543c3f58-65b4-4ac5-9285-ce90dd823c23/ksnip_20250310-113113.png?t=1741602709"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">Finally, you should make sure that your redirect now moves users to </span><code>.auth/login/aadb2c</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">. Overall, the config file should look like this.</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/8ebcad64-34ba-4cab-9632-6f94e23c8f89/ksnip_20250310-113125.png?t=1741602718"/></div><p class="paragraph" style="text-align:left;">Once you’ve made these changes, make sure to rebuild your Quarto project and push the changes to our GH repo.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="set-environment-variables"><b>Set environment variables</b></h1><p class="paragraph" style="text-align:left;">Finally, the remaining thing that we have to do is set up environment variables inside of our app. You see, inside the auth snippet we now use <code>AADB2C_PROVIDER_CLIENT_ID</code> and <code>AADB2C_PROVIDER_CLIENT_SECRET</code>. These need to be set inside the environment variables page of our Azure Static Web App.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7f3193cb-beb8-49c1-9eb5-80599df015dc/07_new_env_variables.png?t=1741602271"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="redirect-to-login"><b>Redirect to login</b></h1><p class="paragraph" style="text-align:left;">Nice! We’ve set everything up so it’s time to test it. When you try to access the website of your Quarto project, you should be redirected to the following login screen.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b9f688f9-e658-4718-87e8-7415e17105d3/12_login_screen.png?t=1741602283"/></div><p class="paragraph" style="text-align:left;">While this is nice, it doesn’t matter what you put in there. The system won’t be able to find your user details.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/1d083588-4270-4ea5-9cb9-3164a1492b49/13_access_denied.png?t=1741602311"/></div><p class="paragraph" style="text-align:left;">Clearly, this happens because we’ve never defined a user base.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-a-user"><b>Add a user</b></h1><p class="paragraph" style="text-align:left;">We can add a user to our ADB2C resource via the Users page.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/c3f4f8b4-88c7-48ae-bd63-4b97b7371e5f/14_users.png?t=1741602319"/></div><p class="paragraph" style="text-align:left;">There, we just have to set up a new user.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2a9e7106-06d6-4f44-863c-07e9c90cf66b/15_new_user.png?t=1741602325"/></div><p class="paragraph" style="text-align:left;">The page just requires defining an e-mail address and a password. Once we have set that up we can use this mail and the password to sign up via our login page. This will successfully authenticate us and redirect us to our website.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a7cf3836-4b74-406a-90f6-02134645b773/16_redirected_to_page.png?t=1741602336"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">And with that we have successfully changed the authentication once again 🥳 But this time we can customize who gets to sign in and who doesn’t.</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-user-specific-authentication-for-quarto-projects-on-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=d471de25-5198-40e2-bbcf-ad71e5250cb7&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (GitHub Authentication for Azure Static Web Apps)</title>
  <description>I teach you how to use social logins like the one from GitHub to authenticate with a Quarto website that is hosted on Azure Static Web Apps.</description>
  <link>https://3mw.albert-rapp.de/p/github-authentication-for-azure-static-web-apps</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/github-authentication-for-azure-static-web-apps</guid>
  <pubDate>Wed, 05 Mar 2025 18:00:00 +0000</pubDate>
  <atom:published>2025-03-05T18:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 15.0px 0.0px 15.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;"><b>Enjoy 3 Minute Wednesdays at no cost.</b></span></p><p class="paragraph" style="text-align:left;">This newsletter is brought to you for free. If you want to <b>advance your R skills and support my work</b> at the same time, then you will like my paid offerings:</p><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Data Cleaning Master Class</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Insightful DataViz for “Uncreative” R Users</a></p></li></ul></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Last week, we enabled authentication for our Quarto website that is hosted on Azure Static Web Apps. But this authentication allowed everybody with a Microsoft account to sign in. That’s usually not what we want. So let me show you how to modify the authentication settings in today’s newsletter.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="recap"><b>Recap</b></h1><p class="paragraph" style="text-align:left;">If you recall, all we had to do to add authentication was to include a file called <code>staticwebapp.config.json</code>. Here’s how it looked:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/112ba458-dc8e-4e26-bf30-d9599d7e81d1/image.png?t=1741015938"/></div><p class="paragraph" style="text-align:left;">This is the configuration that redirected unauthenticated users to <code>https://website.com/.auth/login/aad</code>. That’s where users could then sign in with their Microsoft account. And to be more precise, users signed in with their Azure Active Directory (AAD) account. This name still floats around everywhere even though that service is called Azure EntraID nowadays.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="add-custom-authentication"><b>Add custom authentication</b></h1><p class="paragraph" style="text-align:left;">And the nice thing is that we can change the authentication via the same config file. All we have to do is check out this snippet I stole from the <span style="text-decoration:underline;"><a class="link" href="https://learn.microsoft.com/en-us/azure/static-web-apps/authentication-custom?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow" style="color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1))">Azure documentation</a></span>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3c49597f-c3bf-496d-acd4-0dbfb0dde554/image.png?t=1741015955"/></div><p class="paragraph" style="text-align:left;">This snippet allows users to authenticate with their GitHub account. This stil doesn’t restrict the user base that can access our website by a lot. But it’s the first step to understanding how to customize authentication.</p><p class="paragraph" style="text-align:left;">In this snippet, we have two placeholders that we should acknowledge: <code>GITHUB_CLIENT_ID</code> and <code>GITHUB_CLIENT_SECRET_APP_SETTING_NAME</code>.</p><p class="paragraph" style="text-align:left;">Actually, there’s also a third name that we should notice: In the snippet you can see that we use <code>&quot;github&quot;</code> as an identity provider name. This means that when we throw this snippet into <code>staticwebapp.config.json</code>, then we should also change the redirect URL.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/6fd37d02-34a4-461a-aa6f-a83a99fc204e/image.png?t=1741016002"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="failed-redirect"><b>Failed redirect</b></h1><p class="paragraph" style="text-align:left;">Now, if we push these changes to our GitHub repository and try to access our website, we get this error.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/75b3d60a-3743-43d1-99fb-c8868071871c/image.png?t=1741016030"/></div><p class="paragraph" style="text-align:left;">Very sad, I know. But it’s also kind of expected. After all, we didn’t do anything with the names <code>GITHUB_CLIENT_ID</code> and <code>GITHUB_CLIENT_SECRET_APP_SETTING_NAME</code>. So let’s change that.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="create-a-git-hub-client"><b>Create a GitHub Client</b></h1><p class="paragraph" style="text-align:left;">As we can infer from the names <code>GITHUB_CLIENT_ID</code> and <code>GITHUB_CLIENT_SECRET_APP_SETTING_NAME</code>, we need a so-called client. And that is typical for any identity provider. Whether that’s GitHub or Azure Active Directory (AAD), you need a client to handle the back and forth of credentials.</p><p class="paragraph" style="text-align:left;">And the only reason why we didn’t have to do that so far is because the default AAD setting in Azure Static Web Apps uses a default client. But the moment we move away from that, we also have to provide our own client. Luckily, it’s usually quite easy to create one after you found the right menus to click. Let’s see how to do that with GitHub.</p><p class="paragraph" style="text-align:left;">In your GitHub account settings, you can find the developer settings at the bottom of the sidebar.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/3d51fc49-f2c7-4f10-9b71-a2c143499903/image.png?t=1741016039"/></div><p class="paragraph" style="text-align:left;">In there, you can create a new OAuth app.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/81feaabc-9d94-40dc-a395-2c96d3112a99/02_oauth_create.png?t=1741016079"/></div><p class="paragraph" style="text-align:left;">These kind of apps implement the so-called OAuth flow that is commonly used for authentication. Here, I have already created such an app with the name “QuartoAuthenticationTest”.</p><p class="paragraph" style="text-align:left;">But let’s create a new one here. That way, I can show you all the necessary settings.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2f261da4-529a-43dd-9b70-85c2a03342c1/03_oauth_callback.png?t=1741016088"/></div><p class="paragraph" style="text-align:left;">As you can see, you need to register the URL of your hosted website with the client. More importantly, you also need to declare a “callback” url. This is the URL where your authentication service expects credentials to arrive. As per the <span style="text-decoration:underline;"><a class="link" href="https://learn.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=github%2Cinvitations&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps#authentication-callbacks" target="_blank" rel="noopener noreferrer nofollow" style="color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1))">Azure docs</a></span>, that URL is always just the regular URL followed by <code>.auth/login/&lt;IDENTITY_PROVIDER&gt;/callback</code>.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="get-client-id-and-secret"><b>Get client id and secret</b></h1><p class="paragraph" style="text-align:left;">Once you created the OAuth app, you can see the “client ID” on the page that you are being redirected to. Also, you can create a “client secret”.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/ca2269a7-23bf-40fa-ae63-b59883580830/04_new_secret.png?t=1741016107"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="fill-environment-variables"><b>Fill environment variables</b></h1><p class="paragraph" style="text-align:left;">Equipped with ID & secret you can now fill the corresponding environment variables. This doesn’t mean that you have to modify the config file. Instead you have to login to Azure Static Web Apps and set environment variables for your app.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e3ebe6eb-95bb-4dbb-9f97-ec4e6807be48/05_env_variables.png?t=1741016113"/></div><p class="paragraph" style="text-align:left;"></p><p class="paragraph" style="text-align:left;">There, you will need to create the variables <code>GITHUB_CLIENT_ID</code> and <code>GITHUB_CLIENT_SECRET_APP_SETTING_NAME</code>. After all, these are the variable names you have specified in your config file.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/daf6ead8-f065-4c02-891f-953632aca72c/image.png?t=1741016168"/></div><p class="paragraph" style="text-align:left;">And once all settings were saved, the redirect to GitHub should work properly. That way, you will see the following GitHub page when you want to access your Quarto website.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/bdf899eb-f2f1-42fb-8c05-e0e2043300b7/image.png?t=1741016183"/></div><p class="paragraph" style="text-align:left;">And once you sign in, you will be redirected to your Quarto page. Hooray.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/f46c087b-8350-4d2d-891b-a7c7ef1902ee/image.png?t=1741016204"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">Nice! We successfully changed the authentication from AAD to GitHub. That’s not very restrictive but the good news is that the principles with Azure Active Directory are pretty much the same. Thus, you can restrict access to your desired user base. I’ll show you how that works next week.</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-github-authentication-for-azure-static-web-apps" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=bcca35d7-8b3b-4450-93f0-36c6ff9d6002&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Authentication for Quarto Projects on Azure)</title>
  <description>We add a layer of authentication for a Quarto website that we deployed on Azure static web apps. And the nice thing is that we only add a simple config file.</description>
  <link>https://3mw.albert-rapp.de/p/authentication-for-quarto-projects-on-azure</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/authentication-for-quarto-projects-on-azure</guid>
  <pubDate>Wed, 26 Feb 2025 20:00:00 +0000</pubDate>
  <atom:published>2025-02-26T20:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 20.0px 0.0px 20.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;font-size:0.8rem;"><b>3 Minute Wednesdays is brought to you by</b></span></p><p class="paragraph" style="text-align:center;"><span style="font-size:1.5rem;"><b>R in 3 Months Starts March 13</b></span></p><p class="paragraph" style="text-align:left;">The twice-annual cohort-based program that has helped hundreds of people from around the world learn R starts soon. Learn to wrangle, visualize, and report on data – all in R. Get 10% off with the coupon code <b>3MWSPRING2025</b>. </p><div class="button" style="text-align:center;"><a target="_blank" rel="noopener nofollow noreferrer" class="button__link" style="background-color:#06436E;" href="https://rfortherestofus.com/3months?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure"><span class="button__text" style="color:#F9FAFB;"> Sign up now </span></a></div></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter, we want to add authentication to the Quarto project we deployed last week. If you recall, we took a simple Quarto book/website and deployed it via Azure Static Web Apps. And with that set up, it’s actually super easy to add a layer of authentication in front of that. </p><p class="paragraph" style="text-align:left;">But before I show you how that works, it’s time for my regular announcements.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="dcmc-4-finished"><b>DCMC 4 finished</b></h1><p class="paragraph" style="text-align:left;">This week, I uploaded the final lesson of my data cleaning master class. It ties together all the things we have learned throughout the lessons of Part 4. What’s more is that it applies the lessons to a real-world scenario where we run an analysis on time series data.</p><p class="paragraph" style="text-align:left;">If you’re interested in leveling up your skills regarding time-related data, then you can join 100+ learners via</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> This course teaches you everything you need to know about cleaning data in R fast & efficiently. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/share.jpg?v=eac29315"/></a></div><p class="paragraph" style="text-align:left;">And as a little celebration that Part 4 is complete now, you can use the code <b>“DCMC4”</b> to get 10% off. Also, this code is only valid <b>until March 2</b>.</p><h1 class="heading" style="text-align:left;" id="pd-fs-to-data-frame"><b>PDFs to DataFrame</b></h1><p class="paragraph" style="text-align:left;">Also, this week I released a new video that shows viewers how to use the <code>&#123;ellmer&#125;</code> package to</p><ul><li><p class="paragraph" style="text-align:left;">extract specific informations from texts & PDFs and</p></li><li><p class="paragraph" style="text-align:left;">bring that into a DataFrame format.</p></li></ul><p class="paragraph" style="text-align:left;">You can check out the video at</p><iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true" class="youtube_embed" frameborder="0" height="100%" src="https://youtube.com/embed/XurNalXAApw" width="100%"></iframe><hr class="content_break"><h1 class="heading" style="text-align:left;" id="one-config-file-to-rule-them-all"><b>One config file to rule them all</b></h1><p class="paragraph" style="text-align:left;">Now, let’s get back to adding authentication to a Quarto website. It’s actually not as hard as you’d think. Everything is governed by one single JSON file called <code>staticwebapp.config.json</code>.</p><p class="paragraph" style="text-align:left;">Basically, what you need to do is fill this JSON file with specific keywords and values. That way, your website will change all kinds of settings. And that’s how you can easily add authentication.</p><p class="paragraph" style="text-align:left;">And the good news is that you don’t have to know all the keywords yourself. Inside the <a class="link" href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Azure documentation</a>, there are lots of config snippets for all kinds of use cases. For example, there’s a <a class="link" href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure#restrict-access-to-entire-application" target="_blank" rel="noopener noreferrer nofollow">config snippet</a> to “restrict access to the entire application.”</p><p class="paragraph" style="text-align:left;">Sounds exactly like the thing we want. Here’s how it looks.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/42492e66-d733-4761-adc1-86819117cdef/image.png?t=1740319795"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="understanding-the-routes"><b>Understanding the routes</b></h1><p class="paragraph" style="text-align:left;">Now, this might feel intimidating. But there’s actually a very simple logic to the snippet we’ve just seen.</p><p class="paragraph" style="text-align:left;">You see, via the <code>routes</code> setting you can define specific rules for how website visitors should be routed. Here, the <code>routes</code> settings are only filled with one setting, namely this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/6cececf1-6efb-490b-87cf-1e185149cdff/image.png?t=1740319807"/></div><p class="paragraph" style="text-align:left;">Here, the route is defined by <code>/</code> followed by anything (as denoted by the asterisk.) This means that users wanting to access, say, <code>https://website.com/subsite</code>, will be targeted by this rule. You know, because our URL root <code>https://website.com</code> is followed by <code>/*</code>.</p><p class="paragraph" style="text-align:left;">And via the <code>allowedRoles</code> setting inside the routing rule, we can specify which kind of roles a user must have to access the desired page. Here, only users with the role “authenticated” are allowed. This role is already build into any Azure Static Web App.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="can-i-add-other-routes"><b>Can I add other routes?</b></h1><p class="paragraph" style="text-align:left;">To make this example a little more clear, let’s play around with the routes. We could say that the start page <code>index.html</code> is available to anyone. But all other sites are restricted to authenticated users.</p><p class="paragraph" style="text-align:left;">In that case we need to add more rules to the <code>routes</code> settings. Here’s how that could look:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d9b3719c-174e-4719-a93c-33ffaf79bcd5/image.png?t=1740319819"/></div><p class="paragraph" style="text-align:left;">In our Quarto book setting this would mean user can access the start page but no other. But due to the fact that Quarto saves all the style files of any website inside a separate directory and not directly in a file like <code>index.html</code>, the page will look ugly to the unauthenticated users.</p><p class="paragraph" style="text-align:left;">This happens because the user then doesn’t have permissions to access the style files. You can avoid that kind of behavior by making only the <code>index.html</code> file self-contained by adding <code>embed-resources: true</code> inside the YAML header of <code>index.qmd</code>. But for now, let’s just assume that we want to restrict all pages.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="what-happens-to-unauthenticated-use"><b>What happens to unauthenticated users?</b></h1><p class="paragraph" style="text-align:left;">This begs the question <i>“What happens to unauthenticated users?”</i>. Well, the simple answer is that they get denied access. The more specific answer is that the server behind our Azure static web app will return a “401 Unauthorized” response.</p><p class="paragraph" style="text-align:left;">Here, 401 is the standard status code that all web applications know and use. But we don’t want the user’s browser to just get this message. Instead, we want to tell it to maybe first authenticate somewhere else and come back after that.</p><p class="paragraph" style="text-align:left;">This means that instead of serving the user with a “401 Unauthorized”, we want to serve the user’s browser with a “302 Moved Temporarily” status. Additionally, we want to tell the browser where things were moved to. That way, the browser knows where to redirect its request to.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/8d8659a0-751d-4688-b15f-3bec9cc29f0f/image.png?t=1740319833"/></div><p class="paragraph" style="text-align:left;">Here, the redirect will lead to <code>https://website.com/.auth/login/aad</code>. This is the standard authentication with Azure Active directory (nowadays called EntraID). For now, you don’t need to know this service.</p><p class="paragraph" style="text-align:left;">All you need to know is that it’s a service that can store user credentials. Also, the URL the user is then redirected to will prompt the user to authenticate with this service.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="integrate-config-into-quarto"><b>Integrate config into Quarto</b></h1><p class="paragraph" style="text-align:left;">So now that we know how to read the config file, let’s talk about how to integrate it into your Quarto project. You see, Azure static web apps currently only looks at the rendered <code>_book</code> directory in your repo on GitHub.</p><p class="paragraph" style="text-align:left;">But your config file will not be automatically copied to this directory when the project is rendered. Hence, you need to do two things.</p><ol start="1"><li><p class="paragraph" style="text-align:left;">Create the <code>staticwebapp.config.json</code> in the root directory of your project</p></li><li><p class="paragraph" style="text-align:left;">Modify your <code>_quarto.yml</code> file as follows:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/493d1ae7-bc03-40a7-83ba-e71e3ec56023/image.png?t=1740319847"/></div></li></ol><p class="paragraph" style="text-align:left;">This will instruct Quarto to copy the config file into the <code>_book</code> directory when the project is rendered. Now, all that’s left to do is to re-render your project and push all the changes to GitHub.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="did-it-work"><b>Did it work?</b></h1><p class="paragraph" style="text-align:left;">This begs the question: <i>“Is our project secure now?”</i> Well, let’s check. First, we make sure that the corresponding GH Action ran successfully:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/4e45de2e-233c-4cc0-a040-91cfe90acb81/image.png?t=1740319915"/></div><p class="paragraph" style="text-align:left;">Then, we can head to the URL of our hosted project. This is how we’re greeted now:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7dee81de-9e87-46fd-acb1-1fda7372838b/00_login_screen.png?t=1740319945"/></div><p class="paragraph" style="text-align:left;">You may have seen such a window at your workplace before. Congrats, you now understand that the service behind this is Azure Active Directory (EntraID).</p><p class="paragraph" style="text-align:left;">Now you’ll have to login with a Microsoft account. Once you click the button, you’ll see that it asks you to grant permissions.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9ae3d5ec-aa76-4983-97b5-a2cbf6dca7b9/01_consent_form.png?t=1740319955"/></div><p class="paragraph" style="text-align:left;">And once you grant the permissions, you are redirected to your website. This time you can see your Quarto project, though.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/e2a8a9b0-8127-4f7c-aff1-5a7cbfcc1f16/02_post_consent.png?t=1740319976"/></div><p class="paragraph" style="text-align:left;">And in case you’re wondering: You really are authenticated at this point. You can check this by heading to <code>https://website.com/.auth/me</code>. This page now contains a JSON with your user credentials.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/63856c2e-6ef5-412b-b92c-24cefe84dae0/03_auth_me.png?t=1740319985"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">Hooray! We have a first layer of authentication now. But it doesn’t stop anyone with a Microsoft account to access our page. After all, we never specified a specific user pool that can authenticate successfully. Let’s talk about this next week.</p><p class="paragraph" style="text-align:left;">As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-authentication-for-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=dbd7a0c5-980a-4c82-9173-509a13d0f4ce&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Host Quarto Projects on Azure)</title>
  <description>I show you how to host your Quarto websites on Azure Static Web Apps. That way, you can add authentication in front of your website (which we learn next week)</description>
  <link>https://3mw.albert-rapp.de/p/host-quarto-projects-on-azure</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/host-quarto-projects-on-azure</guid>
  <pubDate>Wed, 19 Feb 2025 18:00:00 +0000</pubDate>
  <atom:published>2025-02-19T18:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 20.0px 0.0px 20.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;font-size:0.8rem;"><b>3 Minute Wednesdays is brought to you by</b></span></p><p class="paragraph" style="text-align:center;"><span style="font-size:1.5rem;"><b>R in 3 Months Starts March 13</b></span></p><p class="paragraph" style="text-align:left;">The twice-annual cohort-based program that has helped hundreds of people from around the world learn R starts soon. Learn to wrangle, visualize, and report on data – all in R. Get 10% off with the coupon code <b>3MWSPRING2025</b>. </p><div class="button" style="text-align:center;"><a target="_blank" rel="noopener nofollow noreferrer" class="button__link" style="background-color:#06436E;" href="https://rfortherestofus.com/3months?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure"><span class="button__text" style="color:#F9FAFB;"> Sign up now </span></a></div></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. Today, I’ll show you how to host a Quarto project on Azure. You know, the huge cloud provider from Microsoft. </p><p class="paragraph" style="text-align:left;">And I know that this sounds a bit like overkill when you can easily publish Quarto docs somewhere else. But this will actually set the stage for adding our own layer of authentication later on.</p><p class="paragraph" style="text-align:left;">You see, Azure has a few nice features that make it possible to host your Quarto project with authentication. That way, you could deploy Quarto projects and make it accessible only to a targeted audience. </p><p class="paragraph" style="text-align:left;">But authentication is what we’ll cover next week. First, we have to get our project to Azure. But before we dive in, time for my usual announcements.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="new-time-data-cleaning-tips">New Time Data Cleaning Tips</h1><p class="paragraph" style="text-align:left;">This week, I’ve uploaded two new videos for <a class="link" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Part 4 of my Data Cleaning Master Class</a>. These lessons will show you how to </p><ul><li><p class="paragraph" style="text-align:left;">calculate moving averages for time series and</p></li><li><p class="paragraph" style="text-align:left;">how to check whether your time series data is complete.</p></li></ul><p class="paragraph" style="text-align:left;">These videos also conclude the bite-sized lessons part of Part 4 which means that there’s only the real-world example left. In this real-world example, we’re actually looking at my own data from my content creation career. That way, students get to apply techniques that I use myself to check on my YouTube and LinkedIn stats. </p><p class="paragraph" style="text-align:left;">I’ll upload that 28 minute deep-dive next week. So, if you want to join 100+ students, you can do so at</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> This course teaches you everything you need to know about cleaning data in R fast & efficiently. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/share.jpg?v=eac29315"/></a></div><h1 class="heading" style="text-align:left;" id="5-levels-of-data-cleaning">5 Levels of Data Cleaning</h1><p class="paragraph" style="text-align:left;">I’ve also released a new YT tutorial this week. It shows you the same data cleaning project in 5 different ways. And at every stage the code will get shorter and more efficient. That way, you’ll learn to write less code and get your results much quicker:</p><iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true" class="youtube_embed" frameborder="0" height="100%" src="https://youtube.com/embed/GZ870c6IsWU" width="100%"></iframe><hr class="content_break"><h1 class="heading" style="text-align:left;" id="lets-create-a-dummy-project"><b>Let’s create a dummy project</b></h1><p class="paragraph" style="text-align:left;">In order to deploy anything, we first need a new Quarto project. You can do so via the RStudio “New Project” dialogue.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/60b678cd-5fe3-4560-a65c-061791667ccb/00_new_project.png?t=1739780720"/></div><p class="paragraph" style="text-align:left;">Let’s make it easy and create a new Quarto book.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/045d5477-bdb6-4a7e-b460-1deef200f7a5/01_book_project.png?t=1739780728"/></div><p class="paragraph" style="text-align:left;">But make sure that you also use a git repo.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d5c65c1f-930d-415f-b157-58ec273e6231/02_use_git.png?t=1739780735"/></div><p class="paragraph" style="text-align:left;">Once you’ve set that up, make sure that you have rendered your project. That way, you should see something like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/acee2774-7638-4274-ae8e-cc615703c06a/03_quarto_projects.png?t=1739780773"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="create-a-git-hub-repo"><b>Create a GitHub repo</b></h1><p class="paragraph" style="text-align:left;">Next, the code for our Quarto project needs to be hosted on GitHub. So make sure that you create a new repo on GitHub.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b737bcd7-811b-4762-89d1-4e6c03c91895/04_github.png?t=1739780782"/></div><p class="paragraph" style="text-align:left;">And once you have that, you can push your code to the repository. This should look something like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/039f9399-1cf4-45d3-91f5-88531d8e0daf/05_gh_pushed.png?t=1739780790"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="create-a-static-web-app-on-azure"><b>Create a Static Web App on Azure</b></h1><p class="paragraph" style="text-align:left;">Great! Now, we just have to login to Azure (or create an account if you don’t have one yet.) There, we want to jump to the <a class="link" href="https://azure.microsoft.com/en-us/products/app-service/static?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Static Web Apps</a> Service. This service makes it easy to deploy static web pages (like our Quarto project.)</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7b60541b-59fa-4f43-950f-2d1e610c9c9b/06_create_web_app.png?t=1739780799"/></div><p class="paragraph" style="text-align:left;">At first you will be prompted to assign a resource group. This is nothing but an administrative unit to keep an eye on costs for billing purposes. Hence, you can create a new resource group for this project. Here I’ve just called it Quarto_test.</p><p class="paragraph" style="text-align:left;">Then, our app will need a name. I went with “3mw-demo” but feel free to use a name that suits you.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a3321bfb-9c07-4b15-9c69-210213bfaf19/07_rg_and_name.png?t=1739780811"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="choose-a-plan"><b>Choose a plan</b></h1><p class="paragraph" style="text-align:left;">Next, we need to choose a plan.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/dd76dc9e-b621-4cea-acc8-ba25c93549d2/08_azure_plan.png?t=1739780849"/></div><p class="paragraph" style="text-align:left;">If you don’t need authentication, you can actually deploy your Quarto project for free. But since we want to add authentication, we will need to go for the paid tier that currently costs $9 per month.</p><p class="paragraph" style="text-align:left;">However, if you just want to try it out, you can just delete the static web app after you’re done and you don’t have to pay the full month. In that case, Azure will bill you only for the hours you’ve used.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="linking-your-git-hub-repo"><b>Linking your GitHub repo</b></h1><p class="paragraph" style="text-align:left;">Finally, you need to link to your GitHub repo and the specific branch you want to deploy from.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d70aa938-fabe-4ee8-9e32-2bca7ea11048/09_link_to_gh.png?t=1739780868"/></div><p class="paragraph" style="text-align:left;">And once that is done, Azure will ask you what kind of app you want to deploy. Since we don’t use any of the common web frameworks like Vue, Svelte, etc. we just pick “Custom” (if Azure doesn’t detect that on its own.) Then, we only have to tell Azure that all the necessary files are in the <code>_book</code> directory. So just set the “App location” to <code>./_book</code>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/9cce66c1-3016-40f3-83e1-b831f8b5b085/10_app_location.png?t=1739780878"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="deploy-the-quarto-project"><b>Deploy the Quarto project</b></h1><p class="paragraph" style="text-align:left;">And that’s it. Now you can hit the “review + create” button. After you’ve confirmed the details, Azure will deploy your app.</p><p class="paragraph" style="text-align:left;">This will mean two things:</p><p class="paragraph" style="text-align:left;">First, you’ll see a new GitHub Actions workflow in your repository. This means that whenever you push changes to your repo, your deployed app will be updated via this workflow.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/8caf71ad-160e-47ab-909f-d51e05f483af/11_workflow.png?t=1739780888"/></div><p class="paragraph" style="text-align:left;">Second, on the main page of the Static Web Apps service you can now see your new app. If you click into it, you’ll see lots of details of your web app.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/45a64ff3-840e-4b72-8fce-e99dd6984661/12_deployed_app.png?t=1739780906"/></div><p class="paragraph" style="text-align:left;">And if you head to the mentioned URL you’ll see that your Quarto project was deployed. Have a look.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/7d51a92e-17de-4e43-8137-2d5e64a32fc1/13_visited_url.png?t=1739780957"/></div><hr class="content_break"><p class="paragraph" style="text-align:left;">Hooray! With that we have successfully deployed Quarto on Azure. Next week, we’ll add authentication to that. As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-host-quarto-projects-on-azure" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=1f742cb7-ad4e-48b5-a7ba-2ae4d43c95c9&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>3MW (Use AWS Textract With R &amp; {paws})</title>
  <description></description>
  <link>https://3mw.albert-rapp.de/p/use-aws-textract-with-r-paws</link>
  <guid isPermaLink="true">https://3mw.albert-rapp.de/p/use-aws-textract-with-r-paws</guid>
  <pubDate>Wed, 12 Feb 2025 18:00:00 +0000</pubDate>
  <atom:published>2025-02-12T18:00:00Z</atom:published>
    <dc:creator>Albert Rapp</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><div class="section" style="background-color:#e7f4fe;border-radius:10px;margin:0.0px 20.0px 0.0px 20.0px;padding:10.0px 10.0px 10.0px 10.0px;"><p class="paragraph" style="text-align:center;"><span style="color:#06436E;font-size:0.8rem;"><b>3 Minute Wednesdays is brought to you by</b></span></p><p class="paragraph" style="text-align:center;"><span style="font-size:1.5rem;"><b>R in 3 Months Starts March 13</b></span></p><p class="paragraph" style="text-align:left;">The twice-annual cohort-based program that has helped hundreds of people from around the world learn R starts soon. Learn to wrangle, visualize, and report on data – all in R. Get 10% off with the coupon code <b>3MWSPRING2025</b>. </p><div class="button" style="text-align:center;"><a target="_blank" rel="noopener nofollow noreferrer" class="button__link" style="background-color:#06436E;" href="https://rfortherestofus.com/3months?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws"><span class="button__text" style="color:#F9FAFB;"> Sign up now </span></a></div></div><p class="paragraph" style="text-align:left;">Guten Tag!</p><p class="paragraph" style="text-align:left;">Many greetings from Munich, Germany. In today’s newsletter we’re using OCR services from AWS. This lets us extract texts from any kind of document or image. That way, we can extract information from all sorts of documents and feed that into text processing tools like LLMs.</p><p class="paragraph" style="text-align:left;">But before we do that, it’s time for my regular announcements:</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="new-lessons-on-data-cleaning-with-t">New Lessons On Data Cleaning With Time Data</h1><p class="paragraph" style="text-align:left;">Like every week, my data cleaning master class is making a lot of progress. This week, I’ve uploaded 6 new bite-sized lessons:</p><ul><li><p class="paragraph" style="text-align:left;">Lesson 07: Time length calculations with durations & periods</p></li><li><p class="paragraph" style="text-align:left;">Lesson 08: Calculate time between to time points</p></li><li><p class="paragraph" style="text-align:left;">Lesson 09: Introducing intervals</p></li><li><p class="paragraph" style="text-align:left;">Lesson 10: Using interval functions</p></li><li><p class="paragraph" style="text-align:left;">Lesson 11: Rounding dates</p></li><li><p class="paragraph" style="text-align:left;">Lesson 12: Filter time columns</p></li></ul><p class="paragraph" style="text-align:left;">All of these small little things add up so that you can easily handle any time-related data that comes your way. If you’re interested in joining 100+ learners, you can do so via the course landing page:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> This course teaches you everything you need to know about cleaning data in R fast & efficiently. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/share.jpg?v=eac29315"/></a></div><h1 class="heading" style="text-align:left;" id="using-ai-functions">Using AI Functions</h1><p class="paragraph" style="text-align:left;">If you’ve enjoyed the newsletter from <a class="link" href="https://3mw.albert-rapp.de/p/using-ai-functions-with-r-ellmer?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">a few weeks ago</a>, then I’m sure you’re delighted to hear that there is also a video version available now. This tutorial shows you how you can use AI tools with {ellmer}. </p><iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true" class="youtube_embed" frameborder="0" height="100%" src="https://youtube.com/embed/fIVUFw0ml1M" width="100%"></iframe><hr class="content_break"><h1 class="heading" style="text-align:left;" id="get-a-textract-client"><b>Get a Textract client</b></h1><p class="paragraph" style="text-align:left;">Just like last time, we need to get a client for the specific AWS service we want to use. Here, that’s Textract.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/1f08d3ff-23c1-43f0-98e5-59019462df4f/image.png?t=1739197858"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">And with this client’s </span><code>start_document_text_detection()</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;"> method we can send an object that we have stored in S3 to the text detection service. Here, we will just use the PDF we have stored in S3 </span><a class="link" href="https://3mw.albert-rapp.de/p/save-data-at-aws-s3-with-paws?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">last time</a>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/5233d04b-59e8-4e4c-a12b-153d0e090afb/image.png?t=1739197869"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="handle-the-response"><b>Handle the response</b></h1><p class="paragraph" style="text-align:left;">Notice that we saved the result of the start processing call in a variable called <code>response</code>. Let’s check out what’s in it.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/ca7b3b64-7c53-4b1d-b26c-80d03e564a1a/image.png?t=1739197884"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">This response can be used together with the </span><code>get_document_text_detection()</code><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;"> method.</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/86161431-3406-47df-8b16-e257f00439b1/image.png?t=1739197895"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="make-sense-of-the-output"><b>Make sense of the output</b></h1><p class="paragraph" style="text-align:left;">Woah! That’s a lot of stuff. Thankfully, the <code>&#123;paws&#125;</code> documentation offers some clarity.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2533814b-0fd8-4d85-995e-fcfc1e6a740f/image.png?t=1739198199"/></div><p class="paragraph" style="text-align:left;">With that we know that there is a field called <code>JobStatus</code>. This one can be either <code>&quot;IN_PROGRESS&quot;</code>, <code>&quot;SUCCEEDED&quot;</code>, <code>&quot;FAILED&quot;</code> or <code>&quot;PARTIAL_SUCCESS&quot;</code>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/36db0d86-c4ba-4307-adff-8cae5e7b5c9d/image.png?t=1739197911"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">So, when the OCR job is still in progress, there’s nothing to do but to wait and check in every few seconds.</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/93986846-467d-4729-b8e5-9c79c96aadf4/image.png?t=1739197921"/></div><hr class="content_break"><h1 class="heading" style="text-align:left;" id="check-for-next-tokens"><b>Check for next tokens</b></h1><p class="paragraph" style="text-align:left;">Sweet. Our text processing job finished. Let’s first check the <code>NextToken</code> field in the results.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/91310560-48cd-4241-a418-4550ba082162/image.png?t=1739197933"/></div><p class="paragraph" style="text-align:left;">This one is empty. This means that all OCR’ed texts fit into a single response. That’s great so we don´t have to loop through all the <code>NextToken</code>s.</p><p class="paragraph" style="text-align:left;">You see, for long documents it can happen that you will have to first collect all responses in a list. The code for this could look something like this:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d09cb890-7ac1-4210-87c5-4f8dddfef8fa/image.png?t=1739197946"/></div><p class="paragraph" style="text-align:left;">Thankfully, we don’t have to do that here. Thus, we can directly dive into the blocks of text we want to extract.</p><hr class="content_break"><h1 class="heading" style="text-align:left;" id="extract-blocks"><b>Extract Blocks</b></h1><p class="paragraph" style="text-align:left;">First, we need to find all the blocks that are of type “LINE”.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/2980ed7c-9c4f-40e9-aaa8-b6335bb38166/image.png?t=1739197967"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">From that we can extract the texts:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/b50cd954-11f9-4c4f-95b2-d39b4bedb625/image.png?t=1739197990"/></div><hr class="content_break"><h2 class="heading" style="text-align:left;" id="send-to-ai"><b>Send to AI</b></h2><p class="paragraph" style="text-align:left;">Nice! We have extracted all the texts. With that information we can let AI handle the rest. Let’s first recall how our document looks:</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/f3f8fc31-7bfc-42c4-a4cd-79ba4182f2bf/image.png?t=1739198073"/></div><p class="paragraph" style="text-align:left;">Now, we define a chat and an invoice position type as discussed <a class="link" href="https://3mw.albert-rapp.de/p/turn-text-into-structured-data-with-r-llms?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">a few weeks ago</a>.</p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/d6c2f7b4-6ce8-4b43-a313-effc16349032/image.png?t=1739198015"/></div><p class="paragraph" style="text-align:left;"><span style="color:rgb(33, 37, 41);font-family:system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:17px;">And then we ask our AI to extract the information:</span></p><div class="image"><img alt="" class="image__image" style="" src="https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/asset/file/a8890f7b-5364-4d0e-8592-82b4d67afa92/image.png?t=1739198028"/></div><p class="paragraph" style="text-align:left;">Hoooray! This looks like exactly the content we need. As always, if you have any questions, or just want to reach out, feel free to contact me by replying to this mail or finding me <a class="link" href="https://www.linkedin.com/in/dr-albert-rapp-9a5b9b28b/?utm_source=3mw.albert-rapp.de&utm_medium=referral&utm_campaign=3mw-look-at-all-those-quarto-outputs" target="_blank" rel="noopener noreferrer nofollow" style="color: rgb(6, 67, 110)">on LinkedIn</a> or <a class="link" href="https://bsky.app/profile/albertrapp.bsky.social?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">on Bluesky</a>.</p><p class="paragraph" style="text-align:left;">See you next week, <br>Albert 👋</p><hr class="content_break"><p class="paragraph" style="text-align:left;">Enjoyed this newsletter? Here are other ways I can help you:</p><div class="embed"><a class="embed__url" href="https://data-cleaning.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank"><div class="embed__content"><p class="embed__title"> Data Cleaning With R Master Class </p><p class="embed__description"> A data scientist’s guide to avoid wasting time with data cleaning. Learn 5 fundamental aspects of data cleaning, get to your insights much quicker. </p></div><img class="embed__image embed__image--right" src="https://data-cleaning.albert-rapp.de/assets/images/card.jpg?v=be98840b"/></a></div><div class="embed"><a class="embed__url" href="https://arapp.thinkific.com/courses/insightful-data-visualizations-for-uncreative-r-users?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank"><div class="embed__content"><p class="embed__title"> Insightful Data Visualizations for &quot;Uncreative&quot; R Users </p><p class="embed__description"> In this course, I teach you how to create insightful data visualizations without being a design expert. </p></div><img class="embed__image embed__image--right" src="https://import.cdn.thinkific.com/850523/SGJZ0Ry7TwOBHaC63yap_storytelling-ggplot(1).png"/></a></div><div class="embed"><a class="embed__url" href="https://rfortherestofus.com/courses/tables?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank"><div class="embed__content"><p class="embed__title"> Making Beautiful Tables with R </p><p class="embed__description"> Tables are often boring, hard to read, and, most importantly, they don&#39;t communicate effectively. In this course, I will show you that creating beautiful tables is just a matter of learning a few important principles. </p></div><img class="embed__image embed__image--right" src="https://rfortherestofus.com/img/containers/social_images/3.png/08ba5cd8dd720d5d42f823b1a456d87d.png"/></a></div><ul><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://www.youtube.com/playlist?list=PLBnFxG6owe1EzWjq_rOfdWcWP8QBxcm58&utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">My playlist on YouTube</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://yards.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">Free book: Yet Again - R + Data Science</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://gt.albert-rapp.de/?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">Free book: Beautiful tables with {gt}</a></p></li><li><p class="paragraph" style="text-align:left;"><a class="link" href="https://albert-rapp.de/blog.html?utm_source=3mw.albert-rapp.de&utm_medium=newsletter&utm_campaign=3mw-use-aws-textract-with-r-paws" target="_blank" rel="noopener noreferrer nofollow">Blog posts</a></p><p class="paragraph" style="text-align:left;"></p></li></ul><p class="paragraph" style="text-align:left;"></p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=cf665c26-93a0-41f6-85b3-737a64c53119&utm_medium=post_rss&utm_source=3_minutes_wednesdays">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

  </channel>
</rss>
