This question already has an answer here:
How to create a bipartite network in R with igraph or tnet
(1 answer)
Closed 5 years ago.
I need to create a bipartite graph for consumer-brand relationships.
This is my example data:
datf <- data.frame(Consumers = c("A", "B", "C", "D", "E"),
Brands = c("Costa", "Starbucks", "Cafe2U", "Costa", "Costa"))
The following code gives me a network. But I am not sure how I can add a node type attribute to label consumers and brands:
library(igraph)
dat=read.csv(file.choose(),header=TRUE)
el=as.matrix(dat)
el[,1]=as.character(el[,1])
el[,2]=as.character(el[,2])
g=graph.edgelist(el,directed=FALSE)
I would like to create a bipartite graph with edges that connect each consumer with the brand they like. Ideally, the nodes will be labeled with text.
Could you show me how to do this using library(igraph)?
This resource at Shizuka Lab is really useful for exploring bipartite networks in R with igraph. In short:
library(igraph)
# Your matrix containing consumer choice by brands
m = matrix(data = sample(0:1, 25, replace = TRUE), nrow = 5, ncol = 5)
colnames(m) = c("A", "B", "C", "D", "E")
rownames(m) = c("Costa", "Starbucks", "Cafe2U", "Petes", "Philz")
# Convert it to a bipartitie network
bg = igraph::graph.incidence(m)
bg
# See the vertex attributes
V(bg)$type
V(bg)$name
# Plot the network
shape = ifelse(V(bg)$type, "circle", "square") # assign shape by node type
col = ifelse(V(bg)$type, "red", "yellow") # assign color by node type
plot(bg, vertex.shape = shape, vertex.color = col)
Gives:
Related
With the following code
library(igraph)
actors <- data.frame(name=c("a","b","c","d","e","f","g","h"))
relations <- data.frame(from=c("a", "a", "b", "b",
"b", "c", "d","d",
"g","e","g","d"),
to =c("d", "e", "c", "e",
"g", "f", "f", "g",
"h","b","d","a"),
weight = c(14,30,25,3,5,6,4,13,2,6,10,10))
g <- graph_from_data_frame(relations, directed=TRUE, vertices=actors)
test.layout <- layout_(g,with_dh(weight.edge.lengths = edge_density(g)/1000))
plot(g,vertex.size=30,edge.arrow.size= 0.5,edge.label = relations$weight,
layout = test.layout)
I produce the weighted directed graph
I would like to avoid the double arrows at the end of some edges. I would like to see, instead, two different edges (for example from d to a and from a to d).
You did not set the random seed before generating your layout so I do not get exactly your layout. Nervertheless, you can get two separate edges, by using the edge.curved argument to igraph.plot.
ENDS = ends(g, E(g))
Curv = rep(F, nrow(ENDS))
for(i in 1:nrow(ENDS)) {
Curv[i] = are.connected(g, ENDS[i,2], ENDS[i,1]) }
plot(g,vertex.size=30,edge.arrow.size=0.5,edge.label = relations$weight,
layout = test.layout, edge.curved=Curv)
You can use edge.curved=TRUE directly if you don't mind all curved edges (but you can customize your plot as you want, and the answer by #G5W looks nicer)
plot(g,
vertex.size = 30, edge.arrow.size = 0.5, edge.label = relations$weight,
layout = test.layout,
edge.curved = TRUE
)
I've tried
nodes <- data.frame(id = 1:3, group = c("B", "A", "B"))
edges <- data.frame(from = c(1,2), to = c(2,3))
visNetwork(nodes, edges) %>% visExport(type = "pdf")
and unfortunately, the pdf generated doesn't contain a vectorial image of my network but a bad quality raster image.
How can I get a high-quality vector pdf file?
This question already has an answer here:
(igraph) Grouped layout based on attribute
(1 answer)
Closed 2 years ago.
My example:
library(igraph)
links <- cbind.data.frame(from = rep("A", 6),
to = LETTERS[1:6],
weight = rep((1:3), each =2))
nodes <- cbind.data.frame(id = LETTERS[1:6],
feature = rep((1:3), each =2))
net <- graph_from_data_frame(d = links, vertices = nodes, directed = T)
V(net)$color <- V(net)$feature
plot(net, vertex.size=30, edge.arrow.size = 0)
The resulting figure looks like below:
What I want is to arrange the same colored node together, as shown in the following figure. The same colored nodes are next to each other.
I have found a very simple way to do it. Just need to use as_star layout
LO <- layout_(net, as_star())
plot(net, vertex.size = 30, edge.arrow.size = 0, layout = LO)
I want to plot a graph via Rgraphviz but I can't handle the design attributes of the clusters that I set.
There are similar questions already on SO and elsewhere but none has a real minimal working example and none of them is answered. So I want to try to ask a complete question to receive a complete answer. As an introduction to the package, I read the paper "How To Plot A Graph Using Rgraphviz" by Gentry, Gentleman, and Huber.
My example network:
library(Rgraphviz)
set.seed(123)
V <- letters[1:6]
M <- 1:4
g1 <- randomGraph(V, M, 0.2)
If I want to plot it, I can easily give it some attributes via a list:
attributes <- list(node = list(shape = "rectangle", fixedsize = FALSE),
graph = list(layout = "dot", bgcolor = "transparent"))
plot(g1, attrs = attributes )
Plotting it via plot(g1) gives the following result:
Now I want to define two clusters/subgraphs. This can be done this way:
sg1= subGraph(c("a", "e", "f"), g1)
sg2= subGraph(c("b", "c", "d"), g1)
subGList <- vector(mode = "list", length = 2)
subGList[[1]] <- list(graph = sg1, cluster = TRUE)
subGList[[2]] <- list(graph = sg2, cluster = TRUE)
Plotting the graph again now including a subGlist argument:
plot(g1, attrs = attributes , subGList = subGList)
So, obviously, there has been a change in the setting and even though it would be convenient having the clusters a little bit more separated, the result is ok.
Now if I want to define cluster-specific styles or try to have them framed, I start having problems. According to page 4 of the mentioned introductory paper one can simply add an element called attrs to the sublists of subGlist.
To my understanding, it should work this way:
subGList[[1]] <- list(graph = sg1,
cluster = TRUE,
attrs = c(fontcolor = "red"))
plot(g1, attrs = attrs, subGList = subGList)
Unfortunately, it doesn't. As mentioned, I would like to frame my clusters (similar to this SO post) but as I can't even handle the fontcolors of the clusters, I think I make a somehow more fundamental mistake.
My complete code:
library(Rgraphviz)
set.seed(123)
V <- letters[1:6]
M <- 1:4
g1 <- randomGraph(V, M, 0.2)
attributes <- list(node = list(shape = "rectangle", fixedsize = FALSE),
graph = list(layout = "dot", bgcolor = "transparent"))
#plot(g1, attrs = attributes )
sg1= subGraph(c("a", "e", "f"), g1)
sg2= subGraph(c("b", "c", "d"), g1)
subGList <- vector(mode = "list", length = 2)
subGList[[1]] <- list(graph = sg1, cluster = TRUE)
subGList[[2]] <- list(graph = sg2, cluster = TRUE)
#plot(g1, attrs = attributes , subGList = subGList)
subGList[[1]] <- list(graph = sg1,
cluster = TRUE,
attrs = c(fontcolor = "red"))
plot(g1, attrs = attrs, subGList = subGList)
I hope someone can help! Thank you
I'm using the R package TraMineR. I would like to plot frequent event sequences by using the command seqpcplot. I previously coded the states in the alphabet as to keep them in alphabetical order so that when I compute the sequences by using the seqdef command without specifying the labels and states options I obtain the following output:
[>] state coding:
[alphabet] [label] [long label]
1 a.sin a.sin a.sin
2 b.co0 b.co0 b.co0
3 c.co1 c.co1 c.co1
4 d.co2+ d.co2+ d.co2+
5 e.ma0 e.ma0 e.ma0
6 f.ma1 f.ma1 f.ma1
7 g.ma2+ g.ma2+ g.ma2+
8 h.sin0 h.sin0 h.sin0
9 i.lp1 i.lp1 i.lp1
10 l.lp2+ l.lp2+ l.lp2+
11 m.lp1_18 m.lp1_18 m.lp1_18
12 n.lp2_18 n.lp2_18 n.lp2_18
I then convert the state-sequence objet in an event-sequece objet by using seqecreate. When plotting the event sequences by seqpcplot I obtain a very nice graph where the states are ordered alphabetically on the y-axis according to the alphabet.
However, I would like to use longer labels in the graphs, so that I specified the labels and states options in the seqdef command as
lab<-c("single", "cohabNOchildren","cohab1child","cohab2+children","marrNOchildren","marr1child","marr2+children","singleNOchildren","loneMother1child","loneMother2+children","loneMother1child_over18","loneMother2+children_over18")
obtaining:
[>] state coding:
[alphabet] [label] [long label]
1 a.sin single single
2 b.co0 cohabNOchildren cohabNOchildren
3 c.co1 cohab1child cohab1child
4 d.co2+ cohab2+children cohab2+children
5 e.ma0 marrNOchildren marrNOchildren
6 f.ma1 marr1child marr1child
7 g.ma2+ marr2+children marr2+children
8 h.sin0 singleNOchildren singleNOchildren
9 i.lp1 loneMother1child loneMother1child
10 l.lp2+ loneMother2+children loneMother2+children
11 m.lp1_18 loneMother1child_over18 loneMother1child_over18
12 n.lp2_18 loneMother2+children_over18 loneMother2+children_over18
As before, I then computed the event sequences and plot them by using seqpcplot:
seqpcplot(example.seqe,
filter = list(type = "function",
value = "cumfreq",
level = 0.8),
order.align = "last",
ltype = "non-embeddable",
cex = 1.5, lwd = .9,
lcourse = "downwards")
This time the states on the y-axis were the states are ordered alphabetically but following the order given by the labels and states labels rather than the alphabet, as I wished.
Is there a way to keep the alphabetical order given in the alphabet when plotting with seqpcplot when the labels and states options are specified and may follow a different alphabetical order from the alphabet?
Thanks.
I agree with the solution above. As a supplement, here a number of possible solutions:
Using seqecreate and the alphabet argument in seqpcplot:
dat <- data.frame(id = factor(1, 1, 1),
timestamp = c(0, 20, 22),
event = factor(c("A", "B", "C")))
dat.seqe <- seqecreate(dat)
seqpcplot(dat.seqe, alphabet = c("C", "A", "B"))
Using seqecreate only
dat <- data.frame(id = factor(1, 1, 1),
timestamp = c(0, 20, 22),
event = factor(c("A", "B", "C"),levels = c("C", "A", "B")))
dat.seqe <- seqecreate(dat)
seqpcplot(dat.seqe)
Using seqdef (here the original categories are different than the labels to be shown in the y-axis)
dat <- data.frame(id = factor(1),
ev.0 = factor("AA", levels = c("CC", "AA", "BB")),
ev.20 = factor("BB", levels = c("CC", "AA", "BB")),
ev.22 = factor("CC", levels = c("CC", "AA", "BB")))
dat.seq <- seqdef(dat, var = 2:4, alphabet = c("CC", "AA", "BB"),
states = c("C", "A", "B"))
seqpcplot(dat.seq)
The last solution may be the one you're looking for. Hope it helps.
The alphabet argument of the seqpcplot function is there to control that order. Something like
seqpcplot(example.seqe,
alphabet = lab,
filter = list(type = "function",
value = "cumfreq",
level = 0.8),
order.align = "last",
ltype = "non-embeddable",
cex = 1.5, lwd = .9,
lcourse = "downwards")
should give you the expected plot.