1

I wonder if there is an automated way to align several microscopic images together in R to appear in such form like this image here (source: doi: https://doi.org/10.1101/2019.12.11.873471). I am not looking for image analysis, only grid the images and add labels. I tried with magick in which I was able to write labels on the images and with gridExtra to align them and add the labels outside. but still not satisfied because I wasn't able to control the distance between the blocks and add labels in boxes like the image above. can anybody recommend a package to do something like this ( maybe in R or Python, not sure if Latex can do something like that also?). below is my reproducible code and what I get. Many thanks for your help.


library(magick)
library(grid)
library(gridExtra)


names_of_images <- LETTERS[1:16]


pic_url <- "https://imagehost.imageupload.net/2020/04/30/EXAMPLE.jpg"
pic_cat <- tempfile()
download.file(pic_url,pic_cat,mode="wb")
pic <- image_read(pic_cat)

## write labels on images

image_listall <-  list()

for ( i in names_of_images ) {

 im_read_bor <- image_border(pic , 'white'  ,geometry = "10x10")  

 im_read_bor_anno <-  image_annotate(im_read_bor, paste(i),

   size = 100, color = "white" , location = "+50+40" )

 image_listall[[i]] = im_read_bor_anno

}


## arrange images in rows

row1 <- image_append(c(image_listall$A, image_listall$B ,image_listall$C,image_listall$D  ), stack = F)

row2 <- image_append(c(image_listall$E, image_listall$F ,image_listall$G,image_listall$H  ), stack = F)

row3 <- image_append(c(image_listall$I, image_listall$J,image_listall$K,image_listall$L) ,stack = F)

row4 <- image_append(c(image_listall$M, image_listall$N,image_listall$O, image_listall$P) ,stack = F)


## now add row labels and title


r1 <- grid.arrange(rasterGrob(row1) , top = textGrob(
 "First Block",just = "center",
 gp = gpar(fontface = 'bold', fontsize = 18)) ,  

 left = textGrob(
   "(A)",
   gp = gpar(fontface = 'bold', fontsize = 15)))


r2 <- grid.arrange(rasterGrob(row2) , 

                  left = textGrob(
                    "(B)",
                    gp = gpar(fontface = 'bold', fontsize = 15)))


r3 <- grid.arrange(rasterGrob(row3) , top = textGrob(
 "Second Block", just = "center",
 gp = gpar(fontface = 'bold', fontsize = 18)) ,  

 left = textGrob(
   "(C)",
   gp = gpar(fontface = 'bold', fontsize = 15)))





r4 <- grid.arrange(rasterGrob(row4) , 

                  left = textGrob(
                    "(D)",
                    gp = gpar(fontface = 'bold', fontsize = 15)))


## draw all together 

grid.draw(rbind(r1, r2,r3,r4, size = "last"))

it looks like this:

enter image description here

StupidWolf
  • 45,075
  • 17
  • 40
  • 72
Sam_9090
  • 161
  • 1
  • 10

1 Answers1

1

Maybe not the best and more elegant solution, but a possible way will be to use the function facet_grid from ggplot2 to draw multipanel plot. The advantage of using ggplot2 will be that you can benefit for a large panel of tools pretty easy to use to customize the location, the font, the color of all your labels.

So, you can prepare a fake dataframe with your text for each vertical and horizontal label:

verticallabel <- c("Control", "cKO")
horizontallabel <- c("Text1","Text2","Text3")
text <- expand.grid(verticallabel,horizontallabel)
text <- as.data.frame(text)

     Var1  Var2
1 Control Text1
2     cKO Text1
3 Control Text2
4     cKO Text2
5 Control Text3
6     cKO Text3

Then, you can create an empty plot with 6 panels with both horizontal and vertical labeling as follow:

library(ggplot2)

g <- ggplot(text, aes(x = Var1, y = Var2))+geom_point(color = NA)+
  facet_grid(Var1~Var2, switch = "y")+  labs(tag = "A")+
  theme(strip.background = element_blank(),
        strip.text = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        plot.margin = margin(1,1,1,1, unit = "cm"),
        plot.tag.position = c(-0.015, 1.05))+
  coord_cartesian(clip = "off", ylim = c(0,5), xlim = c(0,2))+
  geom_text(data = subset(text, Var1 == "Control"), aes(label = Var2, x = 1, y = 6.3, color = Var2), show.legend = FALSE,vjust = 0.5)+
  geom_text(data = subset(text, Var2 == "Text1"), aes(label = Var1, x = -0.8, y = 2.5, angle = 90, vjust = 0))+
  geom_rect(data = subset(text, Var1 == "Control"), aes(xmin = -Inf, xmax = Inf, ymax = 6.8, ymin = 5.8), fill = NA, color = "black")+
  geom_rect(data = subset(text, Var2 == "Text1"), aes(ymin = -Inf, ymax = Inf, xmin = -1, xmax = -0.7), fill = NA, color = "black")

enter image description here

Then, if you want to add image on each panel, you can use the excellent solution proposed by @EdgarSantos in this post: Adding custom images to ggplot facets

annotation_custom2 <- 
  function (grob, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, data){ layer(data = data, stat = StatIdentity, position = PositionIdentity, 
                                                                                 geom = ggplot2:::GeomCustomAnn,
                                                                                 inherit.aes = TRUE, params = list(grob = grob, 
                                                                                                                   xmin = xmin, xmax = xmax, 
                                                                                                                   ymin = ymin, ymax = ymax))}

And here with some example images (some are downloaded on my computer, so you need to adapt path for your images):

library(png)

img1 = readPNG(getURLContent('https://cdn2.iconfinder.com/data/icons/animals/48/Turtle.png'))
img2 = readPNG(getURLContent('https://cdn2.iconfinder.com/data/icons/animals/48/Elephant.png'))
img3 = readPNG(getURLContent('https://cdn2.iconfinder.com/data/icons/animals/48/Hippopotamus.png'))

rlogo <- readPNG("../external-content.duckduckgo.com.png")
rstudio <- readPNG("../rstudio.png")

g +
  annotation_custom2(rasterGrob(img1, width =unit(1,"npc"), height = unit(1,"npc")),
                     xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[1,])+
  annotation_custom2(rasterGrob(img2, width =unit(1,"npc"), height = unit(1,"npc")),
                     xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[2,])+
  annotation_custom2(rasterGrob(img3, width =unit(1,"npc"), height = unit(1,"npc")),
                     xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[3,])+
  annotation_custom2(rasterGrob(rlogo, width =unit(1,"npc"), height = unit(1,"npc")),
                     xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[4,])+
  annotation_custom2(rasterGrob(rstudio, width =unit(1,"npc"), height = unit(1,"npc")),
                     xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[5,])

enter image description here

Does it answer your question ?

dc37
  • 15,840
  • 4
  • 15
  • 32