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
- Using AI to find heterogeneous scientific speakers on 04 November 2024
- The many ways to calculate Moran's I for identifying spatially variable genes in spatial transcriptomics data on 29 August 2024
- Characterizing spatial heterogeneity using spatial bootstrapping with SEraster on 23 July 2024
- I use R to (try to) figure out which hospital I should go to for shoppable medical services by comparing costs through analyzing Hospital Price Transparency data on 22 April 2024
- Cross modality image alignment at single cell resolution with STalign on 11 April 2024
- Spatial Transcriptomics Analysis Of Xenium Lymph Node on 24 March 2024
- Querying Google Scholar with Rvest on 18 March 2024
- Alignment of Xenium and Visium spatial transcriptomics data using STalign on 27 December 2023
- Aligning 10X Visium spatial transcriptomics datasets using STalign with Reticulate in R on 05 November 2023
- Aligning single-cell spatial transcriptomics datasets simulated with non-linear disortions on 20 August 2023
TAGS
RELATED POSTS
- Using AI to find heterogeneous scientific speakers
- I use R to (try to) figure out which hospital I should go to for shoppable medical services by comparing costs through analyzing Hospital Price Transparency data
- Querying Google Scholar with Rvest
- I use R to (try to) figure out the cost of medical procedures by analyzing insurance data from the Transparency in Coverage Final Rule