Version 1.6.0 and later

0.1 Overview

Version 1.6.0 introduces server mode, a new way to deploy and use bettr that enables browser-based JSON file uploads, automatic caching, and programmatic data loading via URLs. This makes bettr suitable for:

  • Multi-user server deployments where different users need to visualize their own data
  • Web-based workflows without requiring R programming knowledge
  • Data sharing through portable JSON files and direct links

0.2 What’s New in Version 1.6.0

0.2.1 Server Mode for JSON Uploads

The bettr() function now supports a serverMode parameter that launches the app in a special mode where users upload JSON files through the browser.

Benefits:

  • No R programming required for end users
  • Multiple users can use the same server instance with their own data
  • Data is isolated per user session
  • Automatic browser caching for quick reload

0.2.2 JSON Serialization

New functions for converting bettr data to/from JSON format:

  • bettrToJSON() - Export SummarizedExperiment to JSON
  • bettrFromJSON() - Import JSON back to SummarizedExperiment

Benefits:

  • Portable data format (language-agnostic)
  • Easy data sharing between users and systems
  • Preserves all metadata, colors, weights, and transformations
  • Enables web-based workflows

0.2.3 Browser localStorage Caching

Automatic client-side caching of uploaded JSON data in server mode.

What gets cached:

  • Uploaded JSON data

Benefits:

  • Page refresh doesn’t lose your work
  • Survives browser restarts
  • No manual saving required
  • Automatic caching after upload

0.2.4 Cache Versioning

Administrators can force cache invalidation when deploying updates.

Use cases:

  • Deploy schema changes that require fresh data
  • Force all users to re-upload after breaking changes
  • Manage cache in multi-tenant environments
  • Troubleshooting cache-related issues

0.2.5 URL Parameters for Programmatic Loading

Load JSON data automatically via URL query parameters.

Benefits:

  • Create direct links to specific visualizations
  • Integrate with external tools and pipelines
  • Automate opening visualizations after benchmark runs
  • Share analysis results with a simple URL

0.3 Server Mode Basics

0.3.1 Starting a Server

library(bettr)

# Basic server mode
bettr(serverMode = TRUE)

# With cache versioning
bettr(serverMode = TRUE, cacheVersion = "v1.0")

# Custom theme
bettr(serverMode = TRUE, bstheme = "flatly")

