<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Flexdashboard on R Views</title>
    <link>https://rviews.rstudio.com/tags/flexdashboard/</link>
    <description>Recent content in Flexdashboard on R Views</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 23 Jan 2019 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://rviews.rstudio.com/tags/flexdashboard/" rel="self" type="application/rss+xml" />
    
    
    
    
    <item>
      <title>Onboard and Offboard Data Manipulation in Flexdashboard</title>
      <link>https://rviews.rstudio.com/2019/01/23/onboard-and-offboard-data-manipulation-in-flexdashboard/</link>
      <pubDate>Wed, 23 Jan 2019 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2019/01/23/onboard-and-offboard-data-manipulation-in-flexdashboard/</guid>
      <description>
        

&lt;p&gt;&lt;a href=&#34;https://csbaonline.org/about/people/staff/harrison-schramm&#34;&gt;Harrison Schramm&lt;/a&gt; is a Professional Statistician and Non-Resident Senior Fellow at the Center for Strategic and Budgetary Assessments.&lt;/p&gt;

&lt;p&gt;The Shiny set of tools, and, by extension, Flexdashboard, give professional analysts tools to rapidly put interactive versions of their work in the hands of clients.  Frequently, an end user will interact with data by either uploading or downloading a new set in its entirety (typically from a .csv or other similarly structured source), or do so ‘on the fly’ interactively, using tools like RHandsonTable.  What if you want to do both at the same time?  That is – what if you want to be able to change data interactively, or completely upload a new database &lt;em&gt;without stopping the current instance&lt;/em&gt;  or other ‘clunky’ things?&lt;/p&gt;

&lt;p&gt;It turns out that you can, and the implementation is relatively straightforward.  In this post, our aims are to:
a.  Make the reader more familiar with reactivity, particularly with respect to initializing and containerizing variables
b.  Show how to manage a single object that can be ‘touched’ by the uploadHandler and rHandsonTable
c.  Provide a worked example in Flexdashboard&lt;/p&gt;

&lt;p&gt;We need to create an environment where a data object that may be manipulated by functions inside an app is initialized to a pre-loaded set.  At runtime, the object may be downloaded to a .csv, manipulated directly in a spreadsheet-like interface, or replaced completely with an upload.&lt;/p&gt;

&lt;p&gt;In the following sections, we highlight the working parts of the minimal example (also provided) based on the attributes of different ships in Star Wars.&lt;/p&gt;

