Rendering images in documents and embedded shiny apps - r

When I insert an embedded shiny app to my document like showed on Embedded Shiny Apps, with “runtime: shiny” in the YAML and click the button “Run Document” there are only image placeholder icons.
But when I remove the shiny app and also remove the “runtime: shiny” from the YAML the embedded image is visible after rendering.
The following to links have the topic of embedding images but none solves my issue – in both cases the image placeholder icon remains.
https://github.com/rstudio/rmarkdown/issues/504
Embedding Image in Shiny App
Question:
What should I change in my code to get the images?
Or has it something to do with my initial choice of encoding?
Below my code example with an embedded shiny app – so when necessary you just need to copy and paste. The shiny app is just a copy from the r studio gallery…
EDIT: As suggested by timfaber I added the renderImage() parts in the code. But two question concering the rendering still remain.
How can I suppress the need for scroll up or down to see the entire image? and How can I position an image in an shiny app?
---
title: "Documentation"
author: "tueftla"
date: "23 Mai 2017"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(shiny)
```
Here is my documentation …
and also one of the images.
# my old version
#![](image1.png)
#
```{r, echo=FALSE}
# Here you have to scroll up or down to see the entire image
shinyApp(
ui = fluidPage(
imageOutput("image1")
),
server = function(input, output) {
output$image1=renderImage({
# the images are stored in a subdirectory named images
filename <- normalizePath(file.path('./images',
paste('image1', '.png', sep='')))
# Return a list containing the filename
list(src = filename, height = 600,width=800)
}, deleteFile = FALSE)
}
)
```
In the second code sequence I want to position the image at the right. See the comment "old version"
```{r, echo = FALSE}
shinyApp(
ui = fluidPage(
# Application title
titlePanel("Tabsets"),
# my old version
#img(src=image2.png', align = "right"),
# my new version with bad alignment - note also the change in server
imageOutput("image2", height = 200,width=100),
# Sidebar with controls to select the random distribution type
# and number of observations to generate. Note the use of the
# br() element to introduce extra vertical spacing
sidebarLayout(
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
),
server = function(input, output) {
# the image rendering - necessary for the image in ui of this app
output$image2=renderImage({
# the images are stored in a subdirectory named images
filename <- normalizePath(file.path('./images',
paste('image2', '.png', sep='')))
# Return a list containing the filename
list(src = filename, height = 200,width=100)
}, deleteFile = FALSE)
# Reactive expression to generate the requested distribution.
# This is called whenever the inputs change. The output
# functions defined below then all use the value computed from
# this expression
data <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data. Also uses the inputs to build
# the plot label. Note that the dependencies on both the inputs
# and the data reactive expression are both tracked, and
# all expressions are called in the sequence implied by the
# dependency graph
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(data(),
main=paste('r', dist, '(', n, ')', sep=''))
})
# Generate a summary of the data
output$summary <- renderPrint({
summary(data())
})
# Generate an HTML table view of the data
output$table <- renderTable({
data.frame(x=data())
})
},
)
```
I hope I gave enough information... but when something is missing please comment. I will edit my question.
Many thanks in advance!
Second Edit: The following is showing my folder structure and the result.

I think it can be done a lot easier. For me the problem was defining the right path for the image. No need to use renderImage! Scaling the image resolves the scrolling and using img allows you to define the position (alignment):
---
title: "Documentation"
author: "tueftla"
date: "23 Mai 2017"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(shiny)
```
Here is my documentation …
and also one of the images.
```{r, echo = FALSE}
fluidPage(
titlePanel("Tabsets"),
img(src='www/logotitle.jpg', align = "right",width=100,height=100),
# make sure you define the right (full) path
sidebarLayout(
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
))
data <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data. Also uses the inputs to build
# the plot label. Note that the dependencies on both the inputs
# and the data reactive expression are both tracked, and
# all expressions are called in the sequence implied by the
# dependency graph
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(data(),
main=paste('r', dist, '(', n, ')', sep=''))
})
# Generate a summary of the data
output$summary <- renderPrint({
summary(data())
})
# Generate an HTML table view of the data
output$table <- renderTable({
data.frame(x=data())
})
```
You can remove the renderImage part and all the ui/server functions (as stated earlier), simply keeping the render functions and tabsets. My result:

