I was trying to use the forceNetwork() function for my node plots. However, I can't seem to set the linkDistance. For example, in the attached image, I want to set all the green nodes equidistant from the center. Currently, they appear to be farther away depending on how many pink nodes are attached to them. I followed the suggestion given here, but couldn't get it to work.
Here is my code (sorry for the ramshackle code blocks):
library(networkD3)
library(htmlwidgets)
NUM_PNODES <- 100
NUM_DNODES <- 8
LINKDIST1 <- 1
LINKDIST2 <- 5
N_SIZE1 <- 2
### Parent edges and nodes
nodes.ID <- (1:NUM_PNODES)-1
nodes <- paste0('p',1:NUM_PNODES)
source1 <- rep(nodes[1],max(nodes.ID))
target1 <- nodes[-1]
source_idx1 <- nodes.ID[1]
target_idx1 <- nodes.ID[-1]
linkdist1 <- LINKDIST1
links.df <- data.frame(source1,target1,source_idx1,target_idx1,linkdist1)
type <- rep('parent',NUM_PNODES)
group <- 0
nodesize <- N_SIZE1
node.df <- data.frame(nodes,group,type,nodesize)
source1 <- target1 <- source_idx1 <- target_idx1 <- linkdist1 <- tdat <- c()
for(i in 1:NUM_DNODES){
if(i==1){
NCOUNT <- max(links.df$target_idx1) + 1
}
### clone edges and nodes
source1 <- 'p1'
target1 <- paste0('d',i)
source_idx1 <- 0
target_idx1 <- NCOUNT
linkdist1 <- LINKDIST2
tdat <- data.frame(source1,target1,source_idx1,target_idx1,linkdist1)
ndat <- data.frame(target1,i,'clone',N_SIZE1)
colnames(ndat) <- c('nodes','group','type','nodesize')
links.df <- rbind(links.df,tdat)
node.df <- rbind(node.df,ndat)
### Daughter edges and nodes
source1 <- rep(paste0('d',i),i)
target1 <- paste0('d',i,'.',1:i)
source_idx1 <- rep(NCOUNT,i)
target_idx1 <- (NCOUNT+1):(NCOUNT+i)
NCOUNT <- NCOUNT+i+1
linkdist1 <- LINKDIST1
tdat <- data.frame(source1,target1,source_idx1,target_idx1,linkdist1)
ndat <- data.frame(target1,i,'daughter',N_SIZE1)
colnames(ndat) <- c('nodes','group','type','nodesize')
links.df <- rbind(links.df,tdat)
node.df <- rbind(node.df,ndat)
}
ColourScale <- 'd3.scaleOrdinal()
.domain(["parent", "clone", "daughter"])
.range(["blue", "green", "red"]);'
fn <- forceNetwork(Links = links.df, Nodes = node.df,
Source = 'source_idx1', Target = 'target_idx1',
NodeID = 'nodes', Group = 'type',
bounded = TRUE, opacityNoHover = TRUE, zoom = TRUE,
colourScale = JS(ColourScale),
linkDistance=JS('function(d) {', 'return d.linkdist1;', '}'))
fn$x$links$linkdist1 <- links.df$linkdist1
fn
Thanks for your help!
This took me a bit to figure out. This is a force diagram. So the forces acting on the nodes have a lot to do with their placement. I get the impression that you're not using this graph for the force aspect, specifically.
If you were using the JS version, you would just need to add the parameter linkStrength
. However, it doesn't appear that that was written into the R version. I couldn't figure out how to add it to another call, onRender
, or anything else I could think of. I tried to reduce the energy
, too.
I did make it work, but you may not want to go this route. If you would like to have the parameter linkStrength
, you use the repo I made to answer this question. It will look, feel, and act just like the Cran version. The only difference is that this package has one more parameter in the function forceNetwork
. (In the package, I really only made changes to the forceNetwork.js and forceNetwork.R.)
To use this package:
devtools::install_github("fraupflaume/networkD3")
When you call the library, you do it the same way you did before.
library(networkD3)
If you want to use the Cran version later, just install it again. Installing it will write over the previous version, regardless of whether it was from Cran or Github.
Using the data code exactly as you've provided in your question, here are some examples of the difference between having no control over link strength and using that parameter.
forceNetwork(Links = links.df, Nodes = node.df,
Source = 'source_idx1', Target = 'target_idx1',
NodeID = 'nodes', Group = 'type',
bounded = TRUE, opacityNoHover = TRUE, zoom = TRUE,
colourScale = JS(ColourScale))
forceNetwork(Links = links.df, Nodes = node.df,
Source = 'source_idx1', Target = 'target_idx1',
NodeID = 'nodes', Group = 'type',
bounded = TRUE, opacityNoHover = TRUE, zoom = TRUE,
colourScale = JS(ColourScale),
linkStrength = 1)
This final example reflects the variation of link distances that you were trying to achieve. However, I didn't use 1 and 5. I know the description states the values are relative...but they appear to be quite literal.
forceNetwork(Links = links.df, Nodes = node.df,
Source = 'source_idx1', Target = 'target_idx1',
NodeID = 'nodes', Group = 'type',
bounded = TRUE, opacityNoHover = TRUE, zoom = TRUE,
colourScale = JS(ColourScale),
linkStrength = 1,
linkDistance = JS("
function(d){
return ((d.source.group === 'parent' && d.target.group === 'clone') ? 75 : 50 );
}"))