I am currently working with the R forceNetwork function of the networkD3 package and I have properly validated the correctness of the Nodes and Links data frames for my graph.
My Nodes data frame (node_df) is like this:
node_id node_type node_size
0 T054717 irrelevant 10
1 T095006 irrelevant 10
2 T088658 irrelevant 10
3 T069179 irrelevant 10
4 T009515 irrelevant 10
5 T152167 irrelevant 10
6 T100447 irrelevant 10
7 T150659 irrelevant 10
...
and My Links dataframe (links_df) is like this:
tid1 tid2 edge_dir
0 37 36 10
1 37 0 10
2 37 1 10
3 37 3 10
...
147 34 35 5
148 7 47 5
149 34 47 5
150 35 47 5
151 36 48 5
152 1 48 5
I set the forceNetwork function like this:
network <- forceNetwork (Links = links_df,
Nodes = node_df,
Source = "tid1",
Target = "tid2",
Value = "edge_dir",
NodeID = "node_id",
Nodesize = "node_size",
Group = "node_type",
colourScale = JS("d3.scaleOrdinal(d3.schemeCategory20);"),
fontSize = 10,
linkDistance = 100,
radiusCalculation = JS(" Math.sqrt(d.nodesize)+6"),
charge = -30,
linkColour = ifelse(links_df$edge_dir == 10, "black","red"),
opacity = 1,
zoom = TRUE,
arrows = ifelse(links_df$edge_dir == 10, TRUE, FALSE),
opacityNoHover = TRUE,
clickAction = NULL)
I am struggling with the arrows parameter of the function. In fact I would like to specify if there should be a directed edge (arrows = TRUE) or an undirected edge (arrows = FALSE) for each link, by checking the Value parameter.
In my case Value refers to a column of the Links data frame named edge_dir, which specifies if the edge should be directed (edge_dir = 10) or not (edge_dir = 5).
After looking at this stackoverflow link, specify-colors-for-each-link-in-a-force-directed-network-networkd3
I've tried to set the parameter like this:
arrows = ifelse(links_df$edge_dir == 10, TRUE, FALSE) but the output graph has arrows where there just should be undirected lines.
Using the same structure in the linkColour parameter: linkColour = ifelse(links_df$edge_dir == 10, "black","red") it works fine, directed edges are black and the ones that should be undirected, but they aren't, are red, as shown in this graph output image
Is it possible to display a graph which has directed and undirected edges by modifying the arrows parameter?
Thank you!
This is an imperfect solution, but it's easier than making substantial modifications to the underlying JavaScript yourself. You can use htmlwidgets::onRender() to inject some JavaScript to run just after the plot is generated. Here's an example of how you could turn off the arrows for only those links that have a value equal to 5...
library(tibble)
library(networkD3)
library(htmlwidgets)
node_df <- tibble::tribble(
~node_id, ~node_type, ~node_size, ~directed,
"T054717", "irrelevant", 10, TRUE,
"T095006", "irrelevant", 10, FALSE,
"T088658", "irrelevant", 10, TRUE,
"T069179", "irrelevant", 10, FALSE,
"T009515", "irrelevant", 10, TRUE,
"T152167", "irrelevant", 10, FALSE,
"T100447", "irrelevant", 10, TRUE,
"T150659", "irrelevant", 10, FALSE
)
links_df <- tibble::tribble(
~tid1, ~tid2, ~edge_dir,
0, 1, 10,
0, 2, 10,
0, 3, 10,
1, 3, 10,
2, 4, 5,
2, 5, 5,
3, 6, 5,
4, 5, 5,
5, 6, 5,
5, 6, 5
)
network <- forceNetwork (Links = links_df,
Nodes = node_df,
Source = "tid1",
Target = "tid2",
Value = "edge_dir",
NodeID = "node_id",
Nodesize = "node_size",
Group = "node_type",
colourScale = JS("d3.scaleOrdinal(d3.schemeCategory20);"),
fontSize = 10,
linkDistance = 100,
radiusCalculation = JS(" Math.sqrt(d.nodesize)+6"),
charge = -30,
linkColour = ifelse(links_df$edge_dir == 10, "black","red"),
opacity = 1,
zoom = TRUE,
arrows = ifelse(links_df$edge_dir == 10, TRUE, FALSE),
opacityNoHover = TRUE,
clickAction = NULL)
htmlwidgets::onRender(network, '
function(el) {
d3.select("svg")
.selectAll(".link")
.filter(function(d) { return d.value == 5; })
.style("marker-end", null);
}')
Currently my code looks like this:
library(plotly)
count = data.frame(
row.names = c("Cell1", "Cell2", "Cell3", "Cell4", "Cell5", "Cell6"),
Gene1 = c(10, 11, 8, 3, 2, 1),
Gene2 = c(6, 4, 5, 3, 2.8, 1),
Gene3 = c(12, 9, 10, 2.5, 1.3, 2),
Gene4 = c(5, 7, 6, 2, 4, 7),
stringsAsFactors = FALSE
)
threeD = plotly::plot_ly(
data = count,
x = ~Gene1,
y = ~Gene2,
z = ~Gene3,
type = "scatter3d",
mode = "markers",
marker = list(size = 20),
color = row.names(count)
)
threeD
This code generates following output:
I would like to make the marker scale with the distance. So the markers nearest to "me" is bigger (Cell1 & Cell 2) and the markers far away appear smaller (Cell5 & Cell6). This would achieve a more realistic 3D feeling.
It's possible to make a kind of "bubble" plot by assigning a list of size to the markers so that they grow according to their respective value along the z-axis. The simplest way is to reuse the same data and apply some scaling function (product, log, etc.) as needed for example :
marker = list(size = c(12, 9, 10, 2.5, 1.3, 2)*5)
The problem is that if you change your point of view, the markers won't update magically for the intended 3D feeling.
You can also use color scaling by adding the colorscale property to the marker object, for example :
colorscale = c('#FFE1A1', '#683531')
I am attempting to make a chord diagram of a fairly large 18*65 table (not every cell has a value).
I have generated the image I want but the quallity of it is nothing like what is shown on the github seen below:
I figure maybe the number of cells needing to be plotted may cause problems but otherwise I am not sure why i get such a difference:
circos.par(gap.after = c(rep(2, ncol(chord_data)-1), 10, rep(2, 8-1), 5, rep(2, 10-1), 5, rep(2, 5-1), 5, rep(2, 3-1), 5, rep(2, 1), 5, rep(2, 12-1), 5, rep(2, 10-1), 5, rep(2, 6-1), 5, rep(2, 7-1), rep(2, 3-1), 10))
png(file = "antismash_by_type.png", width = 800, height = 800)
chordDiagram(chord_data,
grid.col = grid.col,
order = order,
annotationTrack = "grid",
preAllocateTracks = 1)
circos.track(track.index = 1, panel.fun = function(x, y) {
circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index,
facing = "clockwise", niceFacing = TRUE, adj = c(0, 0.5))
}, bg.border = NA)
dev.off()
Secondly my chords do not appear to be scaling to the value of the cell which ranges from 0-100 and from what I read this is meant to occure by default but does not appear to be.
I'm using heatmap.2 to create a plot, however, the initial plot that is saved to my source folder is missing a key and title.
When I then run the dev.off() command, the Key and the Title are then used to overwrite the original graph?
For instance, I will produce a plot like this:
Which is far from perfect. But then when I run the dev.off() to close the device (otherwise a host of other errors ensue):
What you are looking at above is a very distorted Key and my 'XYZ' title.
Why on earth is it creating two files, firstly the one with my matrix, and then overwriting this with a second file containing my flipping key and my title? I cannot follow the logic.
I've updated my OS, my version of R, RStudio, all my packages and unistalled RStudio. Nothing seems to help.
If you'd like to try and replicate my error here is the example matrix:
structure(c(1, 4, 5, 3, 3, 4, 6, 1, 7, 5, 5, 4, 4, 8, 1, 3, 9,
2, 2, 9, 3, 1, 3, 4, 4, 5, 5, 5, 1, 4, 4, 3, 3, 3, 9, 1), .Dim = c(6L,
6L))
And this is the script I'm using to plot my example data. You'll need to provide a SourceDir and make sure you assign the matrix to the name "Matrix".
if (!require("gplots")) {
install.packages("gplots", dependencies = TRUE)
library(gplots)
}
if (!require("RColorBrewer")) {
install.packages("RColorBrewer", dependencies = TRUE)
library(RColorBrewer)
}
my_palette <- colorRampPalette(c("snow", "yellow", "darkorange", "red"))(n = 399)
transition
col_breaks = c(seq(0,1,length=100), #white 'snow'
seq(2,4,length=100), # for yellow
seq(5,7,length=100), # for orange 'darkorange'
seq(8,9,length=100)) # for red
png(paste(SourceDir, "Heatmap_Test.png"),
width = 5*1000,
height = 5*1000,
res = 300,
pointsize =15)
heatmap.2(Matrix,
main = paste("XYZ"),
notecol="black",
key = "true" ,
colsep = c(3, 6, 9),
rowsep = c(3, 6, 9),
labCol = NULL,
labRow = NULL,
sepcolor="white",
sepwidth=c(0.08,0.08),
density.info="none",
trace="none",
margins=c(1,1),
col=my_palette,
breaks=col_breaks,
dendrogram="none",
RowSideColors = c(rep("blue", 3), rep("orange", 3)),
ColSideColors = c(rep("blue", 3), rep("orange", 3)),
srtCol = 0 ,
asp = 1 ,
adjCol = c(NA, 0) ,
adjRow = c(0, NA) ,
#keysize = 2 ,
Colv = FALSE ,
Rowv = FALSE ,
key.xlab = paste("Correlation") ,
cexRow = (1.8) ,
cexCol = (1.8) ,
notecex = (1.5) ,
lmat = rbind(c(0,0,0,0), c(0,0,2,0),c(0,1,3,0),c(0,0,0,0)) ,
#par(ColSideColors = c(2,2)),
lhei = c(1, 1, 3, 1) ,
lwid = c(1, 1, 3, 1))
dev.off()
I'd really appreciate any insight into this problem.
I believe this resulted from the fact that I had more than just elements 1 to four, as the coloured rows I had added counted as additional elements that had to be arranged in the display matrix.
As such:
mat = rbind(c(0,0,0,0), c(0,0,2,0),c(0,1,3,0),c(0,0,0,0)) ,
lhei = c(1, 1, 3, 1) ,
lwid = c(1, 1, 3, 1))
No longer cut the butter. After much ado, I finally managed to get the following layout to work (on my actual data, not my example data).
lmat = rbind(c(0,4,5,0), c(0,0,2,0),c(0,1,3,0),c(0,0,6,0)) ,
lhei = c(0.4, 0.16, 3, 0.4) , # Alter dimensions of display array cell heighs
lwid = c(0.4, 0.16, 3, 0.4),
Notice the inclusion of elements 5 and 6.
So my final command looks like this (note that there will be many other changes but the real progress happened once I added in 5 and 6):
png(paste(SourceDir, "XYZ.png"),
width = 5*1500,
height = 5*1500,
res = 300, # 300 pixels per inch
pointsize =30)
heatmap.2(CombinedMtx,
main = paste("XYZ"), # heat map title
notecol="black",
key = "true" ,# change font color of cell labels to black
colsep = c(6, 12, 18),
labCol = c(" "," "," ", "XX"," "," "," "," "," ", "YY"," "," "," "," "," ", "ZZ"," "," "," "," "," ", "QQ"),
rowsep = c(6, 12, 18),
labRow = c(" "," "," ", "XX"," "," "," "," "," ", "YY"," "," "," "," "," ", "ZZ"," "," "," "," "," ", "QQ"),
sepcolor="white",
sepwidth=c(0.08,0.08),
density.info="none",
trace="none",
margins=c(1,1),
col=my_palette,
breaks=col_breaks,
dendrogram="none",
RowSideColors = c(rep("#deebf7", 6), rep("#1c9099", 6), rep("#addd8e", 6), rep("#fee391", 6)),
ColSideColors = c(rep("#deebf7", 6), rep("#1c9099", 6), rep("#addd8e", 6), rep("#fee391", 6)),
srtCol = 0 ,
asp = 1 ,
adjCol = c(1.5, -61.5) ,
adjRow = c(0, -1.38),
offsetRow = (-59.5),
keysize = 2 ,
Colv = FALSE ,
Rowv = FALSE ,
key.xlab = NA ,
key.ylab = NULL ,
key.title = NA ,
cexRow = (1.6) ,
cexCol = (1.6) ,
notecex = (1.5) ,
cex.main = (20),
lmat = rbind(c(0,4,5,0), c(0,0,2,0),c(0,1,3,0),c(0,0,6,0)) ,
#par(ColSideColors = c(2,2)),
lhei = c(0.4, 0.16, 3, 0.4) , # Alter dimensions of display array cell heighs
lwid = c(0.4, 0.16, 3, 0.4),
symkey = any(0.5 < 0, na.rm=FALSE) || col_breaks,
key.par=list(mar=c(3.5,0, 1.8,0) ) #tweak specific key paramters
)
dev.off()
Also, if you don't start each time by creating the PNG and enf each time by using dev.off() it won't work. I believe this might also have been contribution to my confusion, and potentially after drawing the heatmap, some elements were being drawn once the dev.off() command was run, causing the heatmap to be overwritten.
This (with my matrix) creates this image.
What I have done is a really gammy way of labelling my blocks but until I can work out how to get ComplexHeatmap working properly I'll be stuck using hacks like this with Heatmap.2.