2

I have a function that generates a variable number of plotly graphics and creates R markdown headers such as

### Caption for plot

These headers ultimately appear in a floating table of contents in an R markdown html report produced under RStudio.

I know how to use htmltools::tagList to produce a sequence of html and plotly objects that will render all in one stream, but I don't see how to substitute markdown for the htmltools::HTML('foo') piece of an htmltools::tagList(list(plot_ly(...), HTML('caption stuff), ...)) element.

Frank Harrell
  • 1,954
  • 2
  • 18
  • 36
  • 1
    Though not *directly* applicable (it's about `ggplot2`), you could adapt the approach from https://stackoverflow.com/a/47339394/3358272. Specifically, the intent is for a chunk to create the markdown text and have it appear as-is in the (post-`knitr`) markdown file. Maybe the biggest trick you need is the chunk option of `results="asis"`? – r2evans Aug 11 '18 at 20:04
  • That did it. Thank you! I tested it with ```{r test2,results='asis'} k <- c('## TOC test entry', '```{r junk}', 'x1=runif(10);', 'y1=runif(10);', 'plot_ly(data.frame(x1,y1), x=~x1, y=~y1)', '```') cat(trimws(knitr::knit(text = knitr::knit_expand(text = k), quiet = TRUE))) ``` – Frank Harrell Aug 11 '18 at 20:25
  • 2
    I could imagine a problem with caching with this approach, so if there is a more direct approach that would also be nice. I'll wait just a bit before putting in the Answer format. – Frank Harrell Aug 11 '18 at 20:32
  • Now *that's* an interesting question ... – r2evans Aug 11 '18 at 20:36
  • 1
    FrankHarrell, by adding `\`\`\`{r chunkname,cache=TRUE,results='asis'}` for the chunk, it was cached. I tested by adding a `Sys.sleep` in the same chunk as the call to `subchunkify`, and on subsequent calls the sleep did not happen (and the image was still there). It works because `knitr` caches based on the name of the current chunk (not the generated one) and the code within it, so the `runif` has no stochastic impact on the caching of the chunk. – r2evans Aug 11 '18 at 20:48
  • 1
    One side-effect of this is that if your `subchunkify` function definition itself changes, since it is in a different chunk it will likely *not* cause the plotting chunks to invalidate the cache. This could be mitigated by adding `cache.globals="subchunkify"` or `dependson="chunk_with_subchunkify"`, both options defined at http://yihui.name/knitr/options/#cache. – r2evans Aug 11 '18 at 20:52

1 Answers1

2

Thanks to r2evans here is a solution for my problem. Here R is a list of character vectors, each element of which is a mixture of text and markdown. Pl is a list of plotly objects. nP is the length of each list.

bn <- paste0('c', round(runif(1, 0, 1e6)))  # base chunk name
for(i in 1 : nP) {
  cn <- paste0(bn, i)  # name of individual generated chunk
  Plti <- Pl[[i]]      # fetch i'th plotly graphic object
  k <- c(R[[i]], paste0('```{r ', cn, ',echo=FALSE}'), 'Plti', '```')
  cat(trimws(knitr::knit(text=knitr::knit_expand(text=k), quiet=TRUE)))
  }
}
Frank Harrell
  • 1,954
  • 2
  • 18
  • 36
  • Note: if a character vector in list `R` above has a heading, e.g. `"## Subheading"`, the heading will need to be surrounded by character string elements `"\n"` so the heading will be recognized as markdown. Also, `trimws()` needs to be removed. It doesn't work for the `\n` characters to be in the same character string as the heading. – Frank Harrell Oct 21 '18 at 02:55