<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged r</title>
<link>https://coderlegion.com/tag/r</link>
<description>Powered by Question2Answer</description>
<item>
<title>Building Automated Data Reports from Supabase with GitHub Actions and R Markdown</title>
<link>https://coderlegion.com/1831/building-automated-data-reports-from-supabase-with-github-actions-and-r-markdown</link>
<description>&lt;p&gt;Imagine being able to generate professional data reports automatically every week without lifting a finger. In this guide, I'll walk you through creating an automated reporting system that connects to a Supabase database, analyzes data, and publishes the results as a polished PDF report - all using free tools and services.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bfqv6wxpunmp2y7u3nxz.png&quot; alt=&quot;Workflow&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-we-re-building&quot;&gt;What We're Building&lt;/h3&gt;
&lt;p&gt;Let's whiz through how this was created, if you want to go straight to the code, visit here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/AkanimohOD19A/automated-Rmd-outputs&quot;&gt;https://github.com/AkanimohOD19A/automated-Rmd-outputs&lt;/a&gt;&lt;br&gt;
We're going to set up a system that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connects to your Supabase PostgreSQL database&lt;/li&gt;
&lt;li&gt;Pulls and analyzes your data&lt;/li&gt;
&lt;li&gt;Generates beautiful PDF reports with visualizations&lt;/li&gt;
&lt;li&gt;Publishes these reports to GitHub Pages&lt;/li&gt;
&lt;li&gt;Does all this automatically on a schedule (or when triggered manually)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This setup is perfect for businesses that need regular reporting, data analysis teams, or personal projects where you want to keep an eye on your data trends without manual intervention.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Before we start building, we'll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A GitHub account (obviously)&lt;/li&gt;
&lt;li&gt;A Supabase account with some data (a free tier would suffice)&lt;/li&gt;
&lt;li&gt;Basic understanding of R (or willingness to learn)&lt;/li&gt;
&lt;li&gt;No special hardware or paid services required!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1-setting-up-your-repository&quot;&gt;Step 1: Setting Up Your Repository&lt;/h3&gt;
&lt;p&gt;First, create a new repository on GitHub to host your reporting project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Clone the new repository
git clone https://github.com/yourusername/your-repo-name.git
cd your-repo-name

# Create the project structure
mkdir -p .github/workflows
touch .github/workflows/supabase-auto-reports.yml
touch auto-report.Rmd
touch README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-creating-the-github-action-workflow&quot;&gt;Step 2: Creating the GitHub Action Workflow&lt;/h3&gt;
&lt;p&gt;Let's create our automation engine. This GitHub Action will run on a schedule, set up the required environment, and generate our reports.&lt;/p&gt;
&lt;p&gt;Open or &lt;code&gt;touch .github/workflows/supabase-auto-reports.yml&lt;/code&gt; and add:&lt;/p&gt;
&lt;p&gt;Let's break down the GitHub Actions workflow into its major chunks and explain what each part does.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-workflow-trigger-configuration&quot;&gt;job chunk: Workflow Trigger Configuration&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Generate and Deploy Supabase Report
on: 
  schedule:
    - cron: '0 8 *1*' # i.e every Monday @ 8AM UTC
  workflow_dispatch: # Allow manual trigger
  push:
    branches:
      master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This section defines when the workflow will run. It has three trigger conditions: &lt;br&gt;
