How to add node size as legend in Cytoscape 3? - r

From an R function (cnetplot) I've obtained the following image which does not look very nice.
Therefore, I extracted the data from the R object and wrote a script to create an equivalent network data file that is readable by Cytoscape. The following equivalent plot from Cytoscape looks much better but the problem is that I am not able to add legends based on node size in Cytoscape as the R function did. I tried with Legend Creator app in cytoscspe but couldn't do it.
The original data and R code to reproduce the plots can be found in the following link.
ftp://ftp.lrz.de/transfer/Data_For_Plot/StackOverflow/
I looked into this Mapping nodes sizes and adding legends in cytoscape network, but in that case questioner already was able to load the node sizes as legends in cytoscape and moreover, he/she used a python package.
Any suggestions will highly be appreciated

Here's a little R script that will generate a min/max node size legend. You'll need to set the first variable to the name of the Visual Style in your network. This one works with the sample session file, "Yeast Perturbation.cys" if you want to test it there first.
If you are familiar with RCy3, then it should be self-explanatory. You can customize the positioning of the nodes, labels and label font size, etc. You can even adapt it to generate intermediate values (like in your example above) if you want.
NOTE: This adds nodes to your network. If you run a layout after adding these, then they will be moved! If you rely on node counts or connectivity measures, then these will affect those counts! Etc.
If you find this uesful, I might try to add it as helper function in the RCy3 package. Let me know if you have feedback or questions.
# https://bioconductor.org/packages/release/bioc/html/RCy3.html
library(RCy3)
# Set your current style name
style.name <- "galFiltered Style"
# Extract min and max node size
res<-cyrestGET(paste0("styles/",style.name,"/mappings/NODE_SIZE"))
size.col <- res$mappingColumn
min.size <- res$points[[1]]$equal
min.value <- res$points[[1]]$value
max.size <- res$points[[length(res$points)]]$equal
max.value <- res$points[[length(res$points)]]$value
# Prepare as data.frame
legend.df <-data.frame(c(min.size, max.size), c(min.value, max.value))
colnames(legend.df) <- c("legend.label",size.col)
rownames(legend.df) <- c("legend.size.min", "legend.size.max")
# Add legend nodes and data
addCyNodes(c("legend.size.min", "legend.size.max"))
loadTableData(legend.df)
# Style and position
setNodeColorBypass(c("legend.size.min", "legend.size.max"),"#000000")
setNodePropertyBypass(c("legend.size.min", "legend.size.max"),
c("E,W,l,5,0", "E,W,l,5,0"), # node_anchor, label_anchor, justification, x-offset, y-offset
"NODE_LABEL_POSITION")
setNodeLabelBypass(c("legend.size.min", "legend.size.max"), legend.df$legend.label)
setNodePropertyBypass("legend.size.max",
as.numeric(max.size)/2 + as.numeric(min.size)/2 + 10, # vertical spacing
"NODE_Y_LOCATION")
setNodeFontSizeBypass(c("legend.size.min", "legend.size.max"), c(20,20))

Related

Interactive plot in R (part scatterplot, part network)

