Rozmiary figur z konwersją pandoc z markdown na docx

Wpisuję raport z Rmarkdown w Rstudio. Podczas konwersji w {[1] } z knitr, istnieje również plik markdown wyprodukowany przez knitr. Konwertuję ten plik pandoc w następujący sposób:

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

Plik output.docx jest ładny z wyjątkiem jednego problemu: rozmiary figur są zmienione, muszę ręcznie zmienić rozmiar figur w programie Word. Czy jest coś do zrobienia, może opcja z pandoc, aby uzyskać odpowiednie rozmiary liczb ?

Author: user1248490, 2013-02-12

4 answers

Prosty sposób polega na uwzględnieniu współczynnika skali k w poszczególnych opcjach fragmentu:

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

I zmienna dpi w opcjach części globalnej:

opts_chunk$set(dpi = dpi)

Następnie możesz ustawić wartości dpi i k przed utworzeniem pliku Rmd w środowisku globalnym:

dpi <<- 96    
k <<- 1

Lub możesz ustawić je w kawałku w pliku Rmd (na przykład ustaw k w pierwszym kawałku).

 7
Author: Stéphane Laurent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-14 06:21:51

Oto rozwiązanie do zmiany rozmiaru figur za pomocą ImageMagick ze skryptu R. Stosunek 70% wydaje się być dobrym wyborem.

# 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")

Więcej informacji o resize funkcji ImageMagick: www.perturb.org

 3
Author: Stéphane Laurent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-13 13:24:22

Chcę również przekształcić znacznik R w html i a .docx/odt z liczbami w dobrym rozmiarze i rozdzielczości. Do tej pory odkryłem, że najlepszym sposobem na to jest jawne zdefiniowanie rozdzielczości i rozmiaru Wykresów w dokumencie .md (DPI, rys.szerokość i rys.opcje wysokości). Jeśli to zrobisz, masz dobre wykresy nadające się do publikacji i ODT / docx jest ok. Problem, jeśli używasz dpi dużo wyższe niż domyślne 72 dpi, jest to, że wykresy będą wyglądać zbyt duże w pliku html. Oto 3 podejścia, które wykorzystałem do obsługi tego (NB używam skryptów R ze składnią spin ()):

1) zużyć./ width ="75%" / Spowoduje to, że wszystkie wykresy html zajmą 75% szerokości okna. Jest to szybkie rozwiązanie, ale nie optymalne, jeśli masz działki o bardzo Różnych Rozmiarach. (NB wolę pracować z centymetrami niż calami, stąd / 2.54 wszędzie)

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) zużyć.szerokość i na zewnątrz.wysokość aby określić rozmiar Wykresów w pikselach na plik html. Używam stałej "sc", aby zmniejszyć rozmiar wykresu do wyjścia html. Jest to bardziej precyzyjne podejście, ale problem polega na tym, że dla każdego grafu trzeba zdefiniować oba rys.witdth / height i out.szerokość / wysokość i to jest naprawdę boaring ! Idealnie powinieneś być w stanie określić w opcjach globalnych, że np. out./ width = 150 / rys.szerokość (gdzie rys.szerokość zmienia się z kawałka na kawałek). Może coś takiego jest możliwe, ale nie wiem jak.

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

Zauważ, że dla te dwa rozwiązania, myślę, że nie można przekształcić bezpośrednio pliku md do odt za pomocą pandoc (dane nie są uwzględnione). Przekształcam md w html, a następnie html w ODT(nie próbowałem Dla docx). Coś w tym stylu (jeśli poprzednie Skrypty R są nazwami " 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) po prostu skompiluj dokument dwa razy, raz z niską wartością dpi (~96) dla wyjścia html i raz z wysoką rozdzielczością (~300) dla wyjścia ODT/docx. Teraz to mój ulubiony sposób. Główne wadą jest to, że musisz skompilować dwa razy, ale nie jest to naprawdę problem dla mnie, ponieważ generalnie potrzebuję pliku odt tylko na samym końcu zadania, aby zapewnić użytkownikom końcowym. Regularnie kompiluję html podczas pracy z przyciskiem notatnika html w 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])

Następnie skompiluj 2 wyjścia za pomocą następującego skryptu (NB tutaj możesz bezpośrednio przekształcić plik md w 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
Author: Gilles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-27 22:44:31

Oto moje rozwiązanie: zhakuj docx przekonwertowany przez Pandoc, ponieważ docx jest po prostu pakietem plików xml i dostosowywanie rozmiarów figur jest dość proste.

Oto, jak wygląda rysunek w word/document.xml wyodrębniony z przekonwertowanego docx:

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

Więc zastąpienie cx & cy atrybuty węzłów wp:extent & a:ext z pożądaną wartością wykonałoby zadanie zmiany rozmiaru. Następujący kod R działa dla mnie. Najszersza liczba zajmowałaby szerokość całej linii określoną przez zmienna out.width, a reszta jest proporcjonalnie zmieniana.

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
Author: lcn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-24 19:44:41