Related

How to display a reactive plot in a shiny app and then pass it as a parameter to a markdown document?

My intention is to explore some data visually using a shiny app and then to pass the resulting plot to a Markdown document. My question is similar to these two I found on stackoverflow.
How to pass reactive data as a R markdown parameter?
How to pass table and plot in Shiny app as parameters to R Markdown?
Unfortunately I am not able to figure out how to use the answers provided to solve my problem. I assume I do not understand the functionality of reactive values enough.
In the MWE I use an input slider in order to create some random numbers that should be displayed in the shiny app. Once the plot has been created in the shiny app I need it to be embedded into the Markdown document. Passing the plot as a parameter to the Markdown does not create an error, however the parameter can not be accessed (seems not to exist) in the Markdown document. But if I cancel out the code in the shiny app to display the plot in the app directly, the plot can be passed to the Markdown document as a parameter and be displayed there.
I understand that I could recreate the plot in the Markdown document, as explained in
How to pass a plot (renderPlot) from shiny app as parameter to R Markdown?. Still I would like to understand if there is a solution to pass the plot without recreating it.
In order to do so I must understand why displaying the plot in the shiny app prevents it to be passed to the Markdown document. What is it that I do not understand? Please help! Thank you!
MWE:
server.R
library(shiny)
shinyServer(function(input, output) {
# create a scatter plot of random numbers
# based on value of input slicer
chart <- reactive({
plot(x = 1:input$dots, y = rnorm(n = input$dots),
xlab = "Numbers", ylab = "Random")
})
# Display the scatter plot in shiny app
# in reaction to actionButton display
observeEvent(eventExpr = input$display,
output$dotPlot <- renderPlot({
chart()
})
)
# Create R-Markdown Report with plot and
# value of input slider as paramters
output$report <- downloadHandler(
filename = "Dot_Report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "Dot_Report.Rmd")
file.copy(from = "Dot_Report.Rmd",
to = tempReport,
overwrite = TRUE)
pars <- list(n = input$dots,
random_plot = reactive(chart()))
rmarkdown::render(input = tempReport,
output_file = file,
params = pars,
envir = new.env(parent = globalenv()))
})
})
MWE: ui.R
library(shiny)
# Define UI for application that displays a Scatter Plot
shinyUI(fluidPage(
# Title
titlePanel("Simple Plot Export"),
# Sidebar with a slider input for number of random numbers
sidebarLayout(
sidebarPanel(
sliderInput("dots",
"Number of Random dots:",
min = 1,
max = 50,
value = 30)
,
actionButton("display", "Display Plot"),
downloadButton("report", "Generate Report")
),
mainPanel(
plotOutput("dotPlot")
)
)
))
MWE: Dot_Report.Rmd
---
title: "Simple Scatter Plot"
output: html_document
params:
n: NA
random_plot: NA
---
```{r, echo = F}
params$random_plot()
The problem here is, that base plots directly draw on a device.
Please see this related answer for workarounds.
Your code is working fine once we switch to e.g. ggplot (only server.R needs to be modified):
library(shiny)
library(ggplot2)
shinyServer(function(input, output) {
# create a scatter plot of random numbers
# based on value of input slicer
chart <- reactive({
DF <- data.frame(x = 1:input$dots, y = rnorm(n = input$dots))
ggplot(data = DF, aes(x = x, y = y)) + geom_point() + xlab("Numbers") + ylab("Random")
})
# Display the scatter plot in shiny app
# in reaction to actionButton display
observeEvent(eventExpr = input$display,
output$dotPlot <- renderPlot({
chart()
})
)
# Create R-Markdown Report with plot and
# value of input slider as paramters
output$report <- downloadHandler(
filename = "Dot_Report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "Dot_Report.Rmd")
file.copy(from = "Dot_Report.Rmd",
to = tempReport,
overwrite = TRUE)
pars <- list(n = input$dots,
random_plot = reactive(chart()))
rmarkdown::render(input = tempReport,
output_file = file,
params = pars,
envir = new.env(parent = globalenv()))
})
})
Edit: Using base plot() along with recordPlot()
server.R:
# create a scatter plot of random numbers
# based on value of input slicer
chart <- reactive({
plot(x = 1:input$dots, y = rnorm(n = input$dots),
xlab = "Numbers", ylab = "Random")
recordPlot()
})
Some related information - see ?dev.new and ?dev.copy:
Only one device is the ‘active’ device: this is the device in which
all graphics operations occur. There is a "null device" which is
always open but is really a placeholder [...]

Render rmarkdown to character variable

I am fairly new to R markdown. I have built an app that requires the user to provide multiple inputs to generate a table, which can then be saved locally.
I have been now asked to implement a sort of report to list all the variables inserted by the user (in a sort of formatted document), so that before generating the table one can review all the settings and change them in case of errors.
To avoid major UI restructure, I thought about using a r markdown document and visualize it inside a modal. My problem is that rmarkdown::render renders to an output, while bs_modal takes for the argument body a character (HTML) variable.
Is there a way to make this work? Or are there better way to accomplish this?
A minimal example:
my .Rmd
---
title: "Dynamic report"
output:
html_document: default
pdf_document: default
params:
n : NA
---
A plot of `r params$n` random points.
```{r, echo=FALSE}
plot(rnorm(params$n), rnorm(params$n))
```
My App.R
library(shiny)
library(bsplus)
library(rmarkdown)
shinyApp(
ui = fluidPage(
selectInput(
inputId = "numb",
label = "Label with modal help",
choices = 50:100
),
actionButton(inputId = "mysheet",
label = "Open modal") %>% bs_attach_modal(id_modal = "modal1"),
textOutput("result")
),
server = function(input, output) {
observeEvent(input$mysheet, {
params <- input$numb
md_out <-
rmarkdown::render(
"report.Rmd",
params = params,
envir = new.env(parent = globalenv())
)
bs_modal(
id = "modal1",
title = "Equations",
body = md_out,
size = "medium"
)
})
output$result <- renderText({
paste("You chose:", input$numb)
})
}
)
bs_modal does not work like this, it must be in the UI. Below is a solution using the classical Shiny modal, no bsplus or other package.
library(shiny)
shinyApp(
ui = fluidPage(
selectInput(
inputId = "numb",
label = "Label with modal help",
choices = 50:100
),
actionButton(inputId = "mysheet",
label = "Open modal"),
textOutput("result")
),
server = function(input, output) {
observeEvent(input$mysheet, {
params <- list(n = input$numb)
md_out <-
rmarkdown::render(
"report.Rmd",
params = params,
envir = new.env(parent = globalenv())
)
showModal(modalDialog(
includeHTML(md_out),
title = "Equations",
size = "m"
))
})
output$result <- renderText({
paste("You chose:", input$numb)
})
}
)
Use html_fragment as the Rmd output:
---
title: "Dynamic report"
output:
html_fragment
params:
n : NA
---
A plot of `r params$n` random points.
```{r, echo=FALSE}
plot(rnorm(params$n), rnorm(params$n))
```

Filtering a DataTable by button / one click (R Flexdashboard)

I am using DT::datatable in a Flexdashboard to provide some monthly KPIs for about 100 different countries. Five of them are of special interest to some of the dashboard’s users, so I am searching for a solution to easily filter on those countries.
My idea was to generate a button next to the Export Buttons that will filter the data on only those five rows. Clicking it again would most perfectly show the original table again.
I found that there is a possibility to specify custom buttons but still I have no clue how to tackle my problem with this.
Here is a tiny example of the table I get so far:
# Random Data Frame
df <- data.frame(Country = paste("Country", 1:100, sep = "_"),
Revenue = rnorm(n = 100, mean = 5000, sd = 2000))
# Data Table used in Dashboard
datatable(df, class = "hover", rownames = FALSE , extensions = 'Buttons', options = list(
pageLength = 5,
responsive = TRUE,
dom = 'Bftip',
buttons = c('copy', 'csv'),
columnDefs = list(list(className = 'dt-center', targets = "_all"))
)) %>% formatCurrency(columns = "Revenue")
Thanks for any help!
I would use a shinyApp embedded within your flexdashboard file.
Note in Your YAML (front matter) you need to set: runtime: shiny
Your Key Pieces of Code are:
Drop Down Selection Code in the UI
Choices you could specify as the FIVE countries of interest for your team.
# Input: Choose dataset ----
selectInput("dataset", "Choose a Country",
choices = as.character(unique(df$Country)))
Download Button
On the server side the logic is applied to only download the filtered data.
# Button
downloadButton("downloadData", "Download")
Reactive Component
This is important as it allows for the data to be dynamically filtered based on the input selection of the user.
# Reactive value for selected dataset ----
datasetInput <- reactive({
df %>% filter(Country ==input$dataset)
})
Finally this allows you to download the filtered data
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(as.character(input$dataset), ".csv", sep = "")
},
content = function(file) {
write.csv(datasetInput(), file, row.names = FALSE)
}
Useful Links
Shiny App Example
Using Shiny in Flex Dashboards
FULL *.Rmd Code Below
---
title: "Filter Data"
output: flexdashboard::flex_dashboard
runtime: shiny
---
```{r global, include=FALSE}
# load data in 'global' chunk so it can be shared by all users of the dashboard
library(shiny)
library(dplyr)
# Random Data Frame
df <- data.frame(Country = paste("Country", 1:100, sep = "_"),
Revenue = rnorm(n = 100, mean = 5000, sd = 2000))
```
To learn more, see [Interactive Documents](http://rmarkdown.rstudio.com/authoring_shiny.html).
## Inputs and Outputs
You can embed Shiny inputs and outputs in your document. Outputs are automatically updated whenever inputs change. This demonstrates how a standard R plot can be made interactive by wrapping it in the Shiny `renderPlot` function. The `selectInput` and `sliderInput` functions create the input widgets used to drive the plot.
```{r eruptions, echo=FALSE}
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a Country",
choices = as.character(unique(df$Country))),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
tableOutput("table")
)
)
)
# Define server logic to display and download selected file ----
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
df %>% filter(Country ==input$dataset)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(as.character(input$dataset), ".csv", sep = "")
},
content = function(file) {
write.csv(datasetInput(), file, row.names = FALSE)
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
```
Below is a reproducible example in Shiny as I do not think what you are trying to do is feasible in a static document. I assume you have set runtime: shiny.
library(DT)
library(shiny)
countries <- data.frame(
cns = LETTERS,
value = runif(26, 1, 4)
)
TOP5 <- c("A", "B", "X", "Y", "Z")
ui <- fluidPage(
actionButton("filter", "Filter countries of interest"),
DTOutput("table")
)
server <- function(input, output, session) {
output$table <- renderDT({
sel <- if(input$filter %% 2 == 0) countries$cns else TOP5
countries %>%
filter(cns %in% sel) %>%
datatable()
})
}
shinyApp(ui, server)

Unable to render Gauge from Flexdashboard library in Shiny app

I am trying to create a Shiny app which
a) prompts user to upload a file which contains numeric data,
b) reads the file and assigns the data points to different variables,
c) calculates new variables from the captured variables
d) display a 'Gauge' using the calculated variables
The code successfully executes but the Gauge chart is not rendered properly. There is no error or warning message either. Instead, I am getting the following message:
"Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON."
And instead of the gauge output I am getting that tiny spec in the middle, as seen in the attached image.
The entire code is fairly long, hence providing just the relevant snippets of code.
Would really appreciate if you can help fix this.
library(shiny)
library(flexdashboard)
ui <- fluidPage(
tabPanel("Sensitivity Analysis",
sidebarLayout(
sidebarPanel(
uiOutput("Sensitivity_Analysis")
),
mainPanel(
gaugeOutput("sensitivity", width = "600px", height = "600px")
)
)
),
server <- function (input, output)
{
output$input_financials=renderUI({
fluidRow(fileInput("file1", "Choose CSV File",multiple = FALSE,accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
actionButton("process","Process"))})
data_input=reactiveValues()
observeEvent(input$process,{
file_input <- input$file1
if (is.null(file_input)) {
return(NULL)}
## File is read and all the inputs are assigned to variables
....
## Output for Gauge begins
output$sensitivity <- flexdashboard::renderGauge({
gauge_limit <- data_input$wc_value
data_input$cash_rel_dpo <- ## Formula for cash_del_dpo
data_input$cash_rel_dro <- ## Formula for cash_del_dro
data_input$cash_rel_dio <- ## Formula for cash_del_dio
data_input$wc_predicted_value <- (data_input$wc_predicted_value - data_input$cash_rel_dpo - data_input$cash_rel_dro - data_input$cash_rel_dio)
gauge(data_input$wc_predicted_value, min = 0, max = gauge_limit,
gaugeSectors(success = c(0, 10000),
warning = c(10001, 50000),
danger = c(50001, 1000000000))
)
})
shinyApp(ui = ui, server = server)
Screenshot of the output generated upon executing the code
There's a similar gauge in package billboarder, try this example:
library(shiny)
library(billboarder)
ui <- fluidPage(
tabPanel(
title = "Sensitivity Analysis",
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
actionButton(inputId = "process", label = "Process (click here to refresh the gauge)")
),
mainPanel(
billboarderOutput("sensitivity", width = "400px", height = "400px")
)
)
)
)
server <- function (input, output) {
data_input <- reactiveValues(x = 0)
observeEvent(input$process, {
data_input$x <- sample.int(1e5, size = 1)
}, ignoreInit = TRUE)
## Output for Gauge begins
output$sensitivity <- renderBillboarder({
billboarder() %>%
bb_gaugechart(
value = data_input$x,
name = "Predicted value",
steps = c(1e4, 5e4, 1e5),
steps_color = rev(c("#FF0000","#F6C600", "#60B044"))
) %>%
bb_gauge(
min = 0, max = 1e5,
units = "",
label = list(
format = htmlwidgets::JS("function(value, ratio) {return d3.format(',')(value);}") # format value with thousand separator
),
width = 80
)
})
}
shinyApp(ui = ui, server = server)

RShiny: Display Multiple Inputs and Text

I would like to display multiple output objects inside a tab in my RShiny app. In the tutorial the tabPanel(...) command only takes argument:
tabPanel("Plot", plotOutput("plot"))
However in the reference docs here, it reads "UI elements to include within the tab" leading me to believe that multiple are possible, but I cannot find examples. I have attempted passing objects to it as a vector c(...) and a list list(...).
Here are the server.R and ui.R I have been testing with (from the Shiny Tutorial).
ui.R
library(shiny)
# Define UI for random distribution application
shinyUI(fluidPage(
# Application title
titlePanel("Tabsets"),
# Sidebar with controls to select the random distribution type
# and number of observations to generate. Note the use of the
# br() element to introduce extra vertical spacing
sidebarLayout(
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
))
server.R
library(shiny)
# Define server logic for random distribution application
shinyServer(function(input, output) {
# Reactive expression to generate the requested distribution.
# This is called whenever the inputs change. The output
# functions defined below then all use the value computed from
# this expression
data <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data. Also uses the inputs to build
# the plot label. Note that the dependencies on both the inputs
# and the data reactive expression are both tracked, and
# all expressions are called in the sequence implied by the
# dependency graph
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(data(),
main=paste('r', dist, '(', n, ')', sep=''))
})
# Generate a summary of the data
output$summary <- renderPrint({
summary(data())
})
# Generate an HTML table view of the data
output$table <- renderTable({
data.frame(x=data())
})
})
The following worked for me:
mainPanel(
tabsetPanel(
tabPanel("Some Title",
h5(textOutput("some text output")),
htmlOutput("someHTMLElement")
),
tabPanel("Other Title",
h5(textOutput("some other text output")),
htmlOutput("otherHTMLElement")
),
tabPanel("Yet Another Title",
h5(textOutput("yet another text output")),
htmlOutput("yetAnotherHTMLElement")
)
)
Function tabPanel specification is
tabPanel(title, ..., value = NULL)
which means that it accepts variable number of parameters for "UI elements to include within the tab"

Resources