############################################################################################
############################################################################################
# Plotting networks in R - an example how to plot a network and 
# customize its appearance in Cytoscape directly from R using 
# the RCy3 package
############################################################################################
############################################################################################
# Clear workspace 
# rm(list = ls())
############################################################################################

# Read a data set. 
# Data format: dataframe with 3 variables; variables 1 & 2 correspond to interactions; variable 3 is weight of interaction
dataSet <- read.table("lesmis.txt", header = FALSE, sep = "\t")

# Create a graph. Use simplyfy to ensure that there are no duplicated edges or self loops
gD <- igraph::simplify(igraph::graph.data.frame(dataSet, directed=FALSE))

# Print number of nodes and edges
# igraph::vcount(gD)
# igraph::ecount(gD)

############################################################################################
# Calculate some node properties and node similarities that will be used to illustrate 
# different plotting abilities

# Calculate degree for all nodes
degAll <- igraph::degree(gD, v = igraph::V(gD), mode = "all")

# Calculate betweenness for all nodes
betAll <- igraph::betweenness(gD, v = igraph::V(gD), directed = FALSE) / (((igraph::vcount(gD) - 1) * (igraph::vcount(gD)-2)) / 2)
betAll.norm <- (betAll - min(betAll))/(max(betAll) - min(betAll))
rm(betAll)

#Calculate Dice similarities between all pairs of nodes
dsAll <- igraph::similarity.dice(gD, vids = igraph::V(gD), mode = "all")

############################################################################################
# Add new node and edge attributes based on the calculated node properties/similarities

gD <- igraph::set.vertex.attribute(gD, "degree", index = igraph::V(gD), value = degAll)
gD <- igraph::set.vertex.attribute(gD, "betweenness", index = igraph::V(gD), value = betAll.norm)

# Check the attributes
# summary(gD)

F1 <- function(x) {data.frame(V4 = dsAll[which(igraph::V(gD)$name == as.character(x$V1)), which(igraph::V(gD)$name == as.character(x$V2))])}
dataSet.ext <- plyr::ddply(dataSet, .variables=c("V1", "V2", "V3"), function(x) data.frame(F1(x)))

gD <- igraph::set.edge.attribute(gD, "weight", index = igraph::E(gD), value = 0)
gD <- igraph::set.edge.attribute(gD, "similarity", index = igraph::E(gD), value = 0)

# The order of interactions in dataSet.ext is not the same as it is in dataSet or as it is in the edge list
# and for that reason these values cannot be assigned directly

for (i in 1:nrow(dataSet.ext))
{
  igraph::E(gD)[as.character(dataSet.ext$V1) %--% as.character(dataSet.ext$V2)]$weight <- as.numeric(dataSet.ext$V3)
  igraph::E(gD)[as.character(dataSet.ext$V1) %--% as.character(dataSet.ext$V2)]$similarity <- as.numeric(dataSet.ext$V4)
}

# Check the attributes
# summary(gD)

rm(dataSet,dsAll, i, F1)

############################################################################################
# Now, let's do Cytoscape plots

# First, we need to transform our network from the igraph to graphnel format
gD.cyt <- igraph::as_graphnel(gD)

# Check if attributes have been passed
# graph::nodeData(gD.cyt, igraph::V(gD)$name, 'degree')
# graph::nodeData(gD.cyt, igraph::V(gD)$name, 'betweenness')
# graph::edgeData(gD.cyt, as.character(dataSet.ext$V1), as.character(dataSet.ext$V2), 'weight')
# graph::edgeData(gD.cyt, as.character(dataSet.ext$V1), as.character(dataSet.ext$V2), 'similarity')

# We have to create attributes for graphNEL
# We'll keep the same names as before
# In RCytoscape, this would ensure that the values of attributes are passed directly from igraph.
# However, this does not work with RCy3 right now (not sure if it is a bug or a feature has changed).
# Thus, we need to do send attributes to Cytoscape

gD.cyt <- RCy3::initNodeAttribute(gD.cyt, 'degree', 'numeric', 0) 
gD.cyt <- RCy3::initNodeAttribute(gD.cyt, 'betweenness', 'numeric', 0) 
gD.cyt <- RCy3::initEdgeAttribute (gD.cyt, "weight", 'integer', 0)
gD.cyt <- RCy3::initEdgeAttribute (gD.cyt, "similarity", 'numeric', 0)

# Next, we will create a new graph window in cytoscape
gDCW <- RCy3::CytoscapeWindow("Les Miserables", graph = gD.cyt, overwriteWindow = TRUE)

# We can display graph, with defaults color/size scheme
RCy3::displayGraph(gDCW)

# Now let's send/load node and edge attributes into Cytoscape

##########
# This should theoretically work, but there are some problems with attributes when networks
# are created from data frames (see https://github.com/tmuetze/Bioconductor_RCy3_the_new_RCytoscape/issues/25)
# I'll keep this code uncommented, but right now, it doesn't do anything

# setNodeAttributes should transfer the specified node attributes, for all nodes, the named node attribute 
# from the R graph (found in obj@graph) to Cytoscape. 
attribute.names <- RCy3::noa.names(gDCW@graph)

# Print list of attribute names to see if they are ok
# attribute.names 

# All nodes should already be in
RCy3::sendNodes(gDCW)

for (attribute.name in attribute.names){
  RCy3::setNodeAttributes(gDCW, attribute.name)
}

attribute.names <- RCy3::eda.names(gDCW@graph)

# All edges should already be in
RCy3::sendEdges(gDCW)

for (attribute.name in attribute.names){
  RCy3::setEdgeAttributes(gDCW, attribute.name)
}

RCy3::displayGraph(gDCW)

