Commit bda1bd09c5453b550b854962041b66e87068d10e

Authored by Pavel Govyadinov
1 parent e98c381d

Added a network class implemented in python. Reads, writes NWT files, returns Ne…

…tworkX graph objects, and makes layouts.
Showing 1 changed file with 280 additions and 0 deletions   Show diff stats
python/network.py 0 → 100644
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 +Created on Sat Sep 16 16:34:49 2017
  4 +
  5 +@author: pavel
  6 +"""
  7 +
  8 +import struct
  9 +import numpy as np
  10 +import networkx as nx
  11 +import matplotlib.pyplot as plt
  12 +import math
  13 +
  14 +'''
  15 + Definition of the Node class
  16 + Duplicate of the node class in network
  17 + Stores the physical position, outgoing edges list and incoming edges list.
  18 +'''
  19 +class Node:
  20 + def __init__(self, point, outgoing, incoming):
  21 + self.p = point
  22 + self.o = outgoing
  23 + self.i = incoming
  24 +
  25 +'''
  26 + Definition of the Fiber class.
  27 + Duplicate of the Node class in network
  28 + Stores the starting vertex, the ending vertex, the points array and the radius array
  29 +'''
  30 +class Fiber:
  31 +
  32 + def __init__ (self):
  33 + self.v0 = 0
  34 + self.v1 = 0
  35 + self.points = []
  36 + self.radii = []
  37 +
  38 + def __init__ (self, p1, p2, pois, rads):
  39 + self.v0 = p1
  40 + self.v1 = p2
  41 + self.points = pois
  42 + self.radii = rads
  43 +
  44 + '''
  45 + return the length of the fiber.
  46 + '''
  47 + def length(self):
  48 + length = 0
  49 + for i in range(len(self.points)-1):
  50 + length = length + math.sqrt(pow(self.points[i][0]- self.points[i+1][0],2) + pow(self.points[i][1]- self.points[i+1][1],2) + pow(self.points[i][2]- self.points[i+1][2],2))
  51 +
  52 + return length
  53 +
  54 + '''
  55 + returns the turtuosity of the fiber.
  56 + '''
  57 + def turtuosity(self):
  58 + turtuosity = 0
  59 + distance = math.sqrt(math.pow(self.points[0][0]- self.points[len(self.points)-1][0],2) + math.pow(self.points[0][1]- self.points[len(self.points)-1][1],2) + math.pow(self.points[0][2]- self.points[len(self.points)-1][2],2))
  60 + turtuosity = self.length()/distance
  61 + #print(turtuosity)
  62 +
  63 + return turtuosity
  64 +
  65 + '''
  66 + returns the volume of the fiber.
  67 + '''
  68 + def volume(self):
  69 + volume = 0
  70 + for i in range(len(self.points)-1):
  71 + volume = volume + 1.0/3.0 * math.pi * (math.pow(self.radii[i],2) + math.pow(self.radii[i+1],2) + self.radii[i]*self.radii[i+1]) * math.sqrt(math.pow(self.points[i][0]- self.points[i+1][0],2) + math.pow(self.points[i][1]- self.points[i+1][1],2) + math.pow(self.points[i][2]- self.points[i+1][2],2))
  72 +
  73 + #print(volume)
  74 + return volume
  75 +'''
  76 + Writes the header given and open file descripion, number of verticies and number of edges.
  77 +'''
  78 +def writeHeader(open_file, numVerts, numEdges):
  79 + txt = "nwtFileFormat fileid(14B), desc(58B), #vertices(4B), #edges(4B): bindata"
  80 + b = bytearray()
  81 + b.extend(txt.encode())
  82 + open_file.write(b)
  83 + open_file.write(struct.pack('i', numVerts))
  84 + open_file.write(struct.pack('i', numEdges))
  85 +
  86 +
  87 +'''
  88 + Writes a single vertex to a file.
  89 +'''
  90 +def writeVertex(open_file, vertex):
  91 + open_file.write(struct.pack('<f',vertex.p[0]))
  92 + open_file.write(struct.pack('<f',vertex.p[1]))
  93 + open_file.write(struct.pack('<f',vertex.p[2]))
  94 + open_file.write(struct.pack('i', len(vertex.o)))
  95 + open_file.write(struct.pack('i', len(vertex.i)))
  96 + for j in range(len(vertex.o)):
  97 + open_file.write(struct.pack('i',vertex.o[j]))
  98 +
  99 + for j in range(len(vertex.i)):
  100 + open_file.write(struct.pack('i', vertex.i[j]))
  101 +
  102 + return
  103 +
  104 +'''
  105 + Writes a single fiber to a file.
  106 +'''
  107 +def writeFiber(open_file, edge):
  108 + open_file.write(struct.pack('i',edge.v0))
  109 + open_file.write(struct.pack('i',edge.v1))
  110 + open_file.write(struct.pack('i',len(edge.points)))
  111 + for j in range(len(edge.points)):
  112 + open_file.write(struct.pack('<f', edge.points[j][0]))
  113 + open_file.write(struct.pack('<f', edge.points[j][1]))
  114 + open_file.write(struct.pack('<f', edge.points[j][2]))
  115 + open_file.write(struct.pack('<f', edge.radii[j]))
  116 +
  117 + return
  118 +
  119 +'''
  120 + Writes the entire network to a file in str given the vertices array and the edges array.
  121 +'''
  122 +def exportNWT(str, vertices, edges):
  123 + with open(str, "wb") as file:
  124 + writeHeader(file, len(vertices), len(edges))
  125 + for i in range(len(vertices)):
  126 + writeVertex(file, vertices[i])
  127 +
  128 + for i in range(len(edges)):
  129 + writeFiber(file, edges[i])
  130 +
  131 + return
  132 +
  133 +
  134 +'''
  135 + Reads a single vertex from an open file and returns a node Object.
  136 +'''
  137 +def readVertex(open_file):
  138 + points = np.tile(0., 3)
  139 + bytes = open_file.read(4)
  140 + points[0] = struct.unpack('f', bytes)[0]
  141 + bytes = open_file.read(4)
  142 + points[1] = struct.unpack('f', bytes)[0]
  143 + bytes = open_file.read(4)
  144 + points[2] = struct.unpack('f', bytes)[0]
  145 + bytes = open_file.read(4)
  146 +
  147 + numO = int.from_bytes(bytes, byteorder='little')
  148 + outgoing = np.tile(0, numO)
  149 + bts = open_file.read(4)
  150 + numI = int.from_bytes(bts, byteorder='little')
  151 + incoming = np.tile(0, numI)
  152 + for j in range(numO):
  153 + bytes = open_file.read(4)
  154 + outgoing[j] = int.from_bytes(bytes, byteorder='little')
  155 +
  156 + for j in range(numI):
  157 + bytes = open_file.read(4)
  158 + incoming[j] = int.from_bytes(bytes, byteorder='little')
  159 +
  160 + node = Node(points, outgoing, incoming)
  161 + return node
  162 +
  163 +
  164 +'''
  165 + Reads a single fiber from an open file and returns a Fiber object .
  166 +'''
  167 +def readFiber(open_file):
  168 + bytes = open_file.read(4)
  169 + vtx0 = int.from_bytes(bytes, byteorder = 'little')
  170 + bytes = open_file.read(4)
  171 + vtx1 = int.from_bytes(bytes, byteorder = 'little')
  172 + bytes = open_file.read(4)
  173 + numVerts = int.from_bytes(bytes, byteorder = 'little')
  174 + pts = []
  175 + rads = []
  176 +
  177 + for j in range(numVerts):
  178 + point = np.tile(0., 3)
  179 + bytes = open_file.read(4)
  180 + point[0] = struct.unpack('f', bytes)[0]
  181 + bytes = open_file.read(4)
  182 + point[1] = struct.unpack('f', bytes)[0]
  183 + bytes = open_file.read(4)
  184 + point[2] = struct.unpack('f', bytes)[0]
  185 + bytes = open_file.read(4)
  186 + radius = struct.unpack('f', bytes)[0]
  187 + pts.append(point)
  188 + rads.append(radius)
  189 +
  190 + F = Fiber(vtx0, vtx1, pts, rads)
  191 +
  192 + return F
  193 +
  194 +'''
  195 + Imports a NWT file at location str.
  196 + Returns a list of Nodes objects and a list of Fiber objects.
  197 +'''
  198 +def importNWT(str):
  199 + with open(str, "rb") as file:
  200 + header = file.read(72)
  201 + bytes = file.read(4)
  202 + numVertex = int.from_bytes(bytes, byteorder='little')
  203 + bytes = file.read(4)
  204 + numEdges = int.from_bytes(bytes, byteorder='little')
  205 +
  206 + nodeList = []
  207 + fiberList = []
  208 + for i in range(numVertex):
  209 + node = readVertex(file)
  210 + nodeList.append(node)
  211 +
  212 + for i in range(numEdges):
  213 + edge = readFiber(file)
  214 + fiberList.append(edge)
  215 +
  216 + exportNWT("/home/pavel/Documents/Python/NetLayout/from_python_seg.nwt", nodeList, fiberList)
  217 + print(str)
  218 + return nodeList, fiberList;
  219 +
  220 +'''
  221 +Creates a graph from a list of nodes and a list of edges.
  222 +Uses edge length as weight.
  223 +Returns a NetworkX Object.
  224 +'''
  225 +
  226 +def createLengthGraph(nodeList, edgeList):
  227 + G = nx.Graph()
  228 + for i in range(len(nodeList)):
  229 + G.add_node(i, p=V[i].p)
  230 + for i in range(len(edgeList)):
  231 + G.add_edge(edgeList[i].v0, edgeList[i].v1, weight = E[i].length())
  232 +
  233 + return G
  234 +
  235 +'''
  236 +Creates a graph from a list of nodes and a list of edges.
  237 +Uses edge turtuosity as weight.
  238 +Returns a NetworkX Object.
  239 +'''
  240 +def createTortuosityGraph(nodeList, edgeList):
  241 + G = nx.Graph()
  242 + for i in range(len(nodeList)):
  243 + G.add_node(i, p=V[i].p)
  244 + for i in range(len(edgeList)):
  245 + G.add_edge(edgeList[i].v0, edgeList[i].v1, weight = E[i].turtuosity())
  246 +
  247 + return G
  248 +
  249 +
  250 +'''
  251 +Creates a graph from a list of nodes and a list of edges.
  252 +Uses edge volume as weight.
  253 +Returns a NetworkX Object.
  254 +'''
  255 +def createVolumeGraph(nodeList, edgeList):
  256 + G = nx.Graph()
  257 + for i in range(len(nodeList)):
  258 + G.add_node(i, p=V[i].p)
  259 + for i in range(len(edgeList)):
  260 + G.add_edge(edgeList[i].v0, edgeList[i].v1, weight = E[i].volume())
  261 +
  262 + return G
  263 +'''
  264 +Returns the positions dictionary for the Circular layout.
  265 +'''
  266 +def getCircularLayout(graph, dim, radius):
  267 + return nx.circular_layout(graph, dim, radius)
  268 +
  269 +'''
  270 +Return the positions dictionary for the Spring layout.
  271 +'''
  272 +def getSpringLayout(graph, pos, iterations, scale):
  273 + return nx.spring_layout(graph, 2, None, pos, iterations, weight='weight', scale, None)
  274 +
  275 +'''
  276 +Draws the graph.
  277 +'''
  278 +def drawGraph(graph, pos):
  279 + nx.draw(graph, pos)
  280 + return
0 281 \ No newline at end of file
... ...