1) on a schedule every Monday at 8:00 AM UTC using cron syntax (though there appears to be a syntax error with &lt;code&gt;*1*&lt;/code&gt;; it should likely be &lt;code&gt;* * 1&lt;/code&gt;), &lt;br&gt;
2) manually through the GitHub UI with &lt;code&gt;workflow_dispatch&lt;/code&gt;, and &lt;br&gt;
3) whenever code is pushed to the master branch. The workflow's purpose is to generate and deploy a report using data from Supabase.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-permissions-configuration&quot;&gt;job chunk: Permissions Configuration&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;permissions:
  contents: write
  pages: write
  id-token: write
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This section sets the security permissions the workflow needs to function. It requests write access to repository contents (to commit files), GitHub Pages (for deployment), and the ID token (used for authentication). These permissions allow the workflow to make changes to the repository and deploy results to GitHub Pages.&lt;/p&gt;
&lt;p&gt;Remeber to pass the secrets in the Secrets components on GitHub: &lt;br&gt;
&lt;code&gt;Settings &amp;gt; Secrets and variables (Left side) &amp;gt; Actions ..&lt;/code&gt;&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-job-and-environment-setup&quot;&gt;job chunk: Job and Environment Setup&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;jobs:
  render:
    runs-on: ubuntu-latest
    env:
      SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
      SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This section defines the main job called &lt;strong&gt;&quot;render&quot;&lt;/strong&gt; that will run on the latest Ubuntu runner. It also sets up environment variables by retrieving Supabase credentials (URL and API key) from GitHub repository secrets. These credentials will be used to connect to the Supabase database when generating the report.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-initial-setup-steps&quot;&gt;job chunk: Initial Setup Steps&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        
      - name: Set Up R
        uses: r-lib/actions/setup-r@v2
        with:
          r-version: '4.4.2'
          
      - name: Setup Pandoc
        uses: r-lib/actions/setup-pandoc@v2
        with:
          pandoc-version: '3.1.11.1'  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These steps prepare the environment for report generation. First, the workflow checks out the repository code using GitHub's checkout action. Then it installs R programming language (version 4.4.2) and Pandoc (version 3.1.11.1). &lt;em&gt;R&lt;/em&gt; will be used for data analysis and report generation, while &lt;em&gt;Pandoc&lt;/em&gt; helps convert R Markdown documents into the final PDF format.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-system-and-r-dependencies-installation&quot;&gt;job chunk: System and R Dependencies Installation&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev
      
      - name: Install R dependencies
        run: |
          R -e 'options(repos = c(CRAN = &quot;https://cloud.r-project.org&quot;))'
          R -e 'install.packages(c(&quot;rmarkdown&quot;, &quot;knitr&quot;), dependencies=TRUE)'
          R -e 'install.packages(c(&quot;httr&quot;, &quot;jsonlite&quot;, &quot;dplyr&quot;, &quot;ggplot2&quot;, &quot;lubridate&quot;), dependencies=TRUE)'
          R -e 'install.packages(c(&quot;tinytex&quot;, &quot;DBI&quot;, &quot;RPostgres&quot;), dependencies=TRUE)'
          R -e 'tinytex::install_tinytex()'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This section installs all the necessary dependencies. First, Ubuntu system libraries needed for R packages are installed, particularly those required for networking and XML processing. Then, R packages are installed in three batches: &lt;br&gt;
1) &lt;em&gt;rmarkdown&lt;/em&gt; and &lt;em&gt;knitr&lt;/em&gt; for document generation, &lt;br&gt;
2) data manipulation and visualization packages like dpl&lt;em&gt;yr and &lt;/em&gt;ggplot2&lt;em&gt;, and &lt;br&gt;
3) database connectivity packages like &lt;/em&gt;RPostgres&lt;em&gt; for connecting to &lt;strong&gt;Supabase&lt;/strong&gt;. Finally, &lt;/em&gt;TinyTeX* is installed to enable PDF generation from R Markdown.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-credential-and-package-verification&quot;&gt;job chunk: Credential and Package Verification&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;      - name: Check Supabase credentials
        run: |
          if [ -z &quot;$SUPABASE_URL&quot; ] || [ -z &quot;$SUPABASE_KEY&quot; ]; then
            echo &quot;Supabase credentials are not properly set in GitHub secrets.&quot;
            exit 1
          fi
          
      - name: Verify R package installation
        run: |
          R -e 'installed_packages &amp;lt;- installed.packages()[,&quot;Package&quot;]; cat(&quot;Installed packages:&quot;, paste(installed_packages, collapse=&quot;, &quot;), &quot;\n&quot;)'
          R -e 'if(!&quot;httr&quot; %in% installed.packages()[,&quot;Package&quot;]) { install.packages(&quot;httr&quot;, dependencies=TRUE); print(&quot;Reinstalled httr&quot;) }'
          R -e 'library(httr); print(&quot;httr loaded successfully&quot;)'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These steps perform verification to ensure the workflow can proceed successfully. First, it checks if the Supabase credentials are properly set in the GitHub secrets, failing early if they're missing. Then it verifies R package installation by listing all installed packages and specifically checking for the httr package (which is critical for API communication). &lt;br&gt;