0.3.2 What Happens When You Start Server Mode

  1. The app starts listening on a local port (e.g., http://127.0.0.1:4567)
  2. Users navigate to this URL in their browser
  3. The upload interface is displayed
  4. Users can:
    • Upload JSON files manually
    • Have data loaded automatically via URL parameters (if provided)
  5. Once data is uploaded, the full bettr interface appears
  6. All interactions are automatically cached in the browser

0.3.3 User Interface

Upload Mode Interface:

  • Clean, simple upload area
  • “Choose JSON File” button
  • Information about browser caching
  • No “Close app” button (for multi-user safety)

After Upload:

  • Full bettr visualization interface
  • All standard features available
  • “Load Data” panel for uploading new files
  • “Clear Cached Data” button

0.4 JSON Serialization

0.4.1 Creating JSON Files

0.4.1.1 From Data Frames

library(bettr)

# Create benchmark data
benchmark_data <- data.frame(
    Method = c("AlgorithmA", "AlgorithmB", "AlgorithmC"),
    Accuracy = c(0.95, 0.92, 0.89),
    Speed = c(120, 150, 100),
    Memory = c(256, 512, 128)
)

# Add metric metadata
metric_info <- data.frame(
    Metric = c("Accuracy", "Speed", "Memory"),
    Type = c("Quality", "Performance", "Resource"),
    Unit = c("Proportion", "ms", "MB")
)

# Define initial transformations
transforms <- list(
    Speed = list(flip = TRUE, transform = "[0,1]"),
    Memory = list(flip = TRUE, transform = "[0,1]")
)

# Create SummarizedExperiment
bettrSE <- assembleSE(
    df = benchmark_data,
    idCol = "Method",
    metricInfo = metric_info,
    initialTransforms = transforms
)

# Export to JSON
json_file <- tempfile(fileext = ".json")
bettrToJSON(bettrSE, file = json_file)

Click to view example JSON structure

The exported JSON file has the following structure:

{
  "idCol": "Method",
  "data": [
    {
      "Method": "AlgorithmA",
      "Accuracy": 0.95,
      "Speed": 120,
      "Memory": 256,
      "_row": "AlgorithmA"
    },
    {
      "Method": "AlgorithmB",
      "Accuracy": 0.92,
      "Speed": 150,
      "Memory": 512,
      "_row": "AlgorithmB"
    },
    {
      "Method": "AlgorithmC",
      "Accuracy": 0.89,
      "Speed": 100,
      "Memory": 128,
      "_row": "AlgorithmC"
    }
  ],
  "metricInfo": [
    {
      "Metric": "Accuracy",
      "Type": "Quality",
      "Unit": "Proportion"
    },
    {
      "Metric": "Speed",
      "Type": "Performance",
      "Unit": "ms"
    },
    {
      "Metric": "Memory",
      "Type": "Resource",
      "Unit": "MB"
    }
  ],
  "idInfo": {},
  "initialWeights": {},
  "initialTransforms": {
    "Speed": {
      "flip": true,
      "transform": "[0,1]"
    },
    "Memory": {
      "flip": true,
      "transform": "[0,1]"
    }
  }
}

Key components:

  • idCol: Name of the identifier column
  • data: Array of objects, one per method with all metric values
  • metricInfo: Metadata about each metric (optional classifications, units, etc.)
  • idInfo: Additional metadata about methods (optional)
  • initialWeights: Default metric weights (optional)
  • initialTransforms: Transformations to apply to metrics (flip for “lower is better”, transform for normalization)

0.4.1.2 From Existing SummarizedExperiment

# If you already have a SummarizedExperiment
json_file <- tempfile(fileext = ".json")
bettrToJSON(my_existing_SE, file = json_file)

# Get JSON as string (for programmatic use)
json_string <- bettrToJSON(my_existing_SE, file = NULL)

0.4.2 Reading JSON Files

# Read from file
bettrSE <- bettrFromJSON(file = "benchmark_results.json")

# Read from JSON string
bettrSE <- bettrFromJSON(json = json_string)

# Use in non-server mode
bettr(bettrSE = bettrSE)

0.5 URL Parameters for Programmatic Loading

0.5.1 Overview

URL query parameters allow you to automatically load JSON data when users open the app.

0.5.2 Two Loading Methods

0.5.2.1 Load from URL (jsonUrl)

http://localhost:4567/?jsonUrl=https://example.com/data.json

Use cases:

  • Data hosted on web servers
  • GitHub raw file URLs
  • Cloud storage (S3, Google Cloud Storage, etc.)
  • Internal company servers

Example:

# Start server
bettr(serverMode = TRUE)

# Construct URL
base_url <- "http://localhost:4567"
data_url <- "https://raw.githubusercontent.com/user/repo/main/results.json"
full_url <- paste0(base_url, "/?jsonUrl=", URLencode(data_url, reserved = TRUE))

# Open in browser
browseURL(full_url)

0.5.2.2 Load from File Path (jsonFile)

http://localhost:4567/?jsonFile=/absolute/path/to/data.json

Use cases:

  • Local server deployments
  • Internal network file shares
  • Automated pipelines on same machine
  • Development and testing

Example:

# Start server
bettr(serverMode = TRUE)

# Construct URL
base_url <- "http://localhost:4567"
file_path <- "/Users/username/benchmarks/latest_results.json"
full_url <- paste0(base_url, "/?jsonFile=", URLencode(file_path, reserved = TRUE))

# Open in browser
browseURL(full_url)

Using the included example data:

The bettr package includes a pre-exported JSON file from the DuoClustering2018 dataset that can be used for testing and examples.

# Start server
bettr(serverMode = TRUE)

# Get path to included example JSON file
json_path <- system.file("extdata", "duo2018_bettr.json", package = "bettr")

# Construct URL
base_url <- "http://localhost:4567"
full_url <- paste0(base_url, "/?jsonFile=", URLencode(json_path, reserved = TRUE))

# Open in browser
browseURL(full_url)

0.6 Browser Cache Management

0.6.1 How Caching Works

  1. Automatic Save:
    • When you upload a JSON file, it’s saved to browser localStorage
    • Happens immediately after successful upload
    • No manual action required
  2. Automatic Restore:
    • When you reload the page, cached data is automatically restored
    • A notification confirms the restoration
  3. Cache Storage:
    • Stored in browser’s localStorage (typically 5-10MB limit)
    • Specific to your browser and domain
    • Persists across browser restarts
    • Not shared across different browsers or devices

0.6.2 Manual Cache Control

0.6.2.1 Clear Cache Button

Located in the “Load Data” accordion panel:

Load Data
├── Choose JSON File
└── Clear Cached Data (button)

Click to:

  • Remove all cached data
  • Start fresh with a new dataset
  • Free up browser storage

0.6.3 Cache Versioning (Administrators)

0.6.3.1 Setting Up Versioning

# Deploy version 1.0
bettr(serverMode = TRUE, cacheVersion = "v1.0")

# Later, deploy version 1.1 with breaking changes
bettr(serverMode = TRUE, cacheVersion = "v1.1")

0.6.3.2 Version String Format

Any string works - choose what makes sense for your workflow:

# Semantic versioning
cacheVersion = "v1.2.3"

# Date-based
cacheVersion = "2025-10-07"

# Build numbers
cacheVersion = "build-456"

# Custom
cacheVersion = "production-release-oct2025"

0.6.3.3 User Experience

When version changes:

  1. User opens the app
  2. Browser detects version mismatch
  3. Cache is automatically cleared
  4. User sees: “Cache was cleared due to version update. Please upload your data.”
  5. User uploads their JSON file again
  6. New cache is created with current version

Session info

sessionInfo()
#> R Under development (unstable) (2025-10-20 r88955)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.3 LTS
#> 
#> Matrix products: default
#> BLAS:   /home/biocbuild/bbs-3.23-bioc/R/lib/libRblas.so 
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_GB              LC_COLLATE=C              
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: America/New_York
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats4    stats     graphics  grDevices utils     datasets  methods  
#> [8] base     
#> 
#> other attached packages:
#>  [1] dplyr_1.1.4                 tibble_3.3.0               
#>  [3] SummarizedExperiment_1.41.0 Biobase_2.71.0             
#>  [5] GenomicRanges_1.63.0        Seqinfo_1.1.0              
#>  [7] IRanges_2.45.0              S4Vectors_0.49.0           
#>  [9] BiocGenerics_0.57.0         generics_0.1.4             
#> [11] MatrixGenerics_1.23.0       matrixStats_1.5.0          
#> [13] bettr_1.7.1                 BiocStyle_2.39.0           
#> 
#> loaded via a namespace (and not attached):
#>  [1] gridExtra_2.3         rlang_1.1.6           magrittr_2.0.4       
#>  [4] clue_0.3-66           GetoptLong_1.0.5      otel_0.2.0           
#>  [7] compiler_4.6.0        png_0.1-8             vctrs_0.6.5          
#> [10] stringr_1.6.0         pkgconfig_2.0.3       shape_1.4.6.1        
#> [13] crayon_1.5.3          fastmap_1.2.0         magick_2.9.0         
#> [16] backports_1.5.0       XVector_0.51.0        labeling_0.4.3       
#> [19] utf8_1.2.6            learnr_0.11.6         shinyjqui_0.4.1      
#> [22] promises_1.5.0        rmarkdown_2.30        tinytex_0.57         
#> [25] purrr_1.2.0           xfun_0.54             cachem_1.1.0         
#> [28] jsonlite_2.0.0        later_1.4.4           DelayedArray_0.37.0  
#> [31] parallel_4.6.0        cluster_2.1.8.1       R6_2.6.1             
#> [34] bslib_0.9.0           stringi_1.8.7         RColorBrewer_1.1-3   
#> [37] rpart_4.1.24          jquerylib_0.1.4       Rcpp_1.1.0           
#> [40] bookdown_0.45         assertthat_0.2.1      iterators_1.0.14     
#> [43] knitr_1.50            base64enc_0.1-3       httpuv_1.6.16        
#> [46] Matrix_1.7-4          nnet_7.3-20           tidyselect_1.2.1     
#> [49] rstudioapi_0.17.1     dichromat_2.0-0.1     abind_1.4-8          
#> [52] yaml_2.3.10           doParallel_1.0.17     codetools_0.2-20     
#> [55] lattice_0.22-7        shiny_1.11.1          withr_3.0.2          
#> [58] S7_0.2.1              evaluate_1.0.5        foreign_0.8-90       
#> [61] circlize_0.4.16       pillar_1.11.1         BiocManager_1.30.27  
#> [64] checkmate_2.3.3       DT_0.34.0             foreach_1.5.2        
#> [67] rprojroot_2.1.1       ggplot2_4.0.1         scales_1.4.0         
#> [70] xtable_1.8-4          glue_1.8.0            Hmisc_5.2-4          
#> [73] tools_4.6.0           data.table_1.17.8     Cairo_1.7-0          
#> [76] cowplot_1.2.0         grid_4.6.0            tidyr_1.3.1          
#> [79] sortable_0.5.0        colorspace_2.1-2      htmlTable_2.4.3      
#> [82] Formula_1.2-5         cli_3.6.5             S4Arrays_1.11.0      
#> [85] ComplexHeatmap_2.27.0 gtable_0.3.6          sass_0.4.10          
#> [88] digest_0.6.38         SparseArray_1.11.2    rjson_0.2.23         
#> [91] htmlwidgets_1.6.4     farver_2.1.2          htmltools_0.5.8.1    
#> [94] lifecycle_1.0.4       GlobalOptions_0.1.2   mime_0.13