-
-
Notifications
You must be signed in to change notification settings - Fork 15
Adds rmarkdown module
#944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Marked as ready to review to start the discussion |
Code Coverage SummaryDiff against mainResults for commit: d05971a Minimum allowed coverage is ♻️ This comment has been updated with latest results |
gogonzo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't both documets be reproducible?
- document downloaded from tm_rmarkdown
- document downloaded via reporter
R/tm_rmarkdown.R
Outdated
| params = datasets[["rmd_data"]], | ||
| envir = new.env(parent = globalenv()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with this, it's a bit more custom that using params, but it would be cleaner.
The only reason to use params would be to use existing features of R Markdown, instead of custom workflow
That is, if data is passed via envir, what would be the ideal workflow for the statistician to develop the original R Markdown file?
1. Using envir = data() in rmarkdown::render()
- Statistician will have a code chunk that generates whatever data they require
- Removes chunk:
- Manually before sending it or use chunk opts to hide it
{r eval = FALSE, include = FALSE} - We provide a flag in
envir?{r eval = !(exists(".teal_takes_care_data") && isTRUE(.teal_takes_care_data)), include = !(exists(".teal_takes_care_data") && isTRUE(.teal_takes_care_data))}
- Manually before sending it or use chunk opts to hide it
- Send to app developer
- App developer uses it module
2. Using params = as.list(data()) in rmarkdown::render()
As it is right now as it has an override mechanism
---
# ...
params:
ADSL: !r teal.data::rADSL
# ...
---- Statistician develops Rmd with
paramsset to whatever data they use - Send to app developer
- App developer uses it on module
3. Other?
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is, if data is passed via envir, what would be the ideal workflow for the statistician to develop the original R Markdown file?
Maybe sort of a debug-mode where data() is dumped into environment and app-developer can just execute code-chunks one by one.
R/tm_rmarkdown.R
Outdated
| moduleServer(id, function(input, output, session) { | ||
| if (allow_download) { | ||
| output$download_rmd <- downloadHandler( | ||
| filename = function() basename(rmd_file), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't downloadable rmarkdown contain also "reproducible" qenv code? IMO tm_rmarkdown(rmd_file) is just a template and returning a template doesn't make sense if it lacks data to actually execute templete-file.
Edit:
I think app user should be able to download rendered document?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't downloadable rmarkdown contain also "reproducible" qenv code? IMO tm_rmarkdown(rmd_file) is just a template and returning a template doesn't make sense if it lacks data to actually execute templete-file.
Good point. I didn't want to do that before the rendering as it mean that the pre-processing would be run again.
But this can be added in post-rendering to the Download document and in the reporter markdown version.
This does imply we need to parse the Rmd and resulting markdown:
- Read the
md - Find line after
yml header-- fallback to start of document if no header present - Add new R code chunk with contents of
qenv
(we could even inject this in the module UI as well to keep consistency)
I think app user should be able to download rendered document?
They can, when downloading the reporter. I don't think we should overlap functionality here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See how to convert .Rmd to .R and back using knitr (thats' in teal.reporter dependency)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@llrs-roche parsing and adding the section in .R or in .Rmd would have similar challenges?
From my initial findings knitr::purl() is promising, but it does have some minor limitations with chunk options (it doesn't play well when evaluating params: {r, eval = !is.null(params$CO2)})
R/tm_rmarkdown.R
Outdated
|
|
||
| teal.reporter::teal_card(out_data) <- c( | ||
| teal.reporter::teal_card(out_data), | ||
| rendered_html_r() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
markdown fits here better. We can also split it into list() suitable with teal_card()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what would be better as I think of this as a monolith element. At least until we can actually break down the executable code.
We could keep it as a single markdown object (i.e. character vector) and only render as needed. note: the current approach was meant to reduce duplicate rendering (1. Module UI; 2. Reporter previewer; 3. Reporter download).
Splitting might be difficult to achieve as there are multiline grammar and context in markdown (for instance code chunks, or just newlines without a new paragraph in text)
toHTML(c("# ada", "", "bla.", "ca.", "```r", "1+1", "3*3", "```", "some text")) # works
# vs.
lapply(c("# ada", "", "bla.", "ca.", "```r", "1+1", "3*3", "```", "some text"), toHTML) # doesn't workThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could keep it as a single markdown object
I think its good to have a single markdown string because anyway at the end (before download) we will concatenate everything to the single file. Only editor will show one combined text-field for this element (i think it is not a big issue so far)
the current approach was meant to reduce duplicate rendering
This is a fair reason. I feel (not a strong opinion) that if you render markdown using rmarkdown::render and includeMarkdown the speed should be similar to rmarkdown::render to html. rmarkdown renders in two stages to html, first by converting Rmd -> md and then pandoc renders from md -> html.
The biggest issue with including html is that html can't be converted to pdf, otf etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gogonzo see new commits.
- Uses
qenvenvironment instead ofparams - Downloaded Rmd from main module adds data processing in module
- Markdown is rendered once
- HTML is rendered only once on top of markdown
- Uses custom
to_rmdandtoHTMLto achieve goals
Let me know if you have comments :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
Key questions:
|
|
Would it be possible to use the reporter function to download a rendered
document? Ideally the user would have the choice between html and pdf.
What do you think?
…On Fri, Nov 7, 2025 at 8:38 AM Dawid Kałędkowski ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In R/tm_rmarkdown.R
<#944 (comment)>
:
> +
+ if (allow_download) {
+ out_data <- eval_code(
+ q_r(),
+ paste(
+ sep = "\n",
+ sprintf("## R Markdown contents are generated from file, please download it from the module UI."),
+ sprintf("# rmarkdown::render(%s, params = params)", shQuote(basename(rmd_file), type = "cmd"))
+ )
+ )
+ ***@***.*** <- FALSE # manual change verified status as code is being injected
+ }
+
+ teal.reporter::teal_card(out_data) <- c(
+ teal.reporter::teal_card(out_data),
+ rendered_html_r()
We could keep it as a single markdown object
I think its good to have a single markdown string because anyway at the
end (before download) we will concatenate everything to the single file.
Only editor will show one combined text-field for this element (i think it
is not a big issue so far)
the current approach was meant to reduce duplicate rendering
This is a fair reason. I feel (not a strong opinion) that if you render
markdown using rmarkdown::render and includeMarkdown the speed should be
similar to rmarkdown::render to html. rmarkdown renders in two stages to
html, first by converting Rmd -> md and then pandoc renders from md ->
html.
The biggest issue with including html is that html can't be converted to
pdf, otf etc.
—
Reply to this email directly, view it on GitHub
<#944 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AJUWWERCKCNM7NA66YG6VVT33REA3AVCNFSM6AAAAACLHVPL3CVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTIMZSGA3TSNRYGU>
.
You are receiving this because you were mentioned.Message ID:
<insightsengineering/teal.modules.general/pull/944/review/3432079685@
github.com>
|
|
@StefanThoma that's one of our goals with this PR. It's now possible for HTML output, the other formats are a WIP, but I believe we'll make it happen |
| out_data@verified <- FALSE # manual change verified status as code is being injected | ||
| } | ||
|
|
||
| teal.reporter::teal_card(out_data) <- c( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue with keeping it in markdown format: Images are rendered to file that needs to be "kept" until report rendering
Possible workarounds:
- Modify generated
mdfile to convert image from paths to base64- Problem: there's an issue in generating
pdf: Base64 image not appearing inpdf_documentrstudio/rmarkdown#2604- Fix idea (without
rmarkdownrelease): convert the markdown image tag to a code chunk that includes graphic
- Fix idea (without
- Problem: there's an issue in generating
- Keep the images until the report generation
- Re-render during report generation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been solved in c563c71 by creating a custom reporter object for this module.
It keeps the rendered HTML and uses it as caching (only renders once)
It also keeps the contents of images in memory to be dumped and used later on.
Why memory?
- In case files on disk change (multiple reports being added)
- Prevent having to track and keep all images being generated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still room for improvement here, but we have a working solution.
Improvement:
- rmarkdown fixes issue raised above (and we manipulate image tag to use base64)
- Avoid encoding to base64 keep it in raw format for example.


Pull Request
Thanks to @StefanThoma's for working on the first prototype
Changes description
extra_transformparameter to add "generic decorators" to the top of the UITo discuss
.Rto get all the R code from the report and add it to the code of theqenv?markdownwhen rendering doesn't print title nor authortealiframedoesn't extend full height and then creates strange reportstransformersto add extra input / data manipulation(topics below added from conversation with @gogonzo )
teal_reportcontain markdown elements?teal_dataevaluatermarkdown::render()and include this to@codermarkdown::render(envir = <qenv>)instead ofparams = list()?App