&lt;h2 id=&#34;step-1-initialization&#34;&gt;Step 1:  Initialization&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;library(flexdashboard)
library(dplyr)
library(magrittr)
library(rhandsontable)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After calling the applicable libraries (above), we load a starter dataset so that the application isn’t empty when launched.  We also create a &lt;code&gt;reactiveValues&lt;/code&gt; object called &lt;code&gt;values&lt;/code&gt; that sets the handsontable &lt;code&gt;hot&lt;/code&gt; to NULL.  This is necessary because the handsontable object is self-referential in the sense that it is both an output and input device.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;BFL = read.csv(&amp;quot;StarterExampleData.csv&amp;quot;)
BFL$Exclude = FALSE
values &amp;lt;- reactiveValues(hot = NULL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;strong&gt;main&lt;/strong&gt; trick is to hold the R dataframe in a reactive environment that responds to both the handsontable object and the upload handler.  This is done by a series of nested &lt;code&gt;if&lt;/code&gt; statements, that, in order, make the object equal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the initialization file, if the object is empty (from the previous code chunk),&lt;/li&gt;
&lt;li&gt;the uploaded file (from the upload handler, below),&lt;/li&gt;
&lt;li&gt;and finally the handsontable object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note the unglamorous statement &lt;code&gt;read.csv(input$InputBFL$datapath)&lt;/code&gt;.  This is necessary when reading a file provided by an upload handler.  Simply reading the handle attached to the csv will point to the &amp;lsquo;box&amp;rsquo;, not what is &amp;lsquo;in&amp;rsquo; the box.&lt;/p&gt;

&lt;p&gt;This is different than the approaches advocated on many forums where the initialization is done in the &lt;code&gt;rhandsontable&lt;/code&gt; code.  That approach is perfectly valid, but does not offer the flexibility of an uploaded file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;BFLD = reactive({
  if(is.null(input$hot)){BFL}
  else if(!is.null(input$InputBFL)){read.csv(input$InputBFL$datapath)} 
  else{
  hot_to_r(input$hot)
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;step-2-file-handlers&#34;&gt;Step 2: File Handlers&lt;/h2&gt;

&lt;p&gt;Now that we have set up the reactive structure for the object &lt;code&gt;BFLD&lt;/code&gt;, which can be accessed by other functions inside our code, we add the functionality for the upload and download handlers.&lt;/p&gt;

&lt;p&gt;The download function is two separate items: the &lt;code&gt;downloadButton&lt;/code&gt; that triggers the action, and the &lt;code&gt;downloadHandler&lt;/code&gt; that performs the interface.  In Shiny apps, the linkage is explicit.  In Flexdashboard, the linkage is made by putting the handler immediately after the button.  &lt;em&gt;Note:  The handlers do not always work in the RStudio App window; it may be necessary to &amp;lsquo;open in browser&amp;rsquo;&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r,&#34;&gt;downloadButton(&amp;quot;StarWarsDownload&amp;quot;, label = &amp;quot;Star Wars Download&amp;quot;)
downloadHandler(
  filename = function(){&amp;quot;Star_Wars_Download.csv&amp;quot;},
  content = function(file){
    write.csv(BFLD(), file)
  }
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The upload function is a single block.  Here the input File is linked to the reactive variable built in Step 1 by the handle &lt;code&gt;input$InputBFL&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r,&#34;&gt;fileInput(&amp;quot;InputBFL&amp;quot;, &amp;quot;Choose CSV File&amp;quot;,
                multiple = FALSE,
                accept = c(&amp;quot;text/csv&amp;quot;,
                         &amp;quot;text/comma-separated-values,text/plain&amp;quot;,
                         &amp;quot;.csv&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;step-3-hands-on-table&#34;&gt;Step 3: Hands On Table&lt;/h2&gt;

&lt;p&gt;In the final step, we transform the stored reactive object &lt;code&gt;BFLD&lt;/code&gt; into a handsontable object, and output.  Note that because it is a reactive object, we call it as &lt;code&gt;BFLD()&lt;/code&gt; with parentheses, and inside a &amp;lsquo;render&amp;rsquo; context.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r,&#34;&gt;output$hot = renderRHandsontable({
  rhandsontable(BFLD(), height = 550) %&amp;gt;%  hot_rows()
})
rHandsontableOutput(&amp;quot;hot&amp;quot;) 
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We hope that this minimal example will help you use both &lt;code&gt;rhandsontable&lt;/code&gt; and upload/download handlers in flexdashboard.  There should be enough code and explanations here for simpler cases.  These code chunks should help you worry less about IO handling in your applications and spend more time on graphics and analysis. Look &lt;a href=&#34;https://hschramm.shinyapps.io/UploadDownloadMinEx/&#34;&gt;here&lt;/a&gt; to see the example working.&lt;/p&gt;

&lt;p&gt;While we did not develop it here, it seems that this same construct could be used to add a web-based data source.&lt;/p&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2019/01/23/onboard-and-offboard-data-manipulation-in-flexdashboard/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>Enterprise Dashboards with R Markdown</title>
      <link>https://rviews.rstudio.com/2018/05/16/replacing-excel-reports-with-r-markdown-and-shiny/</link>
      <pubDate>Wed, 16 May 2018 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2018/05/16/replacing-excel-reports-with-r-markdown-and-shiny/</guid>
      <description>
        


&lt;p&gt;&lt;em&gt;This is a second post in a series on enterprise dashboards. See our previous post, &lt;a href=&#34;https://rviews.rstudio.com/2017/09/20/dashboards-with-r-and-databases/&#34;&gt;Enterprise-ready dashboards with Shiny Databases&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We have been living with spreadsheets for so long that most office workers think it is obvious that spreadsheets generated with programs like &lt;a href=&#34;https://products.office.com/en-us/excel&#34;&gt;Microsoft Excel&lt;/a&gt; make it easy to understand data and communicate insights. Everyone in a business, from the newest intern to the CEO, has had some experience with spreadsheets. But using Excel as the de facto analytic standard is problematic. Relying exclusively on Excel produces environments where it is almost impossible to organize and maintain efficient operational workflows. In addition to fostering low productivity, organizations risk profits and reputations in an age where insightful analyses and process control translate to a competitive advantage. Most organizations want better control over accessing, distributing, and processing data. You can use the R programming language, along with with R Markdown reports and RStudio Connect, to build enterprise dashboards that are robust, secure, and manageable.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-05-16-replacing-excel-with-r-markdown-and-shiny/tracker-excel.png&#34; width=&#34;400&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;This Excel dashboard attempts to function as a real application by allowing its users to filter and visualize key metrics about customers. It took dozens of hours to build. The intent was to hand off maintenance to someone else, but the dashboard was so complex that the author was forced to maintain it. Every week, the author copied data from an ETL tool and pasted it into the workbook, spot checked a few cells, and then emailed the entire workbook to a distribution list. Everyone on the distribution list got a new copy in their inbox every week. There were no security controls around data management or data access. Anyone with the report could modify its contents. The update process often broke the brittle cell dependencies; or worse, discrepancies between weeks passed unnoticed. It was almost impossible to guarantee the integrity of each weekly report.&lt;/p&gt;
&lt;div id=&#34;why-coding-is-important&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Why coding is important&lt;/h3&gt;
&lt;p&gt;Excel workbooks are hard to maintain, collaborate on, and debug because they are not reproducible. The content of every cell and the design of every chart is set without ever recording the author’s actions. There is no simple way to recreate an Excel workbook because there is no recipe (i.e., set of instructions) that describes how it was made. Because Excel workbooks lack a recipe, they tend to be hard to maintain and prone to errors. It takes care, vigilance, and subject-matter knowledge to maintain a complex Excel workbook. Even then, human errors abound and changes require a lot of effort.&lt;/p&gt;
&lt;p&gt;A better approach is to write code. There are many &lt;a href=&#34;https://twitter.com/MaartenvSmeden/status/995791001825431552&#34;&gt;reasons to start programming&lt;/a&gt;. When you create a recipe with code, anyone can reproduce your work (including your future self). The act of coding implicitly invites others to collaborate with you. You can systematically validate and debug your code. All of these things lead to better code over time. Coding in R has particular advantages given its vast ecosystem of packages, its vibrant community, and its powerful tool chain.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;using-r-markdown&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Using R Markdown&lt;/h3&gt;
&lt;p&gt;There are many tools for replacing complex Excel dashboards with R code. One of these tools is &lt;a href=&#34;https://rmarkdown.rstudio.com/&#34;&gt;R Markdown&lt;/a&gt;, an open-source R package that turns your analyses into high quality documents, reports, presentations and dashboards. R Markdown documents are fully reproducible and support dozens of output formats including HTML, PDF, and Microsoft Word documents.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-05-16-replacing-excel-with-r-markdown-and-shiny/tracker-rmd.png&#34; width=&#34;400&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;http://colorado.rstudio.com/rsc/tracker-report/tracker-report.html&#34;&gt;Here&lt;/a&gt; is the same Excel dashboard translated to an R Markdown report. Because this report is written in code, it is vastly simpler and easier to maintain. Like the Excel dashboard above, this R Markdown report is designed to take user inputs so that it could render custom report versions.&lt;/p&gt;
&lt;p&gt;Many people are already aware that R Markdown reports combine narrative, code, and output in a single document. What is less commonly known is that you can generalize any R Markdown report by declaring parameters in the document header. R Markdown documents with parameters are known as &lt;a href=&#34;https://rmarkdown.rstudio.com/developer_parameterized_reports.html&#34;&gt;parameterized reports&lt;/a&gt;. In the Excel dashboard users can select &lt;code&gt;segment&lt;/code&gt;, &lt;code&gt;group&lt;/code&gt;, and &lt;code&gt;period&lt;/code&gt;. In a parameterized R Markdown document, you would specify these inputs with the following YAML header:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Customer Tracker Report
output: html_notebook
params:
  seg: 
    label: &amp;quot;Segment:&amp;quot;
    value: Total
    input: select
    choices: [Total, Heavy, Mainstream, Focus1, Focus2, 
              Specialty, Diverse1, Diverse2, Other, New]
  grp: 
    label: &amp;quot;Group:&amp;quot;
    value: Total
    input: select
    choices: [Total, Core, Extra]
  per: 
    label: &amp;quot;Period:&amp;quot;
    value: Week
    input: radio
    choices: [Week, YTD]
---&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then call the parameters you declare in the YAML header from your R code chunks.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```{r}
params$segment
params$grp
params$per
```&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can render the document with different inputs by selecting &lt;a href=&#34;https://rmarkdown.rstudio.com/developer_parameterized_reports.html#parameter_user_interfaces&#34;&gt;knit with parameters&lt;/a&gt; in RStudio. This option will open a user interface that allows you to select the parameters you want.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://media.giphy.com/media/vwicMYfRPL6YuRQGfo/giphy.gif&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;If you want to automate the process of creating custom report versions, you can render these documents programmatically with the &lt;code&gt;rmarkdown::render()&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rmarkdown::render(
  input = &amp;quot;tracker-report.Rmd&amp;quot;, 
  params = list(seg = &amp;quot;Focus1&amp;quot;, grp = &amp;quot;Core&amp;quot;, per = &amp;quot;Weekly&amp;quot;)
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;publishing-to-rstudio-connect&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Publishing to RStudio Connect&lt;/h3&gt;
&lt;p&gt;Managing access and permissions for an ocean of Excel files is painful. Data in Excel spreads through an organization without controls like a virus spreads through a body without disease prevention. There are better ways to secure the operation, access, and distribution of information.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://media.giphy.com/media/9M52kMrLHrDfxI3nrq/giphy.gif&#34; /&gt;

&lt;/div&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-05-16-replacing-excel-with-r-markdown-and-shiny/pb-publishing.png&#34; width=&#34;50&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;RStudio Connect is a server product from RStudio that is designed for secure sharing of R content. It is on-premises software you run behind your firewall. You keep control of your data and of who has access. With RStudio Connect, you can see all your content, decide who should be able to view and collaborate on it, tune performance, schedule updates, and view logs. You can schedule your R Markdown reports to run automatically or even distribute the latest version by email.&lt;/p&gt;
&lt;p&gt;When you publish a parameterized R Markdown report to RStudio Connect, an interface appears for selecting inputs. Viewers can create new report versions, then email themselves a copy. Collaborators can save and schedule new report versions, then email others a copy. You can even attach &lt;a href=&#34;http://docs.rstudio.com/connect/1.6.2/user/r-markdown.html#r-markdown-output-files&#34;&gt;output files&lt;/a&gt; to these versions. Using parameterized R Markdown documents in RStudio Connect is a powerful way to communicate information.&lt;/p&gt;
&lt;p&gt;You can publish content from the RStudio IDE by clicking the &lt;a href=&#34;https://support.rstudio.com/hc/en-us/articles/228270928-Push-button-publishing-to-RStudio-Connect&#34;&gt;Publish button&lt;/a&gt; that looks like a blue Eye of Horus. Pressing this button will begin the publishing process. First, it creates a set of instructions for recreating your content. Second, it deploys your content bundle to the server. Third, it recreates your content on RStudio Connect. Push-button publishing has a long history of being used with RStudio. In 2012, RStudio enabled push-button publishing of R Markdown documents to &lt;a href=&#34;https://rpubs.com/&#34;&gt;RPubs&lt;/a&gt;. In 2014, RStudio enabled push-button publishing of Shiny apps to &lt;a href=&#34;http://www.shinyapps.io/&#34;&gt;shinyapps.io&lt;/a&gt;. In 2016, RStudio enabled push-button publishing to &lt;a href=&#34;https://www.rstudio.com/products/connect/&#34;&gt;RStudio Connect&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;adding-shiny&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Adding Shiny&lt;/h3&gt;
&lt;p&gt;R Markdown documents are rendered with batch processing. That makes them ideal for automation, long running workflows, and custom report versions. However, if you want your documents to be immediately reactive to user input, then you can add a Shiny runtime. These &lt;a href=&#34;https://rmarkdown.rstudio.com/authoring_shiny.html&#34;&gt;interactive documents&lt;/a&gt; behave like a Shiny application in that they must be hosted. You can host &lt;a href=&#34;https://rmarkdown.rstudio.com/authoring_shiny.html&#34;&gt;interactive documents&lt;/a&gt; and &lt;a href=&#34;http://shiny.rstudio.com/&#34;&gt;Shiny applications&lt;/a&gt; with RStudio Connect. Deciding when to choose between R Markdown, interactive documents, and Shiny applications is a subject for a later post.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;Reproducible code in R leads to better analysis and collaboration. You can use parameterized R Markdown reports to create complex, interactive dashboards. Hosting these dashboards securely in RStudio Connect gives you control over accessing, distributing, and processing data. You can use the R programming language, along with with R Markdown reports and RStudio Connect, to build enterprise dashboards that are robust, secure, and manageable.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Click &lt;a href=&#34;https://github.com/sol-eng/customer-tracker&#34;&gt;here&lt;/a&gt; for source code.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2018/05/16/replacing-excel-reports-with-r-markdown-and-shiny/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>Printing From Flex Dashboard</title>
      <link>https://rviews.rstudio.com/2017/06/28/printing-from-flex-dashboard/</link>
      <pubDate>Wed, 28 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2017/06/28/printing-from-flex-dashboard/</guid>
      <description>
        


&lt;p&gt;Shiny applications of all stripes (including &lt;a href=&#34;http://rmarkdown.rstudio.com/flexdashboard/shiny.html&#34;&gt;flexdashboard with runtime Shiny&lt;/a&gt;) are revolutionary in that they put the power of R directly in the end user’s hands without needing to interact directly with the language. A common way end-users wish to interact with their data is via a dashboard that they can manipulate on the fly. &lt;a href=&#34;http://rmarkdown.rstudio.com/flexdashboard/&#34;&gt;Flexdashboard&lt;/a&gt; streamlines the process of turning an R-based analysis into a dashboard, so R users can create good-looking output for their analyses - and deploy this output to the web - with very little additional effort.&lt;/p&gt;
&lt;p&gt;There are various ways to extract information from flexdashboard, but no good way to programatically return a printable version of the &lt;em&gt;dashboard itself&lt;/em&gt;. This is partially by design - responsive HTML dashboards aren’t meant to be printed. There are &lt;a href=&#34;https://shiny.rstudio.com/articles/generating-reports.html&#34;&gt;well-documented workflows&lt;/a&gt; about how to share information between a web-centric output and a complementary report that renders to a printable format.&lt;/p&gt;
&lt;p&gt;That said, there are some reasons to want a printable output that looks similar to a related HTML report. Snapshots are valuable for documentation/training materials, for embedding in emails or other reports, or for the all-too-common case of meetings with executives who like dashboards but want to consume paper-based reports. Plus, flexdashboards are an incredibly quick way to create visually appealing &lt;em&gt;(read: pretty)&lt;/em&gt; summary output of a combination of outputs on a single page.&lt;/p&gt;
&lt;p&gt;Both Harrison and Aaron&lt;a href=&#34;#fn1&#34; class=&#34;footnoteRef&#34; id=&#34;fnref1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; have struggled with trying to print flexdashboards in their respective practices. In a recent instance, Harrison was working with a client whose end users would be carrying snapshots of the dashboard into an industrial setting where mobile devices were not desired. It was important to the client to maintain a similar look between the on-screen and paper representations of the dashboard. It was also important to make generating these snapshots an integrated part of the application; it was not sufficient to suggest that the client manually take a screenshot of their browser window. This turned out to be a blessing, because (as you will see below) it allows the creation of a web-friendly ‘tabbed’ report with a companion ‘flat’ printed rendering.&lt;/p&gt;
&lt;div id=&#34;specific-task&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Specific Task&lt;/h3&gt;
&lt;p&gt;Our goal was to create a “printable” flexdashboard with runtime Shiny. Flexdashboard produces a beautiful HTML dashboard with very little effort. &lt;a href=&#34;https://shiny.rstudio.com/articles/interactive-docs.html&#34;&gt;Like all R Markdown documents&lt;/a&gt;, it also allows &lt;a href=&#34;https://shiny.rstudio.com/&#34;&gt;Shiny&lt;/a&gt; objects to be embedded inside of it, so that when rendered locally or on a server, it produces a reactive web application with minimal developer effort. Like many HTML files, however, it does not print well.&lt;/p&gt;
&lt;p&gt;The flexdashboard in question also had tabsets, which make perfect sense on a computer or mobile device, but don’t translate well to printed media. When printed, tabsets communicate that there is pertinent information hidden from the viewer; better to remove the tabset in the printed version. If the information is pertinent, it should be displayed in the printed document; if it is not, it should be removed.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;phantomjs-and-headless-chrome&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;PhantomJS and Headless Chrome&lt;/h3&gt;
&lt;p&gt;The approach we settled on as &lt;em&gt;good enough and easy enough&lt;/em&gt; was to use a &lt;a href=&#34;https://en.wikipedia.org/wiki/Headless_browser&#34;&gt;headless browser&lt;/a&gt; to take a screenshot of a non-reactive HTML document. It’s not a perfect solution: a PDF would be better than a png file, headless browsers add a code dependency, and there is some administrative overhead to create the document to print. It is, however, quick to implement, easy to understand, and robust.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;exampledownload&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Example&lt;a href=&#34;#fn2&#34; class=&#34;footnoteRef&#34; id=&#34;fnref2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The mechanics of building a screen-capture-style report from flexdashboard are neither difficult nor obvious. In general, it requires the following steps:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Add a downloadButton to a &lt;a href=&#34;http://rmarkdown.rstudio.com/flexdashboard/shiny.html&#34;&gt;flexdashboard with runtime Shiny&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;When the download button is invoked, temporarily save non-reactive copies of any objects of interest&lt;/li&gt;
&lt;li&gt;Knit a static HTML version of the flexdashboard, using the objects saved in the prior step&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&#34;https://github.com/wch/webshot&#34;&gt;&lt;code&gt;webshot::webshot&lt;/code&gt;&lt;/a&gt; or &lt;a href=&#34;https://github.com/hrbrmstr/decapitated&#34;&gt;&lt;code&gt;decapitated::chrome_shot&lt;/code&gt;&lt;/a&gt; to capture a .png image of the static dashboard&lt;a href=&#34;#fn3&#34; class=&#34;footnoteRef&#34; id=&#34;fnref3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deliver this version to the client using the downloadHandler function&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The solution requires two separate R documents. The process is as follows:&lt;/p&gt;
&lt;div id=&#34;dynamic-flexdashboard-document&#34; class=&#34;section level4&#34;&gt;
&lt;h4&gt;Dynamic Flexdashboard document&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;
---
title: &#34;Snapshot Example&#34;
runtime: shiny
output:
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: scroll
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is standard YAML header for a flexdashboard, including the command &lt;code&gt;runtime: shiny&lt;/code&gt; to create a Shiny application from an R Markdown document. Let’s examine the next chunks:&lt;/p&gt;
&lt;pre class=&#34;{r}&#34;&gt;&lt;code&gt;gears = mtcars$gear %&amp;gt;% as.factor() %&amp;gt;% levels()
selectizeInput(&amp;quot;grs&amp;quot;, &amp;quot;GEARS&amp;quot;,
               gears, selected = gears[1])
renderUI({
downloadButton(&amp;quot;downloadFile&amp;quot;, &amp;quot;Download&amp;quot;)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this chunk, we have built a &lt;code&gt;selectizeInput&lt;/code&gt; object to choose the number of gears to select, as well as a &lt;code&gt;downloadButton&lt;/code&gt; named ‘downloadFile’. Notice that we have wrapped the button in a &lt;code&gt;renderUI()&lt;/code&gt; context. This is standard shiny / flexdashboard code.&lt;/p&gt;
&lt;pre class=&#34;{r}&#34;&gt;&lt;code&gt;mpgp = reactive({
  mtcars %&amp;gt;% filter(gear %in% input$grs) %&amp;gt;% ggplot(aes(x = hp, y = mpg)) + geom_point() + geom_smooth()
  
})
renderPlot({
  mpgp()
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For veteran shiny programmers, this block may seem redundant. We’re creating a plot called &lt;code&gt;mpgp&lt;/code&gt; in a reactive context and then rendering it. In a ‘standard’ shiny implementation, we would simply have wrapped the plot code in the &lt;code&gt;renderPlot()&lt;/code&gt; context. However, as you will see below, we’re going to need to reuse the object &lt;code&gt;mpgp&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;{r}&#34;&gt;&lt;code&gt;output$downloadFile &amp;lt;- downloadHandler(filename = function() { 
return(paste(&amp;#39;Cars&amp;#39;, &amp;#39;.png&amp;#39;, sep=&amp;#39;&amp;#39;))
},
    content = function(file){
    to_save &amp;lt;- list(
    mpgg = mpgg(),
    mpgp = mpgp()
    )
      saveRDS(to_save, &amp;quot;config_data.RDS&amp;quot;)
      rmarkdown::render(&amp;quot;ShadowCars.Rmd&amp;quot;)
      webshot::webshot(&amp;quot;ShadowCars.html&amp;quot;, file = file)
                        })&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This chunk contains the secret sauce. When the &lt;code&gt;downloadButton&lt;/code&gt; is invoked, the program saves all elements to appear in the downloaded report in a file called ‘config_data.RDS’. These elements are then used as arguments to render a shadow document, ‘ShadowCars.Rmd’. Finally, &lt;code&gt;webshot::webshot&lt;/code&gt; converts the hidden document to a .png and delivers it to the client side.&lt;/p&gt;
&lt;p&gt;The full dashboard looks like this:&lt;/p&gt;
&lt;!-- ![*Screenshot of our minimal implementation of a flexdashboard with downloadable screenshot*](/post/2017-06-19-Printing-From-Flex-Dashboard_files/MinDWN.png) --&gt;

&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-06-19-Printing-From-Flex-Dashboard_files/MinDWN.png&#34; /&gt;

&lt;/div&gt;

&lt;/div&gt;
&lt;div id=&#34;shadow-document&#34; class=&#34;section level4&#34;&gt;
&lt;h4&gt;Shadow Document&lt;/h4&gt;
&lt;p&gt;The key elements of the shadow document code are presented below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: &amp;quot;Snapshot Example&amp;quot;
output:
  flexdashboard::flex_dashboard:
    orientation: rows
---&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that our YAML for the shadow document is similar to the dashboard, except it does &lt;strong&gt;not&lt;/strong&gt; include &lt;code&gt;runtime: shiny&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The code blocks that render the objects created in the dynamic document are straightforward to the point of triviality; they simply reference the saved objects (which are retrieved using &lt;code&gt;readRDS&lt;/code&gt;) and render them using whatever we choose, in this case &lt;code&gt;kable()&lt;/code&gt; for the table and the native &lt;code&gt;print()&lt;/code&gt; for the plot.&lt;/p&gt;
&lt;pre class=&#34;{r}&#34;&gt;&lt;code&gt;data &amp;lt;- readRDS(&amp;quot;config_data.RDS&amp;quot;)
data$mpgg %&amp;gt;% kable() &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;{r}&#34;&gt;&lt;code&gt;data$mpgp %&amp;gt;% print() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And of course, while &lt;code&gt;mpgp&lt;/code&gt; was reactive in the original dashboard, it is static in the shadow doc.&lt;/p&gt;
&lt;p&gt;The report delivered to the client is as follows:&lt;/p&gt;
&lt;!-- ![*Example of the type of report delivered to the client in png format.  Note that while the report contains the same objects as the dynamic page, the chart and graph are laid side-by-side, not tabset*](/post/2017-06-19-Printing-From-Flex-Dashboard_files/Cars.png) --&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-06-19-Printing-From-Flex-Dashboard_files/Cars.png&#34; /&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this short post, we have shown how to create a downloadable custom report by using existing tools to create a static flexdashboard. From the .png environment, the rendered image can be converted to other formats as required.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&#34;fn1&#34;&gt;&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/in/harrisonschramm&#34;&gt;Harrison Schramm&lt;/a&gt; is an Operations Research Analyst at &lt;a href=&#34;http://www.canallc.com/&#34;&gt;CANA Advisors&lt;/a&gt;. &lt;a href=&#34;https://www.linkedin.com/in/aaron-berg-26150917/&#34;&gt;Aaron Berg&lt;/a&gt; is a Customer Success Representative at RStudio.&lt;a href=&#34;#fnref1&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;&lt;p&gt;To recreate this minimal example for yourself, please download the files from &lt;a href=&#34;https://gist.github.com/agberg/d71d3aacb9b9d5691b7ba7ab7555ba5b&#34;&gt;this gist&lt;/a&gt;.&lt;a href=&#34;#fnref2&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;&lt;p&gt;The &lt;a href=&#34;https://github.com/wch/webshot&#34;&gt;&lt;code&gt;webshot&lt;/code&gt;&lt;/a&gt; package requires phantomJS to be installed as an external dependency, but will work on all systems. &lt;a href=&#34;https://github.com/hrbrmstr/decapitated&#34;&gt;&lt;code&gt;decapitated&lt;/code&gt;&lt;/a&gt; will only work on systems with versions of Chrome that can operate in &lt;a href=&#34;https://developers.google.com/web/updates/2017/04/headless-chrome&#34;&gt;headless mode&lt;/a&gt;.&lt;a href=&#34;#fnref3&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2017/06/28/printing-from-flex-dashboard/&#39;;&lt;/script&gt;
      </description>
    </item>
    
  </channel>
</rss>
