In [3]:
from py2cytoscape.data.cynetwork import CyNetwork
from py2cytoscape.data.cyrest_client import CyRestClient
from py2cytoscape.data.style import StyleUtil
import py2cytoscape.util.cytoscapejs as cyjs
import py2cytoscape.cytoscapejs as renderer
from IPython.display import Image
import igraph as igraph
import sand
import sand.cytoscape as sc
In [4]:
network_collection = "lein-topology"
network_name = "57af741"
data_path = "./data/" + network_collection + "-" + network_name
In [5]:
edge_file = data_path + ".csv"
edgelist = sand.csv_to_dicts(edge_file,header=['source', 'target', 'weight'])
g = sand.from_edges(edgelist)
g.summary()
Out[5]:
Namespaces are the modules of the system and will serve as groups / communities in the visualization.
In [6]:
g.vs['group'] = sand.labels_to_groups(g.vs['label'])
g.vs['namespace'] = sand.namespaces(g.vs['label'])
There are some analyses where it will be useful to see all the vertices. For the high-level architecture diagram, we can focus on the functions local to the library's namespaces. We'll also keep functions that have side-effects to see if these are isolated to only a few key parts of the program:
In [7]:
# List all patterns of vertex names that we want to keep:
names_to_keep = ('topology', 'clojure.core/*err*', 'clojure.core/println')
lv = g.vs(lambda v: any(match in v['label'] for match in names_to_keep))
lg = g.subgraph(lv)
# Recompute degree after building the subgraph:
lg.vs['indegree'] = lg.degree(mode="in")
lg.vs['outdegree'] = lg.degree(mode="out")
lg.summary()
Out[7]:
In [8]:
sc.print_version()
In [9]:
# Create py2cytoscape client
cy = CyRestClient()
In [10]:
# Optional: delete all existing networks
cy.session.delete()
In [11]:
# Load the network
network = cy.network.create_from_igraph(lg, name=network_name, collection=network_collection)
In [12]:
style = cy.style.create('Ops')
style.update_defaults(sc.ops)
# Map the label property in the igraph data to Cytoscape's NODE_LABEL visual property
style.create_passthrough_mapping(column='label', vp='NODE_LABEL', col_type='String')
In [15]:
from sand.cytoscape.themes.colors import colors
In [16]:
border_colors = {
'topology.finder': colors.BRIGHT_YELLOW,
'topology.dependencies': colors.BRIGHT_ORANGE,
'topology.dependencies-test': colors.BRIGHT_ORANGE,
'topology.qualifier': colors.BRIGHT_PURPLE,
'topology.symbols': colors.BRIGHT_BLUE,
'clojure.core': colors.BRIGHT_RED,
'topology.printer': colors.BRIGHT_RED,
'leiningen.topology': colors.BRIGHT_WHITE,
}
fill_colors = {
'topology.finder': colors.DARK_YELLOW,
'topology.dependencies': colors.DARK_ORANGE,
'topology.dependencies-test': colors.DARK_ORANGE,
'topology.qualifier': colors.DARK_PURPLE,
'topology.symbols': colors.DARK_BLUE,
'clojure.core': colors.DARK_RED,
'topology.printer': colors.DARK_RED,
'leiningen.topology': colors.DARK_WHITE,
}
style.create_discrete_mapping(column='namespace', col_type='String', vp='NODE_FILL_COLOR', mappings=fill_colors)
style.create_discrete_mapping(column='namespace', col_type='String', vp='NODE_BORDER_PAINT', mappings=border_colors)
In [17]:
cy.style.apply(style, network)
In [18]:
# Apply default layout
cy.layout.apply(name='force-directed', network=network)
In [19]:
# Load layout coordinates from a previous session
positions_file = data_path + "-positions.csv"
sc.layout_from_positions_csv(network, positions_file, cy)
In [20]:
sc.positions_to_csv(network=network, path=positions_file)
In [21]:
# Hide all panels in the UI
sc.hide_panels()
Out[21]:
In [22]:
# Fit to the window:
cy.layout.fit(network=network)
In [23]:
view_id = network.get_views()[0]
In [24]:
view = network.get_view(view_id=view_id, format='view')
In [25]:
# Zoom out slightly:
view.update_network_view('NETWORK_SCALE_FACTOR', 0.7)
In [26]:
# Shift the network to the left:
view.update_network_view('NETWORK_CENTER_X_LOCATION', 750.0)
In [27]:
from IPython.display import SVG, display
svg_data = network.get_svg()
display(SVG(svg_data))
In [28]:
# Write the svg to a file if everything looks good:
with open(data_path + '.svg', 'wb') as f:
f.write(svg_data)