Quicker render and save of ggplot

Hello,

I am hoping to find a quicker way to preview and save the following graph. The run time is really long and I am running on a very strong system. Is there any way to render the preview quicker or to change the save of the plot?

I'd be open to any suggestions/answers.

# Load packages
library(aRtwork)
library(ggplot2)
library(tweenr)

# Generate data
df <- procedural_ring(seed = 3, n = 400, n_circles = 4, r_0 = 5000,
                      eps = 500, eps_big = 5000, p_defect = 0.1, delta = 2.02)

# Create plot
p <- ggplot() +
  geom_segment(aes(x, y, xend = xend, yend = yend), df, size = 0.025, alpha = 0.05) +
  coord_equal() +
  theme_void()

# Save plot (might take a few moments)
ggsave("procedural_ring.png", p, width = 20, height = 20, units = "cm")

Does using procedural_ring.svg save you any time? Vector plot should be quicker than raster.

Thanks for the reply! It does reduce the saving time considerably. I am slightly stuck still as the .svg is 778mb which is massive. So far any attempts to preview or to convert it to .pdf and .png have failed. Any way to convert a file of this size with ease?

1 Like

I did notice that 20 in x 20 in was a tad large :grin:

I don't know what your ultimate plans are for this image, but if you want to be able to preview it, try reducing the size to 5 x 5 for a look-see, then go up to 10, 15, maybe back to 12.5 and see what the quartering search tells you.

My ultimate plans will be to print this at a very high resolution and DPI scale (600) so ideally I would want to go as large as possible. Still not winning as it is. I am sure there is some ways to get around this. I just need to read up more and experiment.

Using raster is gonna require AWS EC2 scale RAM; encourage using vector

I am not exactly sure how I should use vector here. Can you elaborate slightly? :slight_smile:

1 Like

Sorry to be obscure. Think of it in art terms.

Raster is George Seurat

Lots of ink = many pixels = many bytes

Vector is Al Hirshfield, the late Line King

Screen Shot 2020-03-21 at 3.39.40 PM

If your graphic looks like the first, you're stuck with raster rendering; if it looks like the second, you can use vector rendering, which consists of scaleless representation of lines, plots and curves and ignores the whitespace, cutting way down on file size.

svg is vector

1 Like

If you need your preview to determine whether you generally "like" what you see and because df is likely a dataframe you could down-sample this dataframe first to some reasonable size, get a (much) smaller image and if you like it render a full-sized dataframe later

2 Likes

As @ychinenov said, your image size may also be affected by the size of the object you are plotting, in addition to the size you are trying to render it to. I'd add the complexity of the plot

1 Like

I believe the major bottleneck here is the rendering to a device part...
ragg is an indevelopment package with perfomance benefits.
Note I chose 2362 pixel dimension, as I estimated at 300dpi default, a 20cm by 20cm image would be approx 2362^2

library(aRtwork)
library(ggplot2)
library(ragg) #devtools::install_github('r-lib/ragg')
#https://ragg.r-lib.org/

# Generate data
df <- procedural_ring(seed = 3, n = 400, n_circles = 4, r_0 = 5000,
                      eps = 500, eps_big = 5000, p_defect = 0.1, delta = 2.02)


  file <- knitr::fig_path('.png')

ragg::agg_png(file, width = 2362, height = 2362, units = 'px')

ggplot() +
  geom_segment(aes(x, y, xend = xend, yend = yend), df, size = 0.025, alpha = 0.05) +
  coord_equal() +
  theme_void()


invisible(dev.off())

knitr::include_graphics(file)

3 Likes

1 in = 2.54 cm (he said imperiously)

With 600dpi and 50.8 cm, a raster image may not be plot-able, even with a shallow color space. Still suggest a package such as svglite

1 Like

Definitely a good recommendation! I sampled 30% of the points and that didn't really make it more plotable or saveable with the default code above so I do think the rendering to a device is indeed the issue here as @nirgrahamuk pointed out. This might be something to keep in mind later on in different circumstances.

1 Like

This worked surprisingly well. I could push it up really high as in 9449 x 9449 pixels (~1200 dpi) without a problem. Do you know why this rendering lacks some of the more darker elements that you see in the example here: https://github.com/marcusvolz/generative ?

I am going to experiment more with what you provided. I just wanted to know - is the best way to introduce smoothing to the lines by upping the DPI more or is there some ways within ragg to do that? I see it is often able to provide better quality or smoother outputs.

svglite is probably the way to go. I am assuming that is how Thomas Pedersen gets his big generative art out likely. I will have to check how to take the code and put it through svglite. I would appreciate it if you do have a quick way of showing how likely to do so!

I'm really not sure, about the lightness issue, perhaps there is some option regarding anti-aliasing or something.
Also it seems to me that you could divide the dataframe which is a list of instructions for line segments to draw, such that you could partition a 2d space into 4 quads, and render an image for each corner, stitching them together perhaps with some higher level image processing package (or even manually with photoshop or gimp)

1 Like

Perhaps stitching with grobs

I wanted to ask - in terms of this code:

library(aRtwork)
library(ggplot2)
library(ragg) #devtools::install_github('r-lib/ragg')
#https://ragg.r-lib.org/

# Generate data
df <- procedural_ring(seed = 3, n = 400, n_circles = 4, r_0 = 5000,
                      eps = 500, eps_big = 5000, p_defect = 0.1, delta = 2.02)


  file <- knitr::fig_path('.png')

ragg::agg_png(file, width = 2362, height = 2362, units = 'px')

ggplot() +
  geom_segment(aes(x, y, xend = xend, yend = yend), df, size = 0.025, alpha = 0.05) +
  coord_equal() +
  theme_void()


invisible(dev.off())

knitr::include_graphics(file)

What is the correct way to for loop it? Somehow adding a normal loop over it and changing the seed doesn't work. It just creates blank canvases?

Could you try replacing this:

ggplot() +
  geom_segment(aes(x, y, xend = xend, yend = yend), df, size = 0.025, alpha = 0.05) +
  coord_equal() +
  theme_void()

by this

p <-
  ggplot() +
  geom_segment(aes(x, y, xend = xend, yend = yend), df, size = 0.025, alpha = 0.05) +
  coord_equal() +
  theme_void()
print(p)

in your loop? Plots within blocks often need to be explicitly printed to be rendered.

1 Like

Thank for this. I just want to add that everyone's replies have been extremely helpful to get me more up to speed with this and how best to work. I really appreciate and love this about the community.

Just to update the overall thread. I finally came to a solution. To change the graphic device really did the trick. I opted to use Cairo and this has been giving the correct colouring from the original plot and I've pushed it to really far limits (such as the below example code within a reasonable amount of time).

library(Cairo)
Cairo::Cairo(10000, 10000, file="plot1.png", type="png", bg="white", dpi = 600)
plot(p)
dev.off()

1 Like