Usar bucles con knitr para producir múltiples informes en PDF … necesito un poco de ayuda para superar la joroba

Antes que nada, debo admitir que soy muy nuevo en knitr y en el concepto de análisis reproducible, pero puedo ver su potencial para mejorar mi flujo de trabajo actual (que incluye mucho copiar y pegar en documentos de Word).

A menudo tengo que producir múltiples informes por grupo (Hospital en este ejemplo) y dentro de cada hospital, puede haber muchos Wards diferentes sobre los que estoy informando un resultado. Anteriormente ejecuté todos mis gráficos y análisis en R usando bucles, luego comencé el trabajo de copiar / pegar; sin embargo, después de leer esta publicación ( ¿Puede Sweave producir muchos archivos PDF automáticamente? ), y me dio la esperanza de que realmente podría saltar varios pasos y pasar directamente de R a informar a través de Rnw / knitr.

Sin embargo, después de intentarlo, veo que hay algo que no está funcionando (ya que el entorno R dentro del Rnw no parece reconocer las variables de bucle que estoy tratando de pasarle).

## make my data Hospital <- c(rep("A", 20), rep("B", 20)) Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2) Month <- rep(seq(1:10), 4) Outcomes <- rnorm(40, 20, 5) df <- data.frame(Hospital, Ward, Month, Outcomes) ## Here is my current work flow-- produce all plots, but export as png and cut/paste for(hosp in unique(df$Hospital)){ subgroup <- df[ df$Hospital == hosp,] for(ward in unique(subgroup$Ward)){ subgroup2 <- subgroup[subgroup$Ward == ward,] savename <- paste(hosp, ward) plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename)) } } # followed by much copy/pasting ## Here is what I'm trying to go for using knitr library(knitr) for (hosp in unique(df$Hospital)){ knit("C:file.path\\testing_loops.Rnw", output=paste('report_', Hospital, '.tex', sep="")) } ## With the following *Rnw file ## start *.Rnw Code \documentclass[10pt]{article} \usepackage[margin=1.15 in]{geometry} <>= Hospital <- c(rep("A", 20), rep("B", 20)) Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2) Month <- rep(seq(1:10), 4) Outcomes <- rnorm(40, 20, 5) df <- data.frame(Hospital, Ward, Month, Outcomes) subgroup <- df[ df$Hospital == hosp,] @ \begin{document} <>= opts_chunk$set(fig.path = paste("test", hosp , sep="")) @ Some infomative text about hospital \Sexpr{hosp} <>= for(ward in unique(subgroup$Ward)){ subgroup2 <- subgroup[subgroup$Ward == ward,] # subgroup2 <- subgroup2[ order(subgroup2$Month),] savename <- paste(hosp, ward) plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename)) } @ \end{document} ## To be then turned into pdf with this tools::texi2pdf("C:file.path\\report_A.tex", clean = TRUE, quiet = TRUE) 

Después de tratar de ejecutar mi fragmento de código knit () obtengo este error:

 Error in file(con, "w") : invalid 'description' argument 

Y cuando miro en el directorio donde iba a crearse el archivo * .tex, puedo ver que se produjeron las 2 ttwigs PDF del hospital A (ninguna para B) y ningún archivo * .tex específico del hospital para unir en un pdf. ¡Gracias de antemano por cualquier ayuda que pueda ofrecer!

No necesita volver a definir los datos en el archivo .Rnw y creo que la advertencia proviene del hecho de que está colocando el nombre del resultado junto con Hospital (el vector completo de hospitales) en lugar de hosp (el índice del ciclo )

