Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign different images to different vertices in an igraph?

Tags:

r

igraph

I've looked at this question which seems similar but I am having difficulty getting it to work with my data.

Let's say my edgelist consists of the following:

P1 P2 weight
a  b  1
a  c  3
a  d  2
b  c  8

I use read.csv to collect the data, and then I convert it to a matrix. Then I graph it using the following:

g=graph.edgelist(x[,1:2],directed=F)
E(g)$weight=as.numeric(x[,3])
tkplot(g,layout=layout.fruchterman.reingold,edge.width=E(g)$weight)

And this returns a network with vertices and edges. I would like to replace vertex a with one image, vertex b with another and so on. I know how to apply the same image to all, but I want to apply a different image to every vertex. How do I go about doing this?

Edit: Adding reproducible code below as requested by user20650

# loading libraries
library(igraph)
library(rgdal)

# reading data from edgelist
x <- read.csv('edgelist', colClasses = c("character","character","numeric"), header=T)
# however, to replicate the data, use this line instead (Above line included just to show how I get the data)
x <- data.frame(P1 = c("a","a","a","b"), P2 = c("b","c","d","c"), weight = c(1,3,2,8))

# converting x to a matrix
x = as.matrix(x)

# preparing graph (getting rid of arrows, edge colors)
g = graph.edgelist(x[,1:2], directed=F)
E(g)$weight=as.numeric(x[,3])
E(g)[weight<=1]$color='dodgerblue'
E(g)[weight>=2&weight<=3]$color='dodgerblue1'
E(g)[weight>=4&weight<=7]$color='dodgerblue2'
E(g)[weight>=8&weight<=9]$color='dodgerblue3'
E(g)[weight==10]$color='dodgerblue4'

# plot the graph 
# beginning of stuff I do not do anymore - the tkplot and adj lines below here I do not do anymore as they have been replaced with suggestions by user20650
tkplot(g, canvas.width=640, canvas.height=640, layout=layout.fruchterman.reingold, edge.width=E(g)$weight)

# just to make sure everything is correct, I was also verifying with this
adj <- get.adjacency(g, attr='weight')
# end of stuff I do not do anymore and I replaced it with what follows

# this is where I started placing user20650's lines (survcont1.png through survcont13.png are local files - 1 is the image for a, 2 for b, and so on)
url <- paste0("survcont", 1:13, ".png")

# my mapply which I guess I don't need anymore (I'm using rgdal because it is a library I already have that can read the images, am willing to use a better method if one exists)
mapply(readGDAL, url)
img <- lapply(url, png::readPNG)

set.seed(1)
adj <- matrix(sample(0:1,3^2,T,prob=c(0.8,0.8)),13,13)
g <- graph.adjacency(adj)
set.seed(1)

l <- layout.fruchterman.reingold(g)
l[,1]=(l[,1]-min(l[,1]))/(max(l[,1])-min(l[,1]))*2-1
l[,2]=(l[,2]-min(l[,2]))/(max(l[,2])-min(l[,2]))*2-1

# I added in the label so I can verify if the right vertices are showing up in the right places, I will remove in final version, also added in the edge weights
plot(g, layout=l, vertex.size=10, vertex.shape="square", vertex.color="#00000000", vertex.frame.color="#00000000", vertex.label="", edge.width=E(g)$weight)

# and finally plotting of the images
for(i in 1:nrow(l)) {  
  rasterImage(img[[i]], l[i, 1]-0.2, l[i, 2]-0.2, l[i, 1]+0.2, l[i, 2]+0.2)
}

I am guessing something is going wrong with the adj line and I'm somehow not linking my data to the images. I also don't get why I need to set.seed.

The images plot, which is great, but my original edge widths and colors do not and I am not sure image 1 is linking to a, 2 to b, and so on.

like image 712
thequerist Avatar asked Mar 22 '15 00:03

thequerist


1 Answers

You can use Sacha's answer in the question you link to, to do this. If your images are stored in a list, just iterate through it to render the png files. I had to tweak the manual adjustment (from 0.1 to 0.2) to resize the image.

EDIT Using OP's data and adding edge weight and colour (deleted original post as this largely repeats it)

First need some images for the vertices.

# As i dont have access to your images i will download and use the 
# images as before. We need four images as there are four vertices
# You dont need to do this bit exactly, all you need to do is read 
# in your images into your R session, in a list called img

url <- paste0("http://pngimg.com/upload/cat_PNG", 1632:1635, ".png")
mapply(download.file, url, basename(url))
img <- lapply( basename(url), png::readPNG)


library(igraph)

# data
x <- data.frame(P1 = c("a","a","a","b"), 
                P2 = c("b","c","d","c"), 
                weight = c(1,3,2,8))

# this reads in the third column which you can then assign to be weights
g <- graph.data.frame(x, directed=FALSE)
# check
E(g)$weight

# edge colour - you might need to tweak this depending on your
# data, with the right argument etc
E(g)$colour <- as.character(cut(as.numeric(E(g)$weight), 
                      breaks = c(0, 1, 3, 7, 9, 10), 
                      labels=paste0("dodgerblue", c("", 1:4))))

# you need to set the seed as the layout function is an 
# iterative process and not deterministic
set.seed(1)    
l <- layout.norm(layout.fruchterman.reingold(g), 
                           xmin=-1, xmax=1, ymin=-1, ymax=1)


par(mar=rep(0,4))
plot(g, layout=l, vertex.size=20, vertex.shape="square", 
     vertex.color="#00000000", vertex.frame.color="#00000000", 
     vertex.label="", edge.width=E(g)$weight, edge.color=E(g)$colour)

# and finally plotting of the images
for(i in 1:nrow(l)) {  
  rasterImage(img[[i]], l[i, 1]-0.2, l[i, 2]-0.2, l[i, 1]+0.2, l[i, 2]+0.2)
}

enter image description here

like image 124
user20650 Avatar answered Sep 30 '22 12:09

user20650