Open iago-pssjd opened 6 months ago
Not sure from which data Distance
or Speed
comes from to reproduce, but several comments.
Instead of for
loop with cat()
, you should consider going all knit_child
way, and generate the all md
content you want to iterate on as a child using knit_expand()
or directly text content in knit_child
with inline R code
See the others recipes in the cookbook about that:
This will allow you to add your plots inside a chunk, with right conditional. That way each plot will be differently handle and correctly by knitr.
You can't just cat()
plot, so having it process by knit_child()
could be rather important.
I let you try a version. I can show you if you share with the data.
@cderv Sorry because the minrep was not complete. Now I updated including data source.
Can you format correctly please ? https://yihui.org/issue/#please-format-your-issue-correctly
Also you can try with what I shared. I believe it will make your intention works
@cderv Yes. I updated the format again. Sorry for the inconvenience.
Going to matter, I do not understand how should I do. https://bookdown.org/yihui/rmarkdown-cookbook/child-document.html with knit_child
is what I am already using. How should be the exemple adapted to your proposal?
Thanks!
Several examples
This is close to what you are doing, but instead, you are just generating the child content as a whole as a vector. Not using cat()
and letting knit_child()
to all the printing when knitting
---
title: test
output:
html_document:
keep_md: true
---
```{r setup, echo=TRUE, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, results = 'asis',
fig.height = 6, fig.width = 10,
eval = TRUE, message = FALSE, warning = FALSE)
library(knitr)
Speed <- cars$speed
Distance <- cars$dist
content <- c()
for (i in 1:1) {
for (j in 1:2) {
content <- c(
content,
sprintf("j = %d", j),
"\n\n",
"```{r, echo = FALSE}",
if (j == 1) 'plot(Speed, Distance, panel.first = grid(8, 8), pch = 0, cex = 1.2, col = "blue")',
if (j == 2) 'plot(Speed, Distance, panel.first = lines(stats::lowess(Speed, Distance), lty = "dashed"), pch = 0, cex = 1.2, col = "blue")',
"```",
"\n\n",
"```{r, echo = FALSE}",
"kable(mtcars)",
"```",
"\n\n"
)
}
content <- c(
content,
c(
'```{r}',
'plot(pressure)',
"```",
"\n\n"
)
)
}
knitr::knit_child(text = content, envir = environment(), quiet = TRUE) |> cat(sep = "\n")
## Using an external child document
You write the content to use in `knit_child` in another doc, using inline R code and code chunk as you would in a generic doc, but to access variable from your main document
<details>
<summary>test.Rmd</summary>
````markdown
---
title: test
output:
html_document:
keep_md: true
---
```{r setup, echo=TRUE, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, results = 'asis',
fig.height = 6, fig.width = 10,
eval = TRUE, message = FALSE, warning = FALSE)
library(knitr)
Speed <- cars$speed
Distance <- cars$dist
res <- lapply(1:2, function(j) {
knit_child("_child.Rmd", envir = environment(), quiet = TRUE)
})
cat(unlist(res), sep = '\n')
kable(mtcars)
plot(pressure)
</details>
<details>
<summary>_child.Rmd</summary>
````markdown
j = `r j`
```{r, eval = j == 1, echo = j == 1}
plot(Speed, Distance, panel.first = grid(8, 8), pch = 0, cex = 1.2, col = "blue")
plot(Speed, Distance, panel.first = lines(stats::lowess(Speed, Distance), lty = "dashed"), pch = 0, cex = 1.2, col = "blue")
</details>
## Same but using `knit_expand()` or another template function to fill a child file
You write the content to `knit_child` in an external file, using templating expansion to fill the value you need to be variable
<details>
<summary>test.Rmd</summary>
````markdown
---
title: test
output:
html_document:
keep_md: true
---
```{r setup, echo=TRUE, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, results = 'asis',
fig.height = 6, fig.width = 10,
eval = TRUE, message = FALSE, warning = FALSE)
library(knitr)
Speed <- cars$speed
Distance <- cars$dist
res <- lapply(1:2, function(j) {
knit_child("_child.Rmd", envir = environment(), quiet = TRUE)
})
cat(unlist(res), sep = '\n')
kable(mtcars)
plot(pressure)
</details>
<details>
<summary>Details</summary>
````markdown
j = {{j}}
```{r, eval = {{ j == 1 }}, echo = {{ j == 1 }} }
plot(Speed, Distance, panel.first = grid(8, 8), pch = 0, cex = 1.2, col = "blue")
plot(Speed, Distance, panel.first = lines(stats::lowess(Speed, Distance), lty = "dashed"), pch = 0, cex = 1.2, col = "blue")
</details>
Other templating tools like **brew**, **whisker** , even **glue** could be used with same purpose.
Hope it helps see what you can do to avoid `cat()` and `print()` mixing text and R object output
@cderv Wow! That is impressive.
Finally I could get what I wanted using an external child document and splitting code in distinct chunks there.
Thank you for your help.
I keep the issue open as I believe the behaviour reported is yet a bug. Feel free to close it if that behaviour is expected (and already documented?)
It is tricky as issue because you are missing
cat()
of raw markdow, and print()
of plots and kable()
, without any results = "asis"
set is quite specific, and does not seem correct usage. So I don't know if this is a bug or not.
It would require to minimized the example I believe.
@yihui do you think there is something to look into ?
Actually results = 'asis'
is specified by default through knitr::opts_chunk$set
, and I only use cat
for knit_child
and the separator cat('\n\n<!-- -->\n\n')
, which I would not use if they were unneeded.
Actually results = 'asis' is specified by default through knitr::opts_chunk$set,
Oh that is why. Ok thanks for clarification !
A smaller reprex with knit_child()
---
title: test
output:
html_document:
keep_md: true
---
```{r pressure, results='asis'}
plot(cars$speed, cars$dist, panel.first = grid(8, 8), pch = 0, cex = 1.2, col = "blue")
knitr::kable(head(cars))
knitr::knit_child(text = c(
'```{r}',
'plot(pressure)',
'```'
), envir = environment(), quiet = TRUE) |> cat(sep="\n")
![image](https://github.com/yihui/knitr/assets/6791940/f5007d3f-3536-4a91-8eef-ba2b34fd09e1)
Which do no happen without
````markdown
---
title: test
output:
html_document:
keep_md: true
---
```{r pressure, results='asis'}
plot(cars$speed, cars$dist, panel.first = grid(8, 8), pch = 0, cex = 1.2, col = "blue")
knitr::kable(head(cars))
plot(pressure)
![image](https://github.com/yihui/knitr/assets/6791940/2442f912-4913-43a1-8f48-be1c51ad038e)
So probably something to look into 🤔
This does seem to be a complicated bug. I haven't figured out the reason after some investigation. Sorry.
Hi @yihui!
In the next minimal reproducible example, for j=1, the scatterplot between
Speed
andDistance
is placed before themtcars
kable
, as expected, but forj=2
it is placed just before the plot inknit_child
. This issue happens only when including theknit_child
block. Further, I include 2 different plots for j=1 and j=2, since if it is the same plot it is printed a unique time just before the plot inknit_child
(would be this another bug?).I included the
cat('\n\n<!-- -->\n\n')
thinking if they could solve the issue, as you suggests in https://bookdown.org/yihui/rmarkdown-cookbook/kable.html#generate-multiple-tables-from-a-for-loop.Since that does not work, how may I avoid this issue?
Also, may this issue be related to https://github.com/yihui/knitr/issues/2166 ?
Thanks!
Below the minrep and at the end the promises you ask for to fill an issue.