The goal of lzstring-r is to provide an R wrapper for the lz-string C++ library. lz-string is originally a JavaScript library that provides string compression and decompression using an LZ-based algorithm.
Credit goes to Winston Chang for spotting this missing R package and guiding me over at the R Shinylive repo—check out his awesome contributions which this repo is based on here and here. Also, shoutout to Andy Kras for his implementation in C++ of lzstring, which you can find right here, and pieroxy, the original brain behind lzstring in JavaScript—peek at his work over here.
You can install the released version of lzstring from CRAN with:
install.packages("lzstring")
Or the development version from GitHub:
# install.packages("devtools")
devtools::install_github("parmsam/lzstring-r")
library(lzstring)
# Text data
message <- "The quick brown fox jumps over the lazy dog!"
compressed <- lzstring::compressToBase64(message)
compressed
#> [1] "CoCwpgBAjgrglgYwNYQEYCcD2B3AdhAM0wA8IArGAWwAcBnCTANzHQgBdwIAbAQwC8AnhAAmmAOYBCIA"
decompressed <- lzstring::decompressFromBase64(compressed)
cat(decompressed)
#> The quick brown fox jumps over the lazy dog!
json_data <- list(name = "John Doe", age = 30, email = "[email protected]")
json_string <- jsonlite::toJSON(json_data)
compressed <- lzstring::compressToBase64(json_string)
compressed
#> [1] "N4IgdghgtgpiBcBtEApA9gCzAAgCJrgF0AaECAcziQGYAGEkGKCASwBsFkArTMAOgAmBAAIwAHtAAObGHwDGaKCEIBfIA==="
decompressed <- lzstring::decompressFromBase64(compressed)
identical(json_string, decompressed)
#> [1] FALSE
cat(decompressed)
#> {"name":["John Doe"],"age":[30],"email":["[email protected]"]}
Note: Always serialize complex R objects (lists, data frames, etc.) to JSON before compressing. After decompression, deserialize back to R.
obj <- list(a = 1, b = "text", c = list(x = 1:3))
json <- jsonlite::serializeJSON(obj)
lz <- lzstring::compressToBase64(json)
json2 <- lzstring::decompressFromBase64(lz)
obj2 <- jsonlite::unserializeJSON(json2)
identical(obj, obj2) # TRUE
#> [1] TRUE
r_code <- '
library(dplyr)
data <- data.frame(
name = c("John", "Jane", "Jake"),
age = c(28, 22, 32),
salary = c(50000, 60000, 55000)
)
# Filter data for age greater than 25
filtered_data <- filter(data, age > 25)
# Add a new column with updated salary
data <- mutate(data, updated_salary = salary * 1.05)
'
compressed <- lzstring::compressToBase64(r_code)
compressed
#> [1] "FAGwlgRgTghlCeAKAJgBxPKBKYxkwBcYACAHgFpj8iA6AM1gFsBTRYY4gOxheIF5iAY0QAiAFIB7ABacRAGmLiYnZvMViYAa1VY57YjADmzfkMQAmABwLz5hQGZzu/QGcYIOPFPCArAAYAvwUANkCg4h9/AJwcYABiYgAxMBACZigqQhI6CQyjE0MoZkJ04gIpZWJzH2A6FLSi5AB9ahIKYjrU9JQshXziAD4qn1iEgEFkZAMuZgB3IQkQAFdGTmJZsHLiJdRqZim3DwQ8LLJKRiWiNJ6iBR295sPPUyeEYgAqYgBGGj8R4CAA=="
decompose <- lzstring::decompressFromBase64(compressed)
cat(decompose)
#>
#> library(dplyr)
#>
#> data <- data.frame(
#> name = c("John", "Jane", "Jake"),
#> age = c(28, 22, 32),
#> salary = c(50000, 60000, 55000)
#> )
#>
#> # Filter data for age greater than 25
#> filtered_data <- filter(data, age > 25)
#>
#> # Add a new column with updated salary
#> data <- mutate(data, updated_salary = salary * 1.05)
code <- 'library(shiny)
ui <- fluidPage(
"Hello, world!"
)
server <- function(input, output, session) {
}
shinyApp(ui, server)'
files <- list(
name = jsonlite::unbox("app.R"),
content = jsonlite::unbox(code)
)
files_json <- jsonlite::toJSON(list(files))
files_lz <- lzstring::compressToEncodedURIComponent(as.character(files_json))
cat(paste0("https://shinylive.io/r/app/#code=", files_lz))
#> https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKAZwAtaJWAlAB0IAV1oACADwBaCQDNq4gCYAFKAHM47ERIlCwACTjVqRXBIDuRRtWUBCAyOEROcRgDd30ufNEQCUloSdj5UUVILIgjwyIk3Tk5giAEJEBEAXxEePlYAQXR2cQs3T3cBMAyAXSA
x <- lzstring::decompressFromEncodedURIComponent("NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMAMwCdiYACAZwAsBLCbDOAD1R04LFkw4xUxOmTERUAVzJ4mQiABM4dZfI4AdCPp0YuCsgH0WAGw4a6ACl2RHyxwDlnTAAzKAjJ+9MAEyeAJT64RAAAqq2GBR8ZPoaNExkCXYhiPpMOSpwZPJ0EEw0jhAAVIFioiAmihgQGUzlQQC+jvpgrQC6QA")
y <- jsonlite::fromJSON(x)
cat(y$name)
#> app.py
cat(y$content)
#> from shiny.express import input, render, ui
#>
#> ui.input_slider("n", "N", 0, 100, 20)
#>
#>
#> @render.text
#> def txt():
#> return f"n*2 is {input.n() * 2}"
- lzstring operates on strings. For non-string or binary data, encode as JSON or base64 first.
- Always ensure your input is UTF-8 encoded.
- If you compress an R object directly (without serialization), the result may not decompress as expected.
-
Why do I get an empty string after decompressing?
This may happen if the input was not properly encoded, or if the compressed string is corrupted. -
Why does my decompressed JSON fail to parse?
Ensure you serialize your R object to JSON (or useserializeJSON
) before compressing. -
Can I compress binary data?
Encode it as base64 or hex first, then compress the resulting string.
- Sharing Shiny app code via URL (see Shinylive)
- Compact storage of large JSON blobs
- Embedding compressed data in web apps
- Automatic Shinylive links in documentation:
The roxy.shinylive package uses lzstring to provide a roxygen2 extension that automatically takes the code from the@examples
tag and creates a URL to the shinylive.io service. During documentation build, a new section is added to the function manual containing the link and an iframe to the application itself.
- lz-string JavaScript library (pieroxy)
- lz-string C++ port (Andy Kras)
- Shinylive for R
- roxy.shinylive