PythonとRとVBAでCyREST API

Cytoscapeを自動化するためのCyREST API。
PythonとRとVBAの３種類で使う必要があったのでメモしときます。

#環境
**Windows7(32bit)**
**Cytoscape 3.6.1**
**Python 3.8.3**
　モジュールrequestsとjsonをインストールしておきます。
**R 3.5.2**
　パッケージhttrとjsonliteをインストールしておきます。
**VBA Access 2010**
　Jsonを使うため、[こちら](https://github.com/VBA-tools/VBA-JSON)からJsonConverter.basを拾ってきて、プロシージャに追加しておきます。
　文字コードはUTF8を使うので、[こちら](https://qiita.com/yamashiroakihito/items/9b609653fef6fa8a5ab2)のUTF8変換用コードもプロシージャのどこかにコピペします。
　参照設定で"Microsoft Scripting Runtime"と"Microsoft XML v6.0"を有効にしておきます。 

#CyREST APIのマニュアル
Cytoscapeを立ち上げてメニューの
　　`HELP > Automation > CyREST API または CyREST command API`
でマニュアルを参照できます。

#CyREST APIの動作確認
Cytoscapeが立ち上がっている状態でWebブラウザを開き、アドレス

```:Webブラウザ
http://localhost:1234/v1
```
を開いて

```
{"allAppsStarted":true,"apiVersion":"v1","numberOfCores":X,"memoryStatus":{"usedMemory":XXX,"freeMemory":XXXX,"totalMemory":XXXX,"maxMemory":XXXXX}}
```
のように表示されたら、CyREST APIが正常に起動していることが確認できます。

　以下は、Cytoscapeに何かネットワークが表示されているものとして説明します。


#Cytoscapeで開いている全てのネットワークIDを取得する
　まずは、CyRESTを使ってCytoscapeから情報を取得する一番簡単な方法を試します。
　マニュアル `HELP > Automation > CyREST API > Networks > GET:/v1/networks`
　URLリクエスト　`GET http://localhost:1234/v1/networks`
　戻り値は[ID,ID]の文字列です。これはWebブラウザでも確認できます。

1.Webブラウザ

```:Webブラウザ
http://localhost:1234/v1/networks
```
2.Python

```Python:Python
import json
import requests as req
HD = {'Content-Type':'application/json'}
ret = req.get('http://localhost:1234/v1/networks',headers=HD)
print(ret.json())
```
3.R

```R:R
require(httr)
require(jsonlite)
ret = GET('http://localhost:1234/v1/networks',encode="json")
content(ret)
```

4.VBA

```VB:VBA
Dim res As Object
Dim httpReq As New XMLHTTP60
Dim ret As String
With httpReq
  .Open "GET", "http://localhost:1234/v1/networks"
  .SetRequestHeader "Content-Type","application/json;charset=UTF-8"
  .send
  ret = FromUTF8(httpReq.responseBody)
  Debug.print("netID : " & ret)
End With
```

#現在表示しているネットワークのIDを取得する
　次は、CytoscapeからJson形式の情報を取得する方法を試してみます。
　マニュアル`HELP > Automation > CyREST API > Networks > GET:/v1/networks/currentNetwork`
　URLリクエスト`GET http://localhost:1234/v1/networks/currentNetwork`
　戻り値はJson形式です。これもWebブラウザで確認できます。

1.Webブラウザ

```:Webブラウザ
http://localhost:1234/v1/networks/currentNetwork
```
2.Python

```Python:Python
import json
import requests as req
HD = {'Content-Type':'application/json'}
ret = req.get('http://localhost:1234/v1/networks/currentNetwork',headers=HD)
print(ret.json()['data']['networkSUID'])
```
3.R

```R:R
require(httr)
require(jsonlite)
ret = GET('http://localhost:1234/v1/networks/currentNetwork',encode="json")
content(ret)$data
```

4.VBA

```VB:VBA
Dim res As Object
Dim httpReq As New XMLHTTP60
Dim retDic As Dictionary
Dim ret As String
With httpReq
  .Open "GET", "http://localhost:1234/v1/networks/currentNetwork"
  .SetRequestHeader "Content-Type","application/json;charset=UTF-8"
  .send
  set retDic = JsonConverter.ParseJson(FromUTF8(httpReq.responseBody))
  ret = retDic("data")("networkSUID")
  Debug.print("netID : " & ret)
End With
```

#ノードのIDとnameを取得する
　最後に、CyRESTにパラメータを渡してそれに対応する戻り値を取得する方法を試してみます。
　マニュアル`HELP > Automation > CyREST Command API > node > POST:/v1/commands/node/get attribute`
　URLリクエスト`POST http://localhost:1234/v1/networks/currentNetwork`
　Json形式のパラメータを渡して、戻り値もJson形式です。

1.Python

```Python:Python
import json
import requests as req
HD = {'Content-Type':'application/json'}
ret = req.post('http://localhost:1234/v1/commands/node/get attribute',
          json.dumps(
               {'columnList': 'SUID,name','network': 'current'}),
          headers=HD)
retDic = ret.json()['data']
print(retDic)
```
2.R

```R:R
require(httr)
require(jsonlite)
paraList <- list()
paraList <- c(paraList,list(columnList='SUID,name'))
paraList <- c(paraList,list(network='current'))
ret = POST('http://localhost:1234/v1/commands/node/get%20attribute',
            body=paraList,
            encode="json")
ret <- content(ret)$data
print(ret)
```

3.VBA

```VB:VBA
Dim res As Object
Dim httpReq As New XMLHTTP60
Dim retDic As Dictionary
Dim nodeName() As String
Dim nodeID() As String
Dim param As New Dictionary
Dim bodyStr As String
Dim nCnt As Integer
With httpReq
  param.Add "network","current"
  param.Add "columnList","SUID,name"
  bodyStr = ConvertToJson(param)
  .Open "POST", "http://localhost:1234/v1/commands/node/get%20attribute"
  .SetRequestHeader "Content-Type","application/json;charset=UTF-8"
  .send(bodyStr)
  set retDic = JsonConverter.ParseJson(FromUTF8(httpReq.responseBody))
  ReDim nodeID(retDic("data").Count)
  ReDim nodeName(retDic("data").Count)
  nCnt = 0
  For Each retVal In retDic("data")
    nCnt = nCnt + 1
    nodeID(nCnt) = retVal("SUID")
    nodeName(nCnt) = retVal("name")
  Next retVal
End With
```

#コマンドの調べ方
　マニュアル`HELP > Automation > CyREST API または CyREST command API`は、単なるマニュアルではなく、その中でコマンドを試すことができるようになっています。
　例えば、[Cytoscapeで開いている全てのネットワークIDを取得する](#Cytoscapeで開いている全てのネットワークIDを取得する)のマニュアル`HELP > Automation > CyREST API > Networks > GET:/v1/networks`を開いてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/2597c96e-9372-f514-1f93-6e400d1f69ea.png)
　Response Class に[integer]とあるので、戻り値は[Integer]だろうと予想します。
　左下に「Try it out!」のボタンがあります。これをクリックしてみると、Response Body欄に実行結果が
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/19084b48-341c-6d7c-0a25-3540edfb41b6.png)
　こんな感じで「今開いているネットワークはID61の１枚だよ」と表示されます。
　ここでは、URLリクエストを示すCurl欄と戻り値を示すResponse Body欄をよくよく確認します。
　Curl欄を参考にして実行するURLリクエストを作り、Response Body欄の値を参考にして戻り値の扱いを考え、RとかPythonとかVBAのコードに落とし込むのです。

　[現在表示しているネットワークのIDを取得する](#現在表示しているネットワークのIDを取得する)ではどうでしょうか。マニュアル`HELP > Automation > CyREST API > Networks > GET:/v1/networks/currentNetwork`を開いてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/e90f1df7-b73f-9424-78b4-38af24acfb79.png)
　Response Class に{data (NetworkSUIDModel, optional),.....}とあるので、戻り値は多分jsonでしょう。
　やっぱり左下に「Try it out!」のボタンがあるので、これをクリックしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/abac98b6-1c56-3cb2-a041-9619bb999b1d.png)
　Response Body欄にJSON形式で「今開いているネットワークのIDは61だよ」ということが表示されています。戻り値はJSONデータなので、VBAではJSONデータをパースしてDATAを取り出してうんぬんする処理が必要になります。

　最後に、[ノードのIDとnameを取得する](#ノードのIDとnameを取得する)はどうでしょうか。
　マニュアルの`HELP > Automation > CyREST Command API > node > POST:/v1/commands/node/get attribute`を開いてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/4776c55d-81e7-add0-3ff6-a4c2ad73f8e2.png)
　Parametersには、bodyの入力枠と、その横に長々と英語で何やら説明文が表示されています。
　ParametersのData Type の下の「Example Value」をクリックしてみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/73a78557-7080-b852-7d7b-b17294d0a0ad.png)
と、パラメータの入力例が表示されます。この入力例をクリックすると、Valueの下のbody欄に入力例のデータがそのままペーストされます。その状態で「Try it out!」すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/bbb82b96-8307-513b-bdb3-352a9c044258.png)
　あれ？うまく結果を取得できません。そこで、Parameter Valueを見直して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2247115/b81c44ac-5c6b-01f8-6817-865b4f888cc4.png)
　こんな感じにしてもう一度「Try it out!」すると、ちゃんと結果が返ってきました。
　あとは、Parameter Valueを色々いじって必要な項目を取得できるようにして、それをRとかPythonとかのコードに落とし込みます。（POSTとかGETとかを間違えないように注意）
　ちなみに、Parameter Valueに設定できるnode attributeは`HELP > Automation > CyREST Command API > node > POST:/v1/commands/node/list attributes`で確認できます。

　CyREST APIにはこれ以外にも、
・ネットワークのStyleを変更する`GET: /v1/apply/styles/{styleName}/{networkId}`
・ノードのnameを変更する`POST: /v1/commands/node/rename`
など、魅力的なコマンドが満載です。
　コマンドの使い方は大体同じで、やりたいことができそうなコマンドを探して、マニュアルを開いて、パラメータを変えたりしながら「Try it out!」をして、うまくいったらコードに落とし込んでいく、みたいな感じです。
　とりあえずはマニュアルをあちこち開いて、片っ端から「Try it out!」してみると、どんどん楽しくなってきますよ。


#おまけ
　macのRStudioで日本語が文字化けするようでしたら[こちら](https://qiita.com/sweetdarling/items/c3c374e7a8490973e892)のとおり、ターミナルで

```:
defaults write org.R-project.R force.LANG ja_JP.UTF-8
```
と呪文を唱えた後RStudioを再起動してみてください。