Как получить исходный файл R Markdown, например, `source ('myfile.r')`?

У меня часто есть основной файл R Markdown или файл knitr LaTeX, где яsource некоторый другой R-файл (например, для обработки данных). Однако я подумал, что в некоторых случаях было бы полезно, чтобы эти исходные файлы были их собственными воспроизводимыми документами (например, файл R Markdown, который не только включает команды для обработки данных, но также создает воспроизводимый документ, объясняющий обработку данных. решения).

Таким образом, я хотел бы иметь такую команду, какsource('myfile.rmd') в моем основном файле R Markdown. что бы извлечь и получить весь код R внутри кусков кода Rmyfile.rmd, Конечно, это приводит к ошибке.

Следующая команда работает:

```{r message=FALSE, results='hide'}
knit('myfile.rmd', tangle=TRUE)
source('myfile.R')
```

гдеresults='hide' можно было бы опустить, если вывод был желателен. Т.е. knitr выводит код R изmyfile.rmd вmyfile.R.

Однако это не кажется идеальным:

it results in the creation of an extra file it needs to appear in it's own code chunk if control over display is required. It's not as elegant as simple source(...).

Таким образом, мой вопрос: Is there a more elegant way of sourcing the R code of an R Markdown file?

 Maiasaura10 июн. 2012 г., 07:26
Мне действительно трудно понять ваш вопрос (я прочитал его несколько раз). Вы можете легко найти другие R-скрипты вRmd файл. Но вы также хотите, чтобы источник в другомmarkdown файлы в файл вязаные?
 Jeromy Anglim10 июн. 2012 г., 08:20
Я хочу получить код R внутри фрагментов кода R в файлах R Markdown (т.е. * .rmd)? Я немного отредактировал вопрос, чтобы попытаться прояснить ситуацию.
 Jeromy Anglim10 июн. 2012 г., 13:30
@PaulHiemstra Я полагаю, что также была бы полезна возможность источника текста и фрагментов кода R. Я специально думаю о поиске только кода в документе R Markdown.
 Paul Hiemstra10 июн. 2012 г., 09:36
Нечто подобноеinclude в латексе. Если уценка поддерживает включение других документов уценки, создать такую функцию должно быть относительно легко.

Ответы на вопрос(6)

Решение Вопроса

вы ищете однострочник. Как насчет того, чтобы положить это в свой.Rprofile?

ksource <- function(x, ...) {
  library(knitr)
  source(purl(x, output = tempfile()), ...)
}

Тем не менее, я не понимаю, почему вы хотитеsource() код в самом файле Rmd. Я имею в видуknit() запустит весь код в этом документе, и если вы извлечете код и запустите его в чанке, весь код будет запущен дважды, когда выknit() этот документ (вы запускаете себя в себя). Две задачи должны быть отдельными.

Если вы действительно хотите запустить весь код, RStudio сделал это довольно легко:Ctrl + Shift + R, Это в основном называетpurl() а такжеsource() за кулисами.

 24 июл. 2014 г., 11:03
Привет @ Yihui Я думаю, что это полезно, потому что иногда ваш анализ может быть организован в небольших сценариях, но в вашем отчете вы хотите иметь код для всего конвейера.
 09 янв. 2017 г., 12:58
@Yihui Какой будет предложенная альтернатива источнику (purl (x, ...))? по вашему мнению? Как можно получить несколько * .Rmd-файлов, не столкнувшись с ошибкой, связанной с дублированием меток чанка? Я бы не хотел возвращаться к исходному документу и связывать его. Я использую * .Rmd для многих файлов, которые мне, возможно, придется экспортировать и обсуждать с другими, поэтому было бы здорово иметь возможность получать несколько Rmd-файлов для всех этапов анализа.
 22 авг. 2014 г., 21:43
