quarto-dev / quarto-cli

Open-source scientific and technical publishing system built on Pandoc.
https://quarto.org
Other
3.57k stars 293 forks source link

Quarto book: multiple chapters in one qmd chapter #1712

Open eeholmes opened 1 year ago

eeholmes commented 1 year ago

Quarto version: I tried a few version. Started with 1.0.37 then I updated to the latest dev version (says 99.9.9) using this

git clone https://github.com/quarto-dev/quarto-cli
cd quarto-cli
./configure-macos.sh

Then went back to v1.0.38 by re-installing. RStudio: 2022.02.2 OS: Mac Big Sur 11.6.2

This is specific to a Quarto book project.

If have 2 h1 headers in a chapter qmd, the first appears in TOC and the others appear with the right sequential chapter numbers but don't appear in the TOC and later chapters don't "know" about the new chapters.

Example _quarto.yml

project:
  type: book

book:
  title: "test"
  chapters:
    - index.qmd
    - chap1and2.qmd
    - chap3.qmd

format:
  html:
    theme: cosmo

chap1and2.qmd

# Chapter 1

This is chapter 1

# Chapter 2

This is chapter 2

This is the output. Notice the TOC.

image

quarto check Output

[✓] Checking Quarto installation......OK
      Version: 1.0.37
      Path: /Applications/quarto/bin

[✓] Checking basic markdown render....OK

[✓] Checking Python 3 installation....OK
      Version: 3.9.12
      Path: /opt/homebrew/opt/python@3.9/bin/python3.9
      Jupyter: (None)

      Jupyter is not available in this Python installation.
      Install with python3 -m pip install jupyter

[✓] Checking R installation...........OK
      Version: 4.1.1
      Path: /Library/Frameworks/R.framework/Resources
      LibPaths:
        - /Users/eli.holmes/Library/R/x86_64/4.1/library
        - /Library/Frameworks/R.framework/Versions/4.1/Resources/library
      rmarkdown: 2.14

[✓] Checking Knitr engine render......OK

quarto tools check Output

[✓] Inspecting tools

Tool         Status                    Installed     Latest  
chromium     Not installed             ---           869685  
tinytex      External Installation     ---           v2022.08

Use case, why is this needed?

In report writing situation, you often don't know how many chapters (appendices) you will need. You are using knit_expand() with an child.Rmd that is creating all your chapters (appendices) based on the data (which vary). That knit_expand() is a for loop (or map function) and is creating the markdown dynamically. This works fine in Quarto...except that it doesn't recognize the later h1 levels as proper chapters.

Checklist

jjallaire commented 1 year ago

Currently chapters do indeed need to be in different qmd files. The best way to share data between chapters is to use the save() and load() functions: https://jjallaire.github.io/hopr/a4-data.html#saving-r-files

eeholmes commented 1 year ago

The main issue is not actually sharing data between chapters. Rather it is arising when we don't know how many chapters we will need. This is common when using R Markdown (and now) Quarto for government reports. We are dynamically creating the content (meaning the content in the qmd).

Here is a repo where I am working on a template for government reports with dynamic content. https://github.com/RVerse-Tutorials/QmdReport/blob/main/README.md

The problem is most acute for appendices. This is the area where we are most likely to not know the number of chapters (appendices). Fortunately, Word and PDF output seems to figure out how to deal with the multiple h1 levels in the one appendix qmd. But the HTML is totally messed up. Look just at the appendices.

HTML: https://rverse-tutorials.github.io/QmdReport/ PDF: https://rverse-tutorials.github.io/QmdReport/A-Quarto-Template-Repo-to-Create-Big-Reports-and-Very-Long-Title-Because-Long-Titles-are-Common.pdf

jjallaire commented 1 year ago

Okay, got it! Dynamic number of HTML chapters we indeed do not handle well right now (mostly b/c we build a static index of them before rendering so that we can build the sidebar for each chapter as we go -- kind of a chicken and egg problem unless we move the generation of the sidebar entirely outside of pandoc rendering). Need to think more carefully about it but I am hopeful this is something we can ultimate resolve. Will target this for work in our v1.2 release (later this fall).

eeholmes commented 1 year ago

Got it. The Quarto default HTML looks so similar to bookdown::bs4_book that I assumed it was working under the hood in the same way.

image

This is generated with bookdown at this RStudio Cloud project: https://rstudio.cloud/content/4350137 I am pretty sure it is using Knit then Merge since new_session: true. The two appendices are generated in 08-appendices.Rmd with two # levels in one file.

Anyhow I'll look forward to Quarto v1.2 in the fall!

ThierryO commented 1 year ago

Here is a related minimal example. Our real life example: a report with a standardised chapter for every species (almost 100 species and increasing). Currently we have the report as a bookdown::gitbook(). The standardised chapter is defined as a child document and we loop over the species to generate the report. The example below works, but it adds all child chapters to a single index.html file. This becomes very large file. Whereas bookdown::gitbook() allows to split the content over multiple files by chapter. Making the html files much smaller.

_quarto.yml

project:
  type: book
book:
  chapters:
    - index.qmd
format:
  html: default

index.qmd

    # Main chapter

    ```{r}
    #| label: setup
    #| include: false
    library(knitr)
    opts_chunk$set(echo = FALSE)
    library(tidyverse)
```{r}
#| label: child
#| results: asis
sample(LETTERS, 3) |>
  sapply(
    function(id) {
      knit_expand("_child.qmd", id = id)
    }
  ) %>%
  paste(collapse = "\n") -> qmd
knit(text = qmd, quiet = TRUE) |>
  cat()
```

`_child.qmd`
# {{id}}

```{r}
#| label: {{id}}-plot
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, colour = Species)) +
  geom_point() +
  ggtitle("{{id}}")
```
cderv commented 1 year ago

@ThierryO side note regarding your example :

```{r}
#| label: child
#| results: asis
sample(LETTERS, 3) |>
  sapply(
    function(id) {
      knit_expand("_child.qmd", id = id)
    }
  ) %>%
  paste(collapse = "\n") -> qmd
knit(text = qmd, quiet = TRUE) |>
  cat()
```

I am surprised you don't have issue with this. Usual pattern to do this is to use knitr::knit_child() and not knit() directly. knit_child() is designed to knit content within a knitting process.

See knit_expand() example in the R Markdown cookbook.