from __future__ import print_function, division
%matplotlib inline

"""
Explanation: cy3sbml
Mapping simulation & analysis data on SBML networks.
In this example we use the species concentration from a timecourse simulation to map them to the node size.
End of explanation
"""


import tellurium as te
biomodel = "BIOMD0000000012"
r = te.loads("{}.xml".format(biomodel))

"""
Explanation: Load model
Loading Elowitz2000 - Repressilator in tellurium & roadrunner. A synthetic oscillatory network of transcriptional regulators.
The model is available from Biomodels as BIOMD0000000012.
End of explanation
"""


r.reset()
data = r.simulate(start=0, end=600, steps=300)
r.plot();

"""
Explanation: Simulate model
Simple timecourse simulation which we want to visualize with cy3sbml.
End of explanation
"""


import pandas as pd
from matplotlib import pylab as plt

# sbml ids from timeCourseSelections
print(r.timeCourseSelections)
sbml_ids = [name.replace("[", "").replace("]", "") 
            for name in r.timeCourseSelections]

print(sbml_ids)

# create dataframe
df = pd.DataFrame(data[:, 1:], index=data[:,0], columns=sbml_ids[1:])
df.head(10)

"""
Explanation: Convert to dataframe
We store the resulting data in a pandas dataframe. roadrunner returns a NamedArray, we import this into pandas.
End of explanation
"""


# !!! Start Cytoscape 3 with cyREST App

# start client
import json
import py2cytoscape
from py2cytoscape.data.cyrest_client import CyRestClient
from py2cytoscape.data.cynetwork import CyNetwork
from py2cytoscape.data.style import StyleUtil

cy = CyRestClient()

"""
Explanation: Connect to Cytoscape
We use py2cytoscape has wrapper modules for cyREST RESTful API. Hereby we can can access Cytoscape features in more Pythonic way instead of calling raw REST API via HTTP.
http://idekerlab.github.io/cyREST/#-1099067042
End of explanation
"""


# Reset
cy.session.delete()

# Step 2: Load SBML network
networks = cy.network.create_from('BIOMD0000000012.xml')
print(networks)

"""
Explanation: Load SBML in cy3sbml
All the interaction with cytoscape from now on is via simple REST API!
py2cytoscape is only a simple wrapper to hide some of the REST calls.
The same can be done from anywhere (different programming language, ...).
End of explanation
"""


# Get information about SBML networks
base_net = None
for net in networks:
    # unique id of cytoscape objects
    net_suid = net.get_id()
    net_name = net.get_network_value(column='name') 
    print(net.get_network_value(column='name'))
    if (net_name.startswith('Base')):
        base_net = net

# Selected the Base network (reaction - species graph)
print('-'*60)
print (base_net)
print('-'*60)

"""
Explanation: Information about SBML networks
End of explanation
"""


# get node and edges
nodes = base_net.get_nodes()
edges = base_net.get_edges()

print('* This network has ' + str(len(nodes)) + ' nodes and ' + str(len(edges)) + ' edges\n') 

# Get a row in the node table as pandas Series object
node0 = nodes[0]
row = base_net.get_node_value(id=node0)
print(row)

# Or, pick one cell in the table
cell = base_net.get_node_value(id=node0, column='name')
print('\nThis node has name: ' + str(cell))

"""
Explanation: Information about nodes
End of explanation
"""


# cell = base_net.get_node_value(id=node0, column='name')
node_table = base_net.get_node_table()
node_table.head()

"""
Explanation: Node table
All table attributes are available and can be manipulated.
End of explanation
"""


node_suids = []

# logical indexing to find the nodes
for sid in sbml_ids[1:]:
    suid_index = node_table[node_table["sbml id"]==sid].index
    node_suids.append(suid_index.get_values()[0])

suid2sid = dict(zip(node_suids, sbml_ids[1:]))
suid2sid

"""
Explanation: Find nodes for sbml ids
We now find the nodes which correspond to the species we simulated in the model.
The suid (unique node identifiers) are retrieved and stored for lookup.
End of explanation
"""


# Get views for a network: Cytoscape "may" have multiple views, and that's why it returns list instead of an object.
view_ids = base_net.get_views() 
print(view_ids)

# format option specify the return type
view1 = base_net.get_view(view_ids[0], format='view')

# This is a CyNetworkView object, not dictionary
print(view1)

from py2cytoscape.data.util_network import NetworkUtil as util
import time

# DataFrame for node views
df_vs_node = pd.DataFrame(index=node_suids, 
                  columns=['NODE_WIDTH', 'NODE_HEIGHT'])

for timepoint in df.index:
    # print(timepoint)
    for index, row in df_vs_node.iterrows():
        sbml_id = suid2sid.get(index)
        
        # Set node size from simulation results
        row['NODE_WIDTH'] = df.loc[timepoint, sbml_id]/15
        row['NODE_HEIGHT'] = df.loc[timepoint, sbml_id]/15
    
        # normalisation with max value
        row['NODE_WIDTH'] = 80 * df.loc[timepoint, sbml_id]/max(df[sbml_id])
        row['NODE_HEIGHT'] = 80 * df.loc[timepoint, sbml_id]/max(df[sbml_id])
    

    # Apply for timepoint
    view1.batch_update_node_views(df_vs_node)
    
    # wait
    time.sleep(0.03)

# reset to original size
for index, row in df_vs_node.iterrows():
    sbml_id = suid2sid.get(index)
    # row['NODE_FILL_COLOR'] = '#FF0000'
    row['NODE_WIDTH'] = 40
    row['NODE_HEIGHT'] = 40
view1.batch_update_node_views(df_vs_node)

r.plot()

"""
Explanation: Get CyNetworkView
CyNetworkView is a reference to a network view in your current Cytoscape session. This means CyNetworkView objects do not include actual data, such as node size or edge stroke colors. Instead, they hold a location of the data and create actual REST calls when you execute get/update methods for nodes and edges.
End of explanation
"""


# create results folder
import os
results_dir = "./results/{}".format(biomodel)
if not os.path.exists(results_dir):
    os.mkdir()

# Create images for all species
time = df.index
for sbml_id in df.columns:
    # Create plot
    plt.figure(figsize=[2,2])
    plt.plot(time, df[sbml_id], linewidth=2, color="black")
    plt.xlabel('time')
    plt.ylabel(sbml_id)
    plt.savefig('{}/{}.png'.format(results_dir, sbml_id))

## Serve images
We run a simple file server to serve the images via URL.

# !!! serve the images on webserver
# python -m SimpleHTTPServer
# http://localhost:8000/results/BIOMD0000000012/

The images are than reachable under  
http://localhost:8000/results/BIOMD0000000012/

# DataFrame for node views
df_vs_node = pd.DataFrame(index=node_suids, 
                  columns=['NODE_CUSTOM_PAINT_1'])

# apply all visual changes for the timepoint
for index, row in df_vs_node.iterrows():
    sbml_id = suid2sid.get(index)
    # row['NODE_FILL_COLOR'] = '#FF0000'
    row['NODE_CUSTOM_PAINT_1'] = 'http://localhost:8000/results/BIOMD0000000012/{}.png'.format(sbml_id)

# Apply for timepoint
view1.batch_update_node_views(df_vs_node)


# apply styles
# cy.style.apply(style=minimal_style, network=base_net)
# apply layout
# cy.layout.apply(name='force-directed', network=base_net)


"""
Explanation: Set node images
Create images for species
In a first step we want to display images in the network.
For this the individual figures are created and store in the results folder
End of explanation
"""


