image - engine - Tamaños de figuras con conversión de pandoc de markdown a docx
pandoc pdf-engine (4)
Aquí hay una solución para cambiar el tamaño de las figuras usando ImageMagick desde una secuencia de comandos R. La relación del 70% parece ser una buena opción.
# the path containing the Rmd file :
wd <- "..."
setwd(wd)
# the folder containing the figures :
fig.path <- paste0(wd, "/figure")
# all png figures :
figures <- list.files(fig.path, pattern=".png", all.files=TRUE)
# (safety) create copies of the original files
dir.create(paste0(fig.path,"_copy"))
for(i in 1:length(figures)){
fig <- paste0(fig.path, "/", figures[i])
file.copy(fig,"figure_copy")
}
# resize all figures
for(i in 1:length(figures)){
fig <- paste0(fig.path, "/", figures[i])
comm <- paste("convert -resize 70%", fig, fig)
shell(comm)
}
# then run pandoc from a command line
# or from the pandoc() function :
library(knitr)
pandoc("MyReport.md", "docx")
Más información sobre la función de cambio de resize
de ImageMagick: www.perturb.org
Escribo un informe con Rmarkdown en Rstudio. Al convertirlo en html
con knitr, también hay un archivo de reducción producido por knitr. Convierto este archivo con pandoc
siguiente manera:
pandoc -f markdown -t docx input.md -o output.docx
El archivo output.docx
está bien, excepto por un problema: los tamaños de las figuras están alterados, necesito cambiar manualmente el tamaño de las figuras en Word. ¿Hay algo que hacer, tal vez una opción con pandoc
, para obtener los tamaños de figuras correctos?
También quiero transformar una rebaja R en un html y un .docx / .odt con cifras de buen tamaño y resolución. Hasta ahora, descubrí que la mejor manera de hacerlo es definir explícitamente la resolución y el tamaño de los gráficos en el documento .md (dpi, fig.width y fig.height options). Si haces esto, tienes buenos gráficos utilizables para publicación y el odt / docx está bien. El problema si usa ppp mucho más alto que el valor predeterminado de 72 ppp es que los gráficos se verán demasiado grandes en el archivo html. Aquí hay 3 enfoques que he usado para manejar esto (Nota: yo uso scripts R con la sintaxis spin ()):
1) use out.extra = ''WIDTH = "75%"'' en las opciones knitr. Esto obligará a todos los gráficos del html a ocupar el 75% del ancho de la ventana. Esta es una solución rápida, pero no óptima si tiene parcelas con tamaños muy diferentes. (NB Prefiero trabajar con centímetros en lugar de pulgadas, de ahí el /2.54 en todas partes)
library(knitr)
opts_chunk$set(echo = FALSE, dev = c("png", "pdf"), dpi = 400,
fig.width = 8/2.54, fig.height = 8/2.54,
out.extra =''WIDTH="75%"''
)
data(iris)
#'' # Iris datatset
summary(iris)
boxplot(iris[,1:4])
#+ fig.width=14/2.54, fig.height=10/2.54
par(mar = c(2,2,2,2))
pairs(iris[,-5])
2) use out.width y out.height para especificar el tamaño de los gráficos en píxeles en el archivo html. Uso una "sc" constante para reducir el tamaño de la gráfica en la salida html. Este es el enfoque más preciso, pero el problema es que para cada gráfico tiene que definir tanto fig.witdth / height como out.width / height ¡y esto es realmente aburrido! Idealmente, debería ser capaz de especificar en las opciones globales que, por ejemplo, out.width = 150 * fig.width (donde fig.width cambia de chunk a chunk). Tal vez algo así es posible, pero no sé cómo.
#+ echo = FALSE
library(knitr)
sc <- 150
opts_chunk$set(echo = FALSE, dev = c("png", "pdf"), dpi = 400,
fig.width = 8/2.54, fig.height = 8/2.54,
out.width = sc*8/2.54, out.height = sc*8/2.54
)
data(iris)
#'' # Iris datatset
summary(iris)
boxplot(iris[,1:4])
#+ fig.width=14/2.54, fig.height=10/2.54, out.width= sc * 14/2.54, out.height= sc * 10/2.54
par(mar = c(2,2,2,2))
pairs(iris[,-5])
Tenga en cuenta que para estas dos soluciones, creo que no puede transformar directamente su archivo md en odt con pandoc (las cifras no están incluidas). Transformé el md en html y luego el html en odt (no intenté para docx). Algo así (si los scripts R anteriores son nombres "figsize1.R"):
library(knitr)
setwd("/home/gilles/")
spin("figsize1.R")
system("pandoc figsize1.md -o figsize1.html")
system("pandoc figsize1.html -o figsize1.odt")
3) Simplemente compile su documento dos veces, una vez con un valor bajo de ppp (~ 96) para la salida html y una vez con alta resolución (~ 300) para la salida odt / docx. Esta es mi forma preferida ahora. La principal desventaja es que debe compilar dos veces, pero esto no es realmente un problema para mí, ya que generalmente necesito el archivo odt solo al final del trabajo para proporcionarlo a los usuarios finales. Recopilo regularmente el html durante el trabajo con el botón del cuaderno html en Rstudio.
#+ echo = FALSE
library(knitr)
opts_chunk$set(echo = FALSE, dev = c("png", "pdf"),
fig.width = 8/2.54, fig.height = 8/2.54
)
data(iris)
#'' # Iris datatset
summary(iris)
boxplot(iris[,1:4])
#+ fig.width=14/2.54, fig.height=10/2.54
par(mar = c(2,2,2,2))
pairs(iris[,-5])
Luego compila las 2 salidas con la siguiente secuencia de comandos (NB aquí puedes transformar directamente el archivo md en html):
library(knitr)
setwd("/home/gilles")
opts_chunk$set(dpi=96)
spin("figsize3.R", knit=FALSE)
knit2html("figsize3.Rmd")
opts_chunk$set(dpi=400)
spin("figsize3.R")
system("pandoc figsize3.md -o figsize3.odt")
Una manera fácil consiste en incluir un factor de escala k
en las opciones de fragmentos individuales:
{r, fig.width=8*k, fig.height=6*k}
y una dpi
variable en las opciones globales de fragmentos:
opts_chunk$set(dpi = dpi)
Luego puede establecer los valores de dpi
k
antes de tejer el archivo Rmd
en el entorno global:
dpi <<- 96
k <<- 1
o puede configurarlos en un fragmento en el archivo Rmd
(por ejemplo, establecer k
en el primer fragmento).
Aquí está mi solución: hackear el docx convertido por Pandoc, ya que docx es simplemente un paquete de archivos xml y ajustar los tamaños de las figuras es bastante sencillo.
A continuación, se muestra el aspecto de una figura en la word/document.xml
extraída de un docx convertido:
<w:p>
<w:r>
<w:drawing>
<wp:inline>
<wp:extent cx="1524000" cy="1524000" />
...
<a:graphic>
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic>
...
<pic:blipFill>
<a:blip r:embed="rId23" />
...
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0" />
<a:ext cx="1524000" cy="1524000" />
</a:xfrm>
...
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
</w:p>
Por lo tanto, sustituir los atributos cx
y cy
de los nodos wp:extent
& a:ext
con el valor deseado haría el trabajo de cambio de tamaño. El siguiente código R funciona para mí. La figura más ancha tomaría el ancho de una línea completa especificada por la variable out.width
, y el resto se redimensionaría proporcionalmente.
require(XML)
## default linewidth (inch) for Word 2003
out.width <- 5.77
docx.file <- "report.docx"
## unzip the docx converted by Pandoc
system(paste("unzip", docx.file, "-d temp_dir"))
document.xml <- "temp_dir/word/document.xml"
doc <- xmlParse(document.xml)
wp.extent <- getNodeSet(xmlRoot(doc), "//wp:extent")
a.blip <- getNodeSet(xmlRoot(doc), "//a:blip")
a.ext <- getNodeSet(xmlRoot(doc), "//a:ext")
figid <- sapply(a.blip, xmlGetAttr, "r:embed")
figname <- dir("temp_dir/word/media/")
stopifnot(length(figid) == length(figname))
pdffig <- paste("temp_dir/word/media/",
## in case figure ids in docx are not in dir''ed order
sort(figname)[match(figid, substr(figname, 1, nchar(figname) - 4))], sep="")
## get dimension info of included pdf figures
pdfsize <- do.call(rbind, lapply(pdffig, function (x) {
fig.ext <- substr(x, nchar(x) - 2, nchar(x))
pp <- pipe(paste(ifelse(fig.ext == ''pdf'', "pdfinfo", "file"), x, sep=" "))
pdfinfo <- readLines(pp); close(pp)
sizestr <- unlist(regmatches(pdfinfo, gregexpr("[[:digit:].]+ X [[:digit:].]+", pdfinfo, ignore.case=T)))
as.numeric(strsplit(sizestr, split=" x ")[[1]])
}))
## resizing pdf figures in xml DOM, with the widest figure taking up a line''s width
wp.cx <- round(out.width*914400*pdfsize[,1]/max(pdfsize[,1]))
wp.cy <- round(wp.cx*pdfsize[, 2]/pdfsize[, 1])
wp.cx <- as.character(wp.cx)
wp.cy <- as.character(wp.cy)
sapply(1:length(wp.extent), function (i)
xmlAttrs(wp.extent[[i]]) <- c(cx = wp.cx[i], cy = wp.cy[i]));
sapply(1:length(a.ext), function (i)
xmlAttrs(a.ext[[i]]) <- c(cx = wp.cx[i], cy = wp.cy[i]));
## save hacked xml back to docx
saveXML(doc, document.xml, indent = F)
setwd("temp_dir")
system(paste("zip -r ../", docx.file, " *", sep=""))
setwd("..")
system("rm -fr temp_dir")