Tailles des figures avec conversion pandoc de markdown à docx

<!-Je tape un rapport avec Rmarkdown dans Rstudio. Lors de la conversion en html avec knitr, il y a aussi un markdown fichier produit par knitr. - Je convertir ce fichier avec pandoc comme suit :

pandoc -f markdown -t docx input.md -o output.docx

output.docx le fichier est agréable, sauf pour un seul problème: la taille des chiffres sont modifiés, j'ai besoin de redimensionner manuellement les chiffres dans Word. Est-il quelque chose à faire, peut-être une option pandoc, pour obtenir les bons chiffres tailles ?

19
demandé sur user1248490 2013-02-12 13:57:59

4 réponses

Un moyen simple consiste à inclure un facteur d'échelle k dans les options de morceaux individuels:

{r, fig.width=8*k, fig.height=6*k}

et une variable dpi dans les options global chunk:

opts_chunk$set(dpi = dpi)

Ensuite, vous pouvez définir les valeurs de dpi et k avant de tricoter le Rmd le fichier dans l'environnement global:

dpi <<- 96    
k <<- 1

ou vous pouvez les mettre dans un morceau dans le Rmd fichier (set k dans le premier morceau par exemple).

7
répondu Stéphane Laurent 2014-04-14 06:21:51
ImageMagick à partir d'un Script R. Le ratio de 70% semble être un bon choix.

# 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")
resize fonction de ImageMagick : www.perturb.org

3
répondu Stéphane Laurent 2013-05-13 13:24:22

je veux aussi transformer un markdown R en html et A.docx/.odt avec des chiffres à la bonne taille et la résolution. Jusqu'à présent, j'ai trouvé que la meilleure façon de le faire est de définir explicitement la résolution et la taille des graphiques dans le .document du md (dpi, fig.la largeur et la fig.options de hauteur). Si vous faites cela, vous avez de bons graphiques utilisables pour la publication et l'odt/docx est ok. Le problème si vous utilisez dpi beaucoup plus élevé que le 72 dpi par défaut, est que les graphiques auront l'air trop grand dans le html fichier. Voici 3 approches que j'ai utilisées pour gérer ceci (NB j'utilise des scripts R avec la syntaxe spin ()):

1) utiliser.extra=' WIDTH = "75%" ' dans les options knitr. Cela forcera tous les graphiques du html à occuper 75% de la largeur de la fenêtre. C'est une solution rapide, mais pas optimal si vous avez des parcelles de tailles très différentes. (NB je préfère travailler avec des centimètres plutôt que des pouces, d'où le / 2.54 partout)

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) utiliser.la largeur et la.hauteur de spécifier la taille de la graphiques en pixels dans le fichier html. J'utilise une constante "sc" pour diminuer la taille de la parcelle dans la sortie html. C'est l'approche plus précise, mais le problème est que pour chaque graphique, vous devez définir les deux fig.witdth / height et out.largeur/hauteur et c'est vraiment boaring ! Idéalement, vous devriez être en mesure de spécifier dans les options globales par exemple.Largeur = 150 * fig.largeur (où fig.la largeur des changements de bloc à bloc). Peut-être que quelque chose comme ça est possible mais je ne sais pas comment.

#+ 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])

notez que pour ces deux solutions, je pense que vous ne pouvez pas transformer directement votre fichier md en odt avec pandoc (les chiffres ne sont pas inclus). Je transforme le md en html puis le html en odt (Je n'ai pas essayé docx). Quelque chose comme ça (si les scripts R précédents sont des noms "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) compilez simplement votre document deux fois, une fois avec une faible valeur dpi (~96) pour la sortie html et une fois avec une haute résolution (~300) pour l'odt / docx sortie. C'est ma manière préférée maintenant. Le principal inconvénient est que vous devez compiler deux fois, mais ce n'est pas vraiment un problème pour moi puisque j'ai généralement besoin du fichier odt seulement à la toute fin de la tâche à fournir aux utilisateurs finaux. Je compile régulièrement le html pendant le travail avec le bouton HTML notebook dans 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])

puis compilez les 2 sorties avec le script suivant (NB ici vous pouvez directement transformer le fichier 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")
3
répondu Gilles 2013-05-27 22:44:31

voici ma solution: hacker le docx converti par Pandoc, comme docx est simplement un paquet de fichiers xml et ajuster les tailles de figure est assez simple.

voici à quoi ressemble une figure dans le word/document.xml extrait d'un DOCX converti:

<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>

donc en remplaçant le cx& cy attributs des nœuds wp:extent& a:ext avec la valeur désirée ferait le travail de redimensionnement. Le code R suivant fonctionne pour moi. Le chiffre le plus large prendrait un largeur de la ligne entière spécifiée par la variable out.width, et les autres sont redimensionnés proportionnellement.

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")
2
répondu lcn 2013-07-24 19:44:41