Подтвердить что ты не робот

Размеры рисунков с преобразованием pandoc от уценки до docx

Я печатаю отчет с Rmarkdown в Rstudio. При преобразовании его в html с knitr существует также файл markdown, созданный knitr. Я конвертирую этот файл с pandoc следующим образом:

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

Файл output.docx хорош, за исключением одной проблемы: размеры фигур изменены, мне нужно вручную изменить размеры фигур в Word. Есть ли что-то сделать, возможно, вариант с pandoc, чтобы получить правильные размеры фигур?

4b9b3361

Ответ 1

Легкий способ состоит в том, что в отдельных вариантах пакета включается масштабный коэффициент k:

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

и переменную dpi в глобальных параметрах chunk:

opts_chunk$set(dpi = dpi)

Затем вы можете установить значения dpi и k перед вязанием файла Rmd в глобальной среде:

dpi <<- 96    
k <<- 1

или вы можете установить их в куске в файле Rmd (например, установить k в первом фрагменте).

Ответ 2

Вот решение для изменения размеров фигур с помощью ImageMagick из R Script. 70% -ный коэффициент кажется хорошим выбором.

# 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 для ImageMagick: www.perturb.org

Ответ 3

Я также хочу преобразовать метку R в html и .docx/.odt с цифрами с хорошим размером и разрешением. До сих пор я обнаружил, что лучший способ сделать это - явно определить разрешение и размер графиков в документе .md(dpi, fig.width и fig.height). Если вы это сделаете, у вас есть хорошие графики, которые можно использовать для публикации, а odt/docx - это нормально. Проблема, если вы используете dpi намного выше, чем по умолчанию 72 dpi, заключается в том, что графики будут выглядеть слишком большими в html файле. Вот три подхода, которые я использовал для этого: NB Я использую R-скрипты с синтаксисом spin():

1) используйте out.extra = 'WIDTH = "75%" в параметрах knitr. Это заставит все графики html занять 75% ширины окна. Это быстрое решение, но не оптимальное, если у вас есть сюжеты с очень разными размерами. (NB Я предпочитаю работать с сантиметрами, а не с дюймами, следовательно, /2.54 везде)

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) используйте out.width и out.height, чтобы указать размер графиков в пикселях в html файле. Я использую константу sc, чтобы уменьшить размер графика в html-выходе. Это более точный подход, но проблема в том, что для каждого графика вы должны определить как fig.witdth/height, так и out.width/height, и это действительно здорово! В идеале вы должны указывать глобальные параметры, например, out.width = 150 * fig.width(где fig.width изменяется от chunk до chunk). Возможно, что-то подобное возможно, но я не знаю, как это сделать.

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

Обратите внимание, что для этих двух решений я считаю, что вы не можете напрямую преобразовать свой файл md в odt с помощью pandoc (цифры не включены). Я преобразовываю md в html, а затем html в odt (не пытался для docx). Что-то вроде этого (если предыдущие R-скрипты - это имена "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) Просто скомпилируйте документ дважды, один раз с низким значением dpi (~ 96) для вывода html и один раз с высоким разрешением (~ 300) для вывода odt/docx. Это мой предпочтительный способ. Основной недостаток заключается в том, что вы должны скомпилировать дважды, но это не проблема для меня, поскольку мне обычно нужен файл odt только в самом конце задания, чтобы предоставить конечным пользователям. Я регулярно компилирую html во время работы с кнопкой html notebook в 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])

Затем скомпилируйте 2 выхода со следующим script (здесь вы можете напрямую преобразовать файл md в 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")

Ответ 4

Вот мое решение: взломать docx, преобразованный Pandoc, поскольку docx - это просто набор xml файлов и настройка размеров фигур довольно просто.

Ниже показано, как выглядит фигура в word/document.xml, извлеченном из преобразованного 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>

Таким образом, заменяя атрибуты cx и cy узлов wp:extent и a:ext на нужное значение, будет выполняться задание изменения размера. Для меня работает следующий код R. Самая широкая фигура займет всю ширину линии, указанную переменной out.width, а остальные пропорционально изменены.

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