3

Plots produced with R are not usable for publication if they cannot be exorted properly. I work on a Windows Machine and use MS Word 2016 for all writing purposes. So, I wish to export my plots as .wmf files (.emf would also do, I suppose).

I produce all graphs with ggplot2, so ggsave (device = "wmf") seems a good choice, I suppose. However, I have a major problem with the resulting files: point geoms seem to be printed as raster instead of vector format. Here is an example for producing a simple scatterplot:

library (ggplot2)    

plot_data <- data.frame (a = runif (1:20), 
                         b = seq (1:20))

x11 (width =  3, height = 3)

ggplot (data = plot_data, mapping = aes (x = a, y = b)) +
    geom_point () +
    labs (x = "my x-label", y = "my y-label") +
    theme (panel.background = element_blank(),
           panel.border = element_rect (fill = NA, size = 0.7),
           axis.ticks = element_line (color = "black", lineend = "round"),
           axis.ticks.length = unit (2, "mm"),
           axis.text = element_text (color = "black"),
           plot.margin = unit(rep (0, 4), "cm")
           )

I save the plot with the following code:

ggsave(filename = "my_file.wmf", device = "wmf")

When I open the plot in MS Word or Libre Office, I see that the points are not rendered in good quality, at all. In Libre Office Draw, a point looks like this (zoomed in quite a lot):

enter image description here

In MS Word, the plot looks like this:

enter image description here

with these "points":

enter image description here

The labels and axes, however, are ok. MS Word:

enter image description here

Libre Office Draw:

enter image description here

I suppose that the labels, tick annotations and axes (and even circles around the points) are stored in vector format, whereas the point geoms seem to be stored as rasters. The resulting plots are not useable, I fear. So, I want to find an option to force ggsave () to vectorize point geoms instead of printing raster. I hope very much someone can help - I urgently need a simple way to export plots from R for publication in order to convince my lab to rely more on R.

yenats
  • 531
  • 1
  • 3
  • 16
  • 1
    Likely related: https://github.com/ropensci/pdftools/issues/25. `grDevices::pdf.options(useDingbats=FALSE)` might help – tjebo Oct 29 '19 at 15:58
  • 1
    Another, maybe less satisfying workaround, would be to change the point shape. As you can see in your magnification, geom_point draws both point and stroke (`shape 19`). The stroke looks alright, so you could use `shape = 1`. I think the better option would be to change the Dingbats option as above. I'd probably also not recommend windows proprietary file formats. I personally always save as `pdf`, and then use Adobe illustrator to export this to any image file. This way I stay also flexible when my paper should not be accepted and I need to reformat to other image formats. – tjebo Oct 29 '19 at 16:30
  • I will try the Dingbats option. I know that windows proprietary file formats are not ideal. However, my goal is to convince my collegues to use R for plotting. In order to do so, I'd ideally present a workflow using only R and MS word. – yenats Oct 30 '19 at 12:11
  • Dingbats is a .pdf - option, I suppose. When saving a .wmf file, I get: `Error in grDevices::win.metafile(...) : unused argument (useDingbats = FALSE)` – yenats Oct 30 '19 at 12:22
  • There is another constraint for usage with PDF for me: I use the font "ChantillyLH", which can be registered via `font_import` and `loadfonts (device = "win")` in the `extrafont` package. However, `loadfonts (device = "pdf")`gives an error for ChantillyLH [`More than one version of regular/bold/italic found for ChantillyLH. Skipping setup for this font.`]. I am not able to fix this; I really tried in several ways. ChantillyLH seems not to be in the "standard" - font format with "normal", "italic", "bold" and "bolditalic" style. Unfortunately... – yenats Oct 30 '19 at 14:33
  • if it's only for use in word, why don't you just print in a tif or png device with a reasonnably high resolution, e.g. 300dpi? – tjebo Oct 31 '19 at 09:34
  • For publication, vector graphics are required. some journals ask for *MS word* files containing vector graphics. I do not know why, but there is no way to change this - other formats will just not be accepted. I do also think that it might be relevant for others to be able to print vectorized .wmf files in the future (?). – yenats Nov 03 '19 at 12:53
  • @yenats I'm running into the same kind of problem as you, by some miracle were you able to find a fix for the rasterized points in your wmf files? – Fragilaria Nov 25 '19 at 14:10
  • ... unfortunately no. I now decided to head into another direction and use .svg., which is a pure vector format (I believe). `Cairo::CairoSVG` works best for me because it enables me to embed fonts. .svg files can be opened in incscape (which is freeware) and converted into .emf or .wmf if needed. It's a somehow annoying workaround, but it works. In office 365, one should be able to open .svg files anyway... – yenats Nov 26 '19 at 11:48