@BrashEquilibrium Это вопрос использованияsource() или жеknitr::knit() запустить код. Я знаю, что люди менее знакомы с последним, ноpurl() не надежно Вы были предупреждены:github.com/yihui/knitr/pull/812#issuecomment-53088636
 19 авг. 2014 г., 23:14
Таким образом, здесь используется тот случай, когда вы хотите написать весь код, чтобы он был тщательно документирован и объяснен, но код запускается другим скриптом.

library(readr)
library(stringr)
source_rmd <- function(file_path) {
  stopifnot(is.character(file_path) && length(file_path) == 1)
  .tmpfile <- tempfile(fileext = ".R")
  .con <- file(.tmpfile) 
  on.exit(close(.con))
  full_rmd <- read_file(file_path)
  codes <- str_match_all(string = full_rmd, pattern = "```(?s)\\{r[^{}]*\\}\\s*\\n(.*?)```")
  stopifnot(length(codes) == 1 && ncol(codes[[1]]) == 2)
  codes <- paste(codes[[1]][, 2], collapse = "\n")
  writeLines(codes, .con)
  flush(.con)
  cat(sprintf("R code extracted to tempfile: %s\nSourcing tempfile...", .tmpfile))
  source(.tmpfile)
}

.R и импортировать фрагменты по мере необходимости в файле .Rmd. Я объяснил процессВот.

а затем добавьте этот R-файл в каждый Rmd-файл, в котором он вам нужен.

так, например, скажем, у меня есть два отчета, которые мне нужно сделать: вспышки гриппа и анализ оружия по сравнению с анализом масла. Естественно, я создал два документа Rmd и покончил с этим.

Теперь предположим, что босс пришел и хочет увидеть разницу между вспышками гриппа и ценами на масло (с учетом боеприпасов 9 мм).

Copying and pasting the code to analyze the reports into the new report is a bad idea for code reuse, etc. I want it to look nice.

Моим решением было разделить проект на следующие файлы:

Flu.Rmd flu_data_import.R Guns_N_Butter.Rmd guns_data_import.R butter_data_import.R

в каждом Rmd-файле у меня есть что-то вроде:

```{r include=FALSE}
source('flu_data_import.R')
```

Проблема в том, что мы теряем воспроизводимость. Мое решение заключается в том, чтобы создать общий дочерний документ для включения в каждый Rmd-файл. Таким образом, в конце каждого файла Rmd, который я создаю, я добавляю это:

```{r autodoc, child='autodoc.Rmd', eval=TRUE}
``` 

И, конечно же, autodoc.Rmd:

Source Data & Code
----------------------------
<div id="accordion-start"></div>

