The R markdown is available from the pulldown menu for Code
at the upper-right, choose “Download Rmd”, or download
the Rmd from GitHub.
This vignette illustrates how Cytoscape’s Custom Graphics can be used
to add graphs, charts and other graphics to node, and how to combine
Custom Graphics with the enhancedGraphics app for specialized
visualizations.
Installation
if(!"RCy3" %in% installed.packages()){
install.packages("BiocManager")
BiocManager::install("RCy3")
}
library(RCy3)
Prerequisites
In addition to this package (RCy3), you will need:
- Cytoscape 3.7 or greater, which can be downloaded
from https://cytoscape.org/download.html. Simply follow the
installation instructions on screen.
- Complete installation wizard
- Launch Cytoscape
Open Sample
For this tutorial, we will be using the galFiltered sample session
file, which includes a yeast network and associated data.
Set style and node color
First, lets change the style to a simple default and the color of
nodes to grey:
setVisualStyle('default')
setNodeColorDefault('#D8D8D8')
Custom Graphics
Bar chart
In this example, we will create a bar chart with the three expression
values, gal1RGexp, gal4RGexp and gal80Rexp, available as attributes in
the session file.
Create the Custom Graphic:
setNodeCustomBarChart(c("gal1RGexp","gal4RGexp","gal80Rexp"))
There are 4 types of Bar Charts and customizable parameters for
colors, size, spacing and orientation.
Position the Bar Chart just below the node. This is an optional step
that we are doing here just to make room for subsequent graphics. By
specifying both anchors at opposite ends, we can get a lot of space
between the node and the graphic.
setNodeCustomPosition(nodeAnchor = "S", graphicAnchor = "N")
Stripes
Next we are going to create stripes of gradient mappings using a
horizontal “heatmap”” of the same three data columns and position the
heatmap right above the node. For this vignette, we need to also specify
the slot number to avoid overwriting the Bar Chart:
setNodeCustomHeatMapChart(c("gal1RGexp","gal4RGexp","gal80Rexp"), slot = 2)
setNodeCustomPosition(nodeAnchor = "N", graphicAnchor = "S", slot = 2)
Pie chart
Finally, we will create a pie chart with two columns, Radiality and
Degree, and place it to the left of the node. Here we’ll use the
xOffset parameter to be even more specific about where we want
to place the graphic relative to the node.
setNodeCustomPieChart(c("Radiality", "Degree"), slot = 3)
setNodeCustomPosition(nodeAnchor = "W", xOffset = -20, slot = 3)
Enhanced Graphics
The nodes in the network are labeled with the corresponding protein
names (yeast), but there is additional text information in the Node
Table that could be useful to display as labels on the nodes. We are
going to use the enhancedGraphics app to create a second node label for
the common yeast gene name.
This involves a new step: Filling a new column with parameters for
the enhancedGraphics App. This column is then mapped to a Custom Graphic
slot and (optionally) positioned, like in the examples above.
Install enhancedGraphics
The enhancedGraphics app is available from the Cytoscape App
Store. In Cytoscape 3.7 and above, you can install apps from R with
the following function:
installApp("enhancedGraphics")
Define new label
The new column values have to follow a specific syntax to be
recognized by the enhancedGraphics app. Here, for example, is how you
set a label based on another attribute (e.g., the
column called “COMMON”), specifying its size, color, outline and
background:
"label: attribute=COMMON labelsize=10 color=red outline=false background=false""
For more details on the enhancedGraphics format, see
the manual.
First, we define a dataframe with two columns: node names (“name”)
and the new label (“my second label”):
all.nodes<-getAllNodes()
label.df<-data.frame(all.nodes, "label: attribute=COMMON labelsize=10 color=red outline=false background=false")
colnames(label.df)<-c("name","my second label")
Next, we load this dataframe into the Node Table to create and fill a
new column:
loadTableData(label.df, data.key.column = "name", table.key.column = "name")
Map and position label
We now have a new column, my second label, that we can use
for the mapping. This mapping does not come with a custom helper
function, se we are going to use two alternative functions to prepare
the passthrough mapping property and then update our visual style with
the new mapping:
label.map<-mapVisualProperty('node customgraphics 4','my second label','p')
updateStyleMapping('default', label.map)
Note: the custom graphic slot number is actulally part of the
property’s name.
Finally, we position the new label in the upper right corner:
setNodeCustomPosition(nodeAnchor = "E", graphicAnchor = "C", xOffset = 10, slot = 4)
LS0tCnRpdGxlOiAiQ3VzdG9tIEdyYXBoaWNzIGFuZCBMYWJlbHMiCmF1dGhvcjogIktyaXN0aW5hIEhhbnNwZXJzLCBBbGV4YW5kZXIgUGljbyIKcGFja2FnZTogUkN5MwpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6ICJub25lIgojICBwZGZfZG9jdW1lbnQ6CiMgICAgdG9jOiB0cnVlICAgIAp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5ezExLiBDdXN0b20gR3JhcGhpY3MgYW5kIExhYmVscyB+MTAgbWlufQogICVcVmlnbmV0dGVFbmdpbmV7a25pdHI6OnJtYXJrZG93bn0KICAlXFZpZ25ldHRlRW5jb2Rpbmd7VVRGLTh9Ci0tLQpgYGB7ciwgZWNobyA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZXZhbD1GQUxTRQopCmBgYAoqVGhlIFIgbWFya2Rvd24gaXMgYXZhaWxhYmxlIGZyb20gdGhlIHB1bGxkb3duIG1lbnUgZm9yKiBDb2RlICphdCB0aGUgdXBwZXItcmlnaHQsIGNob29zZSAiRG93bmxvYWQgUm1kIiwgb3IgW2Rvd25sb2FkIHRoZSBSbWQgZnJvbSBHaXRIdWJdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9jeXRvc2NhcGUvY3l0b3NjYXBlLWF1dG9tYXRpb24vbWFzdGVyL2Zvci1zY3JpcHRlcnMvUi9ub3RlYm9va3MvQ3VzdG9tLUdyYXBoaWNzLlJtZCkuKgoKPGhyIC8+CgpUaGlzIHZpZ25ldHRlIGlsbHVzdHJhdGVzIGhvdyBDeXRvc2NhcGUncyBDdXN0b20gR3JhcGhpY3MgY2FuIGJlIHVzZWQgdG8gYWRkIGdyYXBocywgY2hhcnRzIGFuZCBvdGhlciBncmFwaGljcyB0byBub2RlLCBhbmQgaG93IHRvIGNvbWJpbmUgQ3VzdG9tIEdyYXBoaWNzIHdpdGggdGhlIGVuaGFuY2VkR3JhcGhpY3MgYXBwIGZvciBzcGVjaWFsaXplZCB2aXN1YWxpemF0aW9ucy4KCiMgSW5zdGFsbGF0aW9uCmBgYHtyfQppZighIlJDeTMiICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpewogICAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQogICAgQmlvY01hbmFnZXI6Omluc3RhbGwoIlJDeTMiKQp9CmxpYnJhcnkoUkN5MykKYGBgCgojIFByZXJlcXVpc2l0ZXMKSW4gYWRkaXRpb24gdG8gdGhpcyBwYWNrYWdlIChSQ3kzKSwgeW91IHdpbGwgbmVlZDoKCiAgKiAqKkN5dG9zY2FwZSAzLjcqKiBvciBncmVhdGVyLCB3aGljaCBjYW4gYmUgZG93bmxvYWRlZCBmcm9tIGh0dHBzOi8vY3l0b3NjYXBlLm9yZy9kb3dubG9hZC5odG1sLiBTaW1wbHkgZm9sbG93IHRoZSBpbnN0YWxsYXRpb24gaW5zdHJ1Y3Rpb25zIG9uIHNjcmVlbi4KKiBDb21wbGV0ZSBpbnN0YWxsYXRpb24gd2l6YXJkCiogTGF1bmNoIEN5dG9zY2FwZSAKCiMgT3BlbiBTYW1wbGUKRm9yIHRoaXMgdHV0b3JpYWwsIHdlIHdpbGwgYmUgdXNpbmcgdGhlIGdhbEZpbHRlcmVkIHNhbXBsZSBzZXNzaW9uIGZpbGUsIHdoaWNoIGluY2x1ZGVzIGEgeWVhc3QgbmV0d29yayBhbmQgYXNzb2NpYXRlZCBkYXRhLgpgYGB7cn0Kb3BlblNlc3Npb24oKQpgYGAKCiMjIFNldCBzdHlsZSBhbmQgbm9kZSBjb2xvcgpGaXJzdCwgbGV0cyBjaGFuZ2UgdGhlIHN0eWxlIHRvIGEgc2ltcGxlIGRlZmF1bHQgYW5kIHRoZSBjb2xvciBvZiBub2RlcyB0byBncmV5OgoKYGBge3J9CnNldFZpc3VhbFN0eWxlKCdkZWZhdWx0JykKc2V0Tm9kZUNvbG9yRGVmYXVsdCgnI0Q4RDhEOCcpCmBgYAojIEN1c3RvbSBHcmFwaGljcyAKIyMgQmFyIGNoYXJ0IApJbiB0aGlzIGV4YW1wbGUsIHdlIHdpbGwgY3JlYXRlIGEgYmFyIGNoYXJ0IHdpdGggdGhlIHRocmVlIGV4cHJlc3Npb24gdmFsdWVzLCBnYWwxUkdleHAsIGdhbDRSR2V4cCBhbmQgZ2FsODBSZXhwLCBhdmFpbGFibGUgYXMgYXR0cmlidXRlcyBpbiB0aGUgc2Vzc2lvbiBmaWxlLgoKQ3JlYXRlIHRoZSBDdXN0b20gR3JhcGhpYzoKYGBge3J9CnNldE5vZGVDdXN0b21CYXJDaGFydChjKCJnYWwxUkdleHAiLCJnYWw0UkdleHAiLCJnYWw4MFJleHAiKSkKYGBgClRoZXJlIGFyZSA0IHR5cGVzIG9mIEJhciBDaGFydHMgYW5kIGN1c3RvbWl6YWJsZSBwYXJhbWV0ZXJzIGZvciBjb2xvcnMsIHNpemUsIHNwYWNpbmcgYW5kIG9yaWVudGF0aW9uLgoKUG9zaXRpb24gdGhlIEJhciBDaGFydCBqdXN0IGJlbG93IHRoZSBub2RlLiBUaGlzIGlzIGFuIG9wdGlvbmFsIHN0ZXAgdGhhdCB3ZSBhcmUgZG9pbmcgaGVyZSBqdXN0IHRvIG1ha2Ugcm9vbSBmb3Igc3Vic2VxdWVudCBncmFwaGljcy4gQnkgc3BlY2lmeWluZyBib3RoIGFuY2hvcnMgYXQgb3Bwb3NpdGUgZW5kcywgd2UgY2FuIGdldCBhIGxvdCBvZiBzcGFjZSBiZXR3ZWVuIHRoZSBub2RlIGFuZCB0aGUgZ3JhcGhpYy4gCmBgYHtyfQpzZXROb2RlQ3VzdG9tUG9zaXRpb24obm9kZUFuY2hvciA9ICJTIiwgZ3JhcGhpY0FuY2hvciA9ICJOIikKYGBgCgojIyBTdHJpcGVzCk5leHQgd2UgYXJlIGdvaW5nIHRvIGNyZWF0ZSBzdHJpcGVzIG9mIGdyYWRpZW50IG1hcHBpbmdzIHVzaW5nIGEgaG9yaXpvbnRhbCAiaGVhdG1hcCIiIG9mIHRoZSBzYW1lIHRocmVlIGRhdGEgY29sdW1ucyBhbmQgcG9zaXRpb24gdGhlIGhlYXRtYXAgcmlnaHQgYWJvdmUgdGhlIG5vZGUuIEZvciB0aGlzIHZpZ25ldHRlLCB3ZSBuZWVkIHRvIGFsc28gc3BlY2lmeSB0aGUgc2xvdCBudW1iZXIgdG8gYXZvaWQgb3ZlcndyaXRpbmcgdGhlIEJhciBDaGFydDoKCmBgYHtyfQpzZXROb2RlQ3VzdG9tSGVhdE1hcENoYXJ0KGMoImdhbDFSR2V4cCIsImdhbDRSR2V4cCIsImdhbDgwUmV4cCIpLCBzbG90ID0gMikKc2V0Tm9kZUN1c3RvbVBvc2l0aW9uKG5vZGVBbmNob3IgPSAiTiIsIGdyYXBoaWNBbmNob3IgPSAiUyIsIHNsb3QgPSAyKQpgYGAKCiMjIFBpZSBjaGFydApGaW5hbGx5LCB3ZSB3aWxsIGNyZWF0ZSBhIHBpZSBjaGFydCB3aXRoIHR3byBjb2x1bW5zLCBSYWRpYWxpdHkgYW5kIERlZ3JlZSwgYW5kIHBsYWNlIGl0IHRvIHRoZSBsZWZ0IG9mIHRoZSBub2RlLiBIZXJlIHdlJ2xsIHVzZSB0aGUgKnhPZmZzZXQqIHBhcmFtZXRlciB0byBiZSBldmVuIG1vcmUgc3BlY2lmaWMgYWJvdXQgd2hlcmUgd2Ugd2FudCB0byBwbGFjZSB0aGUgZ3JhcGhpYyByZWxhdGl2ZSB0byB0aGUgbm9kZS4KCmBgYHtyfQpzZXROb2RlQ3VzdG9tUGllQ2hhcnQoYygiUmFkaWFsaXR5IiwgIkRlZ3JlZSIpLCBzbG90ID0gMykKc2V0Tm9kZUN1c3RvbVBvc2l0aW9uKG5vZGVBbmNob3IgPSAiVyIsIHhPZmZzZXQgPSAtMjAsIHNsb3QgPSAzKQpgYGAKCjxjZW50ZXI+CiFbXShodHRwczovL2N5dG9zY2FwZS5naXRodWIuaW8vY3l0b3NjYXBlLWF1dG9tYXRpb24vZm9yLXNjcmlwdGVycy9SL25vdGVib29rcy9kYXRhL2ltZy9jdXN0b20tZ3JhcGhpY3MucG5nKXt3aWR0aD02MCV9CjwvY2VudGVyPgoKCiMgRW5oYW5jZWQgR3JhcGhpY3MKVGhlIG5vZGVzIGluIHRoZSBuZXR3b3JrIGFyZSBsYWJlbGVkIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgcHJvdGVpbiBuYW1lcyAoeWVhc3QpLCBidXQgdGhlcmUgaXMgYWRkaXRpb25hbCB0ZXh0IGluZm9ybWF0aW9uIGluIHRoZSBOb2RlIFRhYmxlIHRoYXQgY291bGQgYmUgdXNlZnVsIHRvIGRpc3BsYXkgYXMgbGFiZWxzIG9uIHRoZSBub2Rlcy4gV2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgZW5oYW5jZWRHcmFwaGljcyBhcHAgdG8gY3JlYXRlIGEgc2Vjb25kIG5vZGUgbGFiZWwgZm9yIHRoZSBjb21tb24geWVhc3QgZ2VuZSBuYW1lLgoKVGhpcyBpbnZvbHZlcyBhIG5ldyBzdGVwOiBGaWxsaW5nIGEgbmV3IGNvbHVtbiB3aXRoIHBhcmFtZXRlcnMgZm9yIHRoZSBlbmhhbmNlZEdyYXBoaWNzIEFwcC4gVGhpcyBjb2x1bW4gaXMgdGhlbiBtYXBwZWQgdG8gYSBDdXN0b20gR3JhcGhpYyBzbG90IGFuZCAob3B0aW9uYWxseSkgcG9zaXRpb25lZCwgbGlrZSBpbiB0aGUgZXhhbXBsZXMgYWJvdmUuCgojIyBJbnN0YWxsIGVuaGFuY2VkR3JhcGhpY3MKVGhlIGVuaGFuY2VkR3JhcGhpY3MgYXBwIGlzIGF2YWlsYWJsZSBmcm9tIHRoZSBbQ3l0b3NjYXBlIEFwcCBTdG9yZV0oaHR0cDovL2FwcHMuY3l0b3NjYXBlLm9yZy9hcHBzL2VuaGFuY2VkZ3JhcGhpY3MpLiBJbiBDeXRvc2NhcGUgMy43IGFuZCBhYm92ZSwgeW91IGNhbiBpbnN0YWxsIGFwcHMgZnJvbSBSIHdpdGggdGhlIGZvbGxvd2luZyBmdW5jdGlvbjoKCmBgYHtyfQppbnN0YWxsQXBwKCJlbmhhbmNlZEdyYXBoaWNzIikKYGBgCgojIyBEZWZpbmUgbmV3IGxhYmVsClRoZSBuZXcgY29sdW1uIHZhbHVlcyBoYXZlIHRvIGZvbGxvdyBhIHNwZWNpZmljIHN5bnRheCB0byBiZSByZWNvZ25pemVkIGJ5IHRoZSBlbmhhbmNlZEdyYXBoaWNzIGFwcC4gIEhlcmUsIGZvciBleGFtcGxlLCBpcyBob3cgeW91IHNldCBhICoqbGFiZWwqKiBiYXNlZCBvbiBhbm90aGVyIGF0dHJpYnV0ZSAoZS5nLiwgdGhlIGNvbHVtbiBjYWxsZWQgIkNPTU1PTiIpLCBzcGVjaWZ5aW5nIGl0cyBzaXplLCBjb2xvciwgb3V0bGluZSBhbmQgYmFja2dyb3VuZDoKCmBgYAoibGFiZWw6IGF0dHJpYnV0ZT1DT01NT04gbGFiZWxzaXplPTEwIGNvbG9yPXJlZCBvdXRsaW5lPWZhbHNlIGJhY2tncm91bmQ9ZmFsc2UiIgpgYGAKKkZvciBtb3JlIGRldGFpbHMgb24gdGhlIGVuaGFuY2VkR3JhcGhpY3MgZm9ybWF0LCBbc2VlIHRoZSBtYW51YWxdKGh0dHA6Ly93d3cuY2dsLnVjc2YuZWR1L2N5dG9zY2FwZS91dGlsaXRpZXMzL2VuaGFuY2VkY2cuc2h0bWwpLioKCkZpcnN0LCB3ZSBkZWZpbmUgYSBkYXRhZnJhbWUgd2l0aCB0d28gY29sdW1uczogbm9kZSBuYW1lcyAoIm5hbWUiKSBhbmQgdGhlIG5ldyBsYWJlbCAoIm15IHNlY29uZCBsYWJlbCIpOgpgYGB7cn0KYWxsLm5vZGVzPC1nZXRBbGxOb2RlcygpCmxhYmVsLmRmPC1kYXRhLmZyYW1lKGFsbC5ub2RlcywgImxhYmVsOiBhdHRyaWJ1dGU9Q09NTU9OIGxhYmVsc2l6ZT0xMCBjb2xvcj1yZWQgb3V0bGluZT1mYWxzZSBiYWNrZ3JvdW5kPWZhbHNlIikKY29sbmFtZXMobGFiZWwuZGYpPC1jKCJuYW1lIiwibXkgc2Vjb25kIGxhYmVsIikKYGBgCgpOZXh0LCB3ZSBsb2FkIHRoaXMgZGF0YWZyYW1lIGludG8gdGhlIE5vZGUgVGFibGUgdG8gY3JlYXRlIGFuZCBmaWxsIGEgbmV3IGNvbHVtbjoKYGBge3J9CmxvYWRUYWJsZURhdGEobGFiZWwuZGYsIGRhdGEua2V5LmNvbHVtbiA9ICJuYW1lIiwgdGFibGUua2V5LmNvbHVtbiA9ICJuYW1lIikKYGBgCgojIyBNYXAgYW5kIHBvc2l0aW9uIGxhYmVsCldlIG5vdyBoYXZlIGEgbmV3IGNvbHVtbiwgKm15IHNlY29uZCBsYWJlbCosIHRoYXQgd2UgY2FuIHVzZSBmb3IgdGhlIG1hcHBpbmcuIFRoaXMgbWFwcGluZyBkb2VzIG5vdCBjb21lIHdpdGggYSBjdXN0b20gaGVscGVyIGZ1bmN0aW9uLCBzZSB3ZSBhcmUgZ29pbmcgdG8gdXNlIHR3byBhbHRlcm5hdGl2ZSBmdW5jdGlvbnMgdG8gcHJlcGFyZSB0aGUgcGFzc3Rocm91Z2ggbWFwcGluZyBwcm9wZXJ0eSBhbmQgdGhlbiB1cGRhdGUgb3VyIHZpc3VhbCBzdHlsZSB3aXRoIHRoZSBuZXcgbWFwcGluZzoKYGBge3J9CmxhYmVsLm1hcDwtbWFwVmlzdWFsUHJvcGVydHkoJ25vZGUgY3VzdG9tZ3JhcGhpY3MgNCcsJ215IHNlY29uZCBsYWJlbCcsJ3AnKQp1cGRhdGVTdHlsZU1hcHBpbmcoJ2RlZmF1bHQnLCBsYWJlbC5tYXApCmBgYAoqTm90ZTogdGhlIGN1c3RvbSBncmFwaGljIHNsb3QgbnVtYmVyIGlzIGFjdHVsYWxseSBwYXJ0IG9mIHRoZSBwcm9wZXJ0eSdzIG5hbWUuKgoKRmluYWxseSwgd2UgcG9zaXRpb24gdGhlIG5ldyBsYWJlbCBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyOiAKYGBge3J9CnNldE5vZGVDdXN0b21Qb3NpdGlvbihub2RlQW5jaG9yID0gIkUiLCBncmFwaGljQW5jaG9yID0gIkMiLCB4T2Zmc2V0ID0gMTAsIHNsb3QgPSA0KQpgYGAKCjxjZW50ZXI+CiFbXShodHRwczovL2N5dG9zY2FwZS5naXRodWIuaW8vY3l0b3NjYXBlLWF1dG9tYXRpb24vZm9yLXNjcmlwdGVycy9SL25vdGVib29rcy9kYXRhL2ltZy9jdXN0b20tZ3JhcGhpY3NfbGFiZWwucG5nKXt3aWR0aD02MCV9CjwvY2VudGVyPgo=