Persistent "Package Not Available" Error with renv on RStudio

Hello, I am trying to launch an R Shiny app and I keep running into this error,

rsconnect::deployApp('/Users/cameronwalker/Documents/BCM/Shiny')
── Preparing for deployment ─────────────────────────────────────────
✔ Re-deploying "shiny" using "server: shinyapps.io / username: cam-walker"
ℹ Looking up application with id "12271467"...
✔ Found application <https://cam-walker.shinyapps.io/shiny/>
ℹ Bundling 756 files:
...
ℹ Capturing R dependencies with renv
The following required packages are not installed:
- rstudio
Packages must first be installed before renv can snapshot them.
Use `renv::dependencies()` to see where this package is used in your project.

What do you want to do? 

1: Snapshot, just using the currently installed packages.
2: Install the packages, then snapshot.
3: Cancel, and resolve the situation on your own.

Selection: 2
Error: package 'rstudio' is not available

I tried publishing the app from a different computer and even a server and got the same error. Here is my apps code.

library(shiny)
library(shinythemes)
library(readxl)
library(dplyr)

# Load and clean the data
samples_info <- read_excel(file.path(getwd(), "shiny-server", "samples_info.xlsx")) %>%
  mutate(across(.cols = everything(), ~trimws(.)))

# Load cell types and replace underscores with spaces for display
cell_types <- readLines(file.path(getwd(), "shiny-server", "cell_types.txt"))
cell_types_display <- gsub("_", " ", cell_types)

# Create a named vector for the dropdown choices
cell_types_named <- setNames(cell_types, cell_types_display)

# Custom CSS for better aesthetics
custom_css <- "
  body {
    font-family: 'Arial', sans-serif;
  }
  .sidebar {
    background-color: #f7f7f7;
    border-right: 1px solid #ddd;
    padding: 20px;
  }
  .main-panel {
    padding: 20px;
  }
  .tissue-description {
    color: #333;
    font-weight: bold;
    margin-top: 20px;
    font-size: 18px;
  }
  .no-description {
    color: red;
    font-weight: bold;
    margin-top: 20px;
  }
  .iframe-container {
    margin-bottom: 20px;
    display: inline-block;
    width: 100%;
    vertical-align: top;
  }
  .iframe-container.small {
    width: 32%;
    height: 400px;
  }
  .iframe-container.large {
    width: 100%;
    height: 800px;
  }
  .iframe-container iframe {
    width: 100%;
    height: 100%;
    border: none;
    overflow: hidden;
  }
  .image-display img {
    border: 1px solid #ddd;
    border-radius: 4px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    margin-bottom: 20px;
    max-width: 100%;
    display: block;
    margin-left: auto;
    margin-right: auto;
  }
  .select-input {
    margin-bottom: 20px;
  }
  .visualizations {
    margin-top: 30px;
  }
  .histology-container {
    text-align: center;
    margin-bottom: 30px;
  }
  .histology-container img {
    max-width: 80%;
    height: auto;
  }
  .marker-list {
    margin-top: 20px;
    font-size: 14px;
  }
  .marker-list pre {
    background-color: #f8f9fa;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    max-height: 200px;
    overflow-y: auto;
  }
  .marker-list-label {
    font-weight: bold;
    margin-top: 20px;
    font-size: 16px;
  }
"

# JavaScript code to dynamically adjust iframe height
custom_js <- "
  function resizeIframes() {
    var iframes = document.querySelectorAll('iframe');
    iframes.forEach(function(iframe) {
      iframe.onload = function() {
        var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
        iframe.style.height = iframeDocument.body.scrollHeight + 'px';
      };
    });
  }
  document.addEventListener('DOMContentLoaded', resizeIframes);
  Shiny.addCustomMessageHandler('resizeIframes', resizeIframes);
"

ui <- fluidPage(
  theme = shinytheme("cerulean"),
  tags$head(tags$style(HTML(custom_css))),
  tags$head(tags$script(HTML(custom_js))),
  titlePanel("Spatial Transcriptomics Visualizations"),
  sidebarLayout(
    sidebarPanel(
      class = "sidebar",
      tags$h3("Select Options:"),
      div(class = "select-input", 
          selectInput("sample", "Select Sample:",
                      choices = c("DSG_67289", "DSG_67291", "DSG_67292", "DSG_67293", 
                                  "DSG_67294", "DSG_67295", "DSG_67296", "DSG_67297", 
                                  "DSG_67298", "DSG_67300", "DSG_67804", "DSG_67805"))),
      div(class = "select-input", 
          selectInput("cellType", "Select Cell Type:",
                      choices = c("All" = "All", cell_types_named), selected = "All")),
      uiOutput("markerListDisplay")
    ),
    mainPanel(
      class = "main-panel",
      uiOutput("tissueTypeDisplay"),
      div(class = "histology-container", uiOutput("imageDisplay")),
      tags$h4("Visualizations"),
      div(class = "visualizations", uiOutput("pdfDisplay"))
    )
  )
)