```{r sourcedata, echo=FALSE, results='asis', warnings=FALSE}

if(!exists(autodoc.skip.df)) {
  autodoc.skip.df <- list()
}

#Generate the following table:
for (i in ls(.GlobalEnv)) {
  if(!i %in% autodoc.skip.df) {
    itm <- tryCatch(get(i), error=function(e) NA )
    if(typeof(itm)=="list") {
      if(is.data.frame(itm)) {
        cat(sprintf("### %s\n", i))
        print(xtable(itm), type="html", include.rownames=FALSE, html.table.attributes=sprintf("class='exportable' id='%s'", i))
      }
    }
  }
}
```
### Source Code
```{r allsource, echo=FALSE, results='asis', warning=FALSE, cache=FALSE}
fns <- unique(c(compact(llply(.data=llply(.data=ls(all.names=TRUE), .fun=function(x) {a<-get(x); c(normalizePath(getSrcDirectory(a)),getSrcFilename(a))}), .fun=function(x) { if(length(x)>0) { x } } )), llply(names(sourced), function(x) c(normalizePath(dirname(x)), basename(x)))))

for (itm in fns) {
  cat(sprintf("#### %s\n", itm[2]))
  cat("\n```{r eval=FALSE}\n")
  cat(paste(tryCatch(readLines(file.path(itm[1], itm[2])), error=function(e) sprintf("Could not read source file named %s", file.path(itm[1], itm[2]))), sep="\n", collapse="\n"))
  cat("\n```\n")
}
```
<div id="accordion-stop"></div>
<script type="text/javascript">
```{r jqueryinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://code.jquery.com/jquery-1.9.1.min.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r tablesorterinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://tablesorter.com/__jquery.tablesorter.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r jqueryuiinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://code.jquery.com/ui/1.10.2/jquery-ui.min.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r table2csvinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(file.path(jspath, "table2csv.js")), sep="\n")
```
</script>
<script type="text/javascript">
  $(document).ready(function() {
  $('tr').has('th').wrap('<thead></thead>');
  $('table').each(function() { $('thead', this).prependTo(this); } );
  $('table').addClass('tablesorter');$('table').tablesorter();});
  //need to put this before the accordion stuff because the panels being hidden makes table2csv return null data
  $('table.exportable').each(function() {$(this).after('<a download="' + $(this).attr('id') + '.csv" href="data:application/csv;charset=utf-8,'+encodeURIComponent($(this).table2CSV({delivery:'value'}))+'">Download '+$(this).attr('id')+'</a>')});
  $('#accordion-start').nextUntil('#accordion-stop').wrapAll("<div id='accordion'></div>");
  $('#accordion > h3').each(function() { $(this).nextUntil('h3').wrapAll("<div>"); });
  $( '#accordion' ).accordion({ heightStyle: "content", collapsible: true, active: false });
</script>

N.B., это разработано для Rmd - & gt; HTML рабочий процесс. Это будет ужасный беспорядок, если вы будете использовать латекс или что-то еще. Этот документ Rmd просматривает глобальную среду для всех файлов source () и включает их источник в конце вашего документа. Он включает в себя jquery ui, tablesorter и настраивает документ на использование стиля аккордеона для отображения / скрытия исходных файлов. Это работа в процессе, но не стесняйтесь адаптировать ее для своих собственных нужд.

Я знаю, что это не одна строка. Надеюсь, это даст вам хотя бы некоторые идеи :)

я думаю, что что-то вроде этого должно работать:

Read the markdown/R file with readLines Use grep to find the code chunks, searching for lines that start with <<< for example Take subset of the object that contains the original lines to get only the code Dump this to a temporary file using writeLines Source this file into your R session

Оборачивая это в функцию, вы получите то, что вам нужно.

 Jeromy Anglim10 июн. 2012 г., 14:20
Спасибо, думаю, это сработает. Тем не менее, первые четыре пункта звучат как то, что Stangle уже делает надежным способом для Sweave и чтоknit('myfile.rmd', tangle=TRUE) делает в Knitr. Полагаю, я ищу один вкладыш, который запутывает и использует источники, и в идеале не создает файлов.
 Jeromy Anglim10 июн. 2012 г., 14:30
Да.textConnection может быть место, чтобы посмотреть.
 10 июн. 2012 г., 14:27
Как только вы обернетесь в функцию, она станет единственной;). Что вы могли бы сделать, это использоватьtextConnection имитировать файл и источник из этого. Это позволит избежать создания файла.

нужно начать думать иначе. Моя проблема заключается в следующем: Напишите каждый код, который вы обычно имели бы в чанке .Rmd в файле .R. И для документа Rmd, который вы используете, чтобы связать, т.е. HTML, вы только оставили

```{R Chunkname, Chunkoptions}  
source(file.R)  
```

Таким образом, вы, вероятно, создадите кучу файлов .R, и вы потеряете преимущество обработки всего кода "chunk after chunk". используя ctrl + alt + n (или + c, но обычно это не работает). Но я прочитал книгу о воспроизводимых исследованиях г-на Гандруда и понял, что он определенно использует файлы knitr и .Rmd исключительно для создания html-файлов. Основной анализ сам по себе представляет собой файл .R. Я думаю, что документы .RMD быстро становятся слишком большими, если вы начинаете делать весь свой анализ внутри.

Ваш ответ на вопрос