How to render igraph in R - r

There is dataset with code below. And I need get a graph like in the picture, without changing frame. I tried use rbind to add more hierarchy to data frame in favor to get diagram like in picture. col0 and col1 data is changing debending on data while col2 remains always the same.
df <- data.frame(col0 = c("Cat Dog Wolf", "Cat Dog Wolf", "Cat Dog Wolf"),
col1 = c( "Cat", "Dog", "Wolf"),
col2 = c( "Feline", "Canis", "Canis2"))
df <-rbind(df, data.frame(col0="Cat Dog Wolf", col1 = "Canis2", col2 = "Canis"))
df <-df[c('col1', 'col2')]
names(df) <-c('from', 'to')
abc <-union(df$to, df$from)
g <-graph.data.frame(df, directed = TRUE, vertices = abc)
plot(g, vertex.size = 20, vertex.label.dist = 0.5, vertex.color = "blue",
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g))

You need three edges taken from only two columns ("From" and "To"). But you have three columns in df so you have to choose from them. I created a new column with the names from col1 and col2 pasted together. Then, I chose the first two vertex from the top and rbind the third one.
df <- data.frame(col0 = "Cat Dog Wolf",
col1 = c( "Cat", "Dog", "Wolf"),
col2 = c( "Feline", "Canis", "Canis2"))
df$col1_2 <- paste(df$col2,df$col1)
df <- rbind(df[1:2,c(1,4)],data.frame(col0=df[2,4],col1_2=df[3,4]))
names(df) <-c('from', 'to')
abc <-union(df$to, df$from)
g <-graph.data.frame(df, directed = TRUE, vertices = abc)
plot(g, vertex.size = 20, vertex.label.dist = 0.5, vertex.color = c("lightblue","red","green","white"),
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g))

Related

How to combine plot with text at specific position in r

