Network X is a visualization and analytic platform for Python which focuses on creating and analysing network graphs. These are graphs of interconnected nodes used for representing relationships such as those found in social networks. A similar browser based network graph framework is Sigma JS, a javascript library for displaying interactive network graphs, similar to to the widely used and all powerful D3. They both excel in different areas. Network X excels in analysis and is also great for dynamically creating graph trees, while Sigma is a front end interactive GUI framework. I've been utilizing both of these lately and thought I would share some code I've written up in Python for assembling a graph network in Python using Network X and exporting the resulting JSON in a format for Sigma.
The example code below is part of a larger program that displays word associations from twitter posts. I haven't included the entire Twitter mining component as that is quite complex and uses a lot of natural language processing which isn't related to the use of either Network X or Sigma. The input (list_in) is a list of word associations (index 0 and 1), their ranking (index 2, an integer) and whether they are a primary 'P' or tertiary node 'T' (index 3). This is based around their position in relation to a central node, in this case, the work 'country'.
The output from the print statement can be dropped into any Sigma.JS canvas to be displayed and looks like this.
The example code below is part of a larger program that displays word associations from twitter posts. I haven't included the entire Twitter mining component as that is quite complex and uses a lot of natural language processing which isn't related to the use of either Network X or Sigma. The input (list_in) is a list of word associations (index 0 and 1), their ranking (index 2, an integer) and whether they are a primary 'P' or tertiary node 'T' (index 3). This is based around their position in relation to a central node, in this case, the work 'country'.
The output from the print statement can be dropped into any Sigma.JS canvas to be displayed and looks like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | import json import networkx as nx from networkx.readwrite import json_graph from random import randint as rand def graphing(pair, node, word): word = word.lower() # Creates a primary word list and strips out the key word primary_list = [k.replace( " " + word, ' ') for k, v in pair.items() if v[1] == ' P'] primary_list_test = [k.replace( " " + word, '') for k, v in pair.items()] # Creates a tertiary word list but retains the tertiary_list = [k.split() for k, v in pair.items() if v[ 1 ] = = 'T' ] # Adds in words to the primary list for t in tertiary_list: for n in t: if n not in primary_list: primary_list.append(n) # Index used for providing an ID to the edge num = 1 # creates a new NetworkX graph NG = nx.Graph() for k, v in pair.items(): # Split the key into two words p = k.split( " " , 1 ) # Assign the weight variable w = v[ 0 ] / 2 # Add an edge with nodes, id, weight and color atributes NG.add_edge(p[ 0 ], p[ 1 ], id = num, weight = w, color = '#bcdbf6' , size = 1 ) # Iterates the ID num = num + 1 # Maximum weight value for scaling maxval = max (node.values(), key = lambda x: x) prim_co_ord = {} # Adds the central node with maximum size and centred into frame NG.add_node(word, size = maxval, label = word, x = 3 , y = 3 , color = '#F6851F' , borderColor = '#bcdbf6' , borderWidth = 2 ) # Adds in the primary nodes for p in primary_list: val = node[p] # normalizes size of node. This can be modified or even removed v = ( (val / (maxval * 0.6 ) * 12 ) + 12 ) # Assigns unique random co-ordinates for the graph co_ord_x = rand( 90 , 110 ) / float ( 100 ) co_ord_y = rand( 50 , 200 ) / float ( 100 ) # Store these for later prim_co_ord[p] = [co_ord_x, co_ord_y] # Add node to graph with parameters NG.add_node(p, size = v, label = p, x = co_ord_x, y = co_ord_y, color = '#F6851F' , borderColor = '#bcdbf6' , borderWidth = 2 ) for t in tertiary_list: # Retrieves the word and it's pairs for tertiary nodes u = t[ 0 ] w = t[ 1 ] # The weight for the node of interest val = node[u] # normalizes size of node. This can be modified or even removed v = ((val / (maxval * 0.6 ) * 12 ) + 12 ) # Adds in x, y co-ords close to the primary node. try : tert_co_ord_x = prim_co_ord[w][ 0 ] + (rand( - 5 , 5 ) / float ( 100 )) tert_co_ord_y = prim_co_ord[w][ 1 ] + (rand( - 5 , 5 ) / float ( 100 )) except : tert_co_ord_x = prim_co_ord[u][ 0 ] + (rand( - 5 , 5 ) / float ( 100 )) tert_co_ord_y = prim_co_ord[u][ 1 ] + (rand( - 5 , 5 ) / float ( 100 )) # Adds in node with attributes NG.add_node(u, size = v, label = u, x = tert_co_ord_x, y = tert_co_ord_y, color = '#F6851F' , borderColor = '#bcdbf6' , borderWidth = 2 ) # Converts the Network graph to a JSON format fixNG = json_graph.node_link_data(NG) # Fixes the network so that edges use node names instead of integers fixNG[ 'links' ] = [ { 'source' : fixNG[ 'nodes' ][link[ 'source' ]][ 'id' ], 'target' : fixNG[ 'nodes' ][link[ 'target' ]][ 'id' ], 'id' : link[ 'id' ], 'size' : link[ 'size' ], 'color' : '#bcdbf6' } for link in fixNG[ 'links' ]] # Stringifies the json fixNG = str (json.dumps(fixNG)) # Changes links to edges to comply with Sigma.JS rtnNG = fixNG.replace( 'links' , 'edges' ) return rtnNG def parse(listDB, word): # Parses the data into dictionaries pairDict = {} nodeDict = {} # Separates primary nodes into their own list and sorts on count # A maximum of 15 nodes are selected from t pLst = [l for l in listDB if l[ 3 ] = = 'P' ] pLst = sorted (pLst, key = lambda x: x[ 2 ], reverse = True )[: 15 ] # A temp list for tertiary nodes linked to primary nodes m_pLst = [n[ 0 ] for n in pLst] # Separates tertiary nodes into their own list if in m_pLst tLst = [l for l in listDB if l[ 3 ] = = 'T' and l[ 1 ] in set (m_pLst)] tLst = sorted (tLst, key = lambda x: x[ 2 ], reverse = True )[: 20 ] for l in tLst: pLst.append(l) for lst in pLst: # Defines 1st word, 2nd word and count x = lst[ 0 ].lower() y = lst[ 1 ].lower() z = lst[ 2 ] if x and y: # Defines key and swapped order key for pairs key = (x + " " + y) varkey = (y + " " + x) val = lst[ 2 ], lst[ 3 ] val = list (val) # If these don't exist, add to pairs dict if key in pairDict: pass elif varkey in pairDict: pass else : pairDict[key] = val # Adds weights to node dicts for each word in the pair if x in nodeDict: nodeDict[x] + = z else : nodeDict[x] = z if y in nodeDict: nodeDict[y] + = z else : nodeDict[y] = z return graphing(pairDict, nodeDict, word) list_in = [[ 'friend' , 'country' , 3 , 'P' ], [ 'look' , 'country' , 4 , 'P' ], [ 'person' , 'country' , 2 , 'P' ], [ 'make' , 'country' , 2 , 'P' ], [ 'mimisamat8' , 'look' , 2 , 'T' ], [ 'heoolll' , 'look' , 2 , 'T' ], [ 'look' , 'look' , 1 , 'T' ], [ 'judge' , 'person' , 1 , 'T' ], [ 'kind' , 'person' , 1 , 'T' ], [ 'looks' , 'make' , 1 , 'T' ], [ 'thing' , 'make' , 1 , 'T' ], [ 'personality' , 'make' , 1 , 'T' ], [ 'pasta' , 'make' , 1 , 'T' ], [ 'italy' , 'make' , 1 , 'T' ]] print (parse(list_in, 'country' )) |