rggplot2magick

ggimage shows pixelated SVG but rescaled version does not


I'm making icons with ggimage from an svg :

in.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   version="1.1"
   x="0px"
   y="0px"
   viewBox="0 0 100 100"
   xml:space="preserve"
   style="enable-background:new 0 0 100 100;"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg"><defs
     id="defs1" /><path
     d="m 56.215759,24.245239 2.723511,-3.026123 c 1.063416,0.750855 2.304382,1.141236 3.553894,1.141236 1.583008,0 3.165039,-0.602539 4.370117,-1.807618 2.40918,-2.410156 2.40918,-6.332031 0,-8.742187 -2.410156,-2.4101562 -6.330078,-2.4101562 -8.740234,0 -2.179199,2.179199 -2.367798,5.583618 -0.606201,7.999634 l -3.096131,3.440246 c -46.999406,-0.760793 24.296811,25.305901 1.795044,0.994812 z m 3.32135,-11.02063 c 0.81543,-0.814453 1.885743,-1.222656 2.956055,-1.222656 1.070313,0 2.140625,0.408203 2.956055,1.222656 1.628906,1.63086 1.629883,4.283203 0,5.914063 -1.63086,1.628906 -4.28125,1.628906 -5.91211,0 -1.630859,-1.63086 -1.630859,-4.283203 0,-5.914063 z" /></svg>

Data and plot to make the icons

# https://stackoverflow.com/questions/6862742/draw-a-circle-with-ggplot2
gg_circle <- function(r, xc, yc, color="black", fill=NA, ...) {
  x <- xc + r*cos(seq(0, pi, length.out=100))
  ymax <- yc + r*sin(seq(0, pi, length.out=100))
  ymin <- yc + r*sin(seq(0, -pi, length.out=100))
  annotate("ribbon", x=x, ymin=ymin, ymax=ymax, color=color, fill=fill, ...)
}

df = data.frame(x = c(0,1), y = c(0,1))
df2 = data.frame(x = c(0.5), y = c(.5))
image = "in.svg"
ggincon = ggplot(df, 
                 aes(x=x, y=y)) + 
  gg_circle(r=0.05, xc=0.5, yc=0.5, color=NA, 
            fill='#F4F44F', 
            alpha=1) +
  ggimage::geom_image(data = df2, 
                      mapping = aes(x,y,image = image),
                      colour = '#FA434F', 
                      size = .7) + 
  coord_fixed() + 
  theme_void();ggincon

But as you can see, it is pixelated

enter image description here

So I resize the svg :

magick in.svg  -resize 1200x1200 -gravity center out.svg

image = "out.svg"

And rerun the code :

enter image description here

But now the 'resolution' is fine but the resize command changed the 'smoothness' of the curved lines... as in resizing SVG makes it jagged and not smooth with magick.

How could I make the SVG correctly be imported and placed on the color circle without pixelating it or changing the actual shapes (i.e., circles should stay circles)?


Solution

  • The problem is that ggimage::geom_image returns a grid::rasterGrob, which in its own words draws "a bitmap image" (i.e. not a vector image).

    An alternative solution exists in svgparser, which keeps its input as a native vector image.

    im_svg <- svgparser::read_svg(image, style_default=list(fill="#FA434F"))
    
    ggicon <- ggplot2::ggplot(df, ggplot2::aes(x=x, y=y)) +
      gg_circle(r=0.05, xc=0.5, yc=0.5, color=NA, fill="#F4F44F", alpha=1) +
      ggplot2::annotation_custom(im_svg) +
      ggplot2::coord_fixed() +
      ggplot2::theme_void()
    
    svglite::svglite("ggicon.svg")
    print(ggicon)
    dev.off()
    

    Be sure when drawing/saving this file to use an actual SVG device, such as svglite. (StackOverflow won't let me upload an .svg image to accurately show the result)