Search code examples
rr-markdownquarto

Output from final chunk appears at top of output


In a quarto document, I would like the final R chunk to compute an executive summary based on the results of earlier chunks. How can this final chunk output appear at the top of the report?

Expected Output: final chunk (exec-summary) output should appear under 'Executive Summary' and before 'Number of Rows':

---
title: "exec-summary"
format: html
---

## Executive Summary Presentation

### Number of Rows

```{r chunk1}
x <- nrow(mtcars)
```

### Number of Columns

```{r chunk2}
y <- ncol(mtcars)
```

### Executive Summary Computation

```{r exec-summary}
glue::glue("There are {x} rows an {y} columns")
```

Solution

  • You can either make use of Lua filter to reposition the chunk output that will work across formats (i.e. for pdf, html, docx etc) or can use javascript which will work only for html output format. I am showing both of the approaches below.

    For both of the cases, create a placeholder empty pandoc div with ::: and use an id (which will be used by lua or js code) and wrap the exec-summary code chunk with another div with an id (again which will be used by lua or js code to get the output content).

    Using Lua Filter (Robust approach)

    ---
    title: "exec-summary"
    format: html
    filters: 
      - move-output.lua
    ---
    
    ## Executive Summary Presentation
    
    ::: {#placeholder}
    :::
    
    ### Number of Rows
    
    ```{r chunk1}
    x <- nrow(mtcars)
    ```
    
    ### Number of Columns
    
    ```{r chunk2}
    y <- ncol(mtcars)
    ```
    
    ### Executive Summary Computation
    
    ::: {#exec-summary}
    
    ```{r exec-summary}
    glue::glue("There are {x} rows an {y} columns")
    ```
    
    :::
    
    

    move-output.lua

    local exec_summary_output = nil
    
    function get_exec_summary_output()
      return {
        Div = function(el)
          if el.classes:includes("cell-output") then
            exec_summary_output = el.content
            el.content = ""
            return el
          end
        end
      }
    end
    
    function get_exec_summary() 
      return {
        Div = function(el)
          if el.identifier == "exec-summary" then
            local elm = el:walk(get_exec_summary_output())
            return elm
          end
          return el
        end
      }
    end
    
    function replace_placeholder(content)
      return {
        Div = function(el)
          if el.identifier == "placeholder" then
            el.content = content
          end
          return el
        end
      }
    end
    
    function Pandoc(doc)
      local doc = doc:walk(get_exec_summary())
      return doc:walk(replace_placeholder(exec_summary_output))
    end
    

    Using Javascript

    ---
    title: "exec-summary"
    format: 
      html:
        include-in-header: move-output.html
    ---
    
    ## Executive Summary Presentation
    
    ::: {#placeholder}
    :::
    
    ### Number of Rows
    
    ```{r chunk1}
    x <- nrow(mtcars)
    ```
    
    ### Number of Columns
    
    ```{r chunk2}
    y <- ncol(mtcars)
    ```
    
    ### Executive Summary Computation
    
    ::: {#exec-summary}
    
    ```{r exec-summary}
    glue::glue("There are {x} rows an {y} columns")
    ```
    
    :::
    

    move-output.html

    <script>
      function move_exec_summary() {
        let exec_summary = document.querySelector('div#exec-summary div.cell-output');
        let placeholder = document.querySelector('div#placeholder');
        placeholder.insertBefore(exec_summary, placeholder.firstChild);
      }
    
      window.document.addEventListener("DOMContentLoaded", function (event) {
        move_exec_summary();
      });
    </script>
    

    rendered output for both of the above cases