Output html from function during knitr output - html

This is a small sample of many separate analyses I want to run together, flagging each analysis with a heading generated in the function. The first heading outputs as expected, but the headings generated by the function do not. How can I get the headings generated by the function to format as html?
R version 3.3.2 (2016-10-31)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X El Capitan 10.11.6
RStudio 1.0.136
knitr 1.15.1
```{r initialize, echo=F, comment=NA}
htmPrint = function(htm) {
structure(htm, class='knit_asis')
}
doAnalysis = function(dat, depVar, indVar) {
print(htmPrint(paste0('<h3>AusMCP1 on ', indVar, '</h3>')))
eval(parse(text=paste0('print(summary(lm(', depVar, '~', indVar, ', data=dat)))')))
print(htmPrint('<hr>'))
}
demoData = data.frame(dep1=rnorm(100), dep2=rnorm(100), ind1=runif(100), ind2=runif(100), ind3=runif(100))
varDep = names(demoData)[1:2]
varInd = names(demoData)[3:5]
```
This is a small sample of many separate analyses I want to run together, flagging each analysis with a heading generated in the function.
I could use *results=asis* in the chunk command, but it produces
unwanted formatting and extraneous output in the analysis output.
```{r doAnalyses}
htmPrint('<h2>Begin analyses</h2>')
for (k in 1:length(varDep)) for (i in 1:length(varInd)) doAnalysis(demoData, varDep[k], varInd[i])
```

I think you'll have to use results = 'asis' and just alter you function to get the output that you want. I'm going to use some methods referenced in a previous question that make use of the package pander.
You don't have to use your htmPrint function as you can get the same functionality with cat and html tags. Then you'd just use print_lm instead of print and remove the summary, since you're getting nice tabular output.
```{r initialize, echo=F, comment=NA}
library(pander)
#Use the pander print method to print the model tables.
#You could use other package print methods as well.
print_lm <- function (x, ...) UseMethod("pander")
doAnalysis = function(dat, depVar, indVar) {
cat('<h3>AusMCP1 on ', indVar, '</h3>')
eval(parse(text=paste0('print_lm(summary(lm(', depVar, '~', indVar, ', data=dat)))')))
cat('<hr>')
}
demoData = data.frame(dep1=rnorm(100), dep2=rnorm(100), ind1=runif(100), ind2=runif(100), ind3=runif(100))
varDep = names(demoData)[1:2]
varInd = names(demoData)[3:5]
```
I use *results=asis* and changed the output of your doAnalysis function to create formatted output.
```{r doAnalyses, echo = FALSE, results='asis'}
cat('<h2>Begin analyses</h2>')
for (k in 1:length(varDep)) for (i in 1:length(varInd)) doAnalysis(demoData, varDep[k], varInd[i])
```
You could also do all of the modelling beforehand, and use the broom package to tidy all of your model summaries to your liking, then print them out using kable() or tabular print method of your choice.

Related

embed shiny app into Rmarkdown html document

