Можно создать файлы справки Rd для объектов, не входящих в пакет?

Я использую Rstudio для оптимизации Sweave и R для анализа данных, которые я поделюсь с другими аналитиками. Для того чтобы сделать кодирование переменных кристально чистым, было бы здорово иметь что-то вроде файла справки, чтобы они могли вызвать ?myData и получить полезный файл, если это необходимо. Мне нравится уценка Rd и думаю, что на самом деле у нее есть большой потенциал для документирования аналитических наборов данных, включая общее резюме, переменную с разбивкой по переменным и пример того, как выполнять некоторые поисковые анализы.

Это легко сделать, если вы специально создаете пакет, но я думаю, что это запутывает, поскольку пакеты в конечном итоге представляют собой набор функций, и они не интегрируют файлы Rnw.

Можно ли использовать Roxygen2 для создания файлов справки для наборов данных, которые не являются частью какого-либо пакета?

Ответ 1

Прежде чем я начну с этого, я хотел бы повторить то, что говорят другие. R - это буквально то, что вы ищете. Он успешно используется многими, чтобы распространять только данные и никакого кода. В сочетании с R lazyloading данных вы можете распространять большие наборы данных в виде пакетов и не обременять пользователей, которые не хотят загружать их все.

Кроме того, вы не сможете воспользоваться системой помощи R, если вы не используете пакеты. В исходном вопросе явным образом спрашивает об использовании ?myData, и ваши пользователи не смогут этого сделать, если вы не используете пакет. Это довольно просто ограничение базовой справочной функции R.


Теперь, чтобы ответить на вопрос. Вам нужно будет использовать некоторые неэкспортируемые функции roxygen, чтобы сделать эту работу, но она не слишком обременительна. Кроме того, вам необходимо поместить ваши R файлы (ов), документирующие ваши данные, в их собственную папку, и в этой папке вы захотите создать пустую папку с именем man.

Пример структуры каталогов:

# ./
# ./man/
# ./myData.R
# ./otherData.R

myData.R

#' My dataset
#' 
#' This is data I like.
#' 
#' @name myData
NULL

otherData.R:

#' My other dataset
#' 
#' This is another dataset I like
#' 
#' @name otherData
NULL

Теперь, код, который приведет все это вместе (и вы можете, конечно, обернуть это в функцию):

library(roxygen2)
mydir <- "path/to/your/data/directory/"
myfiles <- c("myData.R","otherData.R")

# get parsed source into roxygen-friendly format
env <- new.env(parent = globalenv())
rfiles <- sapply(myfiles, function(f) file.path(mydir,f))
blocks <- unlist(lapply(rfiles, roxygen2:::parse_file, env=env), recursive=FALSE)
parsed <- list(env=env, blocks=blocks)

# parse roxygen comments into rd files and output then into the "./man" directory
roc <- roxygen2:::rd_roclet()
results <- roxygen2:::roc_process(roc, parsed, mydir)
roxygen2:::roc_output(roc, results, mydir, options=list(wrap=FALSE), check = FALSE)

Теперь вы должны иметь отформатированные файлы myData.Rd и otherData.Rd в однократной папке man.

Ответ 2

Вот хакерский подход, который работает. Создайте фиктивный пакет в каталоге temp, используйте его для генерации ваших файлов Rd, затем извлеките файлы Rd и очистите. См. Код ниже.

Надеюсь, что это поможет.

Примечание. Убедитесь, что у вас есть тег @export в функциях, которые вы хотите сгенерировать для файлов Rd, чтобы это работало.