I am trying to build an interactive plot. It has properties between a scatterplot and a network - I have a list of nodes and edges (network), but I also would like to constrain the nodes, sometimes on the x-axis sometimes on both x- and y- axis (scatterplot). Finally, I have a text label associated with each node that I would like to display (instead of a dot). I was able to create this using ggplot2.
However, some data sets are too large for this to work without the text labels from each node overlapping. Hence, I would now like to add an interactive feature so that the plot consists of dots representing each node, but that upon UI (such as hovering over a dot), the text label belonging to that dot will be revealed.
I would like to achieve this using R.
I tried animint (https://github.com/tdhock/animint) but it seems to mostly allow interaction between two plots, and here I would like to keep it all in one plot.
I also tried htmlwidgets (http://www.htmlwidgets.org/). I looked at two of their packages: I tried using metricsgraphics (mjs_plot), as it has a show_rollover_text option and mouseover option. However, this package does not allow combination of geoms, and so I could not have both dots (nodes) and lines (edges) represented. I also tried network3D package, but that seems to automatically position nodes so that they are distanced far away from each other, and does not seem to provide options to fix each node on a given x and y location.
I am just looking for advice on any other packages I should maybe consider to solve this problem and/or if I may be missing a feature from a package I already tried that could solve this problem. Thank you.
Maybe identify() will be useful for you. But it works only for base plotting system.
x <- rnorm(300)
y <- rnorm(300)
labs <- seq(300)
plot(x,y)
identify(x,y, labels = labs, plot=TRUE)
identify pic

How to pass a fixed igraph layout to plot.networx in phangorn?

Despite the relative popularity of neighborNets, I couldn't find any solutions to the following problem. In R, I'm trying to plot a neighborNet (created using package phangorn, object class networx). The package uses igraph for plotting static 2D graphs, so every time I re-plot the graph, the layout changes/rotates (default behaviour of igraph, apparently). Now, if I were to plot an usual igraph, I'd just save the layout, and then keep re-using it:
fixed = layout.sphere(somegraph)
plot(somegraph, layout=fixed)
But this doesn't work for the current problem. The help file of plot.networx does refer to igraph and layout, but only in the 'See also' section. Creating a x-y coordinate matrix manually wouldn't work (as suggested here), the location of the node labels/tips of nodes is significant on a neighbornet. I tried
library("phangorn")
library("igraph")
mydist = dist(matrix(sample(100), ncol=10)) # example data
nnet = neighborNet(mydist)
fixed = layout.sphere(nnet) # error, Not a graph object
fixed = layout.sphere(as.igraph(nnet)) # doesn't work properly, mangled graph
So the question, how to get it working in the vein of
plot.networx(nnet, type="2D", layout = fixed) # ?
plot.networx calls phangorn:::coords to get the coords which (for 2D) creates an igraph object and then uses layout.kamada.kawai. This is all hard-coded into plot.networx so not flexible enough such that you could use another layout algorithm.
You could follow the code in phangorn:::coords to create the graph layout and replace the layout function with another one, and then call phangorn:::plot2D with those coords. See plot.networx to see how to call phangorn:::plot2D correctly.

Shaded graph/network plot?

I am trying to plot quite large and dense networks (dput here). All I end up with is a bunch of overlapping dots, which does not really give me a sense of the structure or density of the network:
library(sna)
plot(data, mode = "fruchtermanreingold")
However, I have seen plots which utilizes fading to visualize the degree to which points overlap, e.g.:
How can I implement this "fading" in a plot of a graph?
Here's one way:
library(sna)
library(network)
source("modifieddatafromgist.R")
plot.network(data,
vertex.col="#FF000020",
vertex.border="#FF000020",
edge.col="#FFFFFF")
First, I added a data <- to the gist so it could be sourced.
Second, you need to ensure the proper library calls so the object classes are assigned correctly and the proper plot function will be used.
Third, you should use the extra parameters for the fruchtermanreingold layout (which is the default one for plot.network) to expand the area and increase the # of iterations.
Fourth, you should do a set.seed before the plot so folks can reproduce the output example.
Fifth, I deliberately removed cruft so you can see the point overlap, but you can change the alpha for both edges & vertices (and you should change the edge width, too) to get the result you want.
There's a ton of help in ?plot.network to assist you in configuring these options.

plot igraph in a big area

Just wondering if it is possible to increase the size of the plot so that the nodes and edges can be more scattered over the plot.
Original plot:
What are expected:
I tried many parameters in the layout function such as area, niter, and so on, but all of them do not work. By the way, I am using 'igraph' package in R.
If you are referring to the actual size of the produced output (pdf, png, etc), you can configure it with the width and height parameters. Check this link for png,bpm, etc, and this link for PDF format.
A MWE is something like this:
png("mygraph.png", heigh=400, width=600)
#functions to plot your graph
dev.off()
If you are referring to the size of the graphic produced by the layout function, as #MrFlick referred, you should check the parameters of the particular layout you are using.
Hope it helps you.
In your second graph, it's obviously the graph can be divided into several clusters (or sections). If I understood you correctly, you want to have a layout that separates your clusters more visibly.
Then you can draw this by calculating a two-level layout:
First, calculate the layout of the graph in order to find a place for each cluster.
Second, calculate the layout in each cluster according to first step and plot nodes in the corresponding place.

Plot to specific plot in multiple-plot window?

If I create a multi-plot window with par(mfrow=...), is it possible to send data to a specific plot (i.e. "the one in the lower left corner") or is the plotting always necessarily sequential? Is there a package for R that does something like this?
For those that are interested, this problem arises out of the fact that R is a single-threaded application and is not ideal for real-time visualization. I have multiple real-time data streams coming into R from an outside source that produces the data asynchronously (and therefore the data streams don't always come in the same order). This results in R flipping around the order of the data visualization plots every time it updates.
You could use split.screen():
par(bg = "white") # erase.screen() will appear not to work
# if the background color is transparent
# (as it is by default on most devices).
split.screen(c(2,1)) # split display into two screens
split.screen(c(1,3), screen = 2) # now split the bottom half into 3
screen(1) # prepare screen 1 for output
plot(10:1)
screen(4) # prepare screen 4 for output
plot(10:1)
Have a look at help(layout). This allows you to specify the what, where and in which sizes.
Once plotted, I don't think you re-plot just partially. But you you can use dev.set() et al to switch between different 'plot devices' (ie windows); see help(dev.list).
Note that the suggested answer here is to use split.screen(). It may work, but according to the split.screen help file: "The recommended way to use these functions is to completely draw a plot and all additions (i.e. points and lines) to the base plot, prior to selecting and plotting on another screen. The behavior associated with returning to a screen to add to an existing plot is unpredictable and may result in problems that are not readily visible."
In an answer to my question, there is a more useful solution, using the par(mfg) option:
Change plot panel in multipanel plot in R
Another option is that of implementing a little GUI e.g. with RGtk2 or RTclTk.
I generally do this for graphs that I want to change in realtime and it works great.
For instance, with RGtk2 and cairoDevice you could just do something like (I assume you have a Glade interface)
# Helper function to get a widget from the Glade interface
getWidget <- function(name)
{
return (interface$getWidget(name))
}
interface <- gladeXMLNew("interface.glade", root="mainWindow")
# Our cairo devices (to draw graphics).
# plot1, plot2, and plot3 are GtkDrawingArea widgets
asCairoDevice(getWidget("plot1"))
# dev.cur() will give the device number of the last device we created
# You'll use this to switch device when you draw in different plots
# Storing the device number is important because you may have other
# devices open from other unrelated plots
# (so never assume they'll just start from 1 and be sequential!!!)
plot1.dev <- as.integer(dev.cur())
asCairoDevice(getWidget("plot2"))
plot2.dev <- as.integer(dev.cur())
asCairoDevice(getWidget("plot3"))
plot3.dev <- as.integer(dev.cur())
# To draw in a specific plot you just do
dev.set(plot2.dev)
plot(....)
This has many other advantages, like that of being able to positions the graphs easily where you want (using Glade Interface Designer) and having the possibility of user interaction through specific buttons (e.g. you may have a "pause acquisition" button).

Resources