Commit bda1bd09c5453b550b854962041b66e87068d10e
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
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 | ... | ... |