I have a character vector of hierarchical IDs like this one:
ids <- c("0","1","2","3","1.1","1.2","1.3","2.1","2.2","2.11","2.21","2.22")
The hierarchical structure is as follows:
1
1.1
1.2
1.3
2
2.1
2.11
2.2
2.21
2.22
I want to use diagonalNetwork() from the networkD3 package to visualize this hierarchy. But diagonalNetwork() requires a nested list defining each nodes children like this one:
l <- list(name = "0",
children = list(
list(name = "1",
children = list(
list(name = "1.1"),
list(name = "1.2"),
list(name = "1.3")
)
),
list(name = "2",
children = list(
list(name = "2.1",
children = list(
list(name = "2.11")
)
),
list(name = "2.2",
children = list(
list(name = "2.21"),
list(name = "2.22")
)
)
)
)
)
)
My actual set of ids is much larger and deeper (up to 6 digits long), so I need a way to create this nested list automatically. I started with creating a data.frame that stores the ids' digits in several columns like this one:
df <- data.frame(root = 0,
a = c( 1, 1, 1, 1, 2, 2, 2, 2, 2, 2),
b = c(NA, 1, 2, 3,NA, 1, 1, 2, 2, 2),
c = c(NA,NA,NA,NA,NA,NA, 1,NA, 1, 2))
But I can't think of a way to get any further with my concern.
Is there a more promising approach?
Here is a possible solution based on recursive function. And it is by no means a fast solution but should work for you.
library(network3D)
findChildren <- function(pa, ids) {
lapply(ids, function(ch){
if(grepl(paste("^", pa, sep = ""), ch) && ch != pa &&
nchar(gsub("\\.", "", ch)) == nchar(gsub("\\.", "", pa)) + 1)
{
childrenTmp = Filter(Negate(is.null), findChildren(ch, ids))
if(length(childrenTmp) != 0) list(name = ch, children = childrenTmp)
else list(name = ch)
}
}
)
}
myList <- list(name = "0",
children = Filter(
function(x){nchar(x$name) == 1 },
lapply(ids[-1], function(id) {
childrenTmp = Filter(Negate(is.null), findChildren(id, ids))
if(length(childrenTmp) != 0) list(name = id, children = childrenTmp)
else list(name = id)
}
)
)
)
diagonalNetwork(myList)
Related
I have a data like this
df<- structure(list(Core = c("Bestman", "Tetra"), member1 = c("Tera1",
"Brownie1"), member2 = c("Tera2", "Brownie2"), member3 = c("Tera3",
"Brownie3"), member4 = c("Tera4", "Brownie4"), member5 = c("Tera5",
"Brownie5"), member6 = c("", "Brownie6"), member7 = c("", "Brownie7"
)), class = "data.frame", row.names = c(NA, -2L))
I want to connect all the members to their Core. for example if you look at the first row, you can see there are 5 members , I want to connect them to their Core
The same for the second row
Then I connect both Core together
Here is what I have done
mydf <- crossprod(table(cbind(df[1], stack(df[-1]))[-3]))
graph_from_adjacency_matrix(mydf, diag = F, weighted = T, mode = "undirected") %>%
plot(edge.width = E(.)$weight)
If i understood correctly, what you want is:
library(igraph)
df<- data.frame(Core = c("Bestman", "Tetra"), member1 = c("Tera1",
"Brownie1"), member2 = c("Tera2", "Brownie2"), member3 = c("Tera3",
"Brownie3"), member4 = c("Tera4", "Brownie4"), member5 = c("Tera5",
"Brownie5"), member6 = c("", "Brownie6"), member7 = c("", "Brownie7"))
edges <- t(do.call(rbind, apply(
df, 1, function(x) cbind(x[1], x[x!=""][-1]))))
core_edges <- if(nrow(df)>1) combn(df$Core,2) else c()
g<-graph(c(edges,core_edges), directed=F )
plot(g , edge.width = E(g)$weight)
EDIT
To colorize and resize nodes:
V(g)$color <- apply(df, 1, \(x) names(V(g)) %in% x) |> apply(1,which)
V(g)$size <- 15
V(g)[df$Core]$size <- degree(g, V(g)[df$Core]) + 15
plot(g)
I've tried everything I can...I have a large list of lists. They are of varying depths, but they all have a variable name that I need to rename. I tried breaking apart the list into data frames, it just seems unpractical and doesn't even do what I want.
Here's a toy example:
list1 = list(changethis = c("1", "2"))
list2 = list(varname1 = c("1,2,3,4"), changethis = c("5,6,7,8"), varname2 = c("9, 10, 11"))
list3 = list(varname3 = list(varname4 = c("first", "second", "third", list(changethis = c("15, 16, 19"), varname5 = "cat", "dog", "fish"))))
list4 = list(varname6 = list(varname7 = list2, varname8 = list2))
list5a = list(varname13 = c("hat", "key"), changethis = c("5"))
list5 = list(varname9 = list(varname10 = list5a, varname11 = list5a))
list6 = list(varname12 = list5)
list7 = list(first = list1)
listbig = list(sublist1 = list3, sublist2 = list4, sublist3 = list5, sublist4= list6, sublist5=list7, sublist6 = list5a)
Here's a toy code that produces what I want it to look like. The 'changethis' var is renamed to 'change'
sollist1 = list(changed= c("1", "2"))
sollist2 = list(varname1 = c("1,2,3,4"), changed = c("5,6,7,8"), varname2 = c("9, 10, 11"))
sollist3 = list(varname3 = list(varname4 = c("first", "second", "third", list(changed = c("15, 16, 19"), varname5 = "cat", "dog", "fish"))))
sollist4 = list(varname6 = list(varname7 = sollist2, varname8 = sollist2))
sollist5a = list(varname13 = c("hat", "key"), changed = c("5"))
sollist5 = list(varname9 = list(varname10 = sollist7, varname11 = sollist5a))
sollist6 = list(varname12 = sollist5)
sollist7 = list(first = sollist1)
solution_list = list(sublist1 = sollist3, sublist2 = sollist4, sublist3 = sollist5, sublist4= sollist6, sublist5=sollist7, sublist6=sollist7)
Here is one of my many attempts to do this. I extracted sublist1 from the big list and tried to just change the name for it, but nothing gets changed.
extr_sublist1 <- listbig[1]
names(extr_sublist1[[1]][[1]][[1]][4]) <- "changed" #does not do it...
Another failed attempt:
In this I extract a differently hierarchial sublist and create a Var name which I hope to loop over so I can change the name of the 'changethis' var. Also does not work.
extr_sublist4 <- listbig[4]
numvars <- length(extr_sublist4[[1]][[1]][[1]])
for (i in 1: numvars){
varname<-paste("Var",numvar, sep = "")
paste('Var',[i]) <- extr_sublist4[[1]][[1]][[1]][[1]][2]
namespaste('Var',[i])[paste('Var',[i]) == 'changethis'] <- 'changed'
}
I'm sure there's a simple and elegant solution to this...but have no idea what. Thanks in advance for your help.
You can use a recursive method to do the transformation:
changefun <- function(x, change_name, new_name){
idx <- names(x) == change_name
if(any(idx)) names(x)[idx] <- new_name
if (is.list(x)) lapply(x, changefun, change_name, new_name)
else x
}
Now just call
changefun(listbig, 'changethis', 'changed')
I am using RMarkdown to create a word document (I need the output to be in .docx format).
I'd like to use flextable (or any other package) to format my headers properly.
I'm trying to get the greek symbol delta (∆) to display properly... it seems possible because in the help pages here (https://davidgohel.github.io/flextable/articles/format.html#display-function) the author successfully uses \u03BC to insert the "μ" symbol (and I can too if I use his code, below), but I can't get it to work for delta using \u2206 or \u0394, if I replace \u03BC with either code below. The code I'm using produces this table, but I want to replace the highlighted bit with delta.
This is what I get when I try, for example, \u2206.
Any suggestions?
library(flextable)
if( require("xtable") ){
mat <- round(matrix(c(0.9, 0.89, 200, 0.045, 2.0), c(1, 5)), 4)
mat <- xtable(mat)
ft <- xtable_to_flextable(x = mat, NA.string = "-")
print(ft$col_keys)
ft <- flextable::display(ft, i = 1, col_key = "X1",
pattern = "{{val}}{{pow}}", part = "header",
formatters = list(val ~ as.character("R"), pow ~ as.character("2") ),
fprops = list(pow = fp_text(vertical.align = "superscript", font.size = 8))
)
ft <- flextable::display(ft, i = 1, col_key = "X2",
pattern = "{{val}}{{pow}}", part = "header",
formatters = list(val ~ as.character("\u03BC"), pow ~ as.character("x") ),
fprops = list(pow = fp_text(vertical.align = "superscript", font.size = 8))
)
ft <- flextable::display(ft, i = 1, col_key = "rowname",
pattern = "{{val}}{{pow}}", part = "body",
formatters = list(val ~ as.character("y"), pow ~ as.character("t-1") ),
fprops = list(pow = fp_text(vertical.align = "subscript", font.size = 8))
)
ft <- set_header_labels(ft, X3 = "F-stat", X4 = "S.E.E", X5 = "DW", rowname = "")
ft <- autofit(ft)
ft
}
Update
I am getting closer thanks to a helpful suggestion from David, but (not being very familiar with flextable) I am getting strange behaviour when I try to modify the header in the way suggested:
library(magrittr)
library(flextable)
library(officer)
AICtable <- data.frame(Model = "test", Parameters = 9, AICc = 4000, dAICc = 0, w = 1)
v.epi.aic <- flextable(AICtable) %>%
font(fontname = "Times New Roman", part = "all") %>%
flextable::display(col_key = "dAICc", part = "header",
pattern = "{{D}}{{A}}{{cbit}}",
formatters = list(D ~ as.character("D"),
A ~ as.character("AIC"),
cbit ~ as.character("c") ),
fprops = list(D = fp_text(font.family = "Symbol"),
A = fp_text(font.family = "Times New Roman"),
cbit = fp_text(vertical.align = "subscript")))
v.epi.aic
Notice that column headers are now duplicated, and "AIC" appears before the "∆". The column names should be:
Model, Parameters, AICc, ∆AICc, w (and the "c" in the ∆AICc should be a subscript).
Please use "\u394" instead of "\u0394" to generate the capital delta symbol
So I'm working with a list that contains other lists inside, with this structure:
library(graph)
library(RBGL)
library(Rgraphviz)
show(tree)
$`SO:0001968`
$`SO:0001968`$`SO:0001622`
$`SO:0001968`$`SO:0001622`$`SO:0001624`
$`SO:0001968`$`SO:0001622`$`SO:0001624`$`SO:0002090`
[1] 1
$`SO:0001968`$`SO:0001622`$`SO:0001623`
$`SO:0001968`$`SO:0001622`$`SO:0001623`$`SO:0002091`
[1] 1
$`SO:0001968`$`SO:0001969`
$`SO:0001968`$`SO:0001969`$`SO:0002090`
[1] 1
$`SO:0001968`$`SO:0001969`$`SO:0002091`
[1] 1
dput(tree)
list(`SO:0001968` = list(`SO:0001622` = list(`SO:0001624` = list(
`SO:0002090` = 1), `SO:0001623` = list(`SO:0002091` = 1)),
`SO:0001969` = list(`SO:0002090` = 1, `SO:0002091` = 1)))
The data I use to build the list comes from an object called g:
show(g)
A graphNEL graph with directed edges
Number of Nodes = 7
Number of Edges = 8
dput(g)
new("graphNEL",
nodes = c("SO:0001968", "SO:0001969", "SO:0001622",
"SO:0001623", "SO:0001624", "SO:0002090", "SO:0002091"), edgeL = list(
`SO:0001968` = list(edges = 3:2), `SO:0001969` = list(edges = 6:7),
`SO:0001622` = list(edges = 5:4), `SO:0001623` = list(edges = 7L),
`SO:0001624` = list(edges = 6L), `SO:0002090` = list(edges = integer(0)),
`SO:0002091` = list(edges = integer(0))), edgeData = new("attrData",
data = list(`SO:0001968|SO:0001622` = list(weight = 1), `SO:0001968|SO:0001969` = list(
weight = 1), `SO:0001969|SO:0002090` = list(weight = 1),
`SO:0001969|SO:0002091` = list(weight = 1), `SO:0001622|SO:0001624` = list(
weight = 1), `SO:0001622|SO:0001623` = list(weight = 1),
`SO:0001623|SO:0002091` = list(weight = 1), `SO:0001624|SO:0002090` = list(
weight = 1)), defaults = list(weight = 1)), nodeData = new("attrData",
data = list(`SO:0001968` = list(label = "coding_transcript_variant"),
`SO:0001969` = list(label = "coding_transcript_intron_variant"),
`SO:0001622` = list(label = "UTR_variant"), `SO:0001623` = list(
label = "5_prime_UTR_variant"), `SO:0001624` = list(
label = "3_prime_UTR_variant"), `SO:0002090` = list(
label = "3_prime_UTR_intron_variant"), `SO:0002091` = list(
label = "5_prime_UTR_intron_variant")), defaults = list(
label = NA_character_)), renderInfo = new("renderInfo",
nodes = list(), edges = list(), graph = list(), pars = list()),
graphData = list(edgemode = "directed"))
Each SO:000XXX corresponds to a name, and I can find the names using the function nodeData, that returns a named list:
nodeData(g, nodes(g), "label")
$`SO:0001968`
[1] "coding_transcript_variant"
$`SO:0001969`
[1] "coding_transcript_intron_variant"
$`SO:0001622`
[1] "UTR_variant"
$`SO:0001623`
[1] "5_prime_UTR_variant"
$`SO:0001624`
[1] "3_prime_UTR_variant"
$`SO:0002090`
[1] "3_prime_UTR_intron_variant"
$`SO:0002091`
[1] "5_prime_UTR_intron_variant"
What I need is to replace (or rename) the data in the tree list with the corresponding string of the nodeData function.
For example, replace the 'SO:0001968' in the tree list for coding_transcript_variant from the nodeData function.
This recursive function should do the trick :
# you will do this but I couldn't install your packages
# nodeD <- nodeData(g, nodes(g), "label")
nodeD <- list(`SO:0001968` = "coding_transcript_variant",
`SO:0001969` = "coding_transcript_intron_variant",
`SO:0001622` = "UTR_variant",
`SO:0001623` = "5_prime_UTR_variant",
`SO:0001624` = "3_prime_UTR_variant",
`SO:0002090` = "3_prime_UTR_intron_variant",
`SO:0002091` = "5_prime_UTR_intron_variant")
rename_items <- function(item){
if (is.list(item)){
item <- lapply(item,rename_items)
names(item) <- unname(nodeD[names(item)])
}
item
}
tree2 <- rename_items(tree)
Result
# $coding_transcript_variant
# $coding_transcript_variant$UTR_variant
# $coding_transcript_variant$UTR_variant$`3_prime_UTR_variant`
# $coding_transcript_variant$UTR_variant$`3_prime_UTR_variant`$`3_prime_UTR_intron_variant`
# [1] 1
#
#
# $coding_transcript_variant$UTR_variant$`5_prime_UTR_variant`
# $coding_transcript_variant$UTR_variant$`5_prime_UTR_variant`$`5_prime_UTR_intron_variant`
# [1] 1
#
#
#
# $coding_transcript_variant$coding_transcript_intron_variant
# $coding_transcript_variant$coding_transcript_intron_variant$`3_prime_UTR_intron_variant`
# [1] 1
#
# $coding_transcript_variant$coding_transcript_intron_variant$`5_prime_UTR_intron_variant`
# [1] 1
If you save the output from nodeData() to a vector, you can use the names() function to assign the names to a list().
An example of assigning names to list elements:
x <- 1:5
y <- 11:20
z <- 21:25
theList <- list(x,y,z)
listNames <- c("element1","element2","element3")
names(theList) <- listNames
# access first element by name, using $ form of extract operator
theList$element1
...and the output:
> theList$element1
[1] 1 2 3 4 5
>
You may need to unlist() the output of nodeData() as follows:
theNames <- unlist(nodeData(g, nodes(g), "label"))
names(g) <- theNames
Is it anyhow possible to use list as a key for a list? I'd like something as below to work:
lst <- list()
lst[[ list("a", 1:2) ]] <- list(name = "first item", id = 1)
## Error in lst[[list("a", 1:2)]] <- list(name = "first item", id = 1) :
## invalid subscript type 'list'
The idea is to create a lookup table with list keys. The simple solution is to use hashes as keys (e.g. fastdigest), but I am wondering if there is no any direct solution for this?
Example:
lst <- list()
lst[[ list(V1 = "a", V2 = 1:2, V3 = NULL) ]] <- list(name = "first item", id = 1)
lst[[ list(V1 = "a", V2 = 1:2, V3 = "lorem ipsum") ]] <- list(name = "second item", id = 2)
lst[[ list(V1 = "b", V2 = 3, V3 = "") ]] <- list(name = "third item", id = 3)
# calling it:
lst[[ list(V1 = "b", V2 = 3, V3 = "") ]]
## list(name = "third item", id = 3)
The basic problem with using hashes is that I would like also to be able to back-transform this data structure to "flat" list, e.g.
list(V1 = "a", V2 = 1:2, V3 = NULL, name = "first item", id = 1)
and with hashes, for doing this I would need to store the key-hash dictionary separately to be able to re-create them etc. It would also need defining my own, pretty complicated, classes and methods for accessing them. So I'm asking if there is no direct solution, i.e. using lists as keys?