I had some inssues with the &lt;em&gt;httr&lt;/em&gt; package, so I added an extra layer of verification if httr isn't found, it attempts to reinstall it and confirm it loads correctly.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-report-generation-and-status-check&quot;&gt;job chunk: Report Generation and Status Check&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;      - name: Render RMarkdown
        run : |
          Rscript -e 'rmarkdown::render(&quot;auto-report.Rmd&quot;, output_file = &quot;report.pdf&quot;)'
        
      - name: Check Query Status
        id: query_check
        run: |
          if [ -f query_status.txt ] &amp;amp;&amp;amp; [ &quot;$(cat query_status.txt)&quot; == &quot;SUCCESS&quot; ]; then
            echo &quot;Query executed successfully, proceeding with deployment.&quot;
            echo &quot;query_status=success&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
          else
            echo &quot;Query failed, aborting deployment.&quot;
            if [ -f error_log.txt ]; then
              echo &quot;Error details:&quot;
              cat error_log.txt
            fi
            echo &quot;query_status=failed&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            exit 1
          fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This section performs the actual report generation and validation. First, it runs the R script to render an R Markdown file called &lt;strong&gt;&quot;auto-report.Rmd&quot;&lt;/strong&gt; into a PDF report. Then it checks if the process was successful by looking for a &lt;strong&gt;&quot;query_status.txt&quot;&lt;/strong&gt; file that should contain &lt;em&gt;&lt;strong&gt;&quot;SUCCESS&quot;&lt;/strong&gt;&lt;/em&gt; if database queries executed properly. If the status check fails, it displays any available error logs and aborts the workflow. This step also sets an output variable that later steps will use to determine whether to proceed with deployment.&lt;/p&gt;