I am able to create an Rmarkdown file and I'm trying to embed a shiny app into the html output. The interactive graph shows if I run the code in the Rmarkdown file. But in the html output it only shows a blank box. Can anybody help fix it?
Run the code in Rmarkdown file:
In the html output:
My Rmarkdown file (please add the three code sign at the end yourself somehow i cannot do here):
---
title: "Data Science - Tagging"
pagetitle: "Data Science - Style Tagging"
author:
name: "yyy"
params:
creation_date: "`r format(Sys.time(), c('%Y%m%d', '%h:%m'))`"
runtime: shiny
---
```{r plt.suppVSauto.week.EB, out.width = '100%'}
data <- data.frame(BclgID = c('US','US','US','UK','UK','UK','DE','DE','DE'),
week = as.Date(c('2020-06-28', '2020-06-21', '2020-06-14', '2020-06-28', '2020-06-21', '2020-06-14', '2020-06-28', '2020-06-21', '2020-06-14')),
value = c(1,2,3,1,2,2,3,1,1))
shinyApp(
ui <- fluidPage(
radioButtons(inputId = 'BclgID', label = 'Catalog',
choices = type.convert(unique(plot$BclgID), as.is = TRUE),
selected = 'US'),
plotOutput("myplot")
),
server <- function(input, output) {
mychoice <- reactive({
subset(data, BclgID %in% input$BclgID)
})
output$myplot <- renderPlot({
if (length(row.names(mychoice())) == 0) {
print("Values are not available")
}
p <- ggplot(mychoice(), aes(x=as.factor(week), y=value)) +
geom_line() +
labs(title = "test",
subtitle = "",
y="Value",
x ="Date") +
theme(axis.text.x = element_text(angle = 90)) +
facet_wrap( ~ BclgID, ncol = 1)
print(p)
}, height = 450, width = 450)
}
)
EDIT:
Coming back another year later in case anyone still finds this useful. Having done some more work with both shiny and rmarkdown so I understand both better, there isn't really a reason to use them together. Rmarkdown's advantage is being able to come up with a somewhat static pdf that is readable, where shiny is dynamic and requires input.
While my answer below works, if you're using shiny for a GUI, consider removing the rmarkdown portion of what you are writing. It probably isn't adding much/anything, and trying to use the two together can cause headaches.
Original answer below:
I see this was asked a long time ago, so you've probably moved on, but I ran into the same problem and this came up first, so I'll answer it in case anyone else runs into this problem.
I found the answer on this page:
https://community.rstudio.com/t/embedding-shiny-with-inline-not-rendering-with-html-output/41175
The short of it is shiny documents need to be run and not rendered. Rather than calling:
>rmarkdown::render("filename.rmd")
we need to call:
>rmarkdown::run("filename.rmd")
If you are inside Rstudio, it seems the "knit" function changes from render to run when using shiny in RMD.

How to get descriptive table for both continuous and categorical variables?

I want to get descriptive table in html format for all variables that are in data frame. I need for continuous variables mean and standard deviation. For categorical variables frequency (absolute count) of each category and percentage of each category. Also I need the count of missing values to be included.
Lets use this data:
data("ToothGrowth")
df<-ToothGrowth
df$len[2]<-NA
df$supp[5]<-NA
I want to get table in html format that will look like this:
----------------------------------------------------------------------
Variables N (missing) Mean (SD) / %
----------------------------------------------------------------------
len 59 (1) 18.9 (7.65)
supp
OJ 30 50%
VC 29 48.33%
NA 1 1.67%
dose 60 1.17 (0.629)
I need also to set the number of digits after decimal point to show.
If you know better variant to display that information in html in better way than please provide your solution.
Here's a programatic way to create separate summary tables for the numeric and factor columns. Note that this doesn't make note of NAs in the table as you requested, but does ignore NAs to calculate summary stats as you did. It's a starting point, anyway. From here you could combine the tables and format the headers however you want.
If you knit this code within an RMarkdown document with HTML output, kable will automatically generate the html table and a css will format the table nicely with a horizontal rules as pictured below. Note that there's also a booktabs option to kable that makes prettier tables like the LaTeX booktabs package. Otherwise, see the documentation for knitr::kable for options.
library(dplyr)
library(tidyr)
library(knitr)
data("ToothGrowth")
df<-ToothGrowth
df$len[2]<-NA
df$supp[5]<-NA
numeric_cols <- dplyr::select_if(df, is.numeric) %>%
gather(key = "variable", value = "value") %>%
group_by(variable) %>%
summarize(count = n(),
mean = mean(value, na.rm = TRUE),
sd = sd(value, na.rm = TRUE))
factor_cols <- dplyr::select_if(df, is.factor) %>%
gather(key = "variable", value = "value") %>%
group_by(variable, value) %>%
summarize(count = n()) %>%
mutate(p = count / sum(count, na.rm = TRUE))
knitr::kable(numeric_cols)
knitr::kable(factor_cols)
I found r package table1 that does what I want. Here is a code:
library(table1)
data("ToothGrowth")
df<-ToothGrowth
df$len[2]<-NA
df$supp[5]<-NA
table1(reformulate(colnames(df)), data=df)

Using R and plot.ly, how to save multiples htmlwidgets to my html?

I´m starting to play with plot.ly in R and I´m amazed with the possibilities to publish my graphs directly in html using htmlwidgets.
Until now I´m unable to save multiple widgets in the same html.
I have saved multiple widgets in stand-alone htmls and than combine it by hand in the html code, but I would like to be able to do it in R.
A simple example:
#graph
graph<- ggplot(df, aes(x = Data, y=tax))+ geom_bar(stat='identity')
gg <- ggplotly(graph)
# save as HtmlWigdet
htmlwidgets::saveWidget(as.widget(gg), "Index.html")
How can I parse multiple ggplotly objects to saveWidgets?
(This is my first question here in stackoverflow, hope I did it right! Regards!)
This is the function I adapted from bits and pieces of the htmltools package to save a tag list and then return an iframe tag. You can wrap multiple htmlwidgets with htmltools::tagList, and then use this function to save the whole bunch.
save_tags <- function (tags, file, selfcontained = F, libdir = "./lib")
{
if (is.null(libdir)) {
libdir <- paste(tools::file_path_sans_ext(basename(file)),
"_files", sep = "")
}
htmltools::save_html(tags, file = file, libdir = libdir)
if (selfcontained) {
if (!htmlwidgets:::pandoc_available()) {
stop("Saving a widget with selfcontained = TRUE requires pandoc. For details see:\n",
"https://github.com/rstudio/rmarkdown/blob/master/PANDOC.md")
}
htmlwidgets:::pandoc_self_contained_html(file, file)
unlink(libdir, recursive = TRUE)
}
return(htmltools::tags$iframe(src= file, height = "400px", width = "100%", style="border:0;"))
}
What is the use-case you're after? You may want to consider adding these graphs to a Flexdashboard (which is created in R Markdown). It's been my recent goto, combined with Plotly.

Generate an HTML report based on user interactions in shiny

I have a shiny application that allows my user to explore a dataset. The idea is that the user explores the dataset, and any interesting things the user finds he will share with his client via email. I don't know in advance how many things the user will find interesting. So, next to each table or chart I have an "add this item to the report" button, which isolates the current view and adds it to a reactiveValues list.
Now, what I want to do is the following:
Loop through all the items in the reactiveValues list,
Generate some explanatory text describing the item (This text should preferably be formatted HTML/markdown, rather than code comments)
Display the item
Capture the output of this loop as HTML
Display this HTML in Shiny as a preview
write this HTML to a file
knitr seems to do exactly the reverse of what I want - where knitr allows me to add interactive shiny components in an otherwise static document, I want to generate HTML in shiny (maybe using knitr, I don't know) based on static values the user has created.
I've constructed a minimum not-working example below to try to indicate what I would like to do. It doesn't work, it's just for demonstration purposes.
ui = shinyUI(fluidPage(
title = "Report generator",
sidebarLayout(
sidebarPanel(textInput("numberinput","Add a number", value = 5),
actionButton("addthischart", "Add the current chart to the report")),
mainPanel(plotOutput("numberplot"),
htmlOutput("report"))
)
))
server = shinyServer(function(input, output, session){
#ensure I can plot
library(ggplot2)
#make a holder for my stored data
values = reactiveValues()
values$Report = list()
#generate the plot
myplot = reactive({
df = data.frame(x = 1:input$numberinput, y = (1:input$numberinput)^2)
p = ggplot(df, aes(x = x, y = y)) + geom_line()
return(p)
})
#display the plot
output$numberplot = renderPlot(myplot())
# when the user clicks a button, add the current plot to the report
observeEvent(input$addthischart,{
chart = isolate(myplot)
isolate(values$Report <- c(values$Report,list(chart)))
})
#make the report
myreport = eventReactive(input$addthischart,{
reporthtml = character()
if(length(values$Report)>0){
for(i in 1:length(values$Report)){
explanatorytext = tags$h3(paste(" Now please direct your attention to plot number",i,"\n"))
chart = values$Report[[i]]()
theplot = HTML(chart) # this does not work - this is the crux of my question - what should i do here?
reporthtml = c(reporthtml, explanatorytext, theplot)
# ideally, at this point, the output would be an HTML file that includes some header text, as well as a plot
# I made this example to show what I hoped would work. Clearly, it does not work. I'm asking for advice on an alternative approach.
}
}
return(reporthtml)
})
# display the report
output$report = renderUI({
myreport()
})
})
runApp(list(ui = ui, server = server))
You could capture the HTML of your page using html2canvas and then save the captured portion of the DOM as a image using this answer, this way your client can embed this in any HTML document without worrying about the origin of the page contents

integrating manipulate outputs with knitr

I was wondering if there is a way in which its possible to integrate the manipulate package or gWidgetsManipulate package so that their outputs can be viewable/manipulable in the html/markdown output file, as I think that this would be extremely useful when developing reproducible interactive research reports. I know that googleVis has some functionality that allows it to be integrated with knitr so that the outputs go into the html file by using options like results='asis' but googleVis is currently quite restrictive in its capabilities when using sliders for example.
If the package outputs of manipulate or gWidgetsManipulate hasn't quite been integrated yet, would it be possible to suggest a workaround for the time being that will allow it to be viewed in the html file?
i.e. my current code in my Rmd file before running knitr-ing to html looks like the below...but I get the following errors.
```{r}
library(manipulate)
manipulate(plot(1:x), x = slider(5, 10))
```
with output
library(manipulate)
## Error: there is no package called 'manipulate'
manipulate(plot(1:x), x = slider(5, 10))
## Error: could not find function "manipulate"
so trying the package gWidgetsManipulate instead...
```{r}
library(gWidgetsManipulate)
manipulate(plot(1:x), x = slider(5, 10))
```
you get the error...
library("gWidgetsManipulate")
## Loading required package: gWidgets
manipulate(plot(1:x), x = slider(5, 10))
## Error: unable to find an inherited method for function ".gwindow", for signature "NULL"
I have tried to specify a guiToolkit to fix this error by using things like
options(guiToolkit="WWW")
but to no avail...
Any help would be greatly appreciated, thanks in advance
If you don't absolutely need to use the gwidgets, I have a solution with Rook and googleVis that does what you want: displaying an interactive chart in html.
The script for the slider: it contains a little javascript function to display the currently chosen value. It also submits the form at each change. You can easily change the min/max/... values here.
slider_script <- '
<input type="range" min="5" max="10" name="plot_max" value="%s" step="1" onchange="document.form1.submit(); showValue(this.value);" />
<span id="range">%s</span>
<script type="text/javascript">
function showValue(newValue)
{
document.getElementById("range").innerHTML=newValue;
}
</script>
'
We build the code of the web page. The structure is typical for rook: html code is written inside res$write().
### this script builds the webpage
webreport_app <- function(
){
newapp = function(env) {
req = Rook::Request$new(env)
res = Rook::Response$new()
# initialise variables for first execution
if (is.null(req$POST())){
plot_max <- 5
} else{
plot_max <- as.numeric(req$POST()[["plot_max"]])
}
res$write('<body style="font-family:Arial">')
res$write("<H3>My App</H3>")
res$write('<form name = "form1" method="POST">\n')
res$write('<br> Number of dots: \n')
res$write(sprintf(slider_script, plot_max, plot_max))
res$write('<br><input type="submit" name="Go!">\n</form>\n')
if (!is.null(req$POST())) {
# generate the plot
library(googleVis)
data_for_plot <- data.frame(x_var = 1:plot_max, y_var = 1:plot_max)
Scatter1 <- gvisScatterChart(data_for_plot)
# extract chart script
chart_script <- capture.output(print(Scatter1, 'chart'))
# write to html
res$write(paste(chart_script, collapse="\n"))
res$write("<br><br></body></html>")
}
res$finish()
}
return(newapp)
}
And finally launch the setup and launch the html server via Rook:
library(Rook)
# launch the web app
if (exists("report_server")){
report_server$remove(app, all = TRUE)
report_server$stop()
rm(report_server)
}
report_server = Rhttpd$new()
report_server$add(app = webreport_app(), name = "My_app")
report_server$start()
report_server$browse("My_app")
report_server$browse()