Coloring SVGs in R
Jun 17, 2022
Beyond spatial transcriptomics analysis, coding is a useful skill for lots of other fun things too! So just for fun, in this blog post, I use R
to recolor an SVG to make some funny colored hot dog dogs.

Getting Started
Let’s first read in an SVG image into R using svgparser
. For the SVG image we’re using, I simplified an SVG image by catalyststuff just so that we can have fewer paths to deal with (more on paths later).
svgparser
parses the SVG elements into grid
graphical objects, aka “grobs”. So we can use grid
to display the original SVG image as a grob.
library(grid)
library(svgparser)
## read in file
file <- 'hotdogdog.svg'
img_grob <- svgparser::read_svg(file)
## show original
grid::grid.newpage()
grid::grid.draw(img_grob)

What is an SVG?
SVGs, or Scalable Vector Graphics, are an XML-based markup language for describing 2D vector graphics. Vector graphics is the set of mechanisms for creating visual images directly from geometric shapes.
If we look at the SVG image using a text editor, we can see that it is just a series of geometric paths defined by sets of 2D points with colors set by hexadecimal fills.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
width="5333.3335"
height="5333.3335"
viewBox="0 0 5333.3335 5333.3335"
>
<path
d="M 0,5333.3333 H 5333.3332 V 1e-4 H 0 Z"
style="fill:#4db7ff;"
id="path14" /><path
d="m 1766.2,3819.6667 c -71.5467,4.1466 -121.4534,7.24 -121.4534,7.24 -25.28,103.3866 -13.7866,298.68 165.4134,399.76 119.6933,67.52 275.1866,44.7866 383.7866,-17.4267 -264.7733,94.8667 -530.4,-136.0267 -427.7466,-389.5733"
style="fill:#ffffff;"
id="path18" /><path
We can see these paths read in as individual grobs in R
as well.
## get elements
ls <- grid::grid.ls()
print(head(ls))
names <- ls$name[grepl('pathgrob', ls$name)]
print(head(names))
[1] "GRID.pathgrob.4257" "GRID.pathgrob.4260" "GRID.pathgrob.4263" "GRID.pathgrob.4266" "GRID.pathgrob.4270"
[6] "GRID.pathgrob.4273"
## check one
name <- names[1]
ngrob <- grid.get(gPath(name))
print(names(ngrob))
print(names(ngrob$gp))
print(ngrob$gp$fill )
[1] "x" "y" "id" "id.lengths" "pathId" "pathId.lengths" "rule"
[8] "name" "gp" "vp"
[1] "col" "fill" "alpha" "lwd" "lineend" "linejoin" "linemitre" "fontsize" "cex"
[10] "fontface" "fontfamily" "font"
[1] "#4DB7FFFF"
Recoloring our SVG
To recolor our SVG, we should be able to just change the path fill colors to something new. So let’s first grab the current fill colors used by these paths.
## grab original fill colors
fills <- sapply(names, function(name) {
ngrob <- grid.get(gPath(name))
ngrob$gp$fill
})
ncols <- length(unique(fills))
table(fills)
fills
#000000FF #4D4D9DFF #4DB7FFFF #CA7B34FF #CA9368FF #CC721DFF #CCB97DFF #CCCCE3FF #ED1821FF #FC63A2FF #FC9A24FF #FDB866FF
38 2 1 1 2 1 1 1 1 11 9 1
#FFCE00FF #FFFFFFFF
1 13
We can see some paths share the same color. For example, there are 38 paths that are black aka #000000FF. In our recoloring, we will keep this pattern for now. So if two paths previously shared the same color, in the recoloring, they will still share the same color. We will sample from a random palette of 20 rainbow colors for our new colors. I will maintain the black outlines though so the paths previously colored black will remain black just for aesthetic purposes.
## recolor
set.seed(100)
rand_colors <- sample(rainbow(20),ncols)
new_colors <- as.factor(fills)
levels(new_colors) = rand_colors
new_colors <- as.character(new_colors)
new_colors[fills == "#000000FF"] <- "#000000FF" ## maintain black outline
names(new_colors) <- names(fills)
table(new_colors)
new_colors
#000000FF #001AFF #0066FF #00B3FF #00FF19 #00FFFF #3300FF #33FF00 #7F00FF #80FF00 #CC00FF #FF0099
38 1 9 2 13 1 11 1 1 2 1 1
#FF4D00 #FFE500
1 1
Now we can recolor our paths by setting their fills to their new random colors and then redrawing them!
## draw with new colors
sapply(names, function(name) {
ngrob <- grid::grid.get(gPath(name))
ngrob$gp$fill <- new_colors[name]
grid::grid.draw(ngrob)
})

Try it out for yourself!
- Try just using any random colors rather than having paths that previously used the same colors continue to share colors.
- Can you identify the paths corresponding to the mustard swirl? What we if also randomly toggle these paths on and off?
- Find your own SVG image and try it out for yourself
- Older
- Newer
RECENT POSTS
- Impact of normalizing spatial transcriptomics data in dimensionality reduction and clustering versus deconvolution analysis with STdeconvolve on 04 May 2023
- Aligning Spatial Transcriptomics Data With Stalign on 16 April 2023
- 3D animation of the brain in R on 08 November 2022
- Ethical Challenges in Biomedical Engineering - Data Collection, Analysis, and Interpretation on 15 October 2022
- I use R to (try to) figure out the cost of medical procedures by analyzing insurance data from the Transparency in Coverage Final Rule on 12 September 2022
- Annotating STdeconvolve Cell-Types with ASCT+B Tables on 30 August 2022
- Deconvolution vs Clustering Analysis: An exploration via simulation on 11 July 2022
- Coloring SVGs in R on 17 June 2022
- Deconvolution vs Clustering Analysis for Multi-cellular Pixel-Resolution Spatially Resolved Transcriptomics Data on 03 May 2022
- Exploring UMAP parameters in visualizing single-cell spatially resolved transcriptomics data on 19 January 2022