I want to plot a picture like this and I have finished the first half of the picture. Now the problem is how to add the below text at bottom-middle (The part of the picture circled in red. The red rectangle is just an emphasis to you and I won't show it in real picture):
For simplifying the question I used fake data:
library(tidyverse)
list <- split(mtcars, mtcars$cyl)
p <- list %>% imap(~ .x %>% ggplot(aes(x = mpg)) + geom_histogram())
plots <- ggarrange(p[[1]], p[[2]], p[[3]],
nrow = 1, ncol = 3)
text1 <- c('Category 1: Quarantinable diseases
Category 4: Vectorborne diseases
Category 7: Sexually transmitted diseases
and bloodborne infections')
text2 <- c('Category 2: Vaccine preventable diseases
Category 5: Zoonotic infections')
text3 <- c('Category 3: Gastrointestinal or
enterovirus diseases
Category 6: Bacterial infections')
text1.p <- ggparagraph(text = text1, face = "italic", size = 10, color = '#1075BC')
text2.p <- ggparagraph(text = text2, face = "italic", size = 10, color = '#EE332E')
text3.p <- ggparagraph(text = text3, face = "italic", size = 10, color = '#27B460')
Then, I combined plots with texts using ggarrange().
ggarrange(plots,
ggarrange(text1.p, text2.p, text3.p, ncol = 3, nrow = 2),
ncol = 1, nrow = 2
)
The result was not what I wanted. The text was evenly distributed in the second row not at bottom-middle. To make both sides of the text blank, I add two NA in ggarrange() but failed.
ggarrange(plots,
NA,
ggarrange(text1.p, text2.p, text3.p, ncol = 3, nrow = 2),
NA,
ncol = 1, nrow = 2
)
Also, the text didn't align as the picture I posted. For solving this I got an idea but don't know how to do it. I want to store the text into a datafram with different columns and then combine plots with the datafram. But I don't know how to do it.
text_df <- structure(list(group = c("Category 1:", "Category 4:", "Category 7:",
NA, "Category 2:", "Category 5:", "Category 3:", NA, "Category 6:"
), text = c("Quarantinable diseases", "Vectorborne diseases",
"Sexually transmitted diseases", "and bloodborne infections",
"Vaccine preventable diseases", "Zoonotic infections", "Gastrointestinal or",
"enterovirus diseases", "Bacterial infections"), color = c("#1075BC",
"#1075BC", "#1075BC", "#1075BC", "#EE332E", "#EE332E", "#27B460",
"#27B460", "#27B460")), row.names = c(NA, -9L), class = c("tbl_df",
"tbl", "data.frame"))
Any help will be highly appreciated! :)

How to make a star plot with igraph?

I am working with igraph for the first time and would like to do a "star plot"(make_star()) with the package igraph.
For this I have prepared a sample data set, it has two columns: name and wght.
I want "ME" to be in the center of the plot and all arrows should go out of it. It would be great if the arrow width corresponded to the values ​​from wght (maybe with edge.width) OR the weights on the arrows.
My code looks like this:
library(igraph)
wght <- runif(6, min = 1, max = 10)
name <- c("John", "Jim", "Jack", "Jesse", "Justin", "Peter")
data <- data.frame(name, wght)
st <- make_star(n = 6, mode = "out")
plot(st, vertex.label = data$name)
Output:
what I want:
Create a graph where "Me" is included as a vertex. Add edge attribute "weight". Create star layout with "Me" as center. Set edge widths according to weights. Plot!
g <- graph_from_data_frame(data.frame(from = "Me", to = name))
E(g)$weights <- wght
plot(g, layout = layout_as_star(g, center = V(g)["Me"]), edge.width = E(g)$weights)
Data
set.seed(1)
wght <- runif(6, min = 1, max = 10)
name <- c("John", "Jim", "Jack", "Jesse", "Justin", "Peter")
Fun to learn about a new package. This should do it for you:
st <- make_star(n=6,mode = "out") %>%
set_vertex_attr("label", index = 1, value = "ME") %>%
set_vertex_attr("label", index = 2:6, value = name[2:6])
plot(st)

How arrange diagram in R

I want to get diagram similar to picture below, but code I use creates different diagram. With rbind I added some hierarchy to a diagram. In data frame col0 there is a string with names of animals. In col1 string is split into individual animals & col2 is adding latin name for a animal. col1 data are always changing and in col2 data constant (there always be feline or canis names in that column).
library(igraph)
# I create my dataframe with animals
df <- data.frame(col0 = c("Cat Dog Wolf", "Cat Dog Wolf", "Cat Dog Wolf"),
col1 = c( "Cat", "Dog", "Wolf"),
col2 = c( "Feline", "Canis", "Canis2"))
# Add extra lines for hierarchy
# These lines work with current graph for a new one these should be replace or deleted
df <-rbind(df, data.frame(col0 = "Cat Dog Wolf", col1 = "Feline", col2 ="Animal"))
df <-rbind(df, data.frame(col0 = "Cat Dog Wolf", col1 = "Canis", col2 = "Animal"))
df <-rbind(df, data.frame(col0 = "Cat Dog Wolf", col1 = "Canis2", col2 = "Canis"))
##########
df <-df[c('col2', 'col1')]
names(df) <-c('from', 'to')
abc <-union(df$to, df$from)
###########
g <-graph.data.frame(df, directed = TRUE, vertices = abc)
plot(g, vertex.size = 20, vertex.label.dist = 0.5, vertex.color = c("blue",
"red", "green", "white", "orange" ),
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g))
This is the graph that the above code outputs, but it's not quite what I want:
I want a similar diagram to what's shown below:
I think that I understand what you want, but I will restate the problem
so that you can confirm whether or not I understood. I think that what
you want to do is this:
Find all of the leaves in the tree, i.e. the nodes with no descendants.
Each leaf will have one parent. Rename the parent with the name of the
leaf, then delete the leaf from the graph. The following code implements that.
## Assume that we have created the graph g using your code
g2 = g # Keep original graph intact
SourceNodes = sapply(strsplit(attr(E(g2), "vnames"), "\\|"), "[", 1)
DestNodes = sapply(strsplit(attr(E(g2), "vnames"), "\\|"), "[", 2)
## Leaf nodes are nodes that are destinations, but not sources
## Also need the node numbers for later deletion
(LeafNodes = DestNodes[which(!(DestNodes%in% SourceNodes ))])
[1] "Cat" "Dog" "Wolf"
(LeafNumbers = match(LeafNodes, attr(V(g), "name")))
[1] 1 2 3
## Find the parents of the leaves
(UpOne = SourceNodes[match(LeafNodes, DestNodes)])
[1] "Feline" "Canis" "Canis2"
## Rename the UpOne nodes (parents of leaves)
vertex_attr(g2)$name[match(UpOne, vertex_attr(g2)$name)] = LeafNodes
## Now delete the leaf nodes and plot
g2 = delete_vertices(g2, LeafNumbers)
plot(g2, vertex.size = 20, vertex.label.dist = 0.5,
vertex.color = c("red", "green", "white", "orange" ),
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g2))
Result

How to change node color in Diagrammer

I have diagram and want to add variety of colors to the nodes, so I added this code line from grviz that change node color from the value he has node = "[fillcolor = red]Canis" but it didn't change anything in diagram.
The rest code for diagram:
df <- data.frame(col1 = c( "Cat", "Dog", "Bird"),
col2 = c( "Feline", "Canis", "Avis"),
stringsAsFactors=FALSE)
uniquenodes <- unique(c(df$col1, df$col2))
library(DiagrammeR)
nodes <- create_node_df(n=length(uniquenodes), nodes = seq(uniquenodes), type="number", label=uniquenodes, nodes = "[fillcolor = red]Canis")
edges <- create_edge_df(from=match(df$col1, uniquenodes), to=match(df$col2, uniquenodes), rel="related")
g <- create_graph(nodes_df=nodes, edges_df=edges, attr_theme = NULL)
render_graph(g)

Keeping the label order on the y-axis when using seqpcplot in TraMineR

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.

Resources