From 79551f462c92050db5ea7864e61f44d9747f9e67 Mon Sep 17 00:00:00 2001 From: Keiichiro Ono Date: Wed, 6 Aug 2014 19:29:36 -0700 Subject: [PATCH] New samples added. --- .../CytoscapeREST_Basic1-checkpoint.ipynb | 522 ++++++++++++------ .../CytoscapeREST_Basic2-checkpoint.ipynb | 234 ++++++++ .../python/basic/CytoscapeREST_Basic1.ipynb | 522 ++++++++++++------ .../python/basic/CytoscapeREST_Basic2.ipynb | 234 ++++++++ examples/python/basic/cytoscape/__init__.pyc | Bin 573 -> 573 bytes examples/python/basic/cytoscape/viewer.pyc | Bin 4417 -> 4417 bytes .../internal/service/MiscDataService.java | 79 ++- .../internal/service/NetworkDataService.java | 20 +- 8 files changed, 1247 insertions(+), 364 deletions(-) create mode 100644 examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic2-checkpoint.ipynb create mode 100644 examples/python/basic/CytoscapeREST_Basic2.ipynb diff --git a/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic1-checkpoint.ipynb b/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic1-checkpoint.ipynb index c1429761..08ba5660 100644 --- a/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic1-checkpoint.ipynb +++ b/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic1-checkpoint.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:547a7fc519ef97dbedfd1d1a0f31dda26a0310e09a4939a9a5ac0fd2aae81cbc" + "signature": "sha256:79927e152aec45b69cb333af932e30be6a830241a9ecb6e8328f4d7975a63556" }, "nbformat": 3, "nbformat_minor": 0, @@ -12,18 +12,37 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Basic Workflow Part 1: Fundamentals of Cytoscape RESTful API\n", + "# Basic Workflow 1: Fundamentals of Cytoscape RESTful API\n", + "\n", + "\n", + "by [Keiichiro Ono](http://keiono.github.io/)\n", + "\n", + "\n", + "----\n", + "\n", + "![](http://cytoscape.org/images/logo/cy3logoOrange.svg)\n", + "\n", + "\n", + "![](http://ipython.org/_static/IPy_header.png)\n", + "\n", "\n", "## Introduction\n", - "This is a basic workflow how to access Cytoscape via RESTful API.\n", + "This is an introduction to Cytoscape via RESTful API. You will learn how to access Cytoscape via RESTful API.\n", + "\n", + "### Prerequisites\n", + "* Basic knowledge of RESTful API\n", + " * [This is a good introduction to REST](http://www.restapitutorial.com/)\n", + "* Basic Python skill\n", + "* Basic knowledge of Cytoscape \n", "\n", - "## System Requirments\n", - "* Java 7+\n", - "* Cytoscape 3.1.1 or later\n", - "* Latest version of cy-rest app\n", + "### System Requirments\n", + "* [Java 7+](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)\n", + "* [Cytoscape 3.1.1 or later](http://cytoscape.org/download.html)\n", + "* Latest version of [cy-rest app](https://github.com/keiono/cy-rest/releases/latest)\n", "\n", - "## Questions?\n", - "Send them to our [mailing list]()." + "----\n", + "## Questions or Feature Requests?\n", + "Please send them to our [mailing list](https://groups.google.com/forum/#!forum/cytoscape-discuss)" ] }, { @@ -32,56 +51,127 @@ "source": [ "## 1. Import Python Libraries and Basic Setup\n", "\n", - "### Dependent Libraries\n", - "In this tutorial, we use several popular Python libraries to make this workflow more realistic. Since you need to access Cytoscape via RESTful API, HTTP client library is very important tool. In this example, we use [Requests](http://docs.python-requests.org/en/latest/) library.\n", + "### Libraries\n", + "In this tutorial, we will use several popular Python libraries to make this workflow more realistic.\n", "\n", - "Other libraries:\n", + "#### HTTP Client\n", + "Since you need to access Cytoscape via RESTful API, HTTP client library is the most important tool you need to understand. In this example, we use [Requests](http://docs.python-requests.org/en/latest/) library to simplify API call code.\n", "\n", - "* json - for JSON processing\n", - "* NetworkX - network generation and analysis\n", - "* pandas - very powerful data analysis framework for Python\n", + "#### JSON Encoding and Decoding\n", + "Data will be exchanged as JSON between Cytoscape and Python code. Python has built-in support for JSON and we will use [it](https://docs.python.org/2/library/json.html) in this workflow.\n", "\n", "### Basic Setup for the API\n", - "At this point, there is only one option for the cy-rest module: port number. By default, port number used by cy-rest module is __1234__. To change this, you need set a global Cytoscape property from _Edit-->Preserences-->Properties..._ and add a new property __port.number__." + "At this point, there is only one option for the cy-rest module: port number.\n", + "\n", + "#### URL to Access Cytoscape REST API\n", + "We assume you are running Cytoscape desktop application and IPython Notebook server on a same machine. To access Cytoscape REST API, use the following URL:\n", + "\n", + "```\n", + "http://localhost:PORT_NUMBER/v1/\n", + "```\n", + "\n", + "where __v1__ is the current version number of API. Once the final release is ready, we guarantee compatibility of your scripts as long as major version number is the same.\n", + "\n", + "##### Note\n", + "Of course, you can run Cytoscape and IPython server on different machines. In that case, you need to change the URL to the machine running Cytoscape desktop. Also, you need to open the port.\n", + "\n", + "#### Change Port Number\n", + "By default, port number used by cy-rest module is __1234__. To change this, you need set a global Cytoscape property from _Edit-->Preserences-->Properties..._ and add a new property __port.number__." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Import libraries\n", "import requests\n", "import json\n", - "import networkx as nx\n", - "import pandas as pd\n", "\n", "# Basic Setup\n", - "PORT_NUMBER = 8080\n", + "PORT_NUMBER = 1234\n", "BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'\n", "\n", - "# Header for posting data to the server\n", + "# Header for posting data to the server as JSON\n", "HEADERS = {'Content-Type': 'application/json'}" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 31 + "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Test Cytoscape REST API\n", - "First, run a simple REST call and make sure cy-rest module is running." + "\n", + "### Understand REST Basics\n", + "\n", + "| HTTP Verb | Description |\n", + "|:----------:|:------------|\n", + "| GET | Retrieving resources (in most cases, it is Cytoscape data objects, such as networks or tables) |\n", + "| POST | Creating resources | \n", + "| PUT | Changing/replacing resources or collections |\n", + "| DELETE | Deleting resources |\n", + "\n", + "----\n", + "\n", + "### Check the status of server\n", + "First, send a simple request and check the server status." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Get server status\n", + "res = requests.get(BASE)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Roundtrip between JSON and Python Object\n", + "Now, __res__ object contains return value of API as JSON. Let's convert it into Python object:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "status_object = json.loads(res.content);\n", + "server_name = status_object['server']\n", + "print('Your server is ' + server_name)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Your server is Cytoscape RESTful API version 1.0.0\n" + ] + } + ], + "prompt_number": 13 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can convert it again into human-readable text:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Get version number of Cytoscape and REST API version\n", - "response1 = requests.get(BASE + 'version')\n", - "print(response1.content)" + "print(json.dumps(status_object, indent=4))" ], "language": "python", "metadata": {}, @@ -90,45 +180,79 @@ "output_type": "stream", "stream": "stdout", "text": [ - "{ \"apiVersion\":\"1.0.0\",\"cytoscapeVersion\": \"3.1.1\"}\n" + "{\n", + " \"karaf.version\": \"2.2.11\", \n", + " \"freeMemoryMB\": 415, \n", + " \"processors\": 8, \n", + " \"usedMemoryMB\": 252, \n", + " \"os.version\": \"10.9.4\", \n", + " \"totalMemoryMB\": 668, \n", + " \"java.version\": \"1.7.0_67\", \n", + " \"server\": \"Cytoscape RESTful API version 1.0.0\", \n", + " \"os.name\": \"Mac OS X\", \n", + " \"maxMemoryMB\": 28217\n", + "}\n" ] } ], - "prompt_number": 32 + "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "If the method call above works fine, you are ready to go!\n", + "If you are comfortable with this data type conversion, you are ready to go!\n", + "\n", + "----\n", "\n", "## 3. Import Networks from various data sources\n", - "There are several ways to load networks into Cytoscape:\n", + "There are many ways to load networks into Cytoscape from REST API:\n", + "\n", + "* Load from files\n", + "* Load from web services\n", + "* Send Cytoscape.js style JSON directly to Cytoscape\n", + "* Send edgelist\n", + "\n", + "### 3.1 Create networks from local files and URLs\n", + "\n", + "Let's start from a simple file loading examples. The __POST__ method is used to create new Cytoscape objects. For example,\n", + "\n", + "```\n", + "POST http://localhost:1234/v1/networks\n", + "```\n", "\n", - "* From files\n", - "* From web services\n", - "* From Cytoscape style json\n", - "* From edge list" + "means create new network(s) by specified method. If you want to create networks from files on your machine or remote servers, all you need to do is create a list of file locations and post it to Cytoscape." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Delete all existing networks\n", - "requests.delete(BASE + 'networks')\n", + "# Small utility function to create networks from list of URLs\n", + "def create_from_list(network_list):\n", + " server_res = requests.post(BASE + 'networks?source=url', data=json.dumps(network_list), headers=HEADERS)\n", + " return json.loads(server_res.content)\n", + "\n", + "\n", + "\n", + "# This is not necessary if you directly specify absolute file path like \"/Users/foo/bar/sample_data/yeast_network.json\"\n", + "import os\n", + "filepath = os.path.abspath('sample_data/yeast_network.json')\n", "\n", "# Array of data source. \n", "network_files = [\n", + " # Local file in this example data directory\n", + " 'file://' + filepath,\n", + "\n", " # SIF file on a web server\n", - " 'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif',\n", - " # PSICQUIC web service query\n", - " 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/interactor/brca1_human?format=xml25'\n", + " 'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif'\n", + " \n", + " # And of course, you can add as many files as you need...\n", "]\n", "\n", - "response2 = requests.post(BASE + 'networks?source=url', data=json.dumps(network_files), headers=HEADERS)\n", - "new_networks = json.loads(response2.content)\n", - "print(json.dumps(new_networks, indent=2))" + "\n", + "# Create!\n", + "print(json.dumps(create_from_list(network_files), indent=4))" ], "language": "python", "metadata": {}, @@ -138,213 +262,245 @@ "stream": "stdout", "text": [ "[\n", - " {\n", - " \"source\": \"http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/interactor/brca1_human?format=xml25\", \n", - " \"networkSUID\": [\n", - " 74052\n", - " ]\n", - " }, \n", - " {\n", - " \"source\": \"http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif\", \n", - " \"networkSUID\": [\n", - " 72638\n", - " ]\n", - " }\n", + " {\n", + " \"source\": \"file:///Users/kono/prog/git/cy-rest/examples/python/basic/sample_data/yeast_network.json\", \n", + " \"networkSUID\": [\n", + " 21630\n", + " ]\n", + " }, \n", + " {\n", + " \"source\": \"http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif\", \n", + " \"networkSUID\": [\n", + " 22754\n", + " ]\n", + " }\n", "]\n" ] } ], - "prompt_number": 58 + "prompt_number": 25 }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "# From Cytoscape.js JSON\n", - "\n", - "# This is the basic structure of network JSON object:\n", - "small_network = {\n", - " 'data': {\n", - " 'name': 'manually generated empty network'\n", - " },\n", - " 'elements': {\n", - " 'nodes':[],\n", - " 'edges':[]\n", - " }\n", - "}\n", - "\n", - "response3 = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(small_network), headers=HEADERS)\n", - "\n", - "# From edgelist\n", - "edge_list = '1 2\\n' + '2 3\\n' + '1 3'\n", - "response3 = requests.post(BASE + 'networks?format=edgelist', data=edge_list, headers=HEADERS)" - ], - "language": "python", + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "prompt_number": 57 + "source": [ + "### 3.2 Create networks from public RESTful web services\n", + "There are many public network data services. If the service supports Cytoscape-readable file formats, you can specify the query URL as a network location. For example, the following URL calls [PSICQUIC](https://code.google.com/p/psicquic/) web service and returns the search result in PSIMI 2.5 XML format. Since Cytoscape supports PSIMI2.5 files by default, this automatically creates a network from the response from the web service. " + ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Get the node table as JSON\n", - "\n", - "# Or CSV\n", - "\n", - "# Convert it as DataFrame" + "# This may take a while because Cytoscape fetch the data from a server in UK...\n", + "queries = [ 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25' ]\n", + "print(json.dumps(create_from_list(queries), indent=4))" ], "language": "python", "metadata": {}, - "outputs": [] + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[\n", + " {\n", + " \"source\": \"http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25\", \n", + " \"networkSUID\": [\n", + " 24168\n", + " ]\n", + " }\n", + "]\n" + ] + } + ], + "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Import & Generate Data in Python\n", - "\n", - "### Generate scale-free graphs with NetworkX" + "And of course, you can mix local files, URLs, and list of web service queries in a same list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "graphs = []\n", - "\n", - "# Create 20 small randome networks\n", - "for i in range(20):\n", - " # Generate scale-free graph\n", - " g = nx.scale_free_graph(50);\n", - " \n", - " # Perform simple graph analysis\n", - " \n", - " # Node statistics\n", - " bc = nx.betweenness_centrality(g)\n", - " degree = nx.degree(g)\n", - " cc = nx.closeness_centrality(g)\n", - " nx.set_node_attributes(g, 'betweenness', bc)\n", - " nx.set_node_attributes(g, 'closeness', cc)\n", - " nx.set_node_attributes(g, 'degree', degree)\n", - " \n", - " # Network statistics\n", - " g.graph[\"avg_shortest_path_len\"] = nx.average_shortest_path_length(g)\n", - " g.graph[\"density\"] = nx.density(g)\n", - " graphs.append(g)" + "mixed = [\n", + " 'file://' + filepath,\n", + " 'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif',\n", + " 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca2?format=xml25'\n", + "]\n", + "print(json.dumps(create_from_list(mixed), indent=4))" ], "language": "python", "metadata": {}, - "outputs": [], - "prompt_number": 50 + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[\n", + " {\n", + " \"source\": \"file:///Users/kono/prog/git/cy-rest/examples/python/basic/sample_data/yeast_network.json\", \n", + " \"networkSUID\": [\n", + " 30778\n", + " ]\n", + " }, \n", + " {\n", + " \"source\": \"http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif\", \n", + " \"networkSUID\": [\n", + " 31902\n", + " ]\n", + " }, \n", + " {\n", + " \"source\": \"http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca2?format=xml25\", \n", + " \"networkSUID\": [\n", + " 33316\n", + " ]\n", + " }\n", + "]\n" + ] + } + ], + "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Send all network models to Cytoscape" + "### 3.3 Create networks from Python objects\n", + "And this is the most powerful feature in Cytoscape REST API. __You can easily convert Python objects into Cytoscape networks, tables, or Visual Styles__\n", + "\n", + "#### How does this work?\n", + "Cytoscape REST API sends and receives data as JSON. For networks, it uses [Cytoscape.js style JSON](http://cytoscape.github.io/cytoscape.js/) (support for more file formats are comming!). You can programmatically generates networks by converting Python dictionary into JSON.\n", + "\n", + "#### 3.3.1 Prepare Network as Cytoscape.js JSON\n", + "Let's start with the simplest network JSON:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Remove all networks\n", + "# Start from a clean slate: remove all networks from current session\n", "requests.delete(BASE + 'networks')\n", "\n", - "import cytoscape.viewer as cy\n", + "# Manually generates JSON as dictionary\n", "\n", - "for graph in graphs:\n", - " cyjs_network = cy.from_networkx(graph)\n", - " res1 = requests.post(BASE + 'networks', data=json.dumps(cyjs_network), headers=HEADERS)" + "empty_network = {\n", + " 'data': {\n", + " 'name': 'I\\'m empty!'\n", + " },\n", + " 'elements': {\n", + " 'nodes':[],\n", + " 'edges':[]\n", + " }\n", + "}\n", + "\n", + "res3 = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(empty_network), headers=HEADERS)\n", + "res3_dict = json.loads(res3.content)\n", + "net_suid = res3_dict['networkSUID']\n", + "print('Empty network has SUID ' + str(net_suid))" ], "language": "python", "metadata": {}, - "outputs": [], - "prompt_number": 52 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## (Now graphs are in Cytoscape. Do analysis, visualization, etc...)" - ] + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Empty network has SUID 38868\n" + ] + } + ], + "prompt_number": 101 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Get the visualization back to this notebook." + "Since it's a simple Python dictionary, it is easy to add data to the network. Let's add some nodes and edges:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "response = requests.get(\"http://localhost:8080/v1/networks?format=SUID\")\n", - "network_list = json.loads(response.content)\n", - "print(network_list)\n", - "\n", - "network_views = []\n", - "for suid in network_list:\n", - " response2 = requests.get(\"http://localhost:8080/v1/networks/\" + str(suid) + \"/views/first\")\n", - " network_views.append(json.loads(response2.content))" + "import copy\n", + "\n", + "# Create a copy of the empty network object\n", + "small_network = copy.deepcopy(empty_network)\n", + "\n", + "# Sequence of letters (a-z)\n", + "seq_letters = list(map(chr, range(ord('a'), ord('z')+1)))\n", + "\n", + "# Build nodes and edges (in functional way)\n", + "build_node = lambda x: {'data': { 'id': x }}\n", + "abc_nodes = map(build_node, seq_letters)\n", + "\n", + "build_edge = lambda x: {'data': { 'source': x, 'target': 'a' }}\n", + "rand_edges = map(build_edge, seq_letters)\n", + "\n", + "small_network['elements']['nodes'] = abc_nodes\n", + "small_network['elements']['edges'] = rand_edges\n", + "small_network['data']['name'] = 'A is the hub.'\n", + "\n", + "# Uncomment this if you want to see the actual JSON object\n", + "# print(json.dumps(small_network, indent=4))\n", + "\n", + "res3 = requests.post(BASE + 'networks?collection=My%20Collection2', data=json.dumps(small_network), headers=HEADERS)\n", + "res3_dict = json.loads(res3.content)\n", + "new_suid = res3_dict['networkSUID']\n", + "\n", + "# Apply layout\n", + "requests.get(BASE + 'apply/layouts/force-directed/' + str(new_suid))" ], "language": "python", "metadata": {}, "outputs": [ { - "output_type": "stream", - "stream": "stdout", + "metadata": {}, + "output_type": "pyout", + "prompt_number": 59, "text": [ - "[67314, 68616, 68922, 67654, 68334, 72226, 66680, 69952, 71912, 69292, 67984, 71240, 65946, 70886, 66996, 69640, 66328, 70578, 71576, 70274]\n" + "" ] } ], - "prompt_number": 55 + "prompt_number": 59 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's simple, isn't it?\n", + "\n", + "#### 3.3.2 Prepare Network as edgelist\n", + "Edgelist is a minimalistic data format for networks and it is widely used in popular libraries including NetworkX and igraph. Preparing edgelist in Python is straightforward. You just need to prepare a list of edges as string like:\n", + "\n", + "```\n", + "a b\n", + "b c\n", + "a c\n", + "```\n", + "\n", + "In Python, there are many ways to generate string like this. Here is a naive approach:" + ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Visual Style can be a simple Python object!\n", - "\n", - "my_style = {\n", - " \"title\" : \"My Style 10\",\n", - " \"defaults\" : [ {\n", - " \"visualProperty\" : \"EDGE_WIDTH\",\n", - " \"value\" : 11.0\n", - " }, {\n", - " \"visualProperty\" : \"EDGE_STROKE_UNSELECTED_PAINT\",\n", - " \"value\" : \"#00ddff\"\n", - " }, {\n", - " \"visualProperty\" : \"NODE_WIDTH\",\n", - " \"value\" : 20\n", - " }, {\n", - " \"visualProperty\" : \"NODE_HEIGHT\",\n", - " \"value\" : 20\n", - " }],\n", - " \"mappings\" : [ {\n", - " \"mappingType\" : \"discrete\",\n", - " \"mappingColumn\" : \"degree\",\n", - " \"mappingColumnType\" : \"Integer\",\n", - " \"visualProperty\" : \"NODE_FILL_COLOR\",\n", - " \"map\" : [ {\n", - " \"key\" : \"1\",\n", - " \"value\" : \"#440055\"\n", - " }, {\n", - " \"key\" : \"4\",\n", - " \"value\" : \"#00FF11\"\n", - " } ]\n", - " }, {\n", - " \"mappingType\" : \"passthrough\",\n", - " \"mappingColumn\" : \"name\",\n", - " \"mappingColumnType\" : \"String\",\n", - " \"visualProperty\" : \"NODE_LABEL\"\n", - " } ]\n", - "}\n", + "numbers = range(1,101)\n", + "el_builder = lambda x: str(x) + '\\t' + str(1) if x is 100 else str(x) + '\\t' + str(x+1) + '\\n'\n", "\n", - "requests.post(\"http://localhost:8080/v1/styles\", data=json.dumps(my_style), headers=HEADERS)" + "res3 = requests.post(BASE + 'networks?format=edgelist&collection=Ring', data=reduce(lambda x, y: x + y, map(el_builder, numbers)), headers=HEADERS)\n", + "\n", + "res3_dict = json.loads(res3.content)\n", + "circle_suid = res3_dict['networkSUID']\n", + "requests.get(BASE + 'apply/layouts/circular/' + str(circle_suid))" ], "language": "python", "metadata": {}, @@ -352,13 +508,21 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 53, + "prompt_number": 112, "text": [ "" ] } ], - "prompt_number": 53 + "prompt_number": 112 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Discussion\n", + "In this section, we've learned how to generate networks programmatically from Python. But for real world problems, it is not a good idea to use low level Python objects to generate networks because there are lots of cool libraries such as NetworkX or igraph. In the next session, let's use those to analyze real network data and visualize them in Cytoscape." + ] } ], "metadata": {} diff --git a/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic2-checkpoint.ipynb b/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic2-checkpoint.ipynb new file mode 100644 index 00000000..ae163877 --- /dev/null +++ b/examples/python/basic/.ipynb_checkpoints/CytoscapeREST_Basic2-checkpoint.ipynb @@ -0,0 +1,234 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:d6a3efd7903943b5456e9a2eaee13132dae0cec1b7b0edb74c51396fa893f386" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Workflow 2: NetworkX and Cytoscape\n", + "\n", + "\n", + "by [Keiichiro Ono](http://keiono.github.io/)\n", + "\n", + "\n", + "----\n", + "\n", + "![](http://cytoscape.org/images/logo/cy3logoOrange.svg)\n", + "\n", + "\n", + "![](http://ipython.org/_static/IPy_header.png)\n", + "\n", + "\n", + "## Introduction\n", + "Welcome to the part 2 of basic tutorial. In this example, you will learn how to use Cytoscape with NetworkX, a very poweful network analysis toolkit.\n", + "\n", + "### Prerequisites\n", + "* Basic knowledge of RESTful API\n", + " * [This is a good introduction to REST](http://www.restapitutorial.com/)\n", + "* Basic Python skill\n", + "* Basic knowledge of Cytoscape \n", + "\n", + "### System Requirments\n", + "* [Java 7+](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)\n", + "* [Cytoscape 3.1.1 or later](http://cytoscape.org/download.html)\n", + "* Latest version of [cy-rest app](https://github.com/keiono/cy-rest/releases/latest)\n", + "\n", + "----\n", + "## Questions or Feature Requests?\n", + "Please send them to our [mailing list](https://groups.google.com/forum/#!forum/cytoscape-discuss)" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import requests\n", + "import json\n", + "import networkx as nx\n", + "\n", + "# Basic Setup\n", + "PORT_NUMBER = 1234\n", + "BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'\n", + "\n", + "# Header for posting data to the server as JSON\n", + "HEADERS = {'Content-Type': 'application/json'}" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate Networks with NetworkX\n", + "\n", + "### Generate scale-free networks" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "graphs = []\n", + "\n", + "# Create 10 small randome networks\n", + "for i in range(10):\n", + " # Generate scale-free graph\n", + " g = nx.scale_free_graph(50);\n", + " \n", + " # Perform simple graph analysis\n", + " \n", + " # Node statistics\n", + " bc = nx.betweenness_centrality(g)\n", + " degree = nx.degree(g)\n", + " cc = nx.closeness_centrality(g)\n", + " nx.set_node_attributes(g, 'betweenness', bc)\n", + " nx.set_node_attributes(g, 'closeness', cc)\n", + " nx.set_node_attributes(g, 'degree', degree)\n", + " \n", + " # Network statistics\n", + " g.graph[\"avg_shortest_path_len\"] = nx.average_shortest_path_length(g)\n", + " g.graph[\"density\"] = nx.density(g)\n", + " graphs.append(g)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Send all network models to Cytoscape" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Remove all networks\n", + "requests.delete(BASE + 'networks')\n", + "\n", + "import cytoscape.viewer as cy\n", + "\n", + "for graph in graphs:\n", + " cyjs_network = cy.from_networkx(graph)\n", + " res1 = requests.post(BASE + 'networks', data=json.dumps(cyjs_network), headers=HEADERS)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (Now graphs are in Cytoscape. Do analysis, visualization, etc...)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get the visualization back to this notebook." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "response = requests.get(BASE + 'networks?format=SUID')\n", + "network_list = json.loads(response.content)\n", + "print(network_list)\n", + "\n", + "network_views = []\n", + "for suid in network_list:\n", + " response2 = requests.get(BASE + 'networks/' + str(suid) + \"/views/first\")\n", + " network_views.append(json.loads(response2.content))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[64700, 66370, 66720, 64008, 66054, 64362, 65726, 65028, 67068, 65340]\n" + ] + } + ], + "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Visual Style can be a simple Python object!\n", + "\n", + "my_style = {\n", + " \"title\" : \"My Style 10\",\n", + " \"defaults\" : [ {\n", + " \"visualProperty\" : \"EDGE_WIDTH\",\n", + " \"value\" : 11.0\n", + " }, {\n", + " \"visualProperty\" : \"EDGE_STROKE_UNSELECTED_PAINT\",\n", + " \"value\" : \"#00ddff\"\n", + " }, {\n", + " \"visualProperty\" : \"NODE_WIDTH\",\n", + " \"value\" : 20\n", + " }, {\n", + " \"visualProperty\" : \"NODE_HEIGHT\",\n", + " \"value\" : 20\n", + " }],\n", + " \"mappings\" : [ {\n", + " \"mappingType\" : \"discrete\",\n", + " \"mappingColumn\" : \"degree\",\n", + " \"mappingColumnType\" : \"Integer\",\n", + " \"visualProperty\" : \"NODE_FILL_COLOR\",\n", + " \"map\" : [ {\n", + " \"key\" : \"1\",\n", + " \"value\" : \"#440055\"\n", + " }, {\n", + " \"key\" : \"4\",\n", + " \"value\" : \"#00FF11\"\n", + " } ]\n", + " }, {\n", + " \"mappingType\" : \"passthrough\",\n", + " \"mappingColumn\" : \"name\",\n", + " \"mappingColumnType\" : \"String\",\n", + " \"visualProperty\" : \"NODE_LABEL\"\n", + " } ]\n", + "}\n", + "\n", + "requests.post(BASE + \"styles\", data=json.dumps(my_style), headers=HEADERS)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 11, + "text": [ + "" + ] + } + ], + "prompt_number": 11 + } + ], + "metadata": {} + } + ] +} \ No newline at end of file diff --git a/examples/python/basic/CytoscapeREST_Basic1.ipynb b/examples/python/basic/CytoscapeREST_Basic1.ipynb index c1429761..9dc54a5b 100644 --- a/examples/python/basic/CytoscapeREST_Basic1.ipynb +++ b/examples/python/basic/CytoscapeREST_Basic1.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:547a7fc519ef97dbedfd1d1a0f31dda26a0310e09a4939a9a5ac0fd2aae81cbc" + "signature": "sha256:bf8b29b1a526abb9419d6a90693ed71f1ac6bc64e82ee50c9438b756d57c9a77" }, "nbformat": 3, "nbformat_minor": 0, @@ -12,18 +12,37 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Basic Workflow Part 1: Fundamentals of Cytoscape RESTful API\n", + "# Basic Workflow 1: Fundamentals of Cytoscape RESTful API\n", + "\n", + "\n", + "by [Keiichiro Ono](http://keiono.github.io/)\n", + "\n", + "\n", + "----\n", + "\n", + "![](http://cytoscape.org/images/logo/cy3logoOrange.svg)\n", + "\n", + "\n", + "![](http://ipython.org/_static/IPy_header.png)\n", + "\n", "\n", "## Introduction\n", - "This is a basic workflow how to access Cytoscape via RESTful API.\n", + "This is an introduction to Cytoscape via RESTful API. You will learn how to access Cytoscape via RESTful API.\n", + "\n", + "### Prerequisites\n", + "* Basic knowledge of RESTful API\n", + " * [This is a good introduction to REST](http://www.restapitutorial.com/)\n", + "* Basic Python skill\n", + "* Basic knowledge of Cytoscape \n", "\n", - "## System Requirments\n", - "* Java 7+\n", - "* Cytoscape 3.1.1 or later\n", - "* Latest version of cy-rest app\n", + "### System Requirments\n", + "* [Java 7+](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)\n", + "* [Cytoscape 3.1.1 or later](http://cytoscape.org/download.html)\n", + "* Latest version of [cy-rest app](https://github.com/keiono/cy-rest/releases/latest)\n", "\n", - "## Questions?\n", - "Send them to our [mailing list]()." + "----\n", + "## Questions or Feature Requests?\n", + "Please send them to our [mailing list](https://groups.google.com/forum/#!forum/cytoscape-discuss)" ] }, { @@ -32,56 +51,127 @@ "source": [ "## 1. Import Python Libraries and Basic Setup\n", "\n", - "### Dependent Libraries\n", - "In this tutorial, we use several popular Python libraries to make this workflow more realistic. Since you need to access Cytoscape via RESTful API, HTTP client library is very important tool. In this example, we use [Requests](http://docs.python-requests.org/en/latest/) library.\n", + "### Libraries\n", + "In this tutorial, we will use several popular Python libraries to make this workflow more realistic.\n", "\n", - "Other libraries:\n", + "#### HTTP Client\n", + "Since you need to access Cytoscape via RESTful API, HTTP client library is the most important tool you need to understand. In this example, we use [Requests](http://docs.python-requests.org/en/latest/) library to simplify API call code.\n", "\n", - "* json - for JSON processing\n", - "* NetworkX - network generation and analysis\n", - "* pandas - very powerful data analysis framework for Python\n", + "#### JSON Encoding and Decoding\n", + "Data will be exchanged as JSON between Cytoscape and Python code. Python has built-in support for JSON and we will use [it](https://docs.python.org/2/library/json.html) in this workflow.\n", "\n", "### Basic Setup for the API\n", - "At this point, there is only one option for the cy-rest module: port number. By default, port number used by cy-rest module is __1234__. To change this, you need set a global Cytoscape property from _Edit-->Preserences-->Properties..._ and add a new property __port.number__." + "At this point, there is only one option for the cy-rest module: port number.\n", + "\n", + "#### URL to Access Cytoscape REST API\n", + "We assume you are running Cytoscape desktop application and IPython Notebook server on a same machine. To access Cytoscape REST API, use the following URL:\n", + "\n", + "```\n", + "http://localhost:PORT_NUMBER/v1/\n", + "```\n", + "\n", + "where __v1__ is the current version number of API. Once the final release is ready, we guarantee compatibility of your scripts as long as major version number is the same.\n", + "\n", + "##### Note\n", + "Of course, you can run Cytoscape and IPython server on different machines. In that case, you need to change the URL to the machine running Cytoscape desktop. Also, you need to open the port.\n", + "\n", + "#### Change Port Number\n", + "By default, port number used by cy-rest module is __1234__. To change this, you need set a global Cytoscape property from _Edit-->Preserences-->Properties..._ and add a new property __port.number__." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Import libraries\n", "import requests\n", "import json\n", - "import networkx as nx\n", - "import pandas as pd\n", "\n", "# Basic Setup\n", - "PORT_NUMBER = 8080\n", + "PORT_NUMBER = 1234\n", "BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'\n", "\n", - "# Header for posting data to the server\n", + "# Header for posting data to the server as JSON\n", "HEADERS = {'Content-Type': 'application/json'}" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 31 + "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Test Cytoscape REST API\n", - "First, run a simple REST call and make sure cy-rest module is running." + "\n", + "### Understand REST Basics\n", + "\n", + "| HTTP Verb | Description |\n", + "|:----------:|:------------|\n", + "| GET | Retrieving resources (in most cases, it is Cytoscape data objects, such as networks or tables) |\n", + "| POST | Creating resources | \n", + "| PUT | Changing/replacing resources or collections |\n", + "| DELETE | Deleting resources |\n", + "\n", + "----\n", + "\n", + "### Check the status of server\n", + "First, send a simple request and check the server status." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Get server status\n", + "res = requests.get(BASE)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Roundtrip between JSON and Python Object\n", + "Now, __res__ object contains return value of API as JSON. Let's convert it into Python object:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "status_object = json.loads(res.content);\n", + "server_name = status_object['server']\n", + "print('Your server is ' + server_name)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Your server is Cytoscape RESTful API version 1.0.0\n" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can convert it again into human-readable text:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Get version number of Cytoscape and REST API version\n", - "response1 = requests.get(BASE + 'version')\n", - "print(response1.content)" + "print(json.dumps(status_object, indent=4))" ], "language": "python", "metadata": {}, @@ -90,45 +180,79 @@ "output_type": "stream", "stream": "stdout", "text": [ - "{ \"apiVersion\":\"1.0.0\",\"cytoscapeVersion\": \"3.1.1\"}\n" + "{\n", + " \"karaf.version\": \"2.2.11\", \n", + " \"freeMemoryMB\": 122, \n", + " \"processors\": 8, \n", + " \"usedMemoryMB\": 147, \n", + " \"os.version\": \"10.9.4\", \n", + " \"totalMemoryMB\": 270, \n", + " \"java.version\": \"1.7.0_67\", \n", + " \"server\": \"Cytoscape RESTful API version 1.0.0\", \n", + " \"os.name\": \"Mac OS X\", \n", + " \"maxMemoryMB\": 28217\n", + "}\n" ] } ], - "prompt_number": 32 + "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "If the method call above works fine, you are ready to go!\n", + "If you are comfortable with this data type conversion, you are ready to go!\n", + "\n", + "----\n", "\n", "## 3. Import Networks from various data sources\n", - "There are several ways to load networks into Cytoscape:\n", + "There are many ways to load networks into Cytoscape from REST API:\n", + "\n", + "* Load from files\n", + "* Load from web services\n", + "* Send Cytoscape.js style JSON directly to Cytoscape\n", + "* Send edgelist\n", + "\n", + "### 3.1 Create networks from local files and URLs\n", + "\n", + "Let's start from a simple file loading examples. The __POST__ method is used to create new Cytoscape objects. For example,\n", + "\n", + "```\n", + "POST http://localhost:1234/v1/networks\n", + "```\n", "\n", - "* From files\n", - "* From web services\n", - "* From Cytoscape style json\n", - "* From edge list" + "means create new network(s) by specified method. If you want to create networks from files on your machine or remote servers, all you need to do is create a list of file locations and post it to Cytoscape." ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Delete all existing networks\n", - "requests.delete(BASE + 'networks')\n", + "# Small utility function to create networks from list of URLs\n", + "def create_from_list(network_list):\n", + " server_res = requests.post(BASE + 'networks?source=url', data=json.dumps(network_list), headers=HEADERS)\n", + " return json.loads(server_res.content)\n", + "\n", + "\n", + "\n", + "# This is not necessary if you directly specify absolute file path like \"/Users/foo/bar/sample_data/yeast_network.json\"\n", + "import os\n", + "filepath = os.path.abspath('sample_data/yeast_network.json')\n", "\n", "# Array of data source. \n", "network_files = [\n", + " # Local file in this example data directory\n", + " 'file://' + filepath,\n", + "\n", " # SIF file on a web server\n", - " 'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif',\n", - " # PSICQUIC web service query\n", - " 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/interactor/brca1_human?format=xml25'\n", + " 'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif'\n", + " \n", + " # And of course, you can add as many files as you need...\n", "]\n", "\n", - "response2 = requests.post(BASE + 'networks?source=url', data=json.dumps(network_files), headers=HEADERS)\n", - "new_networks = json.loads(response2.content)\n", - "print(json.dumps(new_networks, indent=2))" + "\n", + "# Create!\n", + "print(json.dumps(create_from_list(network_files), indent=4))" ], "language": "python", "metadata": {}, @@ -138,213 +262,245 @@ "stream": "stdout", "text": [ "[\n", - " {\n", - " \"source\": \"http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/interactor/brca1_human?format=xml25\", \n", - " \"networkSUID\": [\n", - " 74052\n", - " ]\n", - " }, \n", - " {\n", - " \"source\": \"http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif\", \n", - " \"networkSUID\": [\n", - " 72638\n", - " ]\n", - " }\n", + " {\n", + " \"source\": \"file:///Users/kono/prog/git/cy-rest/examples/python/basic/sample_data/yeast_network.json\", \n", + " \"networkSUID\": [\n", + " 42752\n", + " ]\n", + " }, \n", + " {\n", + " \"source\": \"http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif\", \n", + " \"networkSUID\": [\n", + " 43876\n", + " ]\n", + " }\n", "]\n" ] } ], - "prompt_number": 58 + "prompt_number": 5 }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "# From Cytoscape.js JSON\n", - "\n", - "# This is the basic structure of network JSON object:\n", - "small_network = {\n", - " 'data': {\n", - " 'name': 'manually generated empty network'\n", - " },\n", - " 'elements': {\n", - " 'nodes':[],\n", - " 'edges':[]\n", - " }\n", - "}\n", - "\n", - "response3 = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(small_network), headers=HEADERS)\n", - "\n", - "# From edgelist\n", - "edge_list = '1 2\\n' + '2 3\\n' + '1 3'\n", - "response3 = requests.post(BASE + 'networks?format=edgelist', data=edge_list, headers=HEADERS)" - ], - "language": "python", + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "prompt_number": 57 + "source": [ + "### 3.2 Create networks from public RESTful web services\n", + "There are many public network data services. If the service supports Cytoscape-readable file formats, you can specify the query URL as a network location. For example, the following URL calls [PSICQUIC](https://code.google.com/p/psicquic/) web service and returns the search result in PSIMI 2.5 XML format. Since Cytoscape supports PSIMI2.5 files by default, this automatically creates a network from the response from the web service. " + ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Get the node table as JSON\n", - "\n", - "# Or CSV\n", - "\n", - "# Convert it as DataFrame" + "# This may take a while because Cytoscape fetch the data from a server in UK...\n", + "queries = [ 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25' ]\n", + "print(json.dumps(create_from_list(queries), indent=4))" ], "language": "python", "metadata": {}, - "outputs": [] + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[\n", + " {\n", + " \"source\": \"http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25\", \n", + " \"networkSUID\": [\n", + " 45290\n", + " ]\n", + " }\n", + "]\n" + ] + } + ], + "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Import & Generate Data in Python\n", - "\n", - "### Generate scale-free graphs with NetworkX" + "And of course, you can mix local files, URLs, and list of web service queries in a same list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "graphs = []\n", - "\n", - "# Create 20 small randome networks\n", - "for i in range(20):\n", - " # Generate scale-free graph\n", - " g = nx.scale_free_graph(50);\n", - " \n", - " # Perform simple graph analysis\n", - " \n", - " # Node statistics\n", - " bc = nx.betweenness_centrality(g)\n", - " degree = nx.degree(g)\n", - " cc = nx.closeness_centrality(g)\n", - " nx.set_node_attributes(g, 'betweenness', bc)\n", - " nx.set_node_attributes(g, 'closeness', cc)\n", - " nx.set_node_attributes(g, 'degree', degree)\n", - " \n", - " # Network statistics\n", - " g.graph[\"avg_shortest_path_len\"] = nx.average_shortest_path_length(g)\n", - " g.graph[\"density\"] = nx.density(g)\n", - " graphs.append(g)" + "mixed = [\n", + " 'file://' + filepath,\n", + " 'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif',\n", + " 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca2?format=xml25'\n", + "]\n", + "print(json.dumps(create_from_list(mixed), indent=4))" ], "language": "python", "metadata": {}, - "outputs": [], - "prompt_number": 50 + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[\n", + " {\n", + " \"source\": \"file:///Users/kono/prog/git/cy-rest/examples/python/basic/sample_data/yeast_network.json\", \n", + " \"networkSUID\": [\n", + " 46824\n", + " ]\n", + " }, \n", + " {\n", + " \"source\": \"http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif\", \n", + " \"networkSUID\": [\n", + " 47948\n", + " ]\n", + " }, \n", + " {\n", + " \"source\": \"http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca2?format=xml25\", \n", + " \"networkSUID\": [\n", + " 49362\n", + " ]\n", + " }\n", + "]\n" + ] + } + ], + "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Send all network models to Cytoscape" + "### 3.3 Create networks from Python objects\n", + "And this is the most powerful feature in Cytoscape REST API. __You can easily convert Python objects into Cytoscape networks, tables, or Visual Styles__\n", + "\n", + "#### How does this work?\n", + "Cytoscape REST API sends and receives data as JSON. For networks, it uses [Cytoscape.js style JSON](http://cytoscape.github.io/cytoscape.js/) (support for more file formats are comming!). You can programmatically generates networks by converting Python dictionary into JSON.\n", + "\n", + "#### 3.3.1 Prepare Network as Cytoscape.js JSON\n", + "Let's start with the simplest network JSON:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Remove all networks\n", + "# Start from a clean slate: remove all networks from current session\n", "requests.delete(BASE + 'networks')\n", "\n", - "import cytoscape.viewer as cy\n", + "# Manually generates JSON as dictionary\n", "\n", - "for graph in graphs:\n", - " cyjs_network = cy.from_networkx(graph)\n", - " res1 = requests.post(BASE + 'networks', data=json.dumps(cyjs_network), headers=HEADERS)" + "empty_network = {\n", + " 'data': {\n", + " 'name': 'I\\'m empty!'\n", + " },\n", + " 'elements': {\n", + " 'nodes':[],\n", + " 'edges':[]\n", + " }\n", + "}\n", + "\n", + "res3 = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(empty_network), headers=HEADERS)\n", + "res3_dict = json.loads(res3.content)\n", + "net_suid = res3_dict['networkSUID']\n", + "print('Empty network has SUID ' + str(net_suid))" ], "language": "python", "metadata": {}, - "outputs": [], - "prompt_number": 52 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## (Now graphs are in Cytoscape. Do analysis, visualization, etc...)" - ] + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Empty network has SUID 49936\n" + ] + } + ], + "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Get the visualization back to this notebook." + "Since it's a simple Python dictionary, it is easy to add data to the network. Let's add some nodes and edges:" ] }, { "cell_type": "code", "collapsed": false, "input": [ - "response = requests.get(\"http://localhost:8080/v1/networks?format=SUID\")\n", - "network_list = json.loads(response.content)\n", - "print(network_list)\n", - "\n", - "network_views = []\n", - "for suid in network_list:\n", - " response2 = requests.get(\"http://localhost:8080/v1/networks/\" + str(suid) + \"/views/first\")\n", - " network_views.append(json.loads(response2.content))" + "import copy\n", + "\n", + "# Create a copy of the empty network object\n", + "small_network = copy.deepcopy(empty_network)\n", + "\n", + "# Sequence of letters (a-z)\n", + "seq_letters = list(map(chr, range(ord('a'), ord('z')+1)))\n", + "\n", + "# Build nodes and edges (in functional way)\n", + "build_node = lambda x: {'data': { 'id': x }}\n", + "abc_nodes = map(build_node, seq_letters)\n", + "\n", + "build_edge = lambda x: {'data': { 'source': x, 'target': 'a' }}\n", + "rand_edges = map(build_edge, seq_letters)\n", + "\n", + "small_network['elements']['nodes'] = abc_nodes\n", + "small_network['elements']['edges'] = rand_edges\n", + "small_network['data']['name'] = 'A is the hub.'\n", + "\n", + "# Uncomment this if you want to see the actual JSON object\n", + "# print(json.dumps(small_network, indent=4))\n", + "\n", + "res3 = requests.post(BASE + 'networks?collection=My%20Collection2', data=json.dumps(small_network), headers=HEADERS)\n", + "res3_dict = json.loads(res3.content)\n", + "new_suid = res3_dict['networkSUID']\n", + "\n", + "# Apply layout\n", + "requests.get(BASE + 'apply/layouts/force-directed/' + str(new_suid))" ], "language": "python", "metadata": {}, "outputs": [ { - "output_type": "stream", - "stream": "stdout", + "metadata": {}, + "output_type": "pyout", + "prompt_number": 9, "text": [ - "[67314, 68616, 68922, 67654, 68334, 72226, 66680, 69952, 71912, 69292, 67984, 71240, 65946, 70886, 66996, 69640, 66328, 70578, 71576, 70274]\n" + "" ] } ], - "prompt_number": 55 + "prompt_number": 9 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's simple, isn't it?\n", + "\n", + "#### 3.3.2 Prepare Network as edgelist\n", + "Edgelist is a minimalistic data format for networks and it is widely used in popular libraries including NetworkX and igraph. Preparing edgelist in Python is straightforward. You just need to prepare a list of edges as string like:\n", + "\n", + "```\n", + "a b\n", + "b c\n", + "a c\n", + "```\n", + "\n", + "In Python, there are many ways to generate string like this. Here is a naive approach:" + ] }, { "cell_type": "code", "collapsed": false, "input": [ - "# Visual Style can be a simple Python object!\n", - "\n", - "my_style = {\n", - " \"title\" : \"My Style 10\",\n", - " \"defaults\" : [ {\n", - " \"visualProperty\" : \"EDGE_WIDTH\",\n", - " \"value\" : 11.0\n", - " }, {\n", - " \"visualProperty\" : \"EDGE_STROKE_UNSELECTED_PAINT\",\n", - " \"value\" : \"#00ddff\"\n", - " }, {\n", - " \"visualProperty\" : \"NODE_WIDTH\",\n", - " \"value\" : 20\n", - " }, {\n", - " \"visualProperty\" : \"NODE_HEIGHT\",\n", - " \"value\" : 20\n", - " }],\n", - " \"mappings\" : [ {\n", - " \"mappingType\" : \"discrete\",\n", - " \"mappingColumn\" : \"degree\",\n", - " \"mappingColumnType\" : \"Integer\",\n", - " \"visualProperty\" : \"NODE_FILL_COLOR\",\n", - " \"map\" : [ {\n", - " \"key\" : \"1\",\n", - " \"value\" : \"#440055\"\n", - " }, {\n", - " \"key\" : \"4\",\n", - " \"value\" : \"#00FF11\"\n", - " } ]\n", - " }, {\n", - " \"mappingType\" : \"passthrough\",\n", - " \"mappingColumn\" : \"name\",\n", - " \"mappingColumnType\" : \"String\",\n", - " \"visualProperty\" : \"NODE_LABEL\"\n", - " } ]\n", - "}\n", + "numbers = range(1,101)\n", + "el_builder = lambda x: str(x) + '\\t' + str(1) if x is 100 else str(x) + '\\t' + str(x+1) + '\\n'\n", "\n", - "requests.post(\"http://localhost:8080/v1/styles\", data=json.dumps(my_style), headers=HEADERS)" + "res3 = requests.post(BASE + 'networks?format=edgelist&collection=Ring', data=reduce(lambda x, y: x + y, map(el_builder, numbers)), headers=HEADERS)\n", + "\n", + "res3_dict = json.loads(res3.content)\n", + "circle_suid = res3_dict['networkSUID']\n", + "requests.get(BASE + 'apply/layouts/circular/' + str(circle_suid))" ], "language": "python", "metadata": {}, @@ -352,13 +508,21 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 53, + "prompt_number": 10, "text": [ "" ] } ], - "prompt_number": 53 + "prompt_number": 10 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Discussion\n", + "In this section, we've learned how to generate networks programmatically from Python. But for real world problems, it is not a good idea to use low level Python objects to generate networks because there are lots of cool libraries such as NetworkX or igraph. In the next session, let's use those to analyze real network data and visualize them in Cytoscape." + ] } ], "metadata": {} diff --git a/examples/python/basic/CytoscapeREST_Basic2.ipynb b/examples/python/basic/CytoscapeREST_Basic2.ipynb new file mode 100644 index 00000000..ae163877 --- /dev/null +++ b/examples/python/basic/CytoscapeREST_Basic2.ipynb @@ -0,0 +1,234 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:d6a3efd7903943b5456e9a2eaee13132dae0cec1b7b0edb74c51396fa893f386" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Workflow 2: NetworkX and Cytoscape\n", + "\n", + "\n", + "by [Keiichiro Ono](http://keiono.github.io/)\n", + "\n", + "\n", + "----\n", + "\n", + "![](http://cytoscape.org/images/logo/cy3logoOrange.svg)\n", + "\n", + "\n", + "![](http://ipython.org/_static/IPy_header.png)\n", + "\n", + "\n", + "## Introduction\n", + "Welcome to the part 2 of basic tutorial. In this example, you will learn how to use Cytoscape with NetworkX, a very poweful network analysis toolkit.\n", + "\n", + "### Prerequisites\n", + "* Basic knowledge of RESTful API\n", + " * [This is a good introduction to REST](http://www.restapitutorial.com/)\n", + "* Basic Python skill\n", + "* Basic knowledge of Cytoscape \n", + "\n", + "### System Requirments\n", + "* [Java 7+](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)\n", + "* [Cytoscape 3.1.1 or later](http://cytoscape.org/download.html)\n", + "* Latest version of [cy-rest app](https://github.com/keiono/cy-rest/releases/latest)\n", + "\n", + "----\n", + "## Questions or Feature Requests?\n", + "Please send them to our [mailing list](https://groups.google.com/forum/#!forum/cytoscape-discuss)" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import requests\n", + "import json\n", + "import networkx as nx\n", + "\n", + "# Basic Setup\n", + "PORT_NUMBER = 1234\n", + "BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'\n", + "\n", + "# Header for posting data to the server as JSON\n", + "HEADERS = {'Content-Type': 'application/json'}" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate Networks with NetworkX\n", + "\n", + "### Generate scale-free networks" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "graphs = []\n", + "\n", + "# Create 10 small randome networks\n", + "for i in range(10):\n", + " # Generate scale-free graph\n", + " g = nx.scale_free_graph(50);\n", + " \n", + " # Perform simple graph analysis\n", + " \n", + " # Node statistics\n", + " bc = nx.betweenness_centrality(g)\n", + " degree = nx.degree(g)\n", + " cc = nx.closeness_centrality(g)\n", + " nx.set_node_attributes(g, 'betweenness', bc)\n", + " nx.set_node_attributes(g, 'closeness', cc)\n", + " nx.set_node_attributes(g, 'degree', degree)\n", + " \n", + " # Network statistics\n", + " g.graph[\"avg_shortest_path_len\"] = nx.average_shortest_path_length(g)\n", + " g.graph[\"density\"] = nx.density(g)\n", + " graphs.append(g)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Send all network models to Cytoscape" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Remove all networks\n", + "requests.delete(BASE + 'networks')\n", + "\n", + "import cytoscape.viewer as cy\n", + "\n", + "for graph in graphs:\n", + " cyjs_network = cy.from_networkx(graph)\n", + " res1 = requests.post(BASE + 'networks', data=json.dumps(cyjs_network), headers=HEADERS)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (Now graphs are in Cytoscape. Do analysis, visualization, etc...)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get the visualization back to this notebook." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "response = requests.get(BASE + 'networks?format=SUID')\n", + "network_list = json.loads(response.content)\n", + "print(network_list)\n", + "\n", + "network_views = []\n", + "for suid in network_list:\n", + " response2 = requests.get(BASE + 'networks/' + str(suid) + \"/views/first\")\n", + " network_views.append(json.loads(response2.content))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[64700, 66370, 66720, 64008, 66054, 64362, 65726, 65028, 67068, 65340]\n" + ] + } + ], + "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Visual Style can be a simple Python object!\n", + "\n", + "my_style = {\n", + " \"title\" : \"My Style 10\",\n", + " \"defaults\" : [ {\n", + " \"visualProperty\" : \"EDGE_WIDTH\",\n", + " \"value\" : 11.0\n", + " }, {\n", + " \"visualProperty\" : \"EDGE_STROKE_UNSELECTED_PAINT\",\n", + " \"value\" : \"#00ddff\"\n", + " }, {\n", + " \"visualProperty\" : \"NODE_WIDTH\",\n", + " \"value\" : 20\n", + " }, {\n", + " \"visualProperty\" : \"NODE_HEIGHT\",\n", + " \"value\" : 20\n", + " }],\n", + " \"mappings\" : [ {\n", + " \"mappingType\" : \"discrete\",\n", + " \"mappingColumn\" : \"degree\",\n", + " \"mappingColumnType\" : \"Integer\",\n", + " \"visualProperty\" : \"NODE_FILL_COLOR\",\n", + " \"map\" : [ {\n", + " \"key\" : \"1\",\n", + " \"value\" : \"#440055\"\n", + " }, {\n", + " \"key\" : \"4\",\n", + " \"value\" : \"#00FF11\"\n", + " } ]\n", + " }, {\n", + " \"mappingType\" : \"passthrough\",\n", + " \"mappingColumn\" : \"name\",\n", + " \"mappingColumnType\" : \"String\",\n", + " \"visualProperty\" : \"NODE_LABEL\"\n", + " } ]\n", + "}\n", + "\n", + "requests.post(BASE + \"styles\", data=json.dumps(my_style), headers=HEADERS)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 11, + "text": [ + "" + ] + } + ], + "prompt_number": 11 + } + ], + "metadata": {} + } + ] +} \ No newline at end of file diff --git a/examples/python/basic/cytoscape/__init__.pyc b/examples/python/basic/cytoscape/__init__.pyc index 2c634c5d5aeddebd2d13b2e276378c63cd83b837..5f79416292ffbaf1965fc169d7c9cd1dd1a72e21 100644 GIT binary patch delta 16 XcmdnXvX_OO`7}E^=EHeb^ delta 16 XcmdnXvX_OO`7$Evf|# diff --git a/examples/python/basic/cytoscape/viewer.pyc b/examples/python/basic/cytoscape/viewer.pyc index 95a6ea53de255b31c3c9f0173c69ed876f0941b4..a0e8994792bcec820839ef0e78629d043f4f318e 100644 GIT binary patch delta 16 XcmX@8bWn+%`7{fyRFbV}h delta 16 XcmX@8bWn+%`7 envVariables = System.getProperties(); + for(String key:PRESET_PROPS) + builder.append("\"" + key + "\":\"" + envVariables.get(key).toString() + "\","); + } + + + private final void appendMemoryStatus(final StringBuilder builder) { + final Runtime runtime = Runtime.getRuntime(); + final Long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / MB; + builder.append("\"usedMemoryMB\":" + usedMemory + ","); + final Long freeMemory = runtime.freeMemory() / MB; + builder.append("\"freeMemoryMB\":" + freeMemory + ","); + final Long totalMemory = runtime.totalMemory() / MB; + builder.append("\"totalMemoryMB\":" + totalMemory + ","); + final Long maxMemory = runtime.maxMemory() / MB; + builder.append("\"maxMemoryMB\":" + maxMemory); + } + + /** * Return the Cytoscape and API version. * @@ -24,16 +92,17 @@ public class MiscDataService extends AbstractDataService { @Path("/version") @Produces(MediaType.APPLICATION_JSON) public String getCytoscapeVersion() { - - if(props == null) { + + if (props == null) { throw new InternalServerErrorException("Could not find CyProperty object."); } final Properties property = (Properties) this.props.getProperties(); final Object versionNumber = property.get("cytoscape.version.number"); - if(versionNumber != null) { - - return "{ \"apiVersion\":\"" + API_VERSION + "\",\"cytoscapeVersion\": \"" + versionNumber.toString() + "\"}"; + if (versionNumber != null) { + + return "{ \"apiVersion\":\"" + API_VERSION + "\",\"cytoscapeVersion\": \"" + versionNumber.toString() + + "\"}"; } else { throw new NotFoundException("Could not find Cytoscape version number property."); } diff --git a/src/main/java/org/cytoscape/rest/internal/service/NetworkDataService.java b/src/main/java/org/cytoscape/rest/internal/service/NetworkDataService.java index 991ac2f8..c31fb320 100644 --- a/src/main/java/org/cytoscape/rest/internal/service/NetworkDataService.java +++ b/src/main/java/org/cytoscape/rest/internal/service/NetworkDataService.java @@ -631,9 +631,22 @@ public String createNetwork(@DefaultValue(DEF_COLLECTION_PREFIX) @QueryParam("co // Return SUID-to-Original map return getNumberObjectString("networkSUID", newNetwork.getSUID()); } + + /** + * Create a subnetwork from selected nodes & edges + * + * if body is empty, it simply creates new network from current selection. + * Otherwise, select from the list of SUID. + * + * @param networkId + * @param is + * @param headers + * @return + * @throws Exception + */ @POST - @Path("/{networkId}/fromSelected") + @Path("/{networkId}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public String createNetworkFromSelected(@PathParam("networkId") Long networkId, @@ -655,10 +668,15 @@ public String createNetworkFromSelected(@PathParam("networkId") Long networkId, } } catch (Exception e) { e.printStackTrace(); + throw new WebApplicationException("Could not create sub network from selection.", 500); } } is.close(); + + /** + * + */ if(viewTask != null) { final Collection result = ((ObservableTask)viewTask).getResults(Collection.class); if(result.size() == 1) {