magick icon indicating copy to clipboard operation
magick copied to clipboard

`image_graph` device is very slow (with benchmarking code and alternative with `png` device)

Open gavril0 opened this issue 6 months ago • 0 comments
trafficstars

I found that making plot withimage_graph device is very slow. Making plots in temporary files with png (or jpeg) and reading these files with image_read is x15 faster!

Image

Figure Elapsed time to draw n plots.

n png image_draw
1 0.03 0.24
10 0.16 2.40
20 0.30 4.76

Table Elapsed time (sec).

Benchmaking:

# make plots with png device in temporarz files and read them
mk_plot_png <- function(n, tempdir="./tmp") {
    # R base device
    png(filename = paste(tempdir,"graph_%04d.png",sep="/"),
      width = 960, height = 480, res = 72)
    # make plots
    for(i in 1:n) plot(1:10, (1:10)/i)
    dev.off()
    # read graphs
    fn <- sprintf("%s/graph_%04d.png" , tempdir, 1:n)
    graphs <- magick::image_read(fn) 
    # remove files
    #unlink(fn)
    graphs
}

# make plots with image_draw device
mk_plot_image_draw <- function(n) {
    # open magick graphical device (VERY SLOW)
    graphs <- magick::image_graph(width = 960, height = 480, res = 72)
    # create an image for each time 
    for(i in 1:n) plot(1:10, (1:10)/i)
    dev.off()
    graphs
}

# both function generate n png images
mk_plot_image_draw(n=2)

   format width height colorspace matte filesize density
 1    PNG   960    480       sRGB  TRUE        0   72x72
 2    PNG   960    480       sRGB  TRUE        0   72x72

mk_plot_png(n=2, tempdir = "./tmp/")

  format width height colorspace matte filesize density
1    PNG   960    480       sRGB FALSE     2643   28x28
2    PNG   960    480       sRGB FALSE     2619   28x28

Note that density for png is in pixels/cm (28 pixed/cm = 72 dpi) because the PNG format does not support DPI (see http://www.w3.org/TR/2003/REC-PNG-20031110/#11pHYs). In principle, it should be possible to redefine the units when displaying the info

convert r.png -units pixelsperinch -verbose info:

to get the same output but coud not find how to do it with R magick.

# data frame to store timing results
res <- expand.grid(
  device  = c("png","image_draw"), 
  n       = c(1, 10, 20),
  elapsed = NA)

for(i in 1:nrow(res)) {
  n <- res$n[i] # number of plots to draw
  if(res$device[i]=="png") {
    res$elapsed[i] <- system.time(
      graphs <- mk_plot_png(n, tempdir = "./tmp/"))["elapsed"]
  } else {
    res$elapsed[i] <- system.time(
      graphs <- mk_plot_image_draw(n))["elapsed"]
  }
  image_destroy(graphs)
}

# plot (see above)
lattice::xyplot(elapsed ~ n, group=device, data=res, 
  type="b", auto.key=TRUE)

Info:

  • R version 4.4.2
  • magick_2.8.6

`

gavril0 avatar May 19 '25 07:05 gavril0