Reputation: 623
I have a dataframe(df) as follows.
V1 V2 V3 V4
A B C D
A G R T
M A R H
My requirement is to graph the transitions from V1 to V2 to V3 to V4. When I use igraph command
g = graph.data.frame(df)
I see that columns V3 and V4 get dropped. Is there a way to construct transition graph like this.
Upvotes: 2
Views: 1380
Reputation: 1291
Somewhat building upon previous answers, here is a way to do that while also keeping the information contained in the column headings, as it might be valuable attributes for the nodes/vertices.
I acknowledge however that it wouldn't work for the data provided in the question, given that the node "A" is found in two columns (and igraph will error for duplicate vertex names).
Note that:
rbind()
without an error about headings not matching, by setting the names with setNames()
\(x)
anonymous function syntax was introduced in R 4.1# example data.frame
exp_df <- data.frame(cat1 = letters[1:4],
cat2 = LETTERS[1:4],
cat3 = colours()[1:4])
# reshape edges into a two-column dataframe
edges <- do.call(rbind,
lapply(1:(ncol(exp_df)-1),
\(x) setNames(exp_df[,x:(x+1)],
c("from", "to"))))
# also keep the headings as node attributes, in a nodes dataframe
nodes <- do.call(rbind,
lapply(seq_along(exp_df),
\(x) data.frame(node = exp_df[[x]],
category = names(exp_df)[x]))) |>
unique() # in case there are repeats
# build igraph object
library(igraph)
net <- graph_from_data_frame(edges, vertices = nodes)
# see contents (note the "category" attribute)
net
#> IGRAPH 317d257 DN-- 12 8 --
#> + attr: name (v/c), category (v/c)
#> + edges from 317d257 (vertex names):
#> [1] a->A b->B c->C d->D
#> [5] A->white B->aliceblue C->antiquewhite D->antiquewhite1
# colour nodes according to their attribute (the argument can take integers)
plot(net, vertex.color = as.integer(as.factor(V(net)$category)))
Created on 2022-06-18 by the reprex package (v2.0.1)
Upvotes: 0
Reputation: 23101
Try this:
library(igraph)
df <- as.matrix(df)
# to transform the df to the format that igraph expects, following will suffice for your example
df <- as.data.frame(rbind(df[,1:2], df[,2:3], df[,3:4]))
# if you want to make it generic try the following instead
# df <- as.data.frame(do.call(rbind, lapply(1:(ncol(df)-1), function(i) df[,i:(i+1)])))
g = graph.data.frame(df)
plot(g)
Upvotes: 4
Reputation: 886928
We can do this programmatically by subseting the columns pairwise in a list
, use rbindlist
(from data.table
) to bind the dataset, convert to graph
data.frame and plot
library(data.table)
library(igraph)
plot(graph.data.frame(rbindlist(lapply(seq(ncol(df)-1), function(i) df[i:(i+1)]))))
Upvotes: 2