https://github.com/alekrutkowski/autoshiny
R package for an automatic transformation of an R function into a Shiny app
https://github.com/alekrutkowski/autoshiny
Last synced: 4 months ago
JSON representation
R package for an automatic transformation of an R function into a Shiny app
- Host: GitHub
- URL: https://github.com/alekrutkowski/autoshiny
- Owner: alekrutkowski
- Created: 2018-05-29T14:23:55.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2023-03-10T09:16:54.000Z (about 2 years ago)
- Last Synced: 2024-11-15T18:09:14.389Z (5 months ago)
- Language: R
- Size: 408 KB
- Stars: 27
- Watchers: 6
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.Rmd
Awesome Lists containing this project
- jimsghstars - alekrutkowski/autoshiny - R package for an automatic transformation of an R function into a Shiny app (R)
README
---
title: "autoshiny -- R package for automatic transformation of an R function into a Shiny app"
author: "Aleksander Rutkowski"
date: "`r format(Sys.Date())`"
output: github_document
always_allow_html: yes
editor_options:
chunk_output_type: console
---```{r setup, include=FALSE}
# Rendering this doc:
# rmarkdown::render(paste0(getwd(),'/README.Rmd'), envir=globalenv())
knitr::opts_chunk$set(message=FALSE)
knitr::opts_chunk$set(engine='R')
options(python_path = "C:/Python27/python.exe")
i <- 0
print.shiny.appobj2 <- function(x, ...) { # needed to prepare the screenshots, overriding shiny's
i <<- i+1
fname <- paste0('screenshot',i,'.png')
cat("", file=fname) # pre-save the file placeholder so that pandoc dones not complain
webshot::appshot(structure(x, class='shiny.appobj'),
file=paste0(getwd(),'/',fname),
vheight=300,
delay=3)
cat(paste0('\n\n\n', # needs results='asis' in chunk options
'See the [source code](https://github.com/alekrutkowski/autoshiny/tree/master/Example_',i,') generated with `makeFiles` ',
'(and formatted with [rfmt](https://github.com/google/rfmt)) ',
'of the app whose initial-state screenshot is displayed above.'))
}
```## Installation
[From CRAN](https://CRAN.R-project.org/package=autoshiny):
```{r, eval=FALSE}
install.packages('autoshiny')
```or the latest version from GitHub:
```{r, eval=FALSE}
# if package `devtools` not installed, first do this:
# install.packages('devtools')
devtools::install_github('alekrutkowski/autoshiny')
```## Key info
There are two key twin functions: `makeApp` and `makeFiles`.
Both of them take a function as their first argument/parameter.
Function `makeApp` returns [a Shiny app object](https://rdrr.io/cran/shiny/man/shinyApp.html).
`makeFiles` produces `ui.R` and `server.R` files.
These files can be further edited to tweak the app if needed.Using **autoshiny** does not imply any run-time dependency of the compiled app on **autoshiny**
i.e. **autoshiny** is needed only at the compile time. **autoshiny** uses standard Shiny
input and output widgets and render functions. Tiny helper functions are embedded in the
compiled app code to make it self-contained.All the arguments/parameters of the function passed to `makeApp` and `makeFiles` *must have default values* which will
be used by **autoshiny** to define each argument's:- type/class -- Shiny input widget type,
- allowed values -- Shiny input widget's allowed states,
- pre-selected/start-up value of the Shiny input widget -- for categorical values (e.g. integers, factors, character vectors
that will be the first element of the vector).The default values of the function arguments/parameters will be also used to pre-evaluate that function in order to
test it and to determine the type of its output (return value / side effect) and, hence, the Shiny output widget.## Examples
```{r, eval=FALSE}
library(autoshiny)
``````{r}
library(shiny)
``````{r, include=FALSE}
j <- 0
makeApp <- function(...) {
j <<- j + 1
autoshiny::makeFiles(...,directory=getwd())
ExN <- paste0('Example_',j)
if (!dir.exists(ExN))
dir.create(ExN)
fls <- c('server.R','ui.R')
fls2 <- paste0(ExN,'/',fls)
file.copy(fls, fls2)
file.remove(fls)
lapply(fls2,
rfmt::rfmt)
structure(autoshiny::makeApp(...),
class='shiny.appobj2')
}
File <- autoshiny::File
```### Example 1: Trivial anonymous function
```{r, results='asis'}
makeApp(function(x=1:3, y=5:9) x+y)
```### Example 2: Nicer function and argument names
```{r, results='asis', fig.keep='none'}
`Histogram for normal distribution` <-
function(`Number of observations` =
as.integer(c(100,10,1000))) # as.integer => the argument interpreted as categorical
plot(hist(rnorm(`Number of observations`))) # Generic R plots as "return values" are supportedmakeApp(`Histogram for normal distribution`)
```### Example 3: Data frame in (upload CSV), data frame out (displayed and downloadable as CSV)
```{r, results='asis'}
`Table of sin and cos values` <-
function(`Upload CSV file with column "x"` =
data.frame(x = seq(0, 2*pi, .25))) {
dta <- `Upload CSV file with column "x"`
data.frame(X = dta$x,
`Sin of X` = sin(dta$x),
`Cos of X` = cos(dta$x),
check.names = FALSE)
}
makeApp(`Table of sin and cos values`)
```### Example 4: Arbitrary input and output files
```{r, results='asis'}
openxlsx::write.xlsx(data.frame(x=1:5,
y=11:15),
'my_test_file.xlsx')
`Excel file in and out` <-
function(`Input Excel file` =
File('my_test_file.xlsx')) { # File() obligatory here!
my.data <- openxlsx::read.xlsx(`Input Excel file`)
my.data2 <- within(my.data,
z <- x + y)
openxlsx::write.xlsx(my.data2,
'my_test_file_2.xlsx')
File('my_test_file_2.xlsx') # File() obligatory here too!
}
makeApp(`Excel file in and out`)
```### Example 5: Using a button as a (re-)evaluation trigger
Use this option if:
- the evaluation of your functon takes time, so it should not be re-evaluated with every minor change of the value of inputs/arguments/parameter;
- the function is impure e.g. depends on some external data fetched internally and takes no arguments/parameters -- in such a case the function would be re-evaluated only through page refresh of the browser; the button is a faster and a more elegant solution.```{r, results='asis'}
`Get "GDP and main components" from Eurostat` <-
function() {
# Getting data from
# http://ec.europa.eu/eurostat/estat-navtree-portlet-prod/BulkDownloadListing?sort=1&file=data%2Fnama_10_gdp.tsv.gz
x <- eurodata::importData('nama_10_gdp')
head(x, 10)
}
makeApp(`Get "GDP and main components" from Eurostat`,
withGoButton = TRUE)
```### Example 6: Lists of inputs (arguments) and the output list (composite return value) are always decomposed
```{r, results='asis'}
`A function with lists everywhere` <-
function(`First argument group,` = list(`number one` = 1:3,
`number two` = letters[1:3]),
`2nd arg group,` = list(`1st argument` = 11:14,
`second arg.` = LETTERS[1:5]))
list(`Some text` =
as.character(c(`First argument group,`$`number two`,
`2nd arg group,`$`second arg.`)),
`Some numbers` =
`First argument group,`$`number one` +
`2nd arg group,`$`1st argument`,
`Even a ggplot2 chart` =
ggplot2::qplot(a,b,data=data.frame(a=1:20,b=log(1:20))))
makeApp(`A function with lists everywhere`)
```