2 Answers2

5

You can directly create a fully vectorized EMF (or EMF+) file in R using the add-on CRAN package devEMF. This avoids any need to export to SVG and later convert to EMF. I'm not sure why the ggsave(..., device="wmf") call (which uses the window API to generate the file) is using raster plotting symbols here, but the functions in devEMF definitely use vectors (I say this both as the developer of devEMF and confirmed by zooming in with LibreOffice).

After installing devEMF, you can run the example code from the original question and then:

library(devEMF)
ggsave(filename = "my_file.emf", device = emf)

NOTE: emf (without quotes) used in the code above is the name of a function defined by devEMF (analogous to x11 used in the original question). "emf" (with quotes) would be interpreted by ggsave as a request to the use windows API. You want the former without quotes, not the latter with quotes.

Alternatively, the original call to x11 could be replaced and the emf file generated directly without the need for ggsave:

library (ggplot2)
library (devEMF)

plot_data <- data.frame (a = runif (1:20), 
                         b = seq (1:20))

emf (file = "my_file.emf", width =  3, height = 3)

ggplot (data = plot_data, mapping = aes (x = a, y = b)) +
    geom_point () +
    labs (x = "my x-label", y = "my y-label") +
    theme (panel.background = element_blank(),
           panel.border = element_rect (fill = NA, size = 0.7),
           axis.ticks = element_line (color = "black", lineend = "round"),
           axis.ticks.length = unit (2, "mm"),
           axis.text = element_text (color = "black"),
           plot.margin = unit(rep (0, 4), "cm")
           )

dev.off() #must close device to close file!

In my experience, MS Office support for EMF & EMF+ is as complete as for WMF, so generating EMF is a reasonable solution for this use case. If you run into compatibility problems, look at the emfPlus* arguments to the emf function (see help("emf", package="devEMF")).

Philip Johnson
  • 186
  • 1
  • 5
  • Thank you for this very neat solution. However, for my purposes I have a problem that cannot be solved this way. I need to embed fonts but "EMF/EMF+ do not allow for embedding fonts. Thus you must be careful that your desired font is present both on the system that you use when you create the emf file (i.e., when you run R) and on the system that you use to import/view the resulting file. Sticking to the standard Adobe PostScript font families is probably a good idea." Saving as .svg and then converting to .emf is the only workaround I have found so far... – yenats Jul 06 '20 at 10:07
  • Oh, interesting -- CairoSVG seems to convert the font glyphs to curves. I could hypothetically implement a similar procedure in devEMF; if I end up doing so, I'll post here. – Philip Johnson Jul 07 '20 at 22:34
  • Perfect. I have no idea how much work this is. However, I imagine that more people run into similar issues as I did. So an update of devEMF could be much appreciated, I suppose. In any case, I am looking forward to your solution if you find the time for it. – yenats Jul 09 '20 at 19:58
  • 1
    Version 4.0 of devEMF (on CRAN now) has an option "emfPlusFontToPath" that converts fonts to curves (paths). Technically this isn't font embedding (the font gylphs are not accessible to downstream programs for further text editing), but it ensures that the resulting EMF+ files are portable. Note this option is currently only implemented for Linux and Windows (not Apple). – Philip Johnson Sep 02 '20 at 18:53
  • wow, this is a major improvement, I think. thank you! – yenats Sep 03 '20 at 07:44
1

I didn't find a way to make the WMF device behave, but you can save to SVG and then use R to automate conversion from SVG to EMF via Inkscape (a free software you need to download separately) as:

inkscape_path <-'C:/Program Files/Inkscape/inkscape.exe'
if(!file.exists(inkscape_path)) {
  warning("Could not find inkscape, will not convert to .emf")
} else {
   input_file <- "plot.svg"
   output_file <- "plot.emf"
   system(paste0('"', inkscape_path,'"', ' --file "', input_file, '" --export-emf "', output_file, '"'))
}

(Inkscape doesn't support export to WMF from command line but for the purpose of importing int Office, WMF and EMF should be interchangeable)

EDIT: Unfortunately, you cannot access some export settings from the command line (notably the "convert text to paths" option). However, the command line will use the settings you last used to export WMF, so you can save once manually with the desired settings and do further conversions automatically. (this is a known limitation: https://bugs.launchpad.net/inkscape/+bug/1747696)

Martin Modrák
  • 746
  • 8
  • 17
  • until I am getting the newest version of ms office, which is told to be able to read .svg files, this might be the best solution so far. My current workaround was to manually open the .svg files in inkscape and sacing them as .emf, so some R action for automation seems to be a very welcome enhancement of this method... – yenats Jan 24 '20 at 15:10