server <- function(input, output, session) {
  output$tissueTypeDisplay <- renderUI({
    req(input$sample)  # Ensure input is not empty
    
    sample_row <- samples_info[samples_info$`Template ID` == input$sample, ]
    
    if (nrow(sample_row) > 0 && !is.na(sample_row$`Tissue type`)) {
      tissueType <- sample_row$`Tissue type`
      tags$h5(tissueType, class = "tissue-description")
    } else {
      tags$h5("No tissue type description found.", class = "no-description")
    }
  })
  
  output$imageDisplay <- renderUI({
    req(input$sample)
    
    imagePath <- normalizePath(file.path("/Users/cameronwalker/Documents/BCM/Shiny/tissue_images", input$sample, "tissue_hires_image.png"), mustWork = FALSE)
    if (file.exists(imagePath)) {
      tags$img(src = sub("^/Users/cameronwalker/Documents/BCM/Shiny", "http://localhost:8000", imagePath))
    } else {
      h5("No histology image found.", class = "no-description")
    }
  })
  
  output$pdfDisplay <- renderUI({
    req(input$sample)
    
    sampleDir <- file.path("/Users/cameronwalker/Documents/BCM/Shiny/DSG", input$sample)
    pdfFiles <- list.files(path = sampleDir, pattern = "\\.pdf$", full.names = TRUE)
    
    if (input$cellType != "All") {
      cellTypePattern <- paste0("^", gsub(" ", "_", input$cellType), "_rank_sums\\.pdf$")
      pdfFiles <- pdfFiles[grepl(cellTypePattern, basename(pdfFiles))]
    }
    
    pdfURLs <- sapply(pdfFiles, function(x) sub("^/Users/cameronwalker/Documents/BCM/Shiny", "http://localhost:8000", x))
    
    # Determine the class for iframes based on the selected cell type
    iframeClass <- if (input$cellType == "All") "iframe-container small" else "iframe-container large"
    
    iframes <- lapply(pdfURLs, function(url) {
      tags$div(class = iframeClass, tags$iframe(src = url, onload = "resizeIframes()"))
    })
    
    do.call(tagList, iframes)
  })
  
  output$markerListDisplay <- renderUI({
    req(input$cellType)
    
    if (input$cellType != "All") {
      markerFile <- file.path("/Users/cameronwalker/Documents/BCM/Shiny/marker_lists", paste0(gsub(" ", "_", input$cellType), ".txt"))
      
      if (file.exists(markerFile)) {
        markerGenes <- readLines(markerFile)
        tags$div(
          class = "marker-list",
          tags$h5("Marker Genes", class = "marker-list-label"),
          tags$pre(paste(markerGenes, collapse = "\n"))
        )
      } else {
        h5("No marker list found.", class = "no-description")
      }
    } else {
      NULL
    }
  })
  
  # Send message to resize iframes whenever the pdfDisplay is rendered
  observe({
    input$sample
    input$cellType
    session$sendCustomMessage("resizeIframes", list())
  })
}

shinyApp(ui = ui, server = server)

Please let me know if you have any idea what is going on.

This is a lot of files that make up your application:

ℹ Bundling 756 files:

That many files might be reasonable if you are including some big external JS libraries.

But if not, my first question is what makes up the files you are including in this bundle aside from the app.R file? Because if any of the additional files have something in them that tricks renv into thinking that "rstudio" is a required package, it might pick it up as a dependency. You could try a "find in all files" starting from the /Users/cameronwalker/Documents/BCM/Shiny directory for "rstudio".

If there's no sensitive filenames to worry about, I might ask to see what

list.files('/Users/cameronwalker/Documents/BCM/Shiny')

looks like. You may even want to check the recursive version too

list.files('/Users/cameronwalker/Documents/BCM/Shiny', recursive = TRUE)
1 Like