Calling variables before they're declared in a notebook?

I typically like to have my chunks in a manner that is coherent for someone (me) reading the code. For example, I'll often have some text declaring what I'm trying to achieve, what is in the following figure(s), and whether there's some statistical difference e.g. 'In figure 1.1 we show x and y... mean = .... (p < 0.05)'. Then I'll have 2 chunks, one for the graph, followed by a chunk that finds summary info (means, medians, etc) and some statistical analysis.

The problem I have is referencing within the text before the chunks. It works fine for figure references, but I can't reference variables before they're defined. Below is a MWE hopefully illustrating what I mean. Is there any way around this? The obvious answer is to move the summary stats chunk before the paragraph of text, but I find this more confusing when I revisit the code.

I can reference figures before they're plotted: Figure \@ref(fig:cars-plot) but not other things: `r mean_speed`.

```{r cars-plot, fig.cap = "plot of cars"}
plot(cars)
```

```{r}
mean_speed <- mean(cars$speed)
```

Which throws the following error, because I'm trying to call it before the chunk is executed:

Error in eval(parse_only(code), envir = envir) : object 'mean_speed' not found

notebook.Rmd works a bit differently. Preview throws the error, but if you look at the tiny dropdown arrow and knit to html, no problem

---
title: "R Notebook"
output:
  html_document:
    df_print: paged
---


```{r cars-plot, fig.cap = "plot of cars"}
plot(cars)
mean_speed <- mean(cars$speed)

The mean speed of the cars is `r mean_speed`

Hmm, I'm having the issue when I use 'knit to html' too (FWIW I'm actually using bookdown and have the same issue when using bookdown::render_book("index.Rmd", "bookdown::gitbook") too).

Also perhaps I'm misunderstanding, but in your example, it looks like you define mean_speed before using the inline reference? Your example works fine for me but what I really want to do is call mean_speed in my blurb before the chunk, so like this:

  1. Explanatory text; aims, what the figure is, and some summary info (I pull summary values (e.g. mean_speed) from chunks defined below)
  2. Chunk with figure
  3. Chunk with summary statistics (e.g. define mean_speed here)

Like I said in the original post, the obvious solution (and the one I've been using), is to move chunk 3 above chunk 1, but when I revisit my notebooks, particularly after a period of time, I find it more difficult to see which bits of analysis relate to which bit of text.

Ah, sorry to have misread, but not I'm more confused

title: "R Notebook"
output:
  html_document:
    df_print: paged
---

I can reference figures before they're plotted: Figure \@ref(fig:cars-plot) but not other things: # omitted mean_speed

But you can also reference \@fig:cars-no_plot. AFAICT, neither figure reference shows up in the output

```{r cars-plot, fig.cap = "plot of cars"}
plot(cars)

Ok, so, I know even less than I thought I did... It appears this is a limitation of R Notebooks but works fine in bookdown. What happened is I ran the above code within my bookdown 'environment', where the figure referencing does work. Here is the output of the above code (where I've omitted the mean_speed bit):

I thought .Rmd files 'within' bookdown and 'outside' were equivalent, but evidently not!

1 Like

Good catch! Different rendering chain with multiple passes, I'd guess.

Yes, I suppose that is the reason. It's a shame this doesn't work for my specific use case. I wish there was some way to define the 'priority' for a chunk in order execute it before inline code (or I wish I could find the documentation on how to do this!). I find I rarely, if ever, define stuff inline but will often report the output from a chunk inline instead.

First solution : ref.label

You can use ref.label chunk option to reference another chunk and get the code.

In your case it works

---
title: "R Notebook"
output: html_document
---

```{r, ref.label="mean-speed", echo = FALSE}
```


I can get the value of `mean_speed` even if it is define in a chunk after. Mean speed = `r mean_speed`.

```{r cars-plot, fig.cap = "plot of cars"}
plot(cars)
```

```{r mean-speed}
mean_speed <- mean(cars$speed)
```

This trick will place the last chunk at the beginning of the document. It won't work in all case but in yours it could be ok.

You can reference several chunks in one if required

```{r exec-summary, echo = FALSE, ref.label = c("model", "table")}
```

Another solution: caching mechanism.

There is a fonction knitr::load_cache() that allows to load all objects or specific one. You can activate the cache with cache = 'TRUE' and you'll need to pass on the document to make it work.

See the knitr example 114 in knitr example repo:

Also, as you are \@ref(fig:cars-plot), are you using a bookdown format ? not classic html_document I think.

Hope you'll make it work ! :slight_smile:

2 Likes

Thank you for the suggested solutions, I will try them out and see how it all works. To answer your last question first, yes, I'm using bookdown::gitbook. I naively thought rmd files would behave the same (bookdown was my first introduction to rmarkdown files), so didn't think to mention that in my original post :roll_eyes:.

I thought about using cache before, but I've tried to stay clear of it because a) none of my data/code are that time consuming and b) I don't understand it! It's my understanding that it stores the output but that might be dangerous if the code chunk is dependent on other chunks (e.g. if a previous chunk reads in a csv that changes)? Anyway, I'll have a play around and try and figure out it's behaviour!

If you haven’t seen these already, a couple of links to help with trying to understand knitr’s cache:


But personally, I think that the ref.label approach is nice in this case, because it seems to me that allowing you to program your document in a way that puts human readability first is kind of the whole point of literate programming, and very much in the spirit of knitr.

3 Likes

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.