{"id":4407,"date":"2019-07-16T17:35:05","date_gmt":"2019-07-16T15:35:05","guid":{"rendered":"https:\/\/engel-wolf.com\/?p=4407"},"modified":"2019-10-27T17:40:21","modified_gmt":"2019-10-27T15:40:21","slug":"shinymeta%e2%80%8a-%e2%80%8aa-revolution-for-reproducibility","status":"publish","type":"post","link":"https:\/\/engel-wolf.com\/?p=4407","title":{"rendered":"shinymeta\u200a\u2014\u200aa revolution for reproducibility"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\" id=\"4b4b\">Joe Cheng presented shinymeta enabling reproducibility in shiny at useR in July 2019. This is a simple application using shinymeta. You will see how reactivity and reproducibility do not exclude each other. I am really thankful for Joe Cheng realizing the shinymeta project.<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"7084\">Introduction<\/h3>\n\n\n\n<p>In 2018 at the&nbsp;<a href=\"https:\/\/github.com\/jcheng5\/rpharma-demo\" rel=\"noreferrer noopener\" target=\"_blank\">R\/Pharma conference<\/a>&nbsp;I first heard of the concept of using quotations. With quotations to make your shiny app code reproducible. This means you can play around in shiny and afterward get the code to generate the exact same outputs as R code. This feature is needed in Pharma. Why is that the case? The pharmaceutical industry needs to report data and analysis to regulatory authorities. I talked about this in&nbsp;<a href=\"https:\/\/medium.com\/datadriveninvestor\/why-do-we-need-human-readable-tests-for-a-programming-language-1786d552f450\" target=\"_blank\" rel=\"noreferrer noopener\">several articles<\/a>&nbsp;already. How great would it be to provide a shiny-app to the regulatory authorities? Great. How great would it be to provide a shiny app that enables them to reproduce every single plot or table? Even better.<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/waddella\" rel=\"noreferrer noopener\" target=\"_blank\">Adrian Waddell<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/github.com\/dgkf\" rel=\"noreferrer noopener\" target=\"_blank\">Doug Kelkhoff<\/a>&nbsp;are both my colleges of mine that proposed solutions for this task. Doug built the&nbsp;<a href=\"https:\/\/github.com\/dgkf\/scriptgloss\" rel=\"noreferrer noopener\" target=\"_blank\">scriptgloss&nbsp;<\/a>package which reconstructs static code from shiny apps. Adrian presented a modular shiny-based exploratory framework at&nbsp;<a href=\"http:\/\/rinpharma.com\/program\/analyzing-clinical-trials-data-with-r.html\" rel=\"noreferrer noopener\" target=\"_blank\">R\/Pharma 2018<\/a>. The framework provides dynamic encodings, variable-based filtering, and R-code generation. In this context, I started working out some concepts during my current development project. How to make the code inside a shiny app reproducible? In parallel Doug,&nbsp;<a href=\"https:\/\/github.com\/jcheng5\" rel=\"noreferrer noopener\" target=\"_blank\">Joe Cheng<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/github.com\/cpsievert\" rel=\"noreferrer noopener\" target=\"_blank\">Carson Sievert<\/a>&nbsp;worked on a fascinating tool called&nbsp;<a href=\"https:\/\/github.com\/rstudio\/shinymeta\" rel=\"noreferrer noopener\" target=\"_blank\">shinymeta<\/a>, released on July 11 at the userR conference.<\/p>\n\n\n\n<figure><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/5KByRC6eqC8?feature=oembed\" width=\"525\" height=\"295\"><\/iframe><\/figure>\n\n\n\n<p>The tool is so fascinating because it created handlers for the task I talked about. It allows changing a simple shiny app into a reproducible shiny app with just a few tweaks. As shiny apps in Pharma have a strong need for this functionality, I am a shiny-developer in Pharma and I wanted to know: How does it work? How good is it?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"aefb\">Let\u2019s create a shiny app relevant in&nbsp;Pharma<\/h3>\n\n\n\n<p>As a simple example of a shiny app in Pharma, I will use a linear regression app. The app will detect if a useful linear model can show a correlation between the properties of the patient and the survival rate. Properties of the patient are AGE or GENDER. Survival rates include how long the patient will survive (OS = overall survival), survives without progression (PFS = progression-free survival) or survives without any events occurring (EFS). Each patient can have had all three stages of survival. Let\u2019s create the data sets for this use case with random data:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">library(tibble)<br>library(dplyr)<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># Patient listing<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">pat_data &lt;- list(<br>  SUBJID = 1:200,<br>  STUDYID = c(rep(1, 40), rep(2, 100), rep(3, 60)),<br>  AGE = sample(20:88, 200, replace = T) %&gt;% as.numeric(),<br>  SEX = c(sample(c(\"M\", \"F\"), 180, replace = T), rep(\"U\", 20)) %&gt;% as.factor()<br>) %&gt;% as_tibble()<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># Days where Overall Survival (OS), Event free survival (EFS) and Progression Free Survival (PFS) happened<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">event_data &lt;- list(<br>  SUBJID = rep(1:200, 3),<br>  STUDYID = rep(c(rep(1, 40), rep(2, 100), rep(3, 60)), 3),<br>  PARAMCD = c(rep(\"OS\", 200), rep(\"EFS\", 200), rep(\"PFS\", 200)),<br>  AVAL = c(rexp(200, 1 \/ 100), rexp(200, 1 \/ 80), rexp(200, 1 \/ 60)) %&gt;% as.numeric(),<br>  AVALU = rep(\"DAYS\", 600) %&gt;% as.factor()<br>) %&gt;% as_tibble()<\/pre>\n\n\n\n<p>You can see that patient AGE and GENDER (SEX) are randomly distributed. The survival values in days should exponentially decrease. By these distributions, we do not expect to see anything in the data, but this is fine for this example.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/cdn-images-1.medium.com\/max\/600\/1*2OQ6sddfH8yoHTajWySW0g.png\" alt=\"\"\/><figcaption>Simple app showing a linear regression of patient&nbsp;data<\/figcaption><\/figure>\n\n\n\n<p>Inside the screenshot, you can see the app applied to this data. The app contains the regression plot and the summary of the linear model created with\u00a0<code>lm<\/code>\u00a0. It basically has one input to filter the\u00a0<code>event_data<\/code>\u00a0by\u00a0<code>PARAMCD.<\/code>\u00a0A second input to selects columns from the\u00a0<code>pat_data<\/code>\u00a0. The interesting part of this app is the server function. Inside the server function, there are just two outputs and one reactive value. The reactive performs multiple steps. It generates the formula for the linear model, filters the\u00a0<code>event_data<\/code>, selects the\u00a0<code>pat_data<\/code>, merges the data sets and calculates the linear model by\u00a0<code>lm<\/code>\u00a0. The two outputs generate a plot and a summary text from the linear model.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\n# Create a linear model\nmodel_reactive &lt;- reactive({\n      validate(need(is.character(input$select_regressor), &quot;Cannot work without selected column&quot;))\n\n      regressors &lt;- Reduce(function(x, y) call(&quot;+&quot;, x, y), rlang::syms(input$select_regressor))\n      formula_value &lt;- rlang::new_formula(rlang::sym(&quot;AVAL&quot;), regressors)\n\n      event_data_filtered &lt;- event_data %&gt;% dplyr::filter(PARAMCD == input$filter_param)\n      ads_selected &lt;- pat_data %&gt;% dplyr::select(dplyr::one_of(c(input$select_regressor, c(&quot;SUBJID&quot;, &quot;STUDYID&quot;))))\n\n      anl &lt;- merge(ads_selected, event_data_filtered, by = c(&quot;SUBJID&quot;, &quot;STUDYID&quot;))\n\n      lm(formula = formula_value, data = anl)\n    })\n\n# Plot Regression vs fitted\noutput$plot1 &lt;- renderPlot({\n      plot(model_reactive(), which = 1)\n    })\n\n# show model summary\noutput$text1 &lt;- renderPrint({\n  model_reactive() %&gt;% summary()\n})\n<\/pre><\/div>\n\n\n<p>Of course, you think this app can be easily reproduced by a smart programmer. Now imagine you just see the user-interface and the output. What is missing? Two things are missing:<\/p>\n\n\n\n<ol><li>How to create the data?<\/li><li>What is the formula used for creating the linear model?<\/li><\/ol>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"aa1c\">Let\u2019s make the app reproducible!<\/h3>\n\n\n\n<p>By&nbsp;<a href=\"https:\/\/github.com\/rstudio\/shinymeta\" rel=\"noreferrer noopener\" target=\"_blank\">shinymeta<\/a>&nbsp;and the approach of metaprogramming, we will make the whole app reproducible. Even if shinymeta is still experimental, you will see, right now it works great.<\/p>\n\n\n\n<p>But we need to go step by step. The most important idea behind metaprogramming came from&nbsp;<a href=\"http:\/\/github.com\/waddella\" rel=\"noreferrer noopener\" target=\"_blank\">Adrian Waddell<\/a>. Instead of adding code to your app, you wrap the code in quotations. (Step 1 and the most important).<\/p>\n\n\n\n<p><strong>Creating the data<\/strong><\/p>\n\n\n\n<p>We can use this for the data added to the app:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ndata_code &lt;- quote({\n\n  # Patient listing\n  pat_data &lt;- ...\n\n  # Days where Overall Survival (OS), Event free survival (EFS) and Progression Free Survival (PFS) happened\n  event_data &lt;- ...\n})\n\neval(data_code)\n<\/pre><\/div>\n\n\n<p>Instead of running the code, we wrap it into&nbsp;<code>quote<\/code>. This will return a&nbsp;<code>call<\/code>&nbsp;that we can evaluate after by&nbsp;<code>eval<\/code>&nbsp;. It enables reproducibility. The code that we used to produce the data sets is stored in&nbsp;<code>data_code<\/code>&nbsp;. We can later on reuse this variable. This variable will allow us to show how the data set was constructed.<\/p>\n\n\n\n<p><strong>Filtering and selecting the data<\/strong><\/p>\n\n\n\n<p>To enable reproducible filtering and selection we will use the shinymeta functions. Thus we will create a&nbsp;<code>metaReactive<\/code>&nbsp;returning the merged data set. A metaReactive behaves like a&nbsp;<code>reactive<\/code>&nbsp;with the difference, that you can get the code used inside back, afterward. This is similar to the principle of quotation. But for the&nbsp;<code>metaReactive<\/code>&nbsp;you do not need to use an&nbsp;<code>eval<\/code>&nbsp;function, you can basically stick to the&nbsp;<code>()<\/code>&nbsp;evaluation, as before.<\/p>\n\n\n\n<p>An important new operator inside the&nbsp;<code>metaReactive<\/code>&nbsp;is the&nbsp;<code>!!<\/code>&nbsp;(bang, bang) operator. It allows inserting standard reactive values. It behaves a bit like in the&nbsp;<code>rlang<\/code>&nbsp;package. You can either use it to inline values from a standard reactive value. Or you can use it to inline&nbsp;<code>metaReactive<\/code>&nbsp;objects as code. As a summary the operator&nbsp;<code>!!<\/code>&nbsp;has two functionalities:<\/p>\n\n\n\n<ol><li>De-reference reactive objects\u200a\u2014\u200aget their values<\/li><li>Chain&nbsp;<code>metaReactive<\/code>&nbsp;objects by inlining them as code into each other<\/li><\/ol>\n\n\n\n<p>To get to know the&nbsp;<code>!!<\/code>&nbsp;operator better, check out the shinymeta vignettes:&nbsp;<a href=\"https:\/\/github.com\/rstudio\/shinymeta\/tree\/master\/vignettes\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/github.com\/rstudio\/shinymeta\/tree\/master\/vignettes<\/a><\/p>\n\n\n\n<p>This code will be used to filter and select and merge the data:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\n\ndata_set_reactive &lt;- metaReactive({\n    event_data_filtered &lt;- event_data %&gt;% dplyr::filter(PARAMCD == !!input$filter_param)\n    ads_selected &lt;- pat_data %&gt;% dplyr::select(dplyr::one_of(c(!!input$select_regressor, c(&quot;SUBJID&quot;, &quot;STUDYID&quot;))))\n    merge(ads_selected, event_data_filtered, by = c(&quot;SUBJID&quot;, &quot;STUDYID&quot;))\n  })\n<\/pre><\/div>\n\n\n<p>Inside the code, you can see that the&nbsp;<code>!!<\/code>&nbsp;operator interacts with the reactive values&nbsp;<code>input$select_regressor<\/code>&nbsp;and&nbsp;<code>input$filter_param<\/code>&nbsp;as values. This means we de-reference the reactive value and replace it with its static value. The outcome of this reactive is the merged data set. Of course, this code will not run until we call&nbsp;<code>data_set_reactive()<\/code>&nbsp;anywhere inside the server function.<\/p>\n\n\n\n<p><strong>Creating the model formula<\/strong><\/p>\n\n\n\n<p>The formula for the linear model will be created as it was done before:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nformula_reactive &lt;- reactive({\n  validate(need(is.character(input$select_regressor), &quot;Cannot work without selected column&quot;))\n  regressors &lt;- Reduce(function(x, y) call(&quot;+&quot;, x, y), rlang::syms(input$select_regressor))\n  rlang::new_formula(rlang::sym(&quot;AVAL&quot;), regressors)\n})\n<\/pre><\/div>\n\n\n<p>It is necessary to check the select regressor value, as without a selection no model can be derived<\/p>\n\n\n\n<p><strong>Creating the linear model<\/strong><\/p>\n\n\n\n<p>The code to produce the linear model without metaprogramming was as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">lm(formula = formula_value, data = anl)<\/pre>\n\n\n\n<p>We need to replace&nbsp;<code>formula_value<\/code>&nbsp;and&nbsp;<code>anl<\/code>&nbsp;. Additionally replace the reactive with a<code>metaReactive<\/code>&nbsp;. Therefore we use the function&nbsp;<code>metaReactive2<\/code>&nbsp;which allows running standard shiny code before the metaprogramming code. Inside this&nbsp;<code>metaReactive2<\/code>&nbsp;it is necessary to check the data and the formula:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">validate(need(is.data.frame(data_set_reactive()), \"Data Set could not be created\"))<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">validate(need(is.language(formula_reactive()), \"Formula could not be created from column selections\"))<\/pre>\n\n\n\n<p>The&nbsp;<code>metaReactive<\/code>&nbsp;<code>data_set_reactive<\/code>&nbsp;can be called like any reactive object. The code to produce the model shall be in meta-programmed because the user wants to see it. The function&nbsp;<code>metaExpr<\/code>&nbsp;allows this. To get nice reproducible code the call needs to look like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">metaExpr(bindToReturn = TRUE, {<br>  model_data &lt;- !!data_set_reactive()<br>  lm(formula = !!formula_reactive(), data = model_data)<br>})<\/pre>\n\n\n\n<p>If you do not want to see the whole data set inside the&nbsp;<code>lm<\/code>&nbsp;call we need to store it inside a variable.<\/p>\n\n\n\n<p>To allow the code to be tracible, you need to put&nbsp;<code>!!<\/code>&nbsp;in front of the reactive calls. In front of&nbsp;<code>data_set_reactive<\/code>&nbsp;this allows backtracing the code of&nbsp;<code>data_set_reactive<\/code>&nbsp;and not only the output value.<\/p>\n\n\n\n<p>Second of all, we can de-reference the&nbsp;<code>formula_reactive<\/code>&nbsp;by the&nbsp;<code>!!<\/code>&nbsp;operator. This will directly plug in the formula created into the&nbsp;<code>lm<\/code>&nbsp;call.<\/p>\n\n\n\n<p>Third,&nbsp;<code>bindToReturn<\/code>&nbsp;will force shinymeta to write:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">var1 &lt;- merge(...)<br>model_data &lt;- var_1<br>model_reactive &lt;- lm(formula = AVAL ~ AGE, data = model_data)<\/pre>\n\n\n\n<p>instead of<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">data_set_reactive &lt;- merge(...)<br>{<br>  model_data &lt;- data_set_reactive<br>  lm(AVAL ~ AGE, data = model_data<br>}<\/pre>\n\n\n\n<p>If you want to read more about the\u00a0<code>bindToReturn<\/code>\u00a0feature, there is an<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/rstudio\/shinymeta\/issues\/53\" target=\"_blank\">\u00a0issue on github about the\u00a0<\/a><code><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/rstudio\/shinymeta\/issues\/53\" target=\"_blank\">bindToReturn<\/a><\/code><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/rstudio\/shinymeta\/issues\/53\" target=\"_blank\">\u00a0argument<\/a>. The final\u00a0<code>model_reactive<\/code>\u00a0looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\n# Create a linear model\n  model_reactive &lt;- metaReactive2({\n    validate(need(is.data.frame(data_set_reactive()), &quot;Data Set could not be created&quot;))\n    validate(need(is.language(formula_reactive()), &quot;Formula could not be created from column selections&quot;))\n\n    metaExpr(bindToReturn = TRUE, {\n      model_data &lt;- !!data_set_reactive()\n      lm(formula = !!formula_reactive(), data = model_data)\n    })\n  })\n<\/pre><\/div>\n\n\n<p><strong>Rendering outputs<\/strong><\/p>\n\n\n\n<p>Last but not least we need to output plots and the text in a reproducible way. Instead of a standard\u00a0<code>renderPlot<\/code>\u00a0and\u00a0<code>renderPrint<\/code>\u00a0function it is necessary to wrap them in\u00a0<code>metaRender<\/code>\u00a0.\u00a0<code>metaRender<\/code>\u00a0enables outputting metaprogramming reactive objects with reproducible code. To get not only the values but also the code of the model, the\u00a0<code>!!<\/code>\u00a0operator is used again.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# Plot Regression vs fitted\noutput$plot1 &lt;- metaRender(renderPlot, {\n  plot(!!model_reactive(), which = 1)\n})\n\n# show model summary\noutput$text1 &lt;- metaRender(renderPrint, {\n  !!model_reactive() %&gt;% summary()\n})\n<\/pre><\/div>\n\n\n<p>Using&nbsp;<code>metaRender<\/code>will make the output a metaprogramming object, too. This allows retrieving the code afterward and makes it reproducible.<\/p>\n\n\n\n<p><strong>Retrieving the code inside the user-interface<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>IMPORTANT!<\/p><\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Sorry for using capital letters here, but this part is the real part, that makes the app reproducible. By plugging in a \u201c<em>Show R Code<\/em>\u201d button every user of the app will be allowed to see the code producing outputs. Therefore shinymeta provides the function&nbsp;<code>expandChain<\/code>&nbsp;. The next section shows how it is used.<\/p><\/blockquote>\n\n\n\n<p>In case the user clicks a button, like in this case\u00a0<code>input$show_r_code<\/code>\u00a0a modal with the code should pop up. Inside this modal the\u00a0<code>expandChain<\/code>\u00a0function can handle (1) quoted code and (2)<code>metaRender<\/code>\u00a0objects. Each object of such a kind can be used in the\u00a0<code>\u2026<\/code>\u00a0argument of\u00a0<code>expandChain<\/code>\u00a0. It will return a meta-expression. From this meta-expression, the R code used in the app can be extracted. Simply using\u00a0<code>formatCode()<\/code>\u00a0and\u00a0<code>paste()<\/code>\u00a0will make it pretty code show up in the modal.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nobserveEvent(input$show_r_code, {\n    showModal(modalDialog(\n      title = &quot;R Code&quot;,\n      tags$pre(\n        id = &quot;r_code&quot;,\n        expandChain(\n          library_code,\n          data_code,\n          output$plot1(),\n          output$text1()\n        ) %&gt;% formatCode() %&gt;% paste(collapse = &quot;\\n&quot;)\n      ),\n      footer = tagList(\n        actionButton(&quot;copyRCode&quot;, &quot;Copy to Clipboard&quot;, `data-clipboard-target` = &quot;#r_code&quot;),\n        modalButton(&quot;Dismiss&quot;)\n      ),\n      size = &quot;l&quot;,\n      easyClose = TRUE\n    ))\n  })\n<\/pre><\/div>\n\n\n<p>Please do not forget the&nbsp;<code>()<\/code>&nbsp;after the&nbsp;<code>metaRender<\/code>&nbsp;objects.<\/p>\n\n\n\n<p><strong>Final server function and app<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/cdn-images-1.medium.com\/max\/600\/1*299LU_c943L_Exb76z5WAQ.png\" alt=\"\"\/><figcaption>All code can be found at&nbsp;<a href=\"https:\/\/github.com\/zappingseb\/shinymetaTest\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/github.com\/zappingseb\/shinymetaTest<\/a><\/figcaption><\/figure>\n\n\n\n<p>After going through all steps you can see that the code using shinymeta is not much different from the standard shiny code. Mostly&nbsp;<code>metaReactive<\/code>&nbsp;,&nbsp;<code>metaReactive2<\/code>&nbsp;,&nbsp;<code>metaExpr<\/code>&nbsp;,&nbsp;<code>metaRender<\/code>&nbsp;,&nbsp;<code>!!<\/code>&nbsp;and&nbsp;<code>expandChain<\/code>&nbsp;are the new functions to learn. Even if the package is still experimental, it does a really good job of making something reactive also reproducible. My favorite functionality is the mixed-use of&nbsp;<code>reactive<\/code>&nbsp;and&nbsp;<code>metaReactive<\/code>&nbsp;. By using reactive objects inside meta-code the developer can decide which code goes into the \u201c<em>Show R Code<\/em>\u201d window and which code runs behind the scenes. You can check yourself by looking into the code of this tutorial. Of course this feature is dangerous, as you might forget to put code in your \u201cShow R Code\u201d window and not all code can be rerun or your reproducible code gets ugly.<\/p>\n\n\n\n<p>The whole code of the tutorial is published on&nbsp;<em>github&nbsp;<\/em>at:&nbsp;<a href=\"https:\/\/github.com\/zappingseb\/shinymetaTest\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/github.com\/zappingseb\/shinymetaTest<\/a>.<\/p>\n\n\n\n<p>The app runs at&nbsp;<a href=\"https:\/\/sebastianwolf.shinyapps.io\/shinymetaTest\/\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/sebastianwolf.shinyapps.io\/shinymetaTest<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/1*U5oGqkLbr-wf03hC6d6F8w.png\" alt=\"\"\/><figcaption>App running at:&nbsp;<a href=\"https:\/\/sebastianwolf.shinyapps.io\/shinymetaTest\/\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/sebastianwolf.shinyapps.io\/shinymetaTest\/<\/a><\/figcaption><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"5a1d\">Closing words<\/h4>\n\n\n\n<p>This was the first time I tried to wrap my own work into a totally new package. The app created inside this example was created within my daily work berfore. The new and experimental package shinymeta allowed switching in ~1 hour from my code to metaprogramming. I did not only switch my implementation, but my implementation also became better due to the package.<\/p>\n\n\n\n<p>Shinymeta will make a huge difference in pharmaceutical shiny applications. One week after the presentation by Joe Cheng I am still impressed by the concept of metaprogramming. And how metaprogramming went into shiny. The package makes shiny really reproducible. It will give guidance for how to use shiny in regulatory fields. Moreover, it will allow more users to code in R, as they can see the code needed for a certain output. Clicking will make them learn.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Joe Cheng presented shinymeta enabling reproducibility in shiny at useR in July 2019. This is a simple application using shinymeta. You will see how reactivity and reproducibility do not exclude [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4409,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[387,391,384,385,381],"_links":{"self":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts\/4407"}],"collection":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4407"}],"version-history":[{"count":1,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts\/4407\/revisions"}],"predecessor-version":[{"id":4410,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts\/4407\/revisions\/4410"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/media\/4409"}],"wp:attachment":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4407"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4407"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4407"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}