makeRd <- function(rscript, dir.out){
  stopifnot(require(devtools))

  # Prepare paths
  pkg.path = tempdir()
  r.path = file.path(pkg.path, 'R')
  man.path = file.path(pkg.path, 'man')
  desc.path = file.path(pkg.path, 'DESCRIPTION')

  # Create directories
  dir.create(r.path, F)
  dir.create(man.path, F)

  # Write dummy description
  z = c('Package', 'Type', 'Title', 'Version', 'Date', 'Author', 'Maintainer', 'Description', 'Licence')
  writeLines(paste0(z, ': X'), desc.path)

  # Copy rscript file over to dummy package and generate rd files
  file.copy(rscript, r.path)
  suppressMessages( document(pkg.path) )

  # Copy generated Rd files to output directory
  f.in = list.files(man.path, full.names = T)
  f.out = file.path(dir.out, basename(f.in))
  for(i in 1:length(f.in)) file.copy(f.in[i], f.out[i], overwrite = T)

  # Unlink
  unlink(pkg.path, T, T)
  return(f.out)
}

# Example
rd = makeRd(rscript='foo.R', dir.out='~/Desktop')
print(rd)
# [1] "~/Desktop/myFunction.Rd"

Ответ 3

В пакете tools есть функция, называемая parse_Rd. Вы можете сгенерировать файлы .Rd, запустить parse_Rd на них и сохранить выходные данные как объекты в пространстве имен модулей. Вам понадобится новая функция поиска (возможно, modHelp), которая найдет соответствующий объект Rd в пространстве имен и отобразит его с помощью Rd2text или другого, или специального решения. Не уверен, что вы можете получить что-то другое, кроме основной текстовой справки, которую вырывает Rd2text, но вы можете.

Ответ 4

Теперь roxygen2 поддерживает это изначально, но, поскольку соответствующие функции помечены как "внутренние", они не отображаются в индексе документации.

Тем не менее, функции экспортируются и являются частью официального API:

И, чтобы отобразить полученную помощь, вам потребуется

Рабочий процесс выглядит следующим образом:

source_env = roxygen2::env_file(sourcefile)
rd_blocks = roxygen2::parse_file(sourcefile, source_env)
help_topics = roxygen2::roclet_process(roxygen2::rd_roclet(), rd_blocks, source_env, dirname(sourcefile))
rd_code = lapply(help_topics, format)

Это дает вам список разделов справки в файле. Чтобы отобразить один из них, вам нужен пакет {tools}, который является частью базы R, но не прикреплен по умолчанию.

Ниже показано, как отобразить текстовую справку. Отображение справки HTML немного более запутанно (я предлагаю вам прочитать и понять исходный код utils:::print.help_files_with_topic, который фактически отображает разделы справки, и который полностью недокументирован.

# Display first help topic. In reality youd want to select a specific one.
topic = names(rd_code)[1L]
help_text = rd_code[[topic]]

rd = tools::parse_Rd(textConnection(help_text))
packagename = tools::file_path_sans_ext(basename(sourcefile))
helpfile = tools::Rd2txt(rd, out = tempfile('Rtxt'), package = packagename)
helptitle = gettextf('R Help on %s', sQuote(sub('\\.Rd$', '', topic)))
file.show(helpfile, title = helptitle, delete.file = TRUE)

Ответ 5

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

Вы прокомментируете, что пакеты не интегрируют файлы Rnw, но я скорее считаю, что вы ошибаетесь. Формат по умолчанию для пакета vignettes - это файл Rnw или Sweave. Вы можете легко кооптировать виньетку как способ сделать отчет об анализе пакета.

Я действительно использую этот подход в своих собственных анализах и задокументировал его в нескольких блогах: почему, и сравнение с шаблоном проекта. Я также использовал его как в проектах академического анализа (все больше и больше, пока не могу указать на пример), и в личных проектах (например, https://github.com/rmflight/timmysDensity, http://rmflight.github.io/posts/2013/06/timmysDensity.html, заметьте, что я еще не использовал механизм пакета для поиска данных).

BTW, за исключением размещения данных в пакете (у которых есть только пакеты данных, Bioconductor имеет довольно много), я не думайте, что есть способ сделать то, что вы просите, за пределами простого предоставления сырых тегов roxygen2 в .R файле, как было описано выше для набора данных.