Siguiendo su ejemplo, testingloops.Rnw sería

 \documentclass[10pt]{article} \usepackage[margin=1.15 in]{geometry} <>= subgroup <- df[ df$Hospital == hosp,] @ \begin{document} <>= opts_chunk$set(fig.path = paste("test", hosp , sep="")) @ Some infomative text about hospital \Sexpr{hosp} <>= for(ward in unique(subgroup$Ward)){ subgroup2 <- subgroup[subgroup$Ward == ward,] # subgroup2 <- subgroup2[ order(subgroup2$Month),] savename <- paste(hosp, ward) plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename)) } @ \end{document} 

y el archivo R del controlador sería solo

 ## make my data Hospital <- c(rep("A", 20), rep("B", 20)) Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2) Month <- rep(seq(1:10), 4) Outcomes <- rnorm(40, 20, 5) df <- data.frame(Hospital, Ward, Month, Outcomes) ## knitr loop library("knitr") for (hosp in unique(df$Hospital)){ knit2pdf("testingloops.Rnw", output=paste0('report_', hosp, '.tex')) } 

Gran pregunta! Esto funciona para mí con los otros bits que ha suministrado en su pregunta. Tenga en cuenta que he reemplazado su hosp con solo x . He llamado a tu archivo test.rnw

 # input data Hospital <- c(rep("A", 20), rep("B", 20)) Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2) Month <- rep(seq(1:10), 4) Outcomes <- rnorm(40, 20, 5) df <- data.frame(Hospital, Ward, Month, Outcomes) # generate the tex files, one for each hospital in df library(knitr) lapply(unique(df$Hospital), function(x) knit("C:\\emacs\\test.rnw", output=paste('report_', x, '.tex', sep=""))) # generate PDFs from the tex files, one for each hospital in df lapply(unique(df$Hospital), function(x) tools::texi2pdf(paste0("C:\\emacs\\", paste0('report_', x, '.tex')), clean = TRUE, quiet = TRUE)) 

He reemplazado sus bucles con funciones anónimas y de aplicación, que a menudo parecen ser más de Rish.

Aquí puede ver dónde reemplacé el hosp con x en el archivo rnw :

 \documentclass[10pt]{article} \usepackage[margin=1.15 in]{geometry} <>= Hospital <- c(rep("A", 20), rep("B", 20)) Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2) Month <- rep(seq(1:10), 4) Outcomes <- rnorm(40, 20, 5) df <- data.frame(Hospital, Ward, Month, Outcomes) subgroup <- df[ df$Hospital == x,] @ \begin{document} <>= opts_chunk$set(fig.path = paste("test", x , sep="")) @ Some informative text about hospital \Sexpr{x} <>= for(ward in unique(subgroup$Ward)){ subgroup2 <- subgroup[subgroup$Ward == ward,] # subgroup2 <- subgroup2[ order(subgroup2$Month),] savename <- paste(x, ward) plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename)) } @ \end{document} 

El resultado son dos archivos tex (informe_A.tex, informe_B.tex), cuatro archivos PDF para las figuras (A1, A2, B1, B2) y dos archivos PDF para los informes (informe_A.pdf, informe_B.pdf), cada uno con sus cifras en ellos. ¿Es eso lo que estabas buscando?

En esta respuesta pretendo responder a una pregunta más general: “Usar ciclos para producir múltiples informes en PDF”, y no su ejemplo específico. Esto se debe a que esta tendencia era bastante difícil de seguir como novato. Logré que funcionara eventualmente (versión html), así que esta es mi humilde solución. Probablemente hay algunos mejores publicados aquí, simplemente no puedo entenderlos completamente todavía.

  1. cree un archivo RMD con su diseño y guárdelo en el directorio working \ input (en Rstudio: file-> newfile-> R markdown). Este archivo debe incluir todas las funciones que necesita para hacer las representaciones en el informe (simplemente declare en uno de esos fragmentos de código). Piense en este archivo como la plantilla para todos los informes futuros. No se preocupe por pasar los datos a su entorno después de masticarlos antes; lo cubriré en (2). la cuestión clave que hay que comprender es que todos los cálculos se realizan más adelante (en el momento en que se renderiza el archivo RMD).

  2. crea el bucle que necesitas usar en un archivo r de control diferente. En mi caso, hay un bucle que itera sobre todos los archivos en el directorio y los coloca en el dataframe. entonces quiero pasar esos dataframes al RMD, junto con otras variables de datos, para trazarlos. Así es como se hace:

    run_on_all<-function(path_in="path:\\where\\your\\input\\and\\RMD\\is", path_out="path:\\where\\your\\output\\will\\be") setwd(path_in) ibrary(rmarkdown) library(knitr) list_of_file_names=list.files(path = getwd, pattern = "*.csv") #this gets a list of the input files names for (file_name in list_of_file_names) { data=read.csv(file_name) #read file into data frame report_name=paste(some_variable_name,".html",sep="") render("your_template.Rmd",output_file =report_name,output_dir =path_out,list(data,all other parameters you want to input into the RMD))} }

  3. El comando más importante es la llamada a la función de renderizado . Te permite lanzar al entorno RMD los parámetros que desees. También le permite cambiar el nombre del informe y cambiar la ubicación de salida. Además, al invocarlo, también está generando el informe, de modo que puede obtenerlo todo en una línea. (Tenga en cuenta que si la llamada a RMD está dentro de una función, puede encontrar que faltan las variables que ingresa, pero el informe todavía se publicará correctamente)

resumen

hay dos archivos que necesita: archivo RMD, que será la plantilla para todos los informes adicionales y un archivo de control. el archivo de control obtiene datos, los mastica y pasa los parámetros masticados al RMD (a través de la función de renderizado). el RMD obtiene los datos, realiza algunos cálculos, los traza y los publica en un nuevo archivo (también por la función de representación). Espero haber ayudado.