{ "cells": [ { "cell_type": "markdown", "id": "a13ebf84", "metadata": {}, "source": [ "### ipycytoscape walkthrough\n", "\n", " - cytoscape json\n", " - layouts\n", " - pandas\n", " - styling\n", " - networkx\n", " - directed and undirected graphs\n", " - creating custom elements\n", " - neo4j\n", " - interactiveness with ipywidgets" ] }, { "cell_type": "code", "execution_count": null, "id": "cfe01ef0-a1eb-4bd4-a97c-d5fc6c49131d", "metadata": {}, "outputs": [], "source": [ "import micropip\n", "\n", "await micropip.install(['ipycytoscape==1.2.2', 'pandas', 'networkx'])" ] }, { "cell_type": "code", "execution_count": null, "id": "18a99a16", "metadata": {}, "outputs": [], "source": [ "import ipycytoscape as cy" ] }, { "cell_type": "code", "execution_count": null, "id": "a4e1b979", "metadata": {}, "outputs": [], "source": [ "cyGraph = cy.CytoscapeWidget()" ] }, { "cell_type": "markdown", "id": "e47299e7", "metadata": {}, "source": [ "### **cytoscape json**" ] }, { "cell_type": "code", "execution_count": null, "id": "023a2695", "metadata": {}, "outputs": [], "source": [ "cytoscape_json = {\n", " 'nodes': [\n", " { 'data': { 'id': '0', 'name': 'Cytoscape', 'classes': 'node' }},\n", " { 'data': { 'id': '1', 'name': 'Grid', 'classes': 'node' }},\n", " { 'data': { 'id': '2', 'name': 'Cola', 'classes': 'node' }},\n", " { 'data': { 'id': '3', 'name': 'Popper', 'classes': 'node' }},\n", " { 'data': { 'id': '4', 'name': 'Cytoscape.js', 'classes': 'node'}}\n", " ],\n", " 'edges': [\n", " {'data': { 'source': '4', 'target': '0' }},\n", " {'data': { 'source': '1', 'target': '2' }},\n", " {'data': { 'source': '1', 'target': '3' }},\n", " {'data': { 'source': '2', 'target': '3' }},\n", " {'data': { 'source': '4', 'target': '4' }},\n", " {'data': { 'source': '4', 'target': '3' }},\n", " ]\n", "}" ] }, { "cell_type": "markdown", "id": "192077a1", "metadata": {}, "source": [ "All of the examples in this notebook are created in loco for sake of simplicity but it's also possible to load them externaly in many different ways.\n", "\n", "For an extensive description of all the attributes available on a cytoscape graph, check the [cytoscape documentation](https://js.cytoscape.org/#cy.data)." ] }, { "cell_type": "code", "execution_count": null, "id": "2c398408", "metadata": {}, "outputs": [], "source": [ "cyGraph.graph.add_graph_from_json(cytoscape_json)" ] }, { "cell_type": "code", "execution_count": null, "id": "daf1cfab", "metadata": {}, "outputs": [], "source": [ "cyGraph" ] }, { "attachments": {}, "cell_type": "markdown", "id": "d157a03c", "metadata": {}, "source": [ "#### Layouts:\n", "\n", " - cola\n", " - dagre\n", " - euler\n", " - cose\n", " - breadthfirst\n", " - circle\n", " - grid\n", " - random\n", " - null\n", " \n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "6d54c4dd", "metadata": {}, "outputs": [], "source": [ "cyGraph.set_layout(name='random')" ] }, { "cell_type": "code", "execution_count": null, "id": "a2ffb4cf", "metadata": {}, "outputs": [], "source": [ "cyGraph" ] }, { "cell_type": "markdown", "id": "bcf36188", "metadata": {}, "source": [ "### **pandas**" ] }, { "cell_type": "code", "execution_count": null, "id": "ec28b464", "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "id": "81fd67bc", "metadata": {}, "outputs": [], "source": [ "pdCy = cy.CytoscapeWidget()" ] }, { "cell_type": "code", "execution_count": null, "id": "dc3315b9", "metadata": {}, "outputs": [], "source": [ "robots = ['marvin','c3po','r2d2','data']\n", "universe = ['douglas adams','star wars','star wars','star trek']\n", "cooleness_lvl = ['10', '3', '10', '10']\n", "robotsRates = list(zip(robots, universe, cooleness_lvl))\n", "df = pd.DataFrame(data = robotsRates, columns=['robot', 'universe', 'cooleness_lvl'])" ] }, { "cell_type": "code", "execution_count": null, "id": "51caafac", "metadata": {}, "outputs": [], "source": [ "pdCy.graph.add_graph_from_df(df, ['universe'], ['robot', 'cooleness_lvl'])" ] }, { "cell_type": "code", "execution_count": null, "id": "cdbd643f", "metadata": {}, "outputs": [], "source": [ "pdCy" ] }, { "cell_type": "code", "execution_count": null, "id": "d7d651e3", "metadata": {}, "outputs": [], "source": [ "pdCy.graph.nodes" ] }, { "cell_type": "code", "execution_count": null, "id": "9eb485f9", "metadata": {}, "outputs": [], "source": [ "edge = cy.Edge(data={\"source\": 1, \"target\": 2})" ] }, { "cell_type": "code", "execution_count": null, "id": "6028ac19", "metadata": {}, "outputs": [], "source": [ "pdCy.graph.add_edge(edge)" ] }, { "cell_type": "code", "execution_count": null, "id": "48ba1da2", "metadata": {}, "outputs": [], "source": [ "edge = cy.Edge(data={\"source\": 'parent-2', \"target\": 'parent-1'})\n", "pdCy.graph.add_edge(edge)" ] }, { "cell_type": "code", "execution_count": null, "id": "6e0daa80", "metadata": {}, "outputs": [], "source": [ "pdCy.graph.edges" ] }, { "cell_type": "markdown", "id": "9f6af16d", "metadata": {}, "source": [ "#### **styling**\n", "\n", " - layout\n", " - style\n", " - tooltips" ] }, { "cell_type": "code", "execution_count": null, "id": "3bca4e59", "metadata": {}, "outputs": [], "source": [ "pdCy.set_style([ \n", " {\n", " 'selector': 'node[name] *= \"\"',\n", " 'style': {\n", " 'background-color': 'blue',\n", " }},\n", " {\n", " 'selector': '[id *= \"parent-1\"]',\n", " 'style': {\n", " 'background-color': 'yellow',\n", " }},\n", " {\n", " 'selector': '[id *= \"parent-2\"]',\n", " 'style': {\n", " 'background-color': 'red',\n", " 'color': 'blue'\n", " }\n", " }])" ] }, { "cell_type": "code", "execution_count": null, "id": "767ff20c", "metadata": {}, "outputs": [], "source": [ "pdCy" ] }, { "cell_type": "markdown", "id": "c414b0d8", "metadata": {}, "source": [ "More information about cytoscape selectors are available [here](https://js.cytoscape.org/#selectors)." ] }, { "cell_type": "code", "execution_count": null, "id": "9ac7cd59", "metadata": {}, "outputs": [], "source": [ "pdCy.set_tooltip_source('name')" ] }, { "cell_type": "markdown", "id": "87468fd2", "metadata": {}, "source": [ "More examples of how to set labels and tooltips [here](https://github.com/cytoscape/ipycytoscape/blob/master/examples/Text%20on%20node.ipynb) and [here](https://github.com/cytoscape/ipycytoscape/blob/master/examples/Tooltips%20example.ipynb). Or online via [binder](https://mybinder.org/v2/gh/QuantStack/ipycytoscape/stable?filepath=examples)." ] }, { "cell_type": "markdown", "id": "e358b249", "metadata": {}, "source": [ "### **networkx**" ] }, { "cell_type": "code", "execution_count": null, "id": "2799724e", "metadata": {}, "outputs": [], "source": [ "import networkx as nx" ] }, { "cell_type": "code", "execution_count": null, "id": "6434d10e", "metadata": {}, "outputs": [], "source": [ "nxCyGraph = cy.CytoscapeWidget()\n", "nxGraph = nx.complete_graph(5)" ] }, { "cell_type": "code", "execution_count": null, "id": "33d470ea", "metadata": {}, "outputs": [], "source": [ "nxCyGraph.graph.add_graph_from_networkx(nxGraph)" ] }, { "cell_type": "code", "execution_count": null, "id": "dbf81f6b", "metadata": {}, "outputs": [], "source": [ "nxCyGraph" ] }, { "cell_type": "markdown", "id": "ddba9909", "metadata": {}, "source": [ "#### **directed and undirected graphs**" ] }, { "cell_type": "code", "execution_count": null, "id": "f19617e6", "metadata": {}, "outputs": [], "source": [ "directCyGraph = cy.CytoscapeWidget()\n", "directNxGraph = nx.complete_graph(4)\n", "directCyGraph.graph.add_graph_from_networkx(directNxGraph, directed=True)" ] }, { "cell_type": "code", "execution_count": null, "id": "7c832e6e", "metadata": {}, "outputs": [], "source": [ "directCyGraph" ] }, { "cell_type": "code", "execution_count": null, "id": "b593cb8c", "metadata": {}, "outputs": [], "source": [ "from random import random" ] }, { "cell_type": "code", "execution_count": null, "id": "6f136286", "metadata": {}, "outputs": [], "source": [ "mixedNxGraph = nx.complete_graph(5)\n", "for s, t, data in mixedNxGraph.edges(data=True):\n", " if random() > .5:\n", " mixedNxGraph[s][t]['classes'] = 'directed'\n", "\n", "mixedGraph = cy.CytoscapeWidget()\n", "mixedGraph.graph.add_graph_from_networkx(mixedNxGraph)\n", "mixedGraph" ] }, { "cell_type": "markdown", "id": "d5c5066e", "metadata": {}, "source": [ "#### **Creating custom elements**\n", "Custom Nodes and Edges can be created for any kinds of graphs, meaning it's not only restricted to networkx objects. You just have to use the ipycytoscape API for that. We see an example of the API's use on the Pandas example." ] }, { "cell_type": "code", "execution_count": null, "id": "b65ea933", "metadata": {}, "outputs": [], "source": [ "class CustomNode(cy.Node):\n", " def __init__(self, name, classes = ''):\n", " super().__init__()\n", " self.data['id'] = name\n", " self.classes = classes" ] }, { "cell_type": "code", "execution_count": null, "id": "d94b4bf5", "metadata": {}, "outputs": [], "source": [ "n1 = CustomNode(\"node 1\", classes = 'first')\n", "n2 = CustomNode(\"node 2\", classes = 'second')\n", " \n", "G = nx.Graph()\n", "\n", "G.add_node(n1)\n", "G.add_node(n2)\n", "\n", "G.add_edge(n1, n2)" ] }, { "cell_type": "code", "execution_count": null, "id": "5ada71b3", "metadata": {}, "outputs": [], "source": [ "customInheritedGraph = cy.CytoscapeWidget()\n", "customInheritedGraph.graph.add_graph_from_networkx(G)\n", "customInheritedGraph.graph.nodes" ] }, { "cell_type": "markdown", "id": "a4b71c67", "metadata": {}, "source": [ "### **Neo4j**\n", "\n", "Examples on how to run ipycytoscape with Neo4j can be found [here](https://github.com/sbl-sdsc/neo4j-ipycytoscape) binder and a notebook [here](https://binder.pangeo.io/v2/gh/sbl-sdsc/neo4j-ipycytoscape/master)." ] }, { "cell_type": "code", "execution_count": null, "id": "c5093a38", "metadata": {}, "outputs": [], "source": [ "#from py2neo import Graph\n", "#cy.add_graph_from_neo4j(neo4j_graph)" ] }, { "cell_type": "markdown", "id": "871a2341", "metadata": {}, "source": [ "### **interactvity and interoperability with ipywidgets**\n", "\n", " - javascript events\n", " - DOM (elements, events)\n", " - widgets interaction" ] }, { "cell_type": "code", "execution_count": null, "id": "a3c06c76", "metadata": {}, "outputs": [], "source": [ "import ipywidgets as widgets" ] }, { "cell_type": "code", "execution_count": null, "id": "a24cc3a3", "metadata": {}, "outputs": [], "source": [ "cyGraph" ] }, { "cell_type": "code", "execution_count": null, "id": "62cdf375", "metadata": {}, "outputs": [], "source": [ "cyGraph.set_style([{\n", " \"selector\": \"edge.highlighted\",\n", " \"css\": {\n", " \"line-color\": \"red\"\n", " }\n", " }])" ] }, { "cell_type": "code", "execution_count": null, "id": "064cd743", "metadata": {}, "outputs": [], "source": [ "btn = widgets.Button(description = \"red edges\", disabled = False)\n", "\n", "def btn_callback(b):\n", " for edge in cyGraph.graph.edges:\n", " edge.classes = \" highlighted\"\n", "\n", "btn.on_click(callback = btn_callback)\n", "display(btn)" ] }, { "cell_type": "code", "execution_count": null, "id": "8f84bd01", "metadata": {}, "outputs": [], "source": [ "def paint_blue(event):\n", " auxNode = cyGraph.graph.nodes[int(event['data']['id'])]\n", " auxNode.classes += ' blue'\n", "cyGraph.on('node', 'click', paint_blue)" ] }, { "cell_type": "code", "execution_count": null, "id": "f35a5eac", "metadata": {}, "outputs": [], "source": [ "cyGraph.set_style([{\n", " \"selector\": \"edge.highlighted\",\n", " \"css\": {\n", " \"line-color\": \"red\"\n", " }\n", " },\n", " {\n", " \"selector\": \"node.blue\",\n", " \"css\": {\n", " \"background-color\": \"blue\"\n", " },\n", " }])" ] }, { "cell_type": "code", "execution_count": null, "id": "7dfb6c2b", "metadata": {}, "outputs": [], "source": [ "cyGraph" ] }, { "cell_type": "markdown", "id": "adcfb530", "metadata": {}, "source": [ "**List of events**\n", "\n", "These events can be applied to either `nodes` or `edges` objects:\n", "\n", "* **mousedown :** when the mouse button is pressed\n", "* **mouseup :** when the mouse button is released\n", "* **click :** after mousedown then mouseup\n", "* **mouseover :** when the cursor is put on top of the target\n", "* **mouseout :** when the cursor is moved off of the target\n", "* **mousemove :** when the cursor is moved somewhere on top of the target\n", "* **touchstart :** when one or more fingers starts to touch the screen\n", "* **touchmove :** when one or more fingers are moved on the screen\n", "* **touchend :** when one or more fingers are removed from the screen\n", "* **tapstart :** normalised tap start event (either mousedown or touchstart)\n", "* **vmousedown :** alias for 'tapstart'\n", "* **tapdrag :** normalised move event (either touchmove or mousemove)\n", "* **vmousemove :** alias for 'tapdrag'\n", "* **tapdragover :** normalised over element event (either touchmove or mousemove/mouseover)\n", "* **tapdragout :** normalised off of element event (either touchmove or mousemove/mouseout)\n", "* **tapend :** normalised tap end event (either mouseup or touchend)\n", "* **vmouseup :** alias for 'tapend'\n", "* **tap :** normalised tap event (either click, or touchstart followed by touchend without touchmove)\n", "* **vclick :** alias for 'tap'\n", "* **taphold :** normalised tap hold event\n", "* **cxttapstart :** normalised right-click mousedown or two-finger tapstart\n", "* **cxttapend :** normalised right-click mouseup or two-finger tapend\n", "* **cxttap :** normalised right-click or two-finger tap\n", "* **cxtdrag :** normalised mousemove or two-finger drag after cxttapstart but before cxttapend\n", "* **cxtdragover :** when going over a node via cxtdrag\n", "* **cxtdragout :** when going off a node via cxtdrag\n", "* **boxstart :** when starting box selection\n", "* **boxend :** when ending box selection\n", "* **boxselect :** triggered on elements when selected by box selection\n", "* **box :** triggered on elements when inside the box on boxend" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" } }, "nbformat": 4, "nbformat_minor": 5 }