&lt;h6 id=&quot;job-chunk-deployment-steps&quot;&gt;job chunk: Deployment Steps&lt;/h6&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;      - name: Deploy PDF
        if: steps.query_check.outputs.query_status == 'success'
        uses: actions/upload-artifact@v4
        with: 
          name: supabase-report-pdf
          path: report.pdf
          
      # Github Pages
      - name: Deploy to Github Pages
        if: steps.query_check.outputs.query_status == 'success'
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: .
          publish_branch: gh-pages
          keep_files: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final section handles deployment of the generated report in two ways, but only if the query status check passed. First, it uploads the PDF as a GitHub Actions artifact : &lt;code&gt;[generated report link](https://github.com/AkanimohOD19A/automated-Rmd-outputs/blob/gh-pages/report.pdf)&lt;/code&gt; on the new &lt;code&gt;gh-pages&lt;/code&gt; branch, making it available for download directly from the workflow run page. Second, it deploys the entire directory to GitHub Pages using the &lt;em&gt;peaceiris&lt;/em&gt; action, publishing to the gh-pages branch while preserving any existing files. This makes the report accessible via a public webpage hosted by GitHub Pages.&lt;/p&gt;
&lt;p&gt;This workflow represents an automated reporting pipeline that connects to a Supabase database, generates a PDF report using R and R Markdown, and then publishes that report both as a downloadable artifact and to a website. It's designed to run automatically every Monday, but can also be triggered manually or when changes are pushed to the master branch. Here's the full code&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Generate and Deploy Supabase Report

on: 
  schedule:
    - cron: '0 8 * * 1' # i.e every Monday @ 8AM UTC
  workflow_dispatch: # Allow manual trigger
  push:
    branches:
      master
      
permissions:
  contents: write
  pages: write
  id-token: write
  
jobs:
  render:
    runs-on: ubuntu-latest
    env:
      SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
      SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
      
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        
      - name: Set Up R
        uses: r-lib/actions/setup-r@v2
        with:
          r-version: '4.4.2'
          
      - name: Setup Pandoc
        uses: r-lib/actions/setup-pandoc@v2
        with:
          pandoc-version: '3.1.11.1'  
          
      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev
      
      - name: Install R dependencies
        run: |
          R -e 'options(repos = c(CRAN = &quot;https://cloud.r-project.org&quot;))'
          R -e 'install.packages(c(&quot;rmarkdown&quot;, &quot;knitr&quot;), dependencies=TRUE)'
          R -e 'install.packages(c(&quot;httr&quot;, &quot;jsonlite&quot;, &quot;dplyr&quot;, &quot;ggplot2&quot;, &quot;lubridate&quot;), dependencies=TRUE)'
          R -e 'install.packages(c(&quot;tinytex&quot;, &quot;DBI&quot;, &quot;RPostgres&quot;), dependencies=TRUE)'
          R -e 'tinytex::install_tinytex()'

      - name: Check Supabase credentials
        run: |
          if [ -z &quot;$SUPABASE_URL&quot; ] || [ -z &quot;$SUPABASE_KEY&quot; ]; then
            echo &quot;Supabase credentials are not properly set in GitHub secrets.&quot;
            exit 1
          fi
          
      - name: Verify R package installation
        run: |
          R -e 'installed_packages &amp;lt;- installed.packages()[,&quot;Package&quot;]; cat(&quot;Installed packages:&quot;, paste(installed_packages, collapse=&quot;, &quot;), &quot;\n&quot;)'
          R -e 'if(!&quot;httr&quot; %in% installed.packages()[,&quot;Package&quot;]) { install.packages(&quot;httr&quot;, dependencies=TRUE); print(&quot;Reinstalled httr&quot;) }'
          R -e 'library(httr); print(&quot;httr loaded successfully&quot;)'

      - name: Render RMarkdown
        run : |
          Rscript -e 'rmarkdown::render(&quot;auto-report.Rmd&quot;, output_file = &quot;report.pdf&quot;)'
        
      - name: Check Query Status
        id: query_check
        run: |
          if [ -f query_status.txt ] &amp;amp;&amp;amp; [ &quot;$(cat query_status.txt)&quot; == &quot;SUCCESS&quot; ]; then
            echo &quot;Query executed successfully, proceeding with deployment.&quot;
            echo &quot;query_status=success&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
          else
            echo &quot;Query failed, aborting deployment.&quot;
            if [ -f error_log.txt ]; then
              echo &quot;Error details:&quot;
              cat error_log.txt
            fi
            echo &quot;query_status=failed&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            exit 1
          fi
          
      - name: Deploy PDF
        if: steps.query_check.outputs.query_status == 'success'
        uses: actions/upload-artifact@v4
        with: 
          name: supabase-report-pdf
          path: report.pdf
          
      # Github Pages
      - name: Deploy to Github Pages
        if: steps.query_check.outputs.query_status == 'success'
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: .
          publish_branch: gh-pages
          keep_files: true
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-creating-the-r-markdown-report-template&quot;&gt;Step 3: Creating the R Markdown Report Template&lt;/h3&gt;
&lt;p&gt;Having handled the automation job, let's create our report template in R/R.md. This is where the &lt;em&gt;abracadabra&lt;/em&gt; happens - connecting to your database, analyzing data, and creating visualizations.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;auto-report.Rmd&lt;/code&gt; or create it with &lt;code&gt;touch auto-report.Rmd&lt;/code&gt; and add:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;---
title: &quot;Automated Supabase Data Report&quot;
author: &quot;Your Name&quot; # Daniel
date: &quot;`r format(Sys.Date(), '%B %d, %Y')`&quot; # today's date
output: pdf_document
---

`{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
library(DBI)
library(RPostgres)
library(dplyr)
library(ggplot2)
library(httr)       # For API requests
library(jsonlite)   # For JSON parsing
library(lubridate)  # For date handling

## Fetch secrets
supabase_url &amp;lt;- Sys.getenv(&quot;SUPABASE_URL&quot;)
supabase_key &amp;lt;- Sys.getenv(&quot;SUPABASE_KEY&quot;)
`

## Automated Database Report

This report is automatically generated from our Supabase PostgreSQL database.

`{r fetch-data}
# Function to fetch data from Supabase using REST API
fetch_supabase_data &amp;lt;- function(url, api_key, table_name, query_params = NULL) {
  # Build the API endpoint
  endpoint &amp;lt;- paste0(url, &quot;/rest/v1/&quot;, table_name)
  
  # Prepare headers
  headers &amp;lt;- c(
    &quot;apikey&quot; = api_key,
    &quot;Authorization&quot; = paste(&quot;Bearer&quot;, api_key),
    &quot;Content-Type&quot; = &quot;application/json&quot;,
    &quot;Prefer&quot; = &quot;return=representation&quot;
  )
  
  # Build query parameters
  if (is.null(query_params)) {
    # Default: get data from last 7 days
    query_params &amp;lt;- list(
      # Using Supabase's PostgREST syntax
      `created_at` = paste0(&quot;gte.&quot;, format(Sys.Date() - 7, &quot;%Y-%m-%d&quot;))
    )
  }
  
  tryCatch({
    # Make the GET request
    response &amp;lt;- GET(
      url = endpoint,
      add_headers(.headers = headers),
      query = query_params
    )
    
    # Check for successful response
    if (http_status(response)$category == &quot;Success&quot;) {
      # Parse the JSON response
      data &amp;lt;- fromJSON(content(response, &quot;text&quot;, encoding = &quot;UTF-8&quot;), flatten = TRUE)
      
      # Log success
      write(&quot;SUCCESS&quot;, &quot;query_status.txt&quot;)
      
      # Convert to data frame if it isn't already
      if (!is.data.frame(data)) {
        if (length(data) == 0) {
          # Return empty data frame with expected columns
          data &amp;lt;- data.frame(
            id = integer(0),
            value = numeric(0),
            created_at = character(0),
            description = character(0)
          )
        } else {
          data &amp;lt;- as.data.frame(data)
        }
      }
      
      return(data)
    } else {
      # Log error
      error_msg &amp;lt;- paste(&quot;API Error:&quot;, http_status(response)$message, 
                        &quot;-&quot;, content(response, &quot;text&quot;, encoding = &quot;UTF-8&quot;))
      write(error_msg, &quot;error_log.txt&quot;)
      write(&quot;FAILED&quot;, &quot;query_status.txt&quot;)
      stop(error_msg)
    }
  }, error = function(e) {
    # Log connection errors
    write(paste(&quot;ERROR:&quot;, e$message), &quot;error_log.txt&quot;)
    write(&quot;FAILED&quot;, &quot;query_status.txt&quot;)
    stop(paste(&quot;Supabase API request failed:&quot;, e$message))
  })
}

# Fetch data from Supabase - replace &quot;your_table_name&quot; with your actual table
data &amp;lt;- fetch_supabase_data(
  url = supabase_url,
  api_key = supabase_key,
  table_name = &quot;your_table_name&quot;
)
`


`{r analyze, eval=file.exists(&quot;query_status.txt&quot;) &amp;amp;&amp;amp; readLines(&quot;query_status.txt&quot;)[1] == &quot;SUCCESS&quot;}
# Data analysis code runs only if query was successful

# Check if we have data
if(nrow(data) == 0) {
  cat(&quot;No data available for the selected period.&quot;)
} else {
  # Convert date strings to proper date objects if needed
  if(&quot;created_at&quot; %in% colnames(data) &amp;amp;&amp;amp; !inherits(data$created_at, &quot;Date&quot;)) {
    data$created_at &amp;lt;- as_datetime(data$created_at)
  }

  # Summary statistics
  summary_stats &amp;lt;- data %&amp;gt;%
    summarize(
      count = n(),
      avg_value = mean(value, na.rm = TRUE),
      max_value = max(value, na.rm = TRUE),
      min_value = min(value, na.rm = TRUE)
    )

  knitr::kable(summary_stats, caption = &quot;Summary Statistics&quot;)

  # Create a visualization
  ggplot(data, aes(x = created_at, y = value)) +
    geom_line() +
    geom_point() +
    theme_minimal() +
    labs(title = &quot;Weekly Trend&quot;, x = &quot;Date&quot;, y = &quot;Value&quot;)
}
`

## Conclusion

Report generated automatically at `r Sys.time()`.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without breaking going too deep into what's happening, our template does a few remarkable bits - asides the queries set up for connection with &lt;strong&gt;Supabase&lt;/strong&gt; it incorporates logging and testing with the queries passed to &lt;em&gt;error&lt;/em&gt; and the &lt;em&gt;query&lt;/em&gt; txt files. &lt;/p&gt;
&lt;p&gt;Make sure NOT to expose your credentials - create a &lt;code&gt;.Renviron&lt;/code&gt; file and pass your secrets as well as &lt;code&gt;echo .Renviron &amp;gt; .gitignore&lt;/code&gt; when you push to Github. &lt;/p&gt;
&lt;h3 id=&quot;step-4-setting-up-your-supabase-connection&quot;&gt;Step 4: Setting Up Your Supabase Connection&lt;/h3&gt;
&lt;p&gt;To connect securely to &lt;strong&gt;Supabase&lt;/strong&gt;, you'll need to add your credentials as GitHub Secrets:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In your GitHub repository, go to Settings → Secrets and variables → Actions → New repository secret&lt;/li&gt;
&lt;li&gt;Add two secrets:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SUPABASE_URL&lt;/code&gt;: Your Supabase project URL (looks like &lt;code&gt;https://yourproject.supabase.co&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SUPABASE_KEY&lt;/code&gt;: Your Supabase service role API key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;step-5-customizing-the-report-for-your-data&quot;&gt;Step 5: Customizing the Report for Your Data&lt;/h3&gt;
&lt;p&gt;The template we created is minimal (for PoC) and just a starting point. You'll want to customize it based on your specific data structure and analysis needs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Change the table name&lt;/strong&gt;: Replace &lt;code&gt;&quot;your_table_name&quot;&lt;/code&gt; with your actual Supabase table name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adjust the query parameters&lt;/strong&gt;: Modify the date filters or add additional filters based on your needs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhance the analysis&lt;/strong&gt;: Add more complex statistics or visualizations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, if you wanted to add a bar chart showing counts by category:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-r&quot;&gt;# Add this to your analysis R chunk
if(&quot;category&quot; %in% colnames(data)) {
  # Create category summary
  cat_summary &amp;lt;- data %&amp;gt;%
    group_by(category) %&amp;gt;%
    summarize(count = n()) %&amp;gt;%
    arrange(desc(count))
  
  # Plot categories
  ggplot(cat_summary, aes(x = reorder(category, -count), y = count)) +
    geom_bar(stat = &quot;identity&quot;, fill = &quot;steelblue&quot;) +
    theme_minimal() +
    labs(title = &quot;Data by Category&quot;, x = &quot;Category&quot;, y = &quot;Count&quot;) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-6-testing-locally-before-deployment&quot;&gt;Step 6: Testing Locally Before Deployment&lt;/h3&gt;
&lt;p&gt;Before committing your changes, it's a good idea to test your report locally:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Visit your &lt;code&gt;.Renviron&lt;/code&gt; file in your project root (&lt;strong&gt;make sure to add it to &lt;code&gt;.gitignore&lt;/code&gt;&lt;/strong&gt;):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;SUPABASE_URL=your_supabase_url_here
SUPABASE_KEY=your_supabase_key_here
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Install the required R packages:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-r&quot;&gt;install.packages(c(&quot;rmarkdown&quot;, &quot;knitr&quot;, &quot;httr&quot;, &quot;jsonlite&quot;, 
      
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Data Science</category>
<guid isPermaLink="true">https://coderlegion.com/1831/building-automated-data-reports-from-supabase-with-github-actions-and-r-markdown</guid>
<pubDate>Thu, 10 Apr 2025 07:41:42 +0000</pubDate>
</item>
<item>
<title>Easily Convert PDF Files to Word Documents in R</title>
<link>https://coderlegion.com/1589/easily-convert-pdf-files-to-word-documents-in-r</link>
<description>&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=14673266400460095220&quot; alt=&quot;Convert to Docx R package&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this post, I will show you how you can very easily convert your PDF files into Word documents in the R programming language using the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Ifeanyi55/Convert2Docx&quot;&gt;Convert2Docx&lt;/a&gt; R package.&lt;/p&gt;
&lt;p&gt;Convert2Docx is a lightweight R package that R developers can readily use in their workflow to convert PDF files to Word documents easily.&lt;/p&gt;
&lt;p&gt;I wrote the package as an R wrapper for the &lt;a rel=&quot;nofollow&quot; href=&quot;https://pdf2docx.readthedocs.io/en/latest/&quot;&gt;pdf2docx&lt;/a&gt; Python module, which converts PDF files to Word documents in Python.&lt;/p&gt;
&lt;p&gt;The package contains just three functions for converting your PDF file to Word or DOCX.&lt;/p&gt;
&lt;p&gt;Now, let us see this package in action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Install Package&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the moment, the Convert2Docx R package is only available on GitHub. Therefore, to install it, you will need to first of all install &lt;a rel=&quot;nofollow&quot; href=&quot;https://devtools.r-lib.org/&quot;&gt;devtools&lt;/a&gt;. Therefore, in your R console, run the code below to install devtools:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# install devtools 
install. Packages(&quot;devtools&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having installed devtools, we can now install Convert2Docx package from GitHub. Run the code below to install it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# install Convert2Docx from Github
devtools::install_github(&quot;Ifeanyi55/Convert2Docx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome! We are now ready to do some conversion. The next thing to do now is to install the conversion engine. Run the below code to install it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# install engine
install_engine()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please note that you only need to run this code once, and should you encounter any problem installing the engine, go to your terminal and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install pdf2docx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should take care of any dependency issues. Make sure you have the latest version of Python installed on your machine before running the code, though.&lt;/p&gt;
&lt;p&gt;After doing that, try installing the conversion engine again, and if all goes well, you should be able to access the full functionality of the package.&lt;/p&gt;
&lt;p&gt;Let us now start converting files!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Convert Entire PDF File&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is good to mention at this point that you do not have to read the PDF file into your R environment before you can convert it. All you need to do is just specify the relative path to the file from your current working directory like so and run the converter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# convert entire pdf file
pdf_file &amp;lt;- &quot;myFile.pdf&quot;

Converter(pdf_file = pdf_file,
          docx_filename = &quot;myFile.docx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you check your current working directory, you should see the converted file there. Let us explore this package further by converting from one page to another.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Convert From One Page to the Other&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here, we will use another function in the package to convert pages 3 to 5 of the PDF file to Word&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# convert from one page to the other
pdf_file &amp;lt;- &quot;myFile.pdf&quot;

startANDend(pdf_file = pdf_file,
            docx_filename = &quot;threetofive.docx&quot;,
            start = 2,
            end = 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is good to mention here that the pages of some PDF files might not be correctly numbered.&lt;/p&gt;
&lt;p&gt;Therefore, when the conversion to Word is done, especially when converting from one page to another, you could find that the page numbering is slightly different from what you were expecting.&lt;/p&gt;
&lt;p&gt;In the example above, page 3 of the PDF file starts at page 2 by page count, which is why you see &lt;code&gt;start = 2&lt;/code&gt; in the code instead of 3.&lt;/p&gt;
&lt;p&gt;However, this “problem” does not occur when you convert the entire document to Word as demonstrated earlier.&lt;/p&gt;
&lt;p&gt;Now, let us convert selected pages in the PDF file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Convert Selected Pages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To do this, you will need to parse a numeric vector representing the pages from the PDF file you want to convert&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# convert selected pages
pdf_file &amp;lt;- &quot;myFile.pdf&quot;

selectPages(pdf_file = pdf_file,
            docx_filename = &quot;mySelectedPages.docx&quot;,
            pages = c(2,4,6))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, I selected pages 2, 4, and 6 from the PDF file to be converted to Word, and it did a good job.&lt;/p&gt;
&lt;p&gt;As you convert, don’t forget to check your current working directory for the converted files.&lt;/p&gt;
&lt;p&gt;So, there you have it! Now you can easily convert your PDF files to Word documents in the R programming language thanks to the Convert2Docx R package. &lt;/p&gt;
&lt;p&gt;Please, do not forget to give the Convert2Docx R package’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Ifeanyi55/Convert2Docx&quot;&gt;GitHub repository&lt;/a&gt; a ⭐️ if you find it helpful.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed reading this post.&lt;/p&gt;
&lt;p&gt;You can follow me on GitHub: Ifeanyi55 and on X: @Ifeanyidiaye.&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/1589/easily-convert-pdf-files-to-word-documents-in-r</guid>
<pubDate>Wed, 19 Mar 2025 17:31:00 +0000</pubDate>
</item>
<item>
<title>Handling Looping Errors in a Caching Matrix in R</title>
<link>https://coderlegion.com/1168/handling-looping-errors-in-a-caching-matrix-in-r</link>
<description>&lt;h2 id=&quot;introduction&quot;&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Looping errors in a caching matrix in R can lead to infinite loops, inefficient computations, and performance bottlenecks. These errors often arise due to improper indexing, recursive calls without base cases, or mismanaged caching mechanisms. This article explores common causes of looping errors in caching matrices, how to identify them, and solutions to optimize matrix computations efficiently.&lt;/p&gt;
&lt;h2 id=&quot;understanding-caching-in-r-matrices&quot;&gt;&lt;strong&gt;Understanding Caching in R Matrices&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Caching is an optimization technique used to store previously computed results, avoiding redundant calculations. In R, caching is commonly implemented with functions like memoise or custom environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Caching a Matrix Inversion&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;makeCacheMatrix &amp;lt;- function(x = matrix()) {
  inv &amp;lt;- NULL
  set &amp;lt;- function(y) {
    x &amp;lt;&amp;lt;- y
    inv &amp;lt;&amp;lt;- NULL
  }
  get &amp;lt;- function() x
  setInverse &amp;lt;- function(inverse) inv &amp;lt;&amp;lt;- inverse
  getInverse &amp;lt;- function() inv
  list(set = set, get = get,
       setInverse = setInverse,
       getInverse = getInverse)
}

cacheSolve &amp;lt;- function(x, ...) {
  inv &amp;lt;- x$getInverse()
  if (!is.null(inv)) {
    message(&quot;Getting cached data&quot;)
    return(inv)
  }
  mat &amp;lt;- x$get()
  inv &amp;lt;- solve(mat, ...)
  x$setInverse(inv)
  inv
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;common-looping-errors-in-caching-matrices&quot;&gt;Common Looping Errors in Caching Matrices&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Infinite Recursion in Cache Retrieval&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Issue:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; If the caching function is designed improperly, it may keep calling&lt;br&gt;
 itself without a termination condition, leading to infinite&lt;br&gt;
 recursion.&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cacheSolve &amp;lt;- function(x) {
   if (is.null(x$getInverse())) {
     return(cacheSolve(x)) # Incorrect recursive call
   }
   x$getInverse()
 }



&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; &lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; Ensure that the recursive call is properly managed and that a&lt;br&gt;
 stopping condition exists.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cacheSolve &amp;lt;- function(x) {
   inv &amp;lt;- x$getInverse()
   if (!is.null(inv)) {
     return(inv)
   }
   mat &amp;lt;- x$get()
   inv &amp;lt;- solve(mat)
   x$setInverse(inv)
   inv
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Incorrect Indexing in Loops&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Issue:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; Matrix operations in R rely on correct indexing. Looping over&lt;br&gt;
 incorrect indices can lead to out-of-bounds errors or infinite&lt;br&gt;
 loops.&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; for (i in 1:nrow(matrix)) {
   for (j in 1:ncol(matrix)) {
     matrix[i + 1, j] &amp;lt;- matrix[i, j] * 2 # Incorrect index (i+1)
   }
 }

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; &lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; Fix the indexing to avoid exceeding matrix boundaries.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; for (i in 1:(nrow(matrix) - 1)) {
   for (j in 1:ncol(matrix)) {
     matrix[i + 1, j] &amp;lt;- matrix[i, j] * 2
   }
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Redundant Cache Computations in Loops&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Issue:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; Recomputing the inverse matrix multiple times within a loop negates&lt;br&gt;
 the benefits of caching.&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; for (i in 1:100) {
   cacheSolve(matrixObj) # Recomputes each iteration
 }

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; &lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; Store the cached result outside the loop.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; inv_matrix &amp;lt;- cacheSolve(matrixObj)
 for (i in 1:100) {
   # Use inv_matrix instead of recomputing
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;best-practices-to-avoid-looping-errors&quot;&gt;Best Practices to Avoid Looping Errors&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use Vectorized Operations: Prefer apply, lapply, or matrix operations&lt;br&gt;
instead of explicit loops.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check Base Conditions: Ensure recursive functions have proper&lt;br&gt;
termination conditions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validate Cache State: Before performing operations, check if cached&lt;br&gt;
results are available.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Debug Using Print Statements: Print intermediate results to verify&lt;br&gt;
correct loop execution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use traceback() and debug(): Identify recursion issues and inspect&lt;br&gt;
variable states.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Handling looping errors in a caching matrix in R requires careful management of recursive calls, indexing, and cache retrieval. By following best practices such as vectorization, proper loop termination, and optimized caching, you can significantly improve computational efficiency and prevent infinite loops. Implement these solutions to streamline matrix computations and enhance performance in R programming.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways-&quot;&gt;Key Takeaways:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Caching reduces redundant computations but must be managed correctly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid infinite recursion by setting proper base conditions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure correct indexing to prevent out-of-bounds errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store cached results outside loops to optimize performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>R</category>
<guid isPermaLink="true">https://coderlegion.com/1168/handling-looping-errors-in-a-caching-matrix-in-r</guid>
<pubDate>Thu, 20 Feb 2025 11:09:08 +0000</pubDate>
</item>
</channel>
</rss>