##########
# Thealternative, when we set attributes directly, works fine,
# so we will use it now (although, it seems kind of repetative)

RCy3::setNodeAttributesDirect(gDCW, 'degree', 'numeric', igraph::V(gD)$name, igraph::V(gD)$degree)
RCy3::setNodeAttributesDirect(gDCW, 'betweenness', 'numeric', igraph::V(gD)$name, igraph::V(gD)$betweenness)
RCy3::setEdgeAttributesDirect(gDCW, 'weight', 'integer', as.character (RCy3::cy2.edge.names (gDCW@graph)), graph::edgeData(gD.cyt, as.character(dataSet.ext$V1), as.character(dataSet.ext$V2), 'weight'))
RCy3::setEdgeAttributesDirect(gDCW, 'similarity', 'numeric', as.character (RCy3::cy2.edge.names (gDCW@graph)), graph::edgeData(gD.cyt, as.character(dataSet.ext$V1), as.character(dataSet.ext$V2), 'similarity'))

##########
# Now let's decide on a layout

# If you also want to choose a layout from R, a list  of available layouts can be accessed as follow:
cy <- RCy3::CytoscapeConnection()
hlp <-RCy3::getLayoutNames(cy)

# We'll select the "fruchterman-rheingold" layout. This layout is the layout number 10 
# To see properties for the given layout, use:
# RCy3::getLayoutPropertyNames(cy, hlp[10])
# We can choose any property we want and provide them as a list
RCy3::setLayoutProperties (gDCW, hlp[10], list (gravity_multiplier = 'similarity', nIterations = 1000))
RCy3::layoutNetwork(gDCW, hlp[10])

# I've noticed that if I change property to attraction_multiplier
# RCy3::setLayoutProperties (gDCW, hlp[10], list (attraction_multiplier = 'similarity', nIterations = 1000))
# RCy3::layoutNetwork(gDCW, hlp[10])
# And then go back to the original one
# RCy3::setLayoutProperties (gDCW, hlp[10], list (gravity_multiplier = 'similarity', nIterations = 1000))
# RCy3::layoutNetwork(gDCW, hlp[10])
# The layout won't go back to the original one. I am not sure if this is a bug or not

##########
# Finally, we can define rules for nodes:
RCy3::setNodeColorRule(gDCW, 'degree', c(min(degAll), mean(degAll), max(degAll)), c('#F5DEB3', '#FFA500', '#FF7F50', '#FF4500', '#FF0000'), mode = 'interpolate')
RCy3::setNodeSizeRule(gDCW, 'betweenness', c(min(betAll.norm), mean(betAll.norm), max(betAll.norm)), c(30, 45, 60, 80, 100), mode = 'interpolate')

# And edges:
RCy3::setEdgeLineWidthRule(gDCW, 'weight', dataSet.ext$V3, dataSet.ext$V3)
RCy3::setEdgeColorRule(gDCW, 'weight', c(min(as.numeric(dataSet.ext$V3)), mean(as.numeric(dataSet.ext$V3)), max(as.numeric(dataSet.ext$V3))), c('#FFFF00', '#00FFFF', '#00FF7F', '#228B22', '#006400'), mode='interpolate')

# While I get the "Successfully set rule" for both of the Edge rules, the view in the Cytoscape did not 
# change accordning the rules - setEdgeLineWidthRule command did not make any changes and the 
# setEdgeColorRule command made all edges white.
# One of the GitHub solved issues suggests to first set all rule-based functions and then the direct ones, but
# but it didn't work here (https://github.com/tmuetze/Bioconductor_RCy3_the_new_RCytoscape/issues/21 and
# https://github.com/tmuetze/Bioconductor_RCy3_the_new_RCytoscape/issues/20)

# We will define our own default color/size schema after we defined node and edge rules, due to
# possible issues when using rules
RCy3::setDefaultBackgroundColor(gDCW, '#D3D3D3')
RCy3::setDefaultEdgeColor(gDCW, '#CDC9C9')
RCy3::setDefaultEdgeLineWidth(gDCW, 4)
RCy3::setDefaultNodeBorderColor(gDCW, '#000000')
RCy3::setDefaultNodeBorderWidth(gDCW, 3)
RCy3::setDefaultNodeShape(gDCW, 'ellipse')
RCy3::setDefaultNodeColor(gDCW, '#87CEFA')
RCy3::setDefaultNodeSize(gDCW, 60)
RCy3::setDefaultNodeFontSize(gDCW, 20)
RCy3::setDefaultNodeLabelColor(gDCW, '#000000')

# Running these commands will set color to all edges back to black and set their width to 4,
# ignoring the rules specified above
############################################################################################

sessionInfo()


# R version 3.3.1 (2016-06-21)
# Platform: x86_64-redhat-linux-gnu (64-bit)
# Running under: Fedora 23 (Workstation Edition)
#
# locale:
# [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
# [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
# [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
# [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
# [9] LC_ADDRESS=C               LC_TELEPHONE=C            
# [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
# 
# attached base packages:
# [1] stats     graphics  grDevices utils     datasets  methods  
# [7] base     
# 
# loaded via a namespace (and not attached):
# [1] httr_1.2.1          R6_2.1.2            plyr_1.8.4         
# [4] magrittr_1.5        parallel_3.3.1      tools_3.3.1        
# [7] igraph_1.0.1        RCurl_1.95-4.8      curl_1.1           
# [10] Rcpp_0.12.6         RJSONIO_1.3-0       BiocGenerics_0.18.0
# [13] RCy3_1.2.0          bitops_1.0-6        stats4_3.3.1       
# [16] graph_1.50.0 
#
#####
# Cytoscape version: 3.4.0
# Java version: 1.8.0_101
# cyREST version: 3.3.4

############################################################################################