diff --git a/GraphCanvas.py b/GraphCanvas.py index cece411..1670e63 100644 --- a/GraphCanvas.py +++ b/GraphCanvas.py @@ -13,6 +13,18 @@ from vispy.gloo import set_viewport, set_state, clear, set_blend_color, context from vispy.util.transforms import perspective, translate, rotate, scale import vispy.gloo.gl as glcore from vispy import app +#from shapely.geometry import Polygon +#from shapely.geometry import Point +#from shapely.geometry import MultiPoint +from scipy.spatial import ConvexHull +from scipy.spatial import Delaunay +#import scipy.spatial.ConvexHull + +from vispy.scene.visuals import Text +from vispy.scene.visuals import ColorBar + + + import copy import numpy as np @@ -211,6 +223,10 @@ class GraphCanvas(scene.SceneCanvas): self.timer = app.Timer('auto', connect=self.on_timer, start=False) #self.constant = app.Timer('auto', connect=self.update, start=True) self.num=0 + self.current_color = "" + self.update_text(self.current_color) + self.update_color_bar(self.current_color) + print(self.context.config) def on_timer(self, event): @@ -251,42 +267,42 @@ class GraphCanvas(scene.SceneCanvas): self.vbo_line = gloo.VertexBuffer(self.line_data) self.program_e.bind(self.vbo_line) - - self.update_clusters(self.old_pos) - edges = self.G_cluster.get_edges() -# #generate the vertex buffer and the connections buffer. - for e in range(edges.shape[0]): - idx = int(4*edges[e][2]) - p0 = self.cluster_pos[int(edges[e][0])] - p1 = self.cluster_pos[int(edges[e][1])] - #p0 = self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(edges[e][0])] - #p1 = self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(edges[e][1])] - d = np.subtract(p1, p0) - #d_norm = np.multiply(d, 1/np.sqrt(np.power(d[0],2) + np.power(d[1],2))) - d_norm = d[0:2] - d_norm = d_norm / np.sqrt(np.power(d_norm[0],2) + np.power(d_norm[1],2)) - norm = np.zeros((2,), dtype=np.float32) - norm[0] = d_norm[1] - norm[1] = d_norm[0]*-1 - #print(np.sqrt(norm[0]*norm[0] + norm[1]*norm[1])) - #thickness = G.edge_properties["thickness"][e] - #self.cluster_dict[int(edges[e][0]), int(edges[e][1])] = int(edges[e][2]) - self.cluster_line_data['a_position'][idx] = p0 - self.cluster_line_data['a_normal'][idx] = norm - - self.cluster_line_data['a_position'][idx+1] = p1 - self.cluster_line_data['a_normal'][idx+1] = norm - - self.cluster_line_data['a_position'][idx+2] = p0 - self.cluster_line_data['a_normal'][idx+2] = -norm - - self.cluster_line_data['a_position'][idx+3] = p1 - self.cluster_line_data['a_normal'][idx+3] = -norm - - self.vbo_cluster_lines.set_data(self.cluster_line_data) - self.vbo_s.set_data(self.clusters) - self.program_s.bind(self.vbo_s) - self.program_e_s.bind(self.vbo_cluster_lines) + if(self.subgraphs): + self.update_clusters(self.old_pos) + edges = self.G_cluster.get_edges() + # #generate the vertex buffer and the connections buffer. + for e in range(edges.shape[0]): + idx = int(4*edges[e][2]) + p0 = self.cluster_pos[int(edges[e][0])] + p1 = self.cluster_pos[int(edges[e][1])] + #p0 = self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(edges[e][0])] + #p1 = self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(edges[e][1])] + d = np.subtract(p1, p0) + #d_norm = np.multiply(d, 1/np.sqrt(np.power(d[0],2) + np.power(d[1],2))) + d_norm = d[0:2] + d_norm = d_norm / np.sqrt(np.power(d_norm[0],2) + np.power(d_norm[1],2)) + norm = np.zeros((2,), dtype=np.float32) + norm[0] = d_norm[1] + norm[1] = d_norm[0]*-1 + #print(np.sqrt(norm[0]*norm[0] + norm[1]*norm[1])) + #thickness = G.edge_properties["thickness"][e] + #self.cluster_dict[int(edges[e][0]), int(edges[e][1])] = int(edges[e][2]) + self.cluster_line_data['a_position'][idx] = p0 + self.cluster_line_data['a_normal'][idx] = norm + + self.cluster_line_data['a_position'][idx+1] = p1 + self.cluster_line_data['a_normal'][idx+1] = norm + + self.cluster_line_data['a_position'][idx+2] = p0 + self.cluster_line_data['a_normal'][idx+2] = -norm + + self.cluster_line_data['a_position'][idx+3] = p1 + self.cluster_line_data['a_normal'][idx+3] = -norm + + self.vbo_cluster_lines.set_data(self.cluster_line_data) + self.vbo_s.set_data(self.clusters) + self.program_s.bind(self.vbo_s) + self.program_e_s.bind(self.vbo_cluster_lines) self.refresh() @@ -309,6 +325,8 @@ class GraphCanvas(scene.SceneCanvas): self.vbo = gloo.VertexBuffer(self.data) self.program.bind(self.vbo) #self.program_e.bind(self.vbo) + self.update_text(self.current_color) + self.update_color_bar(self.current_color) self.refresh() def update_color_buffers(self): @@ -622,7 +640,7 @@ class GraphCanvas(scene.SceneCanvas): two. """ def gen_cluster_line_vbo(self, G): - #create a graph that stores the edges of between the clusters + self.G_cluster = nwt.gt.Graph(directed=False) self.G_cluster.vertex_properties["pos"] = self.G_cluster.new_vertex_property("vector", val=np.zeros((3,1), dtype=np.float32)) self.G_cluster.vertex_properties["RGBA"] = self.G_cluster.new_vertex_property("vector", val=np.zeros((4,1), dtype=np.float32)) @@ -630,22 +648,73 @@ class GraphCanvas(scene.SceneCanvas): self.G_cluster.add_vertex() self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(v)] = np.asarray(self.cluster_pos[v], dtype=np.float32) self.G_cluster.edge_properties["weight"] = self.G_cluster.new_edge_property("int", val = 0) + self.G_cluster.edge_properties["volume"] = self.G_cluster.new_edge_property("float", val = 0.0) #for each edge in the original graph, generate appropriate subgraph edges without repretiions #i.e. controls the thichness of the edges in the subgraph view. for e in G.edges(): #if the source and target cluster is not equal to each other #add an inter subgraph edge. if(G.vertex_properties["clusters"][e.source()] != G.vertex_properties["clusters"][e.target()]): + t0 = e.source() + t1 = e.target() + ct0 = self.G_cluster.vertex(G.vertex_properties["clusters"][t0]) + ct1 = self.G_cluster.vertex(G.vertex_properties["clusters"][t1]) + if(self.G_cluster.edge(ct0, ct1) == None): + if(self.G_cluster.edge(ct1, ct0) == None): #temp_e.append([G.vertex_properties["clusters"][e.source()], G.vertex_properties["clusters"][e.target()]]) - self.G_cluster.add_edge(self.G_cluster.vertex(G.vertex_properties["clusters"][e.source()]), \ - self.G_cluster.vertex(G.vertex_properties["clusters"][e.target()])) - self.G_cluster.edge_properties["weight"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][e.source()]), \ - self.G_cluster.vertex(G.vertex_properties["clusters"][e.target()]))] += 1 - self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][e.source()])] \ - = G.vertex_properties["RGBA"][e.source()] - self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][e.target()])] \ - = G.vertex_properties["RGBA"][e.target()] - + self.G_cluster.add_edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t0]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t1])) + self.G_cluster.edge_properties["weight"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t0]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t1]))] += 1 + self.G_cluster.edge_properties["volume"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t0]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t1]))] += G.edge_properties["volume"][e] + self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][t0])] \ + = G.vertex_properties["RGBA"][t0] + self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][t1])] \ + = G.vertex_properties["RGBA"][t1] + else: + self.G_cluster.edge_properties["weight"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t1]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t0]))] += 1 + self.G_cluster.edge_properties["volume"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t1]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t0]))] += G.edge_properties["volume"][e] + self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][t1])] \ + = G.vertex_properties["RGBA"][t1] + self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][t0])] \ + = G.vertex_properties["RGBA"][t0] + else: + self.G_cluster.edge_properties["weight"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t0]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t1]))] += 1 + self.G_cluster.edge_properties["volume"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][t0]), \ + self.G_cluster.vertex(G.vertex_properties["clusters"][t1]))] += G.edge_properties["volume"][e] + self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][t0])] \ + = G.vertex_properties["RGBA"][t0] + self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][t1])] \ + = G.vertex_properties["RGBA"][t1] + #create a graph that stores the edges of between the clusters +# self.G_cluster = nwt.gt.Graph(directed=False) +# self.G_cluster.vertex_properties["pos"] = self.G_cluster.new_vertex_property("vector", val=np.zeros((3,1), dtype=np.float32)) +# self.G_cluster.vertex_properties["RGBA"] = self.G_cluster.new_vertex_property("vector", val=np.zeros((4,1), dtype=np.float32)) +# for v in range(len(self.cluster_pos)): +# self.G_cluster.add_vertex() +# self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(v)] = np.asarray(self.cluster_pos[v], dtype=np.float32) +# self.G_cluster.edge_properties["weight"] = self.G_cluster.new_edge_property("int", val = 0) +# #for each edge in the original graph, generate appropriate subgraph edges without repretiions +# #i.e. controls the thichness of the edges in the subgraph view. +# for e in G.edges(): +# #if the source and target cluster is not equal to each other +# #add an inter subgraph edge. +# if(G.vertex_properties["clusters"][e.source()] != G.vertex_properties["clusters"][e.target()]): +# #temp_e.append([G.vertex_properties["clusters"][e.source()], G.vertex_properties["clusters"][e.target()]]) +# self.G_cluster.add_edge(self.G_cluster.vertex(G.vertex_properties["clusters"][e.source()]), \ +# self.G_cluster.vertex(G.vertex_properties["clusters"][e.target()])) +# self.G_cluster.edge_properties["weight"][self.G_cluster.edge(self.G_cluster.vertex(G.vertex_properties["clusters"][e.source()]), \ +# self.G_cluster.vertex(G.vertex_properties["clusters"][e.target()]))] += 1 +# self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][e.source()])] \ +# = G.vertex_properties["RGBA"][e.source()] +# self.G_cluster.vertex_properties["RGBA"][self.G_cluster.vertex(G.vertex_properties["clusters"][e.target()])] \ +# = G.vertex_properties["RGBA"][e.target()] + + self.G_cluster.vertex_properties["degree"] = self.G_cluster.degree_property_map("total") self.cluster_line_data = np.zeros(self.G_cluster.num_edges()*4, dtype=[('a_position', np.float32, 3), ('a_normal', np.float32, 2), ('a_fg_color', np.float32, 4), @@ -824,6 +893,62 @@ class GraphCanvas(scene.SceneCanvas): """ + Generates a hierarchical layout based on the cluster graph (spdf) and subclusters + """ + def voronoi_layout(self, G = None, n_c = None, G_c = None): + + def gen_subclusters(G, G_cluster, i, reposition = False): + vfilt = np.zeros([G.num_vertices(), 1], dtype='bool') + labels = G.vertex_properties["clusters"].get_array() + num_v_in_cluster = len(np.argwhere(labels == i)) + vfilt[np.argwhere(labels == i)] = 1 + vfilt_prop = G.new_vertex_property("bool", vals = vfilt) + G.set_vertex_filter(vfilt_prop) + + g = nwt.gt.Graph(G, prune=True, directed=False) + + + if reposition == True: + vbetweeness_centrality = g.new_vertex_property("double") + ebetweeness_centrality = g.new_edge_property("double") + nwt.gt.graph_tool.centrality.betweenness(g, vprop=vbetweeness_centrality, eprop=ebetweeness_centrality, norm=True) + g.vertex_properties["bc"] = vbetweeness_centrality + g.edge_properties["bc"] = ebetweeness_centrality + g.vertex_properties["pos"] = nwt.gt.sfdp_layout(g, eweight = ebetweeness_centrality) + + positions = g.vertex_properties["pos"].get_2d_array(range(2)).T + center = np.sum(positions, 0)/num_v_in_cluster + G.clear_filters() + return g, center + + if G_c == None: + G_c = self.G_cluster + G_c.vertex_properties["pos"] = nwt.gt.sfdp_layout(G_c, eweight=G_c.edge_properties["volume"], vweight=G_c.vertex_properties["degree"], C = 1.0, K = 10) + if(G == None): + G = self.G + if(n_c == None): + n_c = self.n_c + else: + if(G == None): + G = self.G + if(n_c == None): + n_c = self.n_c + if self.n_c == G_c.num_vertices(): + for i in range(n_c): + self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(i)] = G_c.vertex_properties["pos"][G_c.vertex(i)] + + + for i in range(n_c): + g, center = gen_subclusters(G, G_c, i, reposition=True) + d = G_c.vertex_properties["pos"][i] - center + for v in g.vertices(): + G.vertex_properties["pos"][g.vertex_properties["idx"][v]] = g.vertex_properties["pos"][v] + d + g.vertex_properties["pos"][v] = g.vertex_properties["pos"][v] + d + #print("stuff") + + + + """ Layout algorithm that expands the cluster based on the location of the of the clusters """ def expand_based_on_clusters(self, G, n): @@ -920,73 +1045,14 @@ class GraphCanvas(scene.SceneCanvas): self.clusters['a_value'][index:index+4] = np.asarray(v, dtype=np.float32) self.G_cluster.vertex_properties["pos"][self.G_cluster.vertex(i)] = self.cluster_pos[i] - - - """ - Function that generates the clusters for an unclustered graph - These are to be represented by the arcs - """ - def gen_clusters(self, G, bbl, bbu, n_c = None, edge_metric = 'volume', vertex_metric = 'degree'): - - #Generate the clusters - self.labels = nwt.Network.spectral_clustering(G,'length', n_clusters = n_c) - bb = nwt.AABB(G) - #print("FLJKKHDFLKJFDLKJFDLKJ ", m) - pts = [] - x, y, z = bb.project_grid(3) - for i in range(3): - for j in range(3): - for k in range(3): - pts.append(np.array([x[i], y[j], z[k]])) - - #self.labels = nwt.Network.spectral_clustering(G,'length') + Function that creates the clusters, assuming that all the data is set already. - #Add clusters as a vertex property - G.vertex_properties["clusters"] = G.new_vertex_property("int", vals=self.labels) - num_clusters = len(np.unique(self.labels)) - self.n_c = n_c - new_indices = [] - pos = G.vertex_properties["p"].get_2d_array(range(3)).T - - #for each cluster find the average vertex position and match to closest point - #in the unique grid. - for i in range(n_c): - point = np.sum(pos[np.argwhere(self.labels == i)], axis=0)/len(np.argwhere(self.labels == i)) - d = 100000000.0 - idx = -1 - for j in range(len(pts)): - dist = np.sqrt(np.power(pts[j][0]-point[0,0],2) + np.power(pts[j][1]-point[0,1],2) + np.power(pts[j][2]-point[0,2],2)) - if dist < d: - d = dist - idx = j - new_indices.append(idx) - pts[idx] = np.array([100000000.0, 1000000000.0, 100000000.0]) - #since there are more points than clusters, we need to make the indices range from - #[0, n_c) - j=0 - unique_indices = np.array(new_indices) - for i in range(n_c): - idx = np.argmin(new_indices) - unique_indices[idx] = j - j += 1 - new_indices[idx] = 100 - - lbl = np.zeros(self.labels.shape) - for i in range(n_c): - idxs = np.argwhere(self.labels == i) - new_idx = np.argwhere(unique_indices == i) - lbl[idxs] = unique_indices[i] - - self.labels = lbl - G.vertex_properties["clusters"] = G.new_vertex_property("int", vals=self.labels) - - - - - - #add colormap - G.vertex_properties["RGBA"] = nwt.Network.map_property_to_color(G, G.vertex_properties["clusters"]) + """ + def gen_cluster_vbo(self, G, bbl, bbu, num_clusters, edge_metric = 'volume', vertex_metric = 'degree', update_color = True): + #add colormap + if(update_color == True): + G.vertex_properties["RGBA"] = nwt.Network.map_property_to_color(G, G.vertex_properties["clusters"]) #generate an empty property set for the clusters. self.clusters = np.zeros(num_clusters*4, dtype=[('a_position', np.float32, 3), @@ -1105,6 +1171,66 @@ class GraphCanvas(scene.SceneCanvas): # self.edges_s = [] #print(self.edges_s) + """ + Function that generates the clusters for an unclustered graph + These are to be represented by the arcs + """ + def gen_clusters(self, G, bbl, bbu, n_c = None, edge_metric = 'volume', vertex_metric = 'degree'): + + #Generate the clusters + self.labels = nwt.Network.spectral_clustering(G,'length', n_clusters = n_c) + bb = nwt.AABB(G) + #print("FLJKKHDFLKJFDLKJFDLKJ ", m) + pts = [] + x, y, z = bb.project_grid(3) + for i in range(3): + for j in range(3): + for k in range(3): + pts.append(np.array([x[i], y[j], z[k]])) + + + #self.labels = nwt.Network.spectral_clustering(G,'length') + #Add clusters as a vertex property + G.vertex_properties["clusters"] = G.new_vertex_property("int", vals=self.labels) + num_clusters = len(np.unique(self.labels)) + self.n_c = n_c + new_indices = [] + pos = G.vertex_properties["p"].get_2d_array(range(3)).T + + #for each cluster find the average vertex position and match to closest point + #in the unique grid. + for i in range(n_c): + point = np.sum(pos[np.argwhere(self.labels == i)], axis=0)/len(np.argwhere(self.labels == i)) + d = 100000000.0 + idx = -1 + for j in range(len(pts)): + dist = np.sqrt(np.power(pts[j][0]-point[0,0],2) + np.power(pts[j][1]-point[0,1],2) + np.power(pts[j][2]-point[0,2],2)) + if dist < d: + d = dist + idx = j + new_indices.append(idx) + pts[idx] = np.array([100000000.0, 1000000000.0, 100000000.0]) + #since there are more points than clusters, we need to make the indices range from + #[0, n_c) + j=0 + unique_indices = np.array(new_indices) + for i in range(n_c): + idx = np.argmin(new_indices) + unique_indices[idx] = j + j += 1 + new_indices[idx] = 100 + + lbl = np.zeros(self.labels.shape) + for i in range(n_c): + idxs = np.argwhere(self.labels == i) + new_idx = np.argwhere(unique_indices == i) + lbl[idxs] = unique_indices[i] + + self.labels = lbl + G.vertex_properties["clusters"] = G.new_vertex_property("int", vals=self.labels) + self.gen_cluster_vbo(self.G, bbl, bbu, num_clusters, edge_metric, vertex_metric) + + """ Function that expands that generates the layout and updates the buffer @@ -1124,11 +1250,288 @@ class GraphCanvas(scene.SceneCanvas): print(self.view) self.refresh() + + """ + Function for generating a distance field based on the clusters in the + clustered 3D network. + """ + def distancefield(self, G): + + import scipy as sp + #generate a meshgrid of the appropriate size and resolution to surround the network + #get the space occupied by the network + lower = self.bbl + upper = self.bbu + R = np.asarray(np.floor(abs(lower-upper)), dtype=np.int) + + x = np.linspace(lower[0], upper[0], R[0]) #get the grid points for uniform sampling of this space + y = np.linspace(lower[1], upper[1], R[1]) + z = np.linspace(lower[2], upper[2], R[2]) + X, Y, Z = np.meshgrid(x, y, z, indexing='ij') + + Q = np.stack((X, Y, Z), 3) + #get a list of all node positions in the network + P = [] + #get a mirrored list of all the point labels + L = [] + + for e in G.edges(): + X_p = G.edge_properties["x"][e] + Y_p = G.edge_properties["y"][e] + Z_p = G.edge_properties["z"][e] + l = list(np.array([X_p,Y_p,Z_p]).T) + #generate points list foe each edge + + P = P + l + #generate labels list for each edge + if G.vertex_properties["clusters"][e.source()] == G.vertex_properties["clusters"][e.target()]: + c = G.vertex_properties["clusters"][e.source()] + for i in range(len(l)): + L.append(c) + #if source and target have the same label, all points have that label + else: + #if source != target label, then point takes on the closest label + source = [] + source.append(0.0) + target = [] + for i in range(1, len(l)): + dist = math.sqrt(pow(l[i][0]-l[i-1][0],2) + pow(l[i][1]-l[i-1][1],2) + pow(l[i][2]-l[i-1][2],2)) + source.append(dist + source[len(source)-1]) + target = source[::-1] + for i in range(len(l)): + if source[i] > target[i]: + L.append(G.vertex_properties["clusters"][e.source()]) + else: + L.append(G.vertex_properties["clusters"][e.target()]) + + #turn that list into a Numpy array so that we can create a KD tree + P = np.array(P) + + #generate a KD-Tree out of the network point array + tree = sp.spatial.cKDTree(P) + + D, I = tree.query(Q) + C = np.zeros(I.shape, dtype=np.int) + for i in range(I.shape[0]): + for j in range(I.shape[1]): + for k in range(I.shape[2]): + C[i,j,k] = L[I[i,j,k]] + + self.write_VTK_R(G, "./test_field.vtk", Q, C, X, Y, Z) + return D, x, y, z, C + + """ + Function for saving the distance field based on the clusters in the + clustered 3D network. + """ + def write_VTK_R(self, G, filepath, Q, C, X, Y, Z):\ + + from pyevtk.hl import gridToVTK + from pyevtk.hl import imageToVTK + from pyevtk.vtk import VtkFile, VtkImageData + import vtk + #T = C.reshape(C.shape[0]*C.shape[1]*C.shape[2]) + #C = T.reshape((C.shape[0], C.shape[1], C.shape[2]), order = 'C') + ColorR = np.zeros((C.shape[0], C.shape[1], C.shape[2])) + ColorG = np.zeros((C.shape[0], C.shape[1], C.shape[2])) + ColorB = np.zeros((C.shape[0], C.shape[1], C.shape[2])) + ColorA = np.zeros((C.shape[0], C.shape[1], C.shape[2])) + #ColorR = ColorG = ColorB = ColorA = np.chararray((P.shape[0], P.shape[1], P.shape[2])) + G.vertex_properties["RGBA"] = nwt.Network.map_property_to_color(G, G.vertex_properties["clusters"]) + self.color_edges(G) + thisdict = {} + otherdict = {} + for v in G.vertices(): + thisdict[G.vertex_properties["clusters"][v]] = G.vertex_properties["RGBA"][v] + color = G.vertex_properties["RGBA"][v].get_array() + c = '#%02x%02x%02x%02x' % (int(color[0]*255), int(color[1]*255), int(color[2]*255), int(color[3]*255*0.3)) + otherdict[G.vertex_properties["clusters"][v]] = c + + print(thisdict, file=open('myfile.txt', 'w')) + i = 0 + for i in range(C.shape[0]): + for j in range(C.shape[1]): + for k in range(C.shape[2]): + c = thisdict[C[i,j,k]] + ColorR[i,j,k] = c[0] + ColorG[i,j,k] = c[1] + ColorB[i,j,k] = c[2] + ColorA[i,j,k] = c[3] + + + # fig = plt.figure() + # ax = fig.gca(projection='3d') + # for e in G.edges(): + # X = G.edge_properties["x"][e] + # Y = G.edge_properties["y"][e] + # Z = G.edge_properties["z"][e] + # color = G.edge_properties['RGBA'][e].get_array() + # c = '#%02x%02x%02x' % (int(color[0]*255), int(color[1]*255), int(color[2]*255)) + # ax.plot(X,Y,Z, color=c) + # print("plotting line") + # + # + # print("generating cells") + # x, y, z = np.indices(np.array(C.shape) + 1).astype(float) + # filled = np.ones(C.shape) + # print("replacing dict") + # vox = replace_with_dict(C, otherdict) + # + # print("plotting voxels") + # ax.voxels(x, y, z, filled, facecolors=vox) + + + #ax.imshow(np.stack((ColorR[:,:,0], ColorG[:,:,0], ColorB[:,:,0]), axis = 2)) + + #plt.show() + + + + + + filename = "./image_fixed.vti" + imageData = vtk.vtkImageData() + imageData.SetDimensions(C.shape[0], C.shape[1], C.shape[2]) + imageData.SetOrigin(0.0, 0.0, 0.0) + imageData.SetSpacing(1.0, 1.0, 1.0) + if vtk.VTK_MAJOR_VERSION <= 5: + imageData.SetNumberOfScalarComponents(4) + imageData.SetScalarTypeToDouble() + else: + imageData.AllocateScalars(vtk.VTK_DOUBLE, 4) + + for z in range(C.shape[2]): + for y in range(C.shape[1]): + for x in range(C.shape[0]): + imageData.SetScalarComponentFromDouble(x, y, z, 0, ColorR[x,y,z]) + imageData.SetScalarComponentFromDouble(x, y, z, 1, ColorG[x,y,z]) + imageData.SetScalarComponentFromDouble(x, y, z, 2, ColorB[x,y,z]) + imageData.SetScalarComponentFromDouble(x, y, z, 3, ColorA[x,y,z]) + + + writer = vtk.vtkXMLImageDataWriter() + writer.SetFileName(filename) + if vtk.VTK_MAJOR_VERSION <= 5: + writer.SetInputConnection(imageData.GetProducerPort()) + else: + writer.SetInputData(imageData) + + writer.Write() + nwt.Network.write_vtk(G, "./vessels_fixed.vtk", binning = False) + + def set_graph(self, G, bbl, bbu, subgraph = False): + self.G = G + self.bbl = bbl + self.bbu = bbu + clear(color=True, depth=True) + self.subgraphs = subgraph + self.current_color = "clusters" + self.color_edges(G) + print(self.G) + color = G.vertex_properties["RGBA"].get_2d_array(range(4)).T + size = nwt.Network.map_vertices_to_range(G, [30*self.pixel_scale, 8*self.pixel_scale], 'degree').get_array() + + position = G.vertex_properties["pos"].get_2d_array(range(3)).T + #for p in range(position.shape[0]): + # position[p][0] = position[p][0] + self.clusters["a_position"][G.vertex_properties["clusters"][G.vertex(p)]][0] + # position[p][1] = position[p][1] + self.clusters["a_position"][G.vertex_properties["clusters"][G.vertex(p)]][1] + # position[p][2] = position[p][2] + self.clusters["a_position"][G.vertex_properties["clusters"][G.vertex(p)]][2] + #G.vertex_properties["pos"] = G.new_vertex_property("vector", vals = position) + edges = G.get_edges(); + edges = edges[:, 0:2] + #width = nwt.Network.map_edges_to_range(G, [1*self.pixel_scale, 5*self.pixel_scale], 'volume').get_array() + #ecolor = G.edge_properties["RGBA"].get_2d_array(range(4)).T + + self.data = np.zeros(G.num_vertices(), dtype=[('a_position', np.float32, 3), + ('a_fg_color', np.float32, 4), + ('a_bg_color', np.float32, 4), + ('a_size', np.float32, 1), + ('a_linewidth', np.float32, 1), + ('a_unique_id', np.float32, 4), + ('a_selection', np.float32, 1), + ]) + + #self.edges = edges.astype(np.uint32) + self.data['a_position'] = position + #fg color is the color of the ring + self.data['a_fg_color'] = 0, 0, 0, 1 + self.data['a_bg_color'] = color + self.data['a_size'] = size + self.data['a_linewidth'] = 4.*self.pixel_scale + self.data['a_unique_id'] = self.gen_vertex_id(G) + self.data['a_selection'] = G.vertex_properties["selection"].get_array() + #self.data['a_graph_size'] = [bbu-bbl] + + #self.program['u_graph_size'] = [bbu-bbl] + + self.vbo = gloo.VertexBuffer(self.data) + self.gen_line_vbo(G) + #self.gen_cylinder_vbo(G) + if(self.subgraphs): + self.labels = self.G.vp["clusters"].get_array() + self.gen_cluster_vbo(self.G, bbl, bbu, self.n_c) + self.vbo_s = gloo.VertexBuffer(self.clusters) + self.index_s = gloo.IndexBuffer(self.edges_s) + #self.index = gloo.IndexBuffer(self.edges) + self.program_e.bind(self.vbo_line) + self.program.bind(self.vbo) + if(self.subgraphs): + #self.program_e_s.bind(self.vbo_s) + self.program_s.bind(self.vbo_s) + if DEBUG: + print(self.view) + self.update_text(self.current_color) + self.update_color_bar(self.current_color) + self.refresh() + + + def update_text(self, text): + self.t1 = Text(text, parent=self.scene, color = 'black', method='gpu', anchor_x = 'right', anchor_y='top') + self.t1.font_size = 24 + #self.t1.anchor_y = 'top' + #self.t1.anchor_x = 'right' +# print(self.t1.bounds(0), self.t1.bounds(1)) + self.t1.pos = self.size[0]-10, self.size[1] // 24 + self.refresh() + + def update_color_bar(self, color_property): + if color_property != "": + prop = self.G.vp[color_property].get_array().T + mx = max(prop) + mn = min(prop) + else: + mx = 1.0 + mn = 0.0 + if(color_property=="clusters"): + cm = 'tab20' + else: + cm = 'plasma' + self.c_bar = ColorBar(cmap=cm, orientation = 'bottom', + size = (self.size[0] // 3, self.size[1] // 24), clim = (mn, mx), + border_width = 10.0,border_color = 'white', + parent=self.scene, + pos=(self.size[0] // 3 // 2 + 20, self.size[1] // 24), + padding = (100, 100) + ) + self.refresh() + """ Loads the data G and generates all the buffers necessary as well as performs spectral clustering on the graph passed if the subgraph is set to true. """ - def set_data(self, G, bbl, bbu, subgraph=True): + def set_data(self, G, bbl, bbu, subgraph=True, G_other = None): + + def in_hull(point, hull, tolerance=1e-6): + return all( + (np.dot(eq[:-1], point) + eq[-1] <= tolerance) + for eq in hull.equations) + +# def in_hull(p, hull): +# if not isinstance(hull,Delaunay): +# hull = Delaunay(hull) +# +# return hull.find_simplex(p)>=0 + if DEBUG: print("Setting data") self.G = G @@ -1137,11 +1540,115 @@ class GraphCanvas(scene.SceneCanvas): clear(color=True, depth=True) self.subgraphs = True self.current_color = "clusters" - if(subgraph==True): - self.gen_clusters(G, bbl, bbu, n_c=19) + if(subgraph==True and G_other == None): + self.gen_clusters(G, bbl, bbu, n_c=19) + self.G.vertex_properties["idx"] = self.G.vertex_index #color based on clusters self.color_edges(G) + else: + #polygons = [] + self.G.vertex_properties["idx"] = self.G.vertex_index + self.G.vertex_properties["clusters"] = self.G.new_vertex_property("int", vals=np.full(self.G.num_vertices(), -1, dtype="int")) + num_clusters = len(np.unique(G_other.vertex_properties["clusters"].get_array().T)) + color_lookup = [] + lbls = G_other.vertex_properties["clusters"].get_array().T + for i in range(num_clusters): + idx = np.where(lbls == i)[0][0] + color_lookup.append(G_other.vertex_properties["RGBA"][G_other.vertex(idx)]) + + + self.n_c = num_clusters + D, x, y, z, C = self.distancefield(G_other) + print(len(x), len(y), len(z)) + for v in self.G.vertices(): + p = self.G.vertex_properties["p"][v] + x_temp = np.fabs(x - p[0]) + idx_x = x_temp.argmin() + y_temp = np.fabs(y - p[1]) + idx_y = y_temp.argmin() + z_temp = np.fabs(z - p[2]) + idx_z = z_temp.argmin() + cluster = C[idx_x][idx_y][idx_z] + self.G.vertex_properties["clusters"][v] = cluster + self.G.vertex_properties["RGBA"][v] = color_lookup[cluster] + + + + ###############OLD Comparison mechanic######################## +# polygons = [] +# for i in range(num_clusters): +# #num_v_in_cluster = len(np.argwhere(self.labels == i)) +# vfilt = np.zeros([G_other.num_vertices(), 1], dtype="bool") +# vfilt[np.argwhere(G_other.vertex_properties["clusters"].get_array().T == i)] = 1 +# vfilt_prop = G_other.new_vertex_property("bool", vals = vfilt) +# G_other.set_vertex_filter(vfilt_prop) +# +# #get the filtered properties +# g = nwt.gt.Graph(G_other, prune=True, directed=False) +# color = g.vertex_properties["RGBA"][g.vertex(0)] +# positions = g.vertex_properties["p"].get_2d_array(range(3)).T +# hull = ConvexHull(positions) +# #hull = Delaunay(positions) +# #hull = multipoint.convex_hull +# polygons.append(hull) +# G_other.clear_filters() +# for v in self.G.vertices(): +# if in_hull(self.G.vertex_properties["p"][v], hull) and self.G.vertex_properties["clusters"][v] == -1: +# self.G.vertex_properties["clusters"][v] = i +# self.G.vertex_properties["RGBA"][v] = color +## if hull.contains(Point(self.G.vertex_properties["p"][v])): +## self.G.vertex_properties["clusters"][v] = i +## self.G.vertex_properties["RGBA"][v] = color +# +# unassigned = np.argwhere(self.G.vertex_properties["clusters"].get_array().T == -1) +# while len(unassigned > 0): +# for i in range(len(unassigned)): +# gen = self.G.vertex(unassigned[i]).all_neighbors() +# neighbors = [] +# neighbors_clusters = [] +# for j in gen: +# neighbors.append(j) +# neighbors_clusters.append(self.G.vertex_properties["clusters"][j]) +# if len(np.unique(neighbors_clusters)) == 1 and np.unique(neighbors_clusters[0]) != -1: +# self.G.vertex_properties["clusters"][self.G.vertex(unassigned[i])] = \ +# self.G.vertex_properties["clusters"][neighbors[0]] +# self.G.vertex_properties["RGBA"][self.G.vertex(unassigned[i])] = \ +# self.G.vertex_properties["RGBA"][neighbors[0]] +# else: +# c, count = np.unique(neighbors_clusters, return_counts=True) +# for k in range(len(c)): +# if c[k] == -1: +# c = np.delete(c, k) +# count = np.delete(count, k) +# break +# if len(c) > 0: +# cluster = np.argwhere(count == max(count))[0] +# self.G.vertex_properties["clusters"][self.G.vertex(unassigned[i])] = c[cluster[0]] +# for v in range(len(neighbors)): +# if self.G.vertex_properties["clusters"][self.G.vertex(unassigned[i])] == c[cluster[0]]: +# self.G.vertex_properties["RGBA"][self.G.vertex(unassigned[i])] = \ +# self.G.vertex_properties["RGBA"][neighbors[v]] +# unassigned = np.argwhere(self.G.vertex_properties["clusters"].get_array().T == -1) +# #print("stuff") +# #for j in range(len(neighbors_clusters)): +# +# #self.G.vertex_properties["RGBA"] = nwt.Network.map_property_to_color(self.G, self.G.vertex_properties["clusters"]) + temp = self.G.vertex_properties["clusters"].get_array().T + print(np.unique(temp)) + self.labels = copy.copy(temp) +# c = np.unique(temp) +# idx = 0 +# for i in range(len(c)): +# self.labels[np.argwhere(temp == c[i])] = idx +# idx += 1 +# + ###############/OLD Comparison mechanic######################## + self.G.vertex_properties["clusters"] = self.G.new_vertex_property("int", vals = self.labels) + self.n_c = len(np.unique(self.labels)) + self.gen_cluster_vbo(self.G, bbl, bbu, self.n_c, update_color = False) + self.color_edges(self.G) + color = G.vertex_properties["RGBA"].get_2d_array(range(4)).T size = nwt.Network.map_vertices_to_range(G, [30*self.pixel_scale, 8*self.pixel_scale], 'degree').get_array() @@ -1193,6 +1700,8 @@ class GraphCanvas(scene.SceneCanvas): self.program_s.bind(self.vbo_s) if DEBUG: print(self.view) + self.update_text(self.current_color) + self.update_color_bar(self.current_color) self.refresh() """ @@ -1201,7 +1710,10 @@ class GraphCanvas(scene.SceneCanvas): def on_resize(self, event): set_viewport(0, 0, *event.physical_size) self.fbo = gloo.FrameBuffer(color=gloo.RenderBuffer(self.size[::-1]), depth=gloo.RenderBuffer(self.size[::-1])) - + self.update_text(self.current_color) + self.update_color_bar(self.current_color) + self.refresh() + app.Canvas.update(self) """ Overloaded function that is called during every self.update() call @@ -1215,8 +1727,10 @@ class GraphCanvas(scene.SceneCanvas): if(self.subgraphs): self.program_e_s.draw('triangles', indices=self.index_clusters_s) self.program_s.draw('triangles', indices=self.index_s) - print("updated ", self.num) - self.num += 1 + #print("updated ", self.num) + #self.num += 1 + self.t1.draw() + self.c_bar.draw() #self._u #self._update_pending = True #app.Canvas.update(self) @@ -1227,6 +1741,7 @@ class GraphCanvas(scene.SceneCanvas): vispy 0.6.3 """ def refresh(self): + self.update_view_global() self.update() app.Canvas.update(self) @@ -1289,6 +1804,7 @@ class GraphCanvas(scene.SceneCanvas): #imsave("test_ori.png", buff) self.fbo.activate() if clusters == False: + self.refresh() self.program['u_picking'] = True clear(color='white', depth=True) self.program.draw('points') @@ -1336,6 +1852,12 @@ class GraphCanvas(scene.SceneCanvas): else: return self.cluster_dict[tuple(color)] + def update_view_global(self): + self.program['u_view'] = self.view + self.program_e['u_view'] = self.view + self.program_s['u_view'] = self.view + self.program_e_s['u_view'] = self.view + """ Top level handle-mouse presee event for either left or right click @@ -1361,8 +1883,10 @@ class GraphCanvas(scene.SceneCanvas): # #if menu.exec_(event.globalPos()): # # print(item.text()) if(event.button == 1): - if(self.view[0][0] > 0.0010): + if(self.view[0][0] > 0.0024): + self.refresh() c_id = self.get_clicked_id(event) + self.refresh() if(c_id != None): self.original_point = self.G.vertex_properties["pos"][self.G.vertex(c_id)] self.location = event.pos @@ -1373,7 +1897,10 @@ class GraphCanvas(scene.SceneCanvas): update_view() #print("Clicked on:", event.pos) else: +# c_id = None + self.refresh() c_id = self.get_clicked_id(event, True) + self.refresh() if DEBUG: print(c_id) if(c_id != None): @@ -1390,6 +1917,27 @@ class GraphCanvas(scene.SceneCanvas): Gets the path and formats it in terms of vertex-to-vertex instead of source(obj)-to-source(obj) """ + + def get_cluster(self, cluster_id): + p = [] + num_v_in_cluster = len(np.argwhere(self.labels == cluster_id)) + vfilt = np.zeros([self.G.num_vertices(), 1], dtype="bool") + vfilt[np.argwhere(self.labels == cluster_id)] = 1 + vfilt_prop = self.G.new_vertex_property("bool", vals = vfilt) + self.G.set_vertex_filter(vfilt_prop) + + #get the filtered properties + g = nwt.gt.Graph(self.G, prune=True, directed=False) + self.G.clear_filters() + for e in g.edges(): + source = g.vp["idx"][e.source()] + target = g.vp["idx"][e.target()] + temp = (int(source), int(target)) + p.append(temp) + + return p + + def get_path(self): p = [] for s in self.path: @@ -1422,12 +1970,14 @@ class GraphCanvas(scene.SceneCanvas): self.G.vertex_properties["selection"][vl[v]] = 2.0 update_vertex_alpha(self, self.G.vertex(vl[v]), 1.0) self.data['a_selection'][int(vl[v])] = 2.0 + self.G.vp["exclude"][self.G.vertex(vl[v])] = True source.v_path.append(int(vl[v])) for e in el: source.e_path.append(e) temp = self.G.edge_properties["RGBA"][e] temp[3] = 1.0 self.G.edge_properties["RGBA"][e] = temp + self.G.edge_properties["exclude"][e] = True def remove_from_path(self, source): @@ -1435,15 +1985,19 @@ class GraphCanvas(scene.SceneCanvas): self.G.vertex_properties["selection"][self.G.vertex(v)] = 0.0 update_vertex_alpha(self,self.G.vertex(v), 0.5) self.data['a_selection'][v] = 0.0 + self.G.vertex_properties["exclude"][v] = False for e in source.e_path: temp = self.G.edge_properties["RGBA"][e] temp[3] = 0.0 self.G.edge_properties["RGBA"][e] = temp + self.G.edge_properties["exclude"][e] = False source.clear_path() if (event.button == 1): - if(self.view[0][0] > 0.0010): + if(self.view[0][0] > 0.0024): + self.refresh() c_id = self.get_clicked_id(event) + self.refresh() if(c_id != None): #check whether this is the first node to be selected if(self.pathing == False): @@ -1496,6 +2050,7 @@ class GraphCanvas(scene.SceneCanvas): self.pathing = False self.make_all_transparent(1.0) self.update_color_buffers() + self.refresh() @@ -1725,6 +2280,43 @@ class GraphCanvas(scene.SceneCanvas): self.location = event.pos self.refresh() + def set_view_matrix(self, matrix): + self.view = matrix + self.program['u_view'] = self.view + self.program_e['u_view'] = self.view + self.program_s['u_view'] = self.view + self.program_e_s['u_view'] = self.view + self.refresh() + + + def center_camera_on(self, camera): + self.translate[0] += (0.0 - camera[0])/self.view[0][0] + self.translate[1] += (0.0 - camera[1])/self.view[1][1] + #self.view[3][0] = self.view[3][0]-(self.location[0]-event.pos[0])/10000.0 + #self.view[3][1] = self.view[3][1]+(self.location[1]-event.pos[1])/10000.0 + + self.view = np.matmul(translate((self.translate[0], self.translate[1], 0)), scale((self.scale[0], self.scale[1], 0))) + + self.program['u_view'] = self.view + self.program_e['u_view'] = self.view + self.program_s['u_view'] = self.view + self.program_e_s['u_view'] = self.view + self.refresh() + + def zoom_camera_on(self, zoom): + self.scale[0] = zoom[0] + self.scale[1] = zoom[1] + + self.view = np.matmul(translate((self.translate[0], self.translate[1], 0)), + scale((self.scale[0], self.scale[1], 0))) + + self.program['u_view'] = self.view + self.program_e['u_view'] = self.view + self.program_s['u_view'] = self.view + self.program_e_s['u_view'] = self.view + #print(event.delta[1]) + self.refresh() + """ Handles the mouse wheel zoom event. """ diff --git a/GraphWidget.py b/GraphWidget.py index 1de24fa..31104a0 100644 --- a/GraphWidget.py +++ b/GraphWidget.py @@ -5,15 +5,79 @@ Created on Mon Aug 5 15:42:19 2019 @author: pavel """ - from GraphCanvas import GraphCanvas +from HistogramWidget import HistogramWidget +#from NodeInformationWidget import NodeInfoWidget from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.Qt import QRect import network_dep as nwt +from TubeWidget import TubeWidget +from vispy.scene.visuals import Text import numpy as np DEBUG = False + + +class NodeInfoWidget(QtWidgets.QWidget): + def __init__(self, *args, **kwargs): + QtWidgets.QWidget.__init__(self) + self.layout = QtWidgets.QGridLayout() + self.resize(900, 300) + self.bar = None + print("stuff 22") + if 'hist' in kwargs: + print("stuff") + self.bar = HistogramWidget() + self.bar.canvas.create_native() + self.fibers_mini = TubeWidget() + self.fibers_mini.canvas.create_native() + + self.graph_mini1 = GraphWidget() + self.graph_mini1.canvas.create_native() + self.graph_mini2 = GraphWidget() + self.graph_mini2.canvas.create_native() + self.graph_mini3 = GraphWidget() + self.graph_mini3.canvas.create_native() + self.graph_mini4 = GraphWidget() + self.graph_mini4.canvas.create_native() + + + + self.graph_mini1.connect(self.fibers_mini) + self.fibers_mini.connect(self.graph_mini1) + self.fibers_mini.connect(self.graph_mini2) + self.fibers_mini.connect(self.graph_mini3) + self.fibers_mini.connect(self.graph_mini4) + + + self.layout.addWidget(self.graph_mini1.canvas.native, 0, 0, 1, 1) + self.layout.addWidget(self.graph_mini2.canvas.native, 0, 1, 1, 1) + self.layout.addWidget(self.graph_mini3.canvas.native, 1, 0, 1, 1) + self.layout.addWidget(self.graph_mini4.canvas.native, 1, 1, 1, 1) + #layout.addItem(vspacer, 0, 2, 2, 1) + if self.bar == None: + self.layout.addWidget(self.fibers_mini.canvas.native, 0, 2, 2, 2) + else: + self.layout.addWidget(self.fibers_mini.canvas.native, 0, 2, 1, 1) + self.layout.addWidget(self.bar.canvas.native, 1, 2, 1, 1) + #layout.setColumnStretch(0, 2) + #layout.setRowStretch(0, 2) + #layout.setColumnStretch(2, 1) + #layout.setRowStretch(0, 1) + + self.setLayout(self.layout) + #print(layout.getContentsMargins()) + #top.show() + + +# def paintEvent(self, e): +# dc = QPainter(self) + + def bye(self): + self.exit(0) + """ Initializes the entire QTlayout and sets the mouse press events. These are connected to the slots such that each is processes by this class @@ -34,11 +98,13 @@ class GraphWidget(QtWidgets.QWidget): self.color = True self.use_3D = False self.camera = [0,0,0] + self.other = None self.canvas.events.mouse_press.connect(self.on_mouse_press) self.canvas.events.mouse_release.connect(self.on_mouse_release) self.canvas.events.mouse_move.connect(self.on_mouse_move) self.canvas.events.mouse_double_click.connect(self.on_mouse_double_click) + self.w = None #self.canvas.events. #self.show() #self.repaint() @@ -55,18 +121,19 @@ class GraphWidget(QtWidgets.QWidget): self.canvas.set_current(event) if event.button == 2: if self.canvas.view[0][0] >= 0.0010: - self.canvas.update() + self.canvas.refresh() c_id = self.canvas.get_clicked_id(event) - self.canvas.update() + self.canvas.refresh() else: - self.canvas.update() + self.canvas.refresh() c_id = self.canvas.get_clicked_id(event, clusters=True) - self.canvas.update() + self.canvas.refresh() #right click if(c_id == None): menu = QtWidgets.QMenu(self) NS = menu.addAction('Node Size') - + if (self.canvas.path != []): + FNP = menu.addAction("Filter Network Path") #tmp = menu.addAction('temp') tmp = menu.addMenu('Node Color') vertex_props = self.canvas.G.vertex_properties.keys() @@ -76,12 +143,14 @@ class GraphWidget(QtWidgets.QWidget): vertex_actions.append(tmp.addAction(vertex_props[i])) #tmp.addAction("Cluster") #NC = menu.addAction('Node Color') - #EXP = menu.addAction('Export VTK') + EXP = menu.addAction('Export VTK') #EXP_adv = menu.addAction('Export VTK Advanced') NL = menu.addAction('New Layout') NSL = menu.addAction('New Spring-Onion Layout (sum)') NSLMI = menu.addAction('New Spring-Onion Layout(max)') EXPAND = menu.addAction('Expand') + CL = menu.addAction('Cluster_Layout') + action = menu.exec_(event.native.globalPos()) if DEBUG: print(action) @@ -101,11 +170,22 @@ class GraphWidget(QtWidgets.QWidget): self.use_3D = False self.canvas.size_vertices(self.canvas.G, 'degree' ) self.canvas.color_vertices(self.canvas.G, 'degree') + if (self.canvas.path != []): + if action == FNP: + net = nwt.Network() + G1 = net.filterBorder(self.canvas.G) + BB = nwt.AABB(G1) + self.canvas.set_graph(G1, BB.A, BB.B, subgraph=True) + self.test.canvas.set_data(G1, BB.A, BB.B, 16) + self.canvas.refresh() + self.test.canvas.refresh() + #self.canvas.set_data() + #if action == NC: # self.canvas.color_vertices(self.canvas.G, not self.color) # self.color = not self.color -# if action == EXP: -# nwt.Network.write_vtk(self.canvas.G, "./nwt.vtk") + if action == EXP: + nwt.Network.write_vtk(self.canvas.G, "./nwt_small.vtk") # if action == EXP_adv: # nwt.Network.write_vtk(self.canvas.G, "./nwt_median_binned.vtk") # nwt.Network.write_vtk(self.canvas.G, "./nwt_median_non_binned.vtk", binning=False) @@ -158,36 +238,221 @@ class GraphWidget(QtWidgets.QWidget): #self.canvas.expand_clusters(self.canvas.G, self.canvas.n_c) self.canvas.animate(old_pos, new_pos) + if action == CL: + old_pos = self.canvas.G.vertex_properties["pos"].get_2d_array(range(3)).T + self.canvas.voronoi_layout() + new_pos = self.canvas.G.vertex_properties["pos"].get_2d_array(range(3)).T + if self.other != None: + other_old_pos = self.other.canvas.G.vertex_properties["pos"].get_2d_array(range(3)).T + self.other.canvas.voronoi_layout(G_c = self.canvas.G_cluster) + other_new_pos = self.other.canvas.G.vertex_properties["pos"].get_2d_array(range(3)).T + self.other.canvas.animate(other_old_pos, other_new_pos) + self.canvas.animate(old_pos, new_pos) #self.canvas.size_vertices(self.canvas.G, 'degree_volume') else: if self.canvas.view[0][0] >= 0.0010: menu = QtWidgets.QMenu(self) - NS = menu.addAction('Display Node Info') + MnOC = menu.addAction('Minimize Other Clusters') + RA = menu.addAction('Reset Alpha') + NI = menu.addAction('Display Node Info') + CI = menu.addAction('Display Cluster Info') action = menu.exec_(event.native.globalPos()) - if action == NS: + if action == MnOC: + self.canvas.set_current(event) + self.canvas.refresh() + c_id = self.canvas.get_clicked_id(event) + + cluster_id = self.canvas.G.vp["clusters"][self.canvas.G.vertex(c_id)] + self.select.emit(self.canvas.get_cluster(cluster_id)) + if action == RA: + t = [] + self.select.emit(self.canvas.get_cluster(t)) + if action == NI: + self.canvas.set_current(event) + self.canvas.refresh() + c_id = self.canvas.get_clicked_id(event) + self.canvas.refresh() print("Display Node Info") + self.w = NodeInfoWidget() + + #generate the subgraph around the node + vfilt = np.zeros([self.canvas.G.num_vertices(), 1], dtype="bool") + center = self.canvas.G.vp["pos"][self.canvas.G.vertex(c_id)] + for v in self.canvas.G.vertex(c_id).all_neighbors(): + vfilt[int(v)] = 1 + vfilt[int(c_id)] = 1 + vfilt_prop = self.canvas.G.new_vertex_property("bool", vals = vfilt) + self.canvas.G.set_vertex_filter(vfilt_prop) + + #get the filtered properties + g = nwt.gt.Graph(self.canvas.G, prune=True, directed=False) + BB = nwt.AABB(g) + #print(BB.A) + #print(BB.B) + self.canvas.G.clear_filters() + self.w.setGeometry(QRect(100, 100, 900, 800)) + self.w.graph_mini1.canvas.set_graph(g, BB.A, BB.B) + self.w.graph_mini1.canvas.center_camera_on(center) + self.w.graph_mini1.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini1.canvas.color_vertices(g, "clusters") + + self.w.graph_mini2.canvas.set_graph(g, BB.A, BB.B) + self.w.graph_mini2.canvas.center_camera_on(center) + self.w.graph_mini2.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini2.canvas.color_vertices(g, "degree") + + self.w.graph_mini3.canvas.set_graph(g, BB.A, BB.B) + #self.w.graph_mini3.canvas.set_view_matrix(self.canvas.view) + self.w.graph_mini3.canvas.center_camera_on(center) + self.w.graph_mini3.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini3.canvas.color_vertices(g, "bc") + + self.w.graph_mini4.canvas.set_graph(g, BB.A, BB.B) + #self.w.graph_mini4.canvas.set_view_matrix(self.canvas.view) + self.w.graph_mini4.canvas.center_camera_on(center) + self.w.graph_mini4.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini4.canvas.color_vertices(g, "degree_volume") + + self.w.fibers_mini.canvas.set_data(g, BB.A, BB.B, 16) + self.w.show() + if action == CI: + self.canvas.set_current(event) + self.canvas.refresh() + c_id = self.canvas.get_clicked_id(event) + #self.canvas.refresh() + self.w = NodeInfoWidget(hist=True) + #self.w = NodeInfoWidget() + + cluster_id = self.canvas.G.vp["clusters"][self.canvas.G.vertex(c_id)] + num_v_in_cluster = len(np.argwhere(self.canvas.labels == cluster_id)) + vfilt = np.zeros([self.canvas.G.num_vertices(), 1], dtype="bool") + vfilt[np.argwhere(self.canvas.labels == cluster_id)] = 1 + vfilt_prop = self.canvas.G.new_vertex_property("bool", vals = vfilt) + self.canvas.G.set_vertex_filter(vfilt_prop) + + #get the filtered properties + g = nwt.gt.Graph(self.canvas.G, prune=True, directed=False) + positions = g.vertex_properties["pos"].get_2d_array(range(3)).T + center = np.sum(positions, 0)/num_v_in_cluster + self.canvas.G.clear_filters() + + BB = nwt.AABB(g) + self.canvas.G.clear_filters() + self.w.setGeometry(QRect(100, 100, 900, 800)) + self.w.graph_mini1.canvas.set_graph(g, BB.A, BB.B) + self.w.graph_mini1.canvas.center_camera_on(center) + self.w.graph_mini1.canvas.zoom_camera_on(self.canvas.scale) + + self.w.graph_mini2.canvas.set_graph(g, BB.A, BB.B) + self.w.graph_mini2.canvas.center_camera_on(center) + self.w.graph_mini2.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini2.canvas.color_vertices(g, "degree") + + self.w.graph_mini3.canvas.set_graph(g, BB.A, BB.B) + #self.w.graph_mini3.canvas.set_view_matrix(self.canvas.view) + self.w.graph_mini3.canvas.center_camera_on(center) + self.w.graph_mini3.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini3.canvas.color_vertices(g, "bc") + + self.w.graph_mini4.canvas.set_graph(g, BB.A, BB.B) + #self.w.graph_mini4.canvas.set_view_matrix(self.canvas.view) + self.w.graph_mini4.canvas.center_camera_on(center) + self.w.graph_mini4.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini4.canvas.color_vertices(g, "degree_volume") + + self.w.fibers_mini.canvas.set_data(g, BB.A, BB.B, 16) + + self.w.bar.set_Graph(g) + + self.w.show() + + print("Display Cluster Info") else: menu = QtWidgets.QMenu(self) MnOC = menu.addAction('Minimize Other Clusters') + CI = menu.addAction('Display Cluster Info') RA = menu.addAction('Reset Alpha') action = menu.exec_(event.native.globalPos()) if action == MnOC: - new_Graph = self.canvas.focus_on_cluster(self.canvas.G, c_id) - self.test.draw_new(new_Graph) + self.canvas.set_current(event) + self.canvas.refresh() + c_id = self.canvas.get_clicked_id(event, clusters=True) + self.canvas.refresh() + + cluster_id = self.canvas.G.vp["clusters"][c_id] + self.select.emit(self.canvas.get_path(cluster_id)) if action == RA: - self.canvas.reset_alpha(c_id[0]) + t = [] + self.select.emit(self.canvas.get_cluster(t)) + if action == CI: + self.canvas.set_current(event) + self.canvas.refresh() + c_id = self.canvas.get_clicked_id(event, clusters=True) + self.canvas.refresh() + + self.w = NodeInfoWidget(hist=True) + #self.w = NodeInfoWidget() + + cluster_id = self.canvas.G.vp["clusters"][c_id] + num_v_in_cluster = len(np.argwhere(self.canvas.labels == c_id)) + vfilt = np.zeros([self.canvas.G.num_vertices(), 1], dtype="bool") + vfilt[np.argwhere(self.canvas.labels == c_id)] = 1 + vfilt_prop = self.canvas.G.new_vertex_property("bool", vals = vfilt) + self.canvas.G.set_vertex_filter(vfilt_prop) + + #get the filtered properties + g = nwt.gt.Graph(self.canvas.G, prune=True, directed=False) + positions = g.vertex_properties["pos"].get_2d_array(range(3)).T + center = np.sum(positions, 0)/num_v_in_cluster + self.canvas.G.clear_filters() + + BB = nwt.AABB(g) + self.canvas.G.clear_filters() + self.w.setGeometry(QRect(100, 100, 900, 800)) + self.w.graph_mini1.canvas.set_graph(g, BB.A, BB.B) + self.w.graph_mini1.canvas.center_camera_on(center) + self.w.graph_mini1.canvas.zoom_camera_on(self.canvas.scale) + + self.w.graph_mini2.canvas.set_graph(g, BB.A, BB.B) + self.w.graph_mini2.canvas.center_camera_on(center) + self.w.graph_mini2.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini2.canvas.color_vertices(g, "degree") + + self.w.graph_mini3.canvas.set_graph(g, BB.A, BB.B) + #self.w.graph_mini3.canvas.set_view_matrix(self.canvas.view) + self.w.graph_mini3.canvas.center_camera_on(center) + self.w.graph_mini3.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini3.canvas.color_vertices(g, "bc") + + self.w.graph_mini4.canvas.set_graph(g, BB.A, BB.B) + #self.w.graph_mini4.canvas.set_view_matrix(self.canvas.view) + self.w.graph_mini4.canvas.center_camera_on(center) + self.w.graph_mini4.canvas.zoom_camera_on(self.canvas.scale) + self.w.graph_mini4.canvas.color_vertices(g, "degree_volume") + + self.w.fibers_mini.canvas.set_data(g, BB.A, BB.B, 16) + + self.w.bar.set_Graph(g) + self.w.show() + + print("Display Cluster Info") + # def selection_change(self, i): # self.canvas.size_vertices(self.canvas.G, self.cb.currentText()) + def set_other(self, other): + self.other = other + """ Handles the mouse double click event. Pass-through function. """ def on_mouse_double_click(self, event): + self.canvas.set_current(event) self.canvas.update_path(event) self.select.emit(self.canvas.get_path()) # old_pos = self.canvas.G.vertex_properties["pos"].get_2d_array(range(3)).T @@ -209,7 +474,11 @@ class GraphWidget(QtWidgets.QWidget): Pass-through function. """ def on_mouse_move(self, event): - n = 2 + self.canvas.set_current(event) + self.canvas.refresh() + c_id = self.canvas.get_clicked_id(event) + self.canvas.refresh() + print(c_id) """ Internal function that interacts with the tube visualization. diff --git a/GuiVisPy_tube.py b/GuiVisPy_tube.py index 908918f..f26087c 100644 --- a/GuiVisPy_tube.py +++ b/GuiVisPy_tube.py @@ -57,23 +57,28 @@ graph.canvas.create_native() graph.connect(fibers) fibers.connect(graph) -#initialize the layout -layout.addWidget(graph.canvas.native, 0, 0, 2, 3) -layout.addWidget(fibers.canvas.native, 0, 2, 2, 3) -layout.setColumnStretch(0, 2) -layout.setRowStretch(0, 2) -layout.setColumnStretch(2, 1) -layout.setRowStretch(0, 1) +#vspacer = QtWidgets.QSpacerItem(10,10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) -top.setLayout(layout) +#initialize the layoutddddddddddd -top.show() +#addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan +#, Qt::Alignment alignment = Qt::Alignment()) +#layout.addWidget(graph.canvas.native, 0, 0, 2, 3) +#layout.addItem(vspacer, 0, 1, 2, 3) +#layout.addWidget(fibers.canvas.native, 0, 2, 2, 3) + +layout.addWidget(graph.canvas.native, 0, 0, 2, 3) +#layout.addItem(vspacer, 0, 2, 2, 1) +layout.addWidget(fibers.canvas.native, 0, 4, 2, 3) +#layout.setColumnStretch(0, 2) +#layout.setRowStretch(0, 2) +#layout.setColumnStretch(2, 1) +#layout.setRowStretch(0, 1) -#def draw_histogram(G, value): -# vals = G.edge_properties[value].get_array() -# y, x = np.histogram(vals,40) -# hist.plot(x,y, stepMode=True, fillLevel=0, brush=(0,0,255,150)) +top.setLayout(layout) +print(layout.getContentsMargins()) +top.show() def load_nwt(filepath): net = nwt.Network(filepath) @@ -115,6 +120,12 @@ fibers.canvas.set_data(G, bbl, bbu, 16) #fibers.draw_all(G, center, fibers, graph, node_tex) graph.set_g_view(fibers) +graph.label = QtWidgets.QLabel(graph) +graph.label.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Sunken) +graph.label.setText("STUFF") +graph.label.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignRight) +graph.label.raise_() + ## Start Qt event loop unless running in interactive mode. if __name__ == '__main__': #import sys diff --git a/GuiVisPy_tube_dual.py b/GuiVisPy_tube_dual.py new file mode 100644 index 0000000..0d2bdaf --- /dev/null +++ b/GuiVisPy_tube_dual.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Jan 31 15:29:40 2019 + +@author: pavel +`""" + +from vispy import app +import vispy + +import network_dep as nwt + +#from pyqtgraph.Qt import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtGui, QtWidgets +#import pyqtgraph as pg +import numpy as np +import math + +from mpl_toolkits.mplot3d import Axes3D +#import matplotlib +#import matplotlib.pyplot as plt +#matplotlib.use('Qt5Agg') + +from GraphWidget import GraphWidget +from TubeWidget import TubeWidget +#vispy.use(app='egl') + + +DEBUG = False + +#set the backend. for different versions of PyQt +app.use_app(backend_name='PyQt5') + +app.set_interactive(True) + +#Define a top level application +appMain = QtWidgets.QApplication([]) +#QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts, True) + +##Define a toplevel Widget +top = QtWidgets.QWidget() +top.resize(900, 900) + + +#fibers = FiberView() +fibers = TubeWidget() +fibers.canvas.create_native() +#fibers = gl.GLViewWidget() + +#plt = hist.addPlot() + +layout = QtWidgets.QGridLayout() +graph = GraphWidget() +graph.canvas.create_native() + + +fibers2 = TubeWidget() +fibers2.canvas.create_native() + +graph2 = GraphWidget() +graph2.canvas.create_native() + +graph.connect(fibers) +fibers.connect(graph) + +graph2.connect(fibers2) +fibers2.connect(graph2) + +#vspacer = QtWidgets.QSpacerItem(10,10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + +#initialize the layoutddddddddddd + +#addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan +#, Qt::Alignment alignment = Qt::Alignment()) +#layout.addWidget(graph.canvas.native, 0, 0, 2, 3) +#layout.addItem(vspacer, 0, 1, 2, 3) +#layout.addWidget(fibers.canvas.native, 0, 2, 2, 3) + +layout.addWidget(graph.canvas.native, 0, 0, 1, 3) +#layout.addItem(vspacer, 0, 2, 2, 1) +layout.addWidget(fibers.canvas.native, 0, 4, 1, 3) + +layout.addWidget(graph2.canvas.native, 1, 0, 1, 3) +#layout.addItem(vspacer, 0, 2, 2, 1) +layout.addWidget(fibers2.canvas.native, 1, 4, 1, 3) + +#layout.setColumnStretch(0, 2) +#layout.setRowStretch(0, 2) +#layout.setColumnStretch(2, 1) +#layout.setRowStretch(0, 1) + +top.setLayout(layout) +print(layout.getContentsMargins()) +top.show() + +def load_nwt(filepath): + net = nwt.Network(filepath) + G = net.createFullGraph_gt() + G = net.filterDisconnected(G) + #G = net.gen_spring_onion_layout(G, 'degree', 1.0, 1000, 0.01, 1.0) + #G = net.filterFullGraph_gt(G, erode=True) + #G = net.filterFullGraph_gt(G, erode=True) + #G = net.gen_new_fd_layout(G) + #G = net.filterBorder(G) + #nwt.Network.saveGraph_gt(nwt, G, "FilteredNetwork_JACK_3.nwt") + color = np.zeros(4, dtype = np.double) + color = [0.0, 1.0, 0.0, 1.0] + G.edge_properties["RGBA"] = G.new_edge_property("vector", val=color) + color = [1.0, 0.0, 0.0, 0.9] + G.vertex_properties["RGBA"] = G.new_vertex_property("vector", val=color) + bbl, bbu = net.aabb() + + + return G, bbl, bbu + +G, bbl, bbu = load_nwt("/home/pavel/Documents/Python/GraphGuiQt/network_4.nwt") + +G2, bbl2, bbu2 = load_nwt("/home/pavel/Documents/Python/GraphGuiQt/network_4.nwt") +#G2, bbl2, bbu2 = load_nwt("/home/pavel/Documents/Python/GraphGuiQt/network_4.nwt") +#nwt.Network.write_vtk(G) + +#G, bbl, bbu = load_nwt("/home/pavel/Documents/Python/GraphGuiQt/net`````````work_test_251_1kx3_short_NEW.nwt") +#ret = nwt.Network.get_affinity_matrix(G, "length") +#node_image = QtGui.QImage("/home/pavel/Documents/Python/GraphGuiQt/node_tex.jpg") +#node_tex = QtGui.QBitmap.fromImage(node_image) + +if DEBUG: + print(node_tex.depth()) +#fibers.opts['distance'] = 5 +# item = NodeItem(G) +# graph.addItem(item) +#draw_histogram(G, "length") + + #self.canvas.events.mouse_press.connect(o_canvas.on_mouse_press) + #self.canvas.events.mouse_release.connect(o_canvas.on_mouse_release) + #self.canvas.events.mouse_move.connect(o_canvas.on_mouse_move) + #self.canvas.events.mouse_wheel.connect(o_canvas.on_mouse_wheel) +#fibers.canvas.events.mouse_press.connect(fibers2.mouse_press) +#fibers.canvas.events.mouse_release.connect(fibers2.mouse_release) +#fibers.canvas.events.on_mouse_wheel.connect(fibers2.canvas.on_mouse_wheel) + +graph.canvas.set_data(G, bbl, bbu) +fibers.canvas.set_data(G, bbl, bbu, 16) +fibers.set_other(fibers2) +fibers2.set_other(fibers) +graph.set_other(graph2) +graph2.set_other(graph) + +graph2.canvas.set_data(G2, bbl2, bbu2, G_other=graph.canvas.G) +fibers2.canvas.set_data(G2, bbl2, bbu2, 16) +#fibers.draw_all(G, center, fibers, graph, node_tex) +graph.set_g_view(fibers) +graph2.set_g_view(fibers2) + + +#fibers.link_cameras(fibers2) +#fibers2.link_cameras(fibers) + +## Start Qt event loop unless running in interactive mode. +if __name__ == '__main__': + #import sys + #if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + #QtGui.QApplication.instance().exec_() + app.set_interactive(enabled=True) + app.run() + diff --git a/HistogramWidget.py b/HistogramWidget.py new file mode 100644 index 0000000..8d2073e --- /dev/null +++ b/HistogramWidget.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Mar 3 13:47:39 2020 + +@author: pavel +""" + +from PyQt5 import QtCore, QtGui, QtWidgets +import network_dep as nwt +import vispy.plot as vp +#import vispy.scene.visuals. as Histogram +from vispy.scene.visuals import Histogram as Histogram + +import numpy as np + +DEBUG = False + + +class HistogramWidget(QtWidgets.QWidget): + def __init__(self): + super(HistogramWidget, self).__init__() + box = QtWidgets.QVBoxLayout(self) + self.resize(500,500) + self.setLayout(box) + self.canvas = vp.Fig(show=False) + self.hist = self.canvas[0, 0].histogram(np.random.rand(100)) + + #data = np.random.rand(100) + #self.canvas[0, 0].histogram(data) + #self.canvas = Histogram() + self.setUpdatesEnabled(True) + box.addWidget(self.canvas.native) + self.G = None + + self.canvas.events.mouse_press.connect(self.on_mouse_press) + #self.canvas.events.mouse_release.connect(self.on_mouse_release) + #self.canvas.events.mouse_move.connect(self.on_mouse_move) + #self.canvas.events.mouse_double_click.connect(self.on_mouse_double_click) + self.current_color = 'clusters' + + def on_mouse_press(self, event): + print("mouse_press") + if event.button == 2: + menu = QtWidgets.QMenu(self) + tmp = menu.addMenu('Histogram Metric') + edge_properties = self.G.edge_properties.keys() + edge_actions = [] + for i in range(len(edge_properties)): + if(edge_properties[i] != "map" or edge_properties[i] != "RGBA"): + edge_actions.append(tmp.addAction(edge_properties[i])) + + action = menu.exec_(event.native.globalPos()) + for i in range(len(edge_actions)): + if action == edge_actions[i]: + self.set_data(prop=edge_properties[i]) + + print("mouse_press") + + def on_mouse_double_click(self, event): + print("mouse_double") + + def on_mouse_release(self, event): + print("mouse_release") + + def on_mouse_move(self, event): + print("mouse_move") + + def set_Graph(self, G): + self.G = G + #self.canvas[0, 0].histogram(np.random.rand(10)) + self.set_data() + + def gen_mesh(self, data, bins=10, orientation='h'): + + data = np.asarray(data) + if data.ndim != 1: + raise ValueError('Only 1D data currently supported') + X, Y = (0, 1) if orientation == 'h' else (1, 0) + + # do the histogramming + data, bin_edges = np.histogram(data, bins) + # construct our vertices + rr = np.zeros((3 * len(bin_edges) - 2, 3), np.float32) + rr[:, X] = np.repeat(bin_edges, 3)[1:-1] + rr[1::3, Y] = data + rr[2::3, Y] = data + bin_edges.astype(np.float32) + # and now our tris + tris = np.zeros((2 * len(bin_edges) - 2, 3), np.uint32) + offsets = 3 * np.arange(len(bin_edges) - 1, + dtype=np.uint32)[:, np.newaxis] + tri_1 = np.array([0, 2, 1]) + tri_2 = np.array([2, 0, 3]) + tris[::2] = tri_1 + offsets + tris[1::2] = tri_2 + offsets + + return rr, tris + + + def set_data(self, prop = 'length'): + #self.canvas = vp.Fig(show=False) + #, xlabel=prop, ylabel='#' + #self.canvas.clear() + #self.canvas[0, 0]._configured = False + p = self.G.ep[prop].get_array().T + self.canvas.bgcolor = 'w' + rr, tris = self.gen_mesh(p) + self.hist.set_data(rr, tris, color = 'b') + #self.canvas.context.clear(color='w', depth=True) + #self.canvas.central_widget().context.clear(color='w', depth=True) + + self.canvas[0, 0].xlabel.text = prop + self.canvas[0, 0].ylabel.text = '# of occurances' + self.canvas[0, 0].title.text = 'edge property distribution' + for hist, pwidget in zip([self.hist], self.canvas.plot_widgets): + #x_data = hist._line.pos[:, 0] + #y_data = hist._line.pos[:, 1] + #print(hist._bounds, hist._bounds[:, 0], hist._bounds[:, 1]) + x_range = hist._bounds[0][0], hist._bounds[0][1] + y_range = hist._bounds[1][0], hist._bounds[1][1] + + + pwidget.view.camera.set_range(x=x_range, y=y_range) + #self.canvas[0, 0]._configured = False + #self.canvas[0, 0].histogram(p, color = 'b') + self.canvas.update() + self.canvas.show() + + + \ No newline at end of file diff --git a/TubeCanvas.py b/TubeCanvas.py index a6fc59e..e7a5481 100644 --- a/TubeCanvas.py +++ b/TubeCanvas.py @@ -95,7 +95,7 @@ class TubeDraw(scene.SceneCanvas): self.bbu = bbu self.bbl = bbl bb = nwt.AABB(G).resample_sides(3) - + print(self.bbu, self.bbl, self.camera) #create program self.gen_cylinder_vbo(self.G, self.num_sides) @@ -115,8 +115,10 @@ class TubeDraw(scene.SceneCanvas): self.program['u_projection'] = self.projection self.program.bind(self.vbo) + print(self.bbu, self.bbl, self.camera) gloo.set_clear_color('white') self.center = (bbu-bbl)/2.0 + print(self.bbu, self.bbl, self.camera) self.translate = [-self.center[0], -self.center[1], -self.center[2]] self.bb = np.ones((26, 3), dtype=np.float32) @@ -132,6 +134,7 @@ class TubeDraw(scene.SceneCanvas): ##### prototype ##### self.camera = self.camera - self.translate + print(self.camera) self.program['u_eye'] = self.camera self.up = np.cross((np.asarray(self.center, dtype=np.float32)-np.asarray(self.camera, dtype=np.float32)), np.asarray(self.up)) self.program['u_up'] = self.up @@ -466,19 +469,17 @@ class TubeDraw(scene.SceneCanvas): #print(event.delta[1]) self.refresh() - + def update_view(self, event): + self.location = event.pos + #self.program['u_view'] = self.view + self.down = True #Handles the mouse press event to rotate the camera if the left mouse button #if clicked down. def on_mouse_press(self, event): - def update_view(): - self.location = event.pos - #self.program['u_view'] = self.view - self.down = True - if(event.button == 1): - update_view() + self.update_view(event) #Handles the rotation of the camera using a quaternion centered around the diff --git a/TubeWidget.py b/TubeWidget.py index f0521dd..9eeea8e 100644 --- a/TubeWidget.py +++ b/TubeWidget.py @@ -32,7 +32,9 @@ class TubeWidget(QtWidgets.QWidget): box.addWidget(self.canvas.native) self.camera = [0,0,0] self.down = False + self.other = None + self.canvas.location = self.geometry().center() self.canvas.events.mouse_press.connect(self.on_mouse_press) self.canvas.events.mouse_release.connect(self.on_mouse_release) self.canvas.events.mouse_move.connect(self.on_mouse_move) @@ -40,15 +42,41 @@ class TubeWidget(QtWidgets.QWidget): #self.show() + + def link_cameras(self, o_canvas): + self.canvas.events.mouse_press.connect(o_canvas.on_mouse_press) + self.canvas.events.mouse_release.connect(o_canvas.on_mouse_release) + self.canvas.events.mouse_move.connect(o_canvas.on_mouse_move) + self.canvas.events.mouse_wheel.connect(o_canvas.on_mouse_wheel) + + def set_other(self, other): + self.other = other + + def pass_event(self, event, case): + if self.other != None: + if case == 0: + self.other.canvas.on_mouse_wheel(event) + if case == 1: + self.other.canvas.on_mouse_press(event) + if case == 2: + self.other.canvas.on_mouse_move(event) + if case == 3: + self.other.canvas.on_mouse_release(event) + #if case == 4: + # self.other.sendCameraInfo() + + #Handles the mouse release event def on_mouse_release(self, event): self.down=False self.sendCameraInfo() + self.pass_event(event, 3) #Handles the mouse move event def on_mouse_move(self, event): if self.down: self.sendCameraInfo() + self.pass_event(event, 2) #Handles the mouse press events def on_mouse_press(self, event): @@ -59,11 +87,14 @@ class TubeWidget(QtWidgets.QWidget): action = menu.exec_(event.native.globalPos()) if action == NS: self.save_stl_mesh() + else: + self.pass_event(event, 1) #Handles the mouse wheel event def on_mouse_wheel(self, event): self.sendCameraInfo() + self.pass_event(event, 0) #controls the emit function of the QT class to send a signal to the slot #located in the other window. @@ -73,6 +104,7 @@ class TubeWidget(QtWidgets.QWidget): #print("stuff", self.view[3, 0], self.view[3, 1], self.view[3, 2]) if DEBUG: print("stuff", self.camera[0], self.camera[1], self.camera[2]) + #self.pass_event(None, 4) self.sigUpdate.emit(self.camera[0], self.camera[1], self.camera[2]) """ diff --git a/graph_shaders.py b/graph_shaders.py index 9dc9265..b3e83b8 100644 --- a/graph_shaders.py +++ b/graph_shaders.py @@ -100,7 +100,7 @@ void main() } else if( d < 0.0 ) { - if(v_zoom_level < 0.0010) + if(v_zoom_level < 0.0024) { float alpha = d/v_antialias; alpha = new_alpha(v_zoom_level); @@ -119,27 +119,28 @@ void main() else { float alpha = d/v_antialias; - if(v_zoom_level < 0.0010) + if(v_zoom_level < 0.0024) alpha = new_alpha(v_zoom_level); else alpha = exp(-alpha*alpha); - if (r > 0 && v_zoom_level >= 0.0010) + if (r > 0 && v_zoom_level >= 0.0024) gl_FragColor = vec4(v_fg_color.rgb, alpha*v_fg_color.a); else - if(v_zoom_level < 0.0010) + if(v_zoom_level < 0.0024) if(vec3(gl_Color.rgb) != vec3(v_bg_color.rgb)) gl_FragColor = mix(vec4(1,1,1,0.9), v_bg_color, max(1.0-alpha, 0.3)); else gl_FragColor = vec4(gl_Color.rgb, max(1.0-alpha, 0.1)); else { - //gl_FragColor = mix(v_bg_color, v_fg_color, alpha); vec3 color = vec3(1.0, 0.0, 0.0); - vec3 normal = normalize(vec3(p.xy, d)); - vec3 direction = normalize(vec3(1.0, 1.0, 5.0)); - float diffuse = max(0.0, dot(direction, normal)); - float specular = pow(diffuse, 24.0); - gl_FragColor = mix(vec4(max(diffuse*v_bg_color.rgb, specular*vec3(0.7)), 1.0), v_fg_color, alpha); + gl_FragColor = mix(v_bg_color, v_fg_color, alpha); + //vec3 color = vec3(1.0, 0.0, 0.0); + //vec3 normal = normalize(vec3(p.xy, d)); + //vec3 direction = normalize(vec3(1.0, 1.0, 1.0)); + //float diffuse = max(0.0, dot(direction, normal)); + //float specular = pow(diffuse, 24.0); + //gl_FragColor = mix(vec4(max(diffuse*v_bg_color.rgb, specular*vec3(1.0)), 1.0), v_fg_color, alpha); } } @@ -151,7 +152,7 @@ void main() float r = marker(gl_PointCoord, size); float d = abs(r) - t; float alpha = d/v_antialias; - if(v_zoom_level < 0.0010) + if(v_zoom_level < 0.0024) alpha = new_alpha(v_zoom_level); else alpha = exp(-alpha*alpha); @@ -172,7 +173,7 @@ float marker(vec2 P, float size) float new_alpha(float zoom_level) { - float val = (zoom_level - 0.0010)/(0.00075-0.0010); + float val = (zoom_level - 0.0024)/(0.00075-0.0024); if(val < 0) { val = 0; @@ -243,14 +244,14 @@ void main() else alpha = 0.5; - if(v_zoom_level < 0.0010) + if(v_zoom_level < 0.0024) alpha = new_alpha(v_zoom_level); gl_FragColor = vec4(v_fg_color.rgb, alpha); } float new_alpha(float zoom_level) { - float val = (zoom_level-0.00075)/(0.0010-0.00075); + float val = (zoom_level-0.00075)/(0.0024-0.00075); if(val < 0.) { val = 0.; diff --git a/network_4.nwt b/network_4.nwt new file mode 100755 index 0000000..20daf07 Binary files /dev/null and b/network_4.nwt differ diff --git a/network_dep.py b/network_dep.py index cbf965f..08535c7 100755 --- a/network_dep.py +++ b/network_dep.py @@ -254,9 +254,9 @@ class AABB(): # or a normal graph. self.is_dual = is_dual #minimum vertex - self.A = np.full((3,1), 1000000.0, dtype=float) + self.A = np.full(3, 1000000.0, dtype=float) #maximum vertex - self.B = np.full((3,1), -1000000.0, dtype=float) + self.B = np.full(3, -1000000.0, dtype=float) if(is_dual == False): #find the minumum and the maximum of the graph. for v in G.vertices(): @@ -507,26 +507,26 @@ class VisitorClassPartition(gt.BFSVisitor): self.dist[e.target()] = self.dist[e.source()] + 1 class Network: - def __init__(self, filename, clock=False): + def __init__(self, filename=None, clock=False): if clock: start_time = time.time() - - with open(filename, "rb") as file: - header = file.read(72) - bytes = file.read(4) - numVertex = int.from_bytes(bytes, byteorder='little') - bytes = file.read(4) - numEdges = int.from_bytes(bytes, byteorder='little') - - self.N = [] - self.F = [] - for i in range(numVertex): - node = NWT.readVertex(file) - self.N.append(node) - - for i in range(numEdges): - edge = NWT.readFiber(file) - self.F.append(edge) + if filename!=None: + with open(filename, "rb") as file: + header = file.read(72) + bytes = file.read(4) + numVertex = int.from_bytes(bytes, byteorder='little') + bytes = file.read(4) + numEdges = int.from_bytes(bytes, byteorder='little') + + self.N = [] + self.F = [] + for i in range(numVertex): + node = NWT.readVertex(file) + self.N.append(node) + + for i in range(numEdges): + edge = NWT.readFiber(file) + self.F.append(edge) if clock: print("Network initialization: " + str(time.time() - start_time) + "s") ''' @@ -821,9 +821,10 @@ class Network: for v in G.vertices(): pt = np.array([G.vertex_properties["p"][v][0], G.vertex_properties["p"][v][1], G.vertex_properties["p"][v][2]]) if G.vertex_properties["degree"][v] == 1 and bb.distance(pt) < 5.0: - TFv[v] = False - for e in v.all_edges(): - TFe[G.edge(e.source(), e.target())] = False + if G.vp["exclude"][v] == False: + TFv[v] = False + for e in v.all_edges(): + TFe[G.edge(e.source(), e.target())] = False else: #print("I have entered this method") for v in G.vertices(): @@ -1144,14 +1145,14 @@ class Network: #find all 2 neighbors for i in one_n: for j in G.vertex(i).all_neighbors(): - if(int(j) not in one_n): - two_n.append(int(j)) +# if(int(j) not in one_n): + two_n.append(int(j)) #find all 3 neighbors for i in two_n: for j in G.vertex(i).all_neighbors(): - if(int(j) not in one_n and int(j) not in two_n): - three_n.append(int(j)) +# if(int(j) not in one_n and int(j) not in two_n): + three_n.append(int(j)) #we do not keep ones that have already counted, i.e. a vertex #appears in all 3 arrays only once. @@ -1209,32 +1210,50 @@ class Network: start = time.time() pos = G.vertex_properties["pos"].get_2d_array(range(3)).T + #x = np.zeros(3, dtype=float) + weight = G.vertex_properties[v_property].get_array().T for n in range(n_steps+1): forces = np.zeros([G.num_vertices(), 3]) + center = np.sum(pos, 0)/G.num_vertices() #pos = G.vertex_properties["pos"].get_2d_array(range(2)).T if Sum: for v in G.vertices(): for i in o1_n[int(v)]: x = pos[int(i), :] - pos[int(v), :] - forces[int(v), 0] += -k*(x[0]) - forces[int(v), 1] += -k*(x[1]) + l = np.sqrt(x[0]*x[0] + x[1]*x[1]) + forces[int(v), 0] += -k*(l-1.0)*(x[0]) + forces[int(v), 1] += -k*(l-1.0)*(x[1]) for i in o2_n[int(v)]: - x = pos[int(i)] - pos[int(v)] - forces[int(v), 0] += -k*(x[0])/2.0 - forces[int(v), 1] += -k*(x[1])/2.0 + x = pos[int(i), :] - pos[int(v), :] + l = np.sqrt(x[0]*x[0] + x[1]*x[1]) + forces[int(v), 0] += -k*(l-2.0)*(x[0])/2.0 + forces[int(v), 1] += -k*(l-2.0)*(x[1])/2.0 for i in o3_n[int(v)]: - x = pos[int(i)] - pos[int(v)] - forces[int(v), 0] += -k*(x[0])/4.0 - forces[int(v), 1] += -k*(x[1])/4.0 + x = pos[int(i), :] - pos[int(v), :] + l = np.sqrt(x[0]*x[0] + x[1]*x[1]) + forces[int(v), 0] += -k*(l-3.0)*(x[0])/4.0 + forces[int(v), 1] += -k*(l-3.0)*(x[1])/4.0 + x = -center[:] + pos[int(v), :] + l = np.sqrt(x[0]*x[0] + x[1]*x[1]) + forces[int(v), 0] += -k/l*(x[0]) + forces[int(v), 1] += -k/l*(x[1]) + else: for v in G.vertices(): for i in o3_n[int(v)]: x = pos[int(i)] - pos[int(v)] - forces[int(v), 0] = -k*(x[0])/4.0 - forces[int(v), 1] = -k*(x[1])/4.0 - + if np.sqrt(np.power(-k*(x[0])/4.0, 2) + np.sqrt(np.power(-k*(x[1])/4.0, 2))) > \ + np.sqrt(np.power(forces[int(v), 0], 2) + np.sqrt(np.power(forces[int(v), 0], 2))): + + forces[int(v), 0] = -k*(x[0])/4.0 + forces[int(v), 1] = -k*(x[1])/4.0 + + x = pos[int(v), :] - center[:] + forces[int(v), 0] += -k*(x[0])/100.0 + forces[int(v), 1] += -k*(x[1])/100.0 +# forces[:, 0] = forces[:, 0]/weight[:] forces[:, 1] = forces[:, 1]/weight[:] # if n < 1: @@ -1248,6 +1267,7 @@ class Network: for v in G.vertices(): if n < 1: velocities = forces * time_step + #pos[int(v), :] = pos[int(v), :] + velocities[int(v), :] * time_step #G.vertex_properties["pos"][v] = pos[int(v), :] + forces[int(v), :] * time_step else: pos[int(v), :] = pos[int(v), :] + velocities[int(v), :] * time_step @@ -1448,7 +1468,7 @@ class Network: degree = G.new_vertex_property("int") #degree degree_volume = G.new_vertex_property("double") #degree scaled by the volume of all in fibers degree_tortuosity = G.new_vertex_property("double") #degree scaled by the tortuosity of all in fibers. - + #add all the required edge properties #G.properties[("x,y,z,r")] = G.new_edge_property("vector 0.25) + { + vec2 p = (v_value.xy); + vec3 normal = normalize(vec3(p.xy, 0.25)); + vec3 direction = normalize(vec3(0.0, 0.0, 5.0)); + float diffuse = max(0.0, dot(direction, normal)); + float specular = pow(diffuse, 24.0); + gl_FragColor = vec4(max(diffuse*v_cluster_color.rgb, specular*vec3(0.6)), exp(-n_alpha*n_alpha)); } if(dist > 0.3 && 0.55 > dist) { @@ -114,7 +124,12 @@ void main() } else { - gl_FragColor = vec4(v_bg_color.rgb, n_alpha*alpha); + vec3 normal = normalize(vec3(v_value.xy, 1.0)); + vec3 direction = normalize(vec3(0.0, 0.0, 5.0)); + float diffuse = max(0.0, dot(direction, normal)); + float specular = pow(diffuse, 24.0); + //gl_FragColor = vec4(v_bg_color.rgb, n_alpha); + gl_FragColor = vec4(max(diffuse*v_bg_color.rgb, specular*vec3(1.0)), n_alpha); } } angle = atan(v_value[1]/dist, v_value[0]/dist); @@ -123,24 +138,36 @@ void main() //THIS NEED TO BE FIXED if(dist > 0.61 && 0.9 > dist) { + vec3 normal = normalize(vec3(v_value.xy, 1.0)); + vec3 direction = normalize(vec3(0.0, 0.0, 5.0)); + float diffuse = max(0.0, dot(direction, normal)); + float specular = pow(diffuse, 24.0); if(angle < v_outer_arc_length[1]) { - gl_FragColor = vec4(0.32, 0.61, 0.93, n_alpha); + vec3 color = vec3(0.32, 0.61, 0.93); + // gl_FragColor = vec4(0.32, 0.61, 0.93, n_alpha); + gl_FragColor = vec4(max(diffuse*color, specular*vec3(1.0)), n_alpha); //gl_FragColor = vec4(1.0, 0.0, 0.0, n_alpha); } else if(angle > v_outer_arc_length[1] && angle < v_outer_arc_length[2]) { - gl_FragColor = vec4(0.337, 0.866, 0.415, n_alpha); + vec3 color = vec3(0.337, 0.866, 0.415); + gl_FragColor = vec4(max(diffuse*color, specular*vec3(1.0)), n_alpha); + //gl_FragColor = vec4(0.337, 0.866, 0.415, n_alpha); //gl_FragColor = vec4(0.0, 1.0, 0.0, n_alpha); } else if(angle > v_outer_arc_length[2] && angle < v_outer_arc_length[3]) { - gl_FragColor = vec4(0.988, 0.631, 0.058, n_alpha); + vec3 color = vec3(0.988, 0.631, 0.058); + gl_FragColor = vec4(max(diffuse*color, specular*vec3(1.0)), n_alpha); + //gl_FragColor = vec4(0.988, 0.631, 0.058, n_alpha); //gl_FragColor = vec4(0.0, 0.0, 1.0, n_alpha); } else //if(angle > v_outer_arc_length[3] && angle < pi) { - gl_FragColor = vec4(0.93, 0.949, 0.329, n_alpha); + vec3 color = vec3(0.93, 0.949, 0.329); + gl_FragColor = vec4(max(diffuse*color, specular*vec3(1.0)), n_alpha); + //gl_FragColor = vec4(0.93, 0.949, 0.329, n_alpha); //gl_FragColor = vec4(1.0, 1.0, 0.0, n_alpha); } } @@ -172,7 +199,7 @@ float atan2(float y, float x) float new_alpha(float zoom_level) { - float val = 1 - (zoom_level - 0.00075)/(0.0010-0.00075); + float val = 1 - (zoom_level - 0.0015)/(0.0024-0.0015); if(val > 1.0) { val = 1.0; @@ -238,14 +265,14 @@ void main() else alpha = 0.0; - if(v_zoom_level < 0.0010) + if(v_zoom_level < 0.0024) alpha = new_alpha(v_zoom_level); gl_FragColor = vec4(v_fg_color.rgb, alpha); } float new_alpha(float zoom_level) { - float val = 1 - (zoom_level - 0.00075)/(0.0010-0.00075); + float val = 1 - (zoom_level - 0.0015)/(0.0024-0.0015); if(val > 1.0) { val = 1.0; diff --git a/tube_shaders.py b/tube_shaders.py index aca4b04..b62c434 100644 --- a/tube_shaders.py +++ b/tube_shaders.py @@ -10,7 +10,7 @@ Created on Mon Aug 5 15:58:30 2019 VERT_SHADER = """ // Uniforms // ------------------------------------ -uniform vec4 u_bb[26]; +uniform vec3 u_bb[26]; uniform mat4 u_model; //uniform mat4 u_view; uniform mat4 u_projection; diff --git a/voronoi_test.py b/voronoi_test.py index ca51823..3769a36 100644 --- a/voronoi_test.py +++ b/voronoi_test.py @@ -162,7 +162,7 @@ class Polygon_mass: def plot_graph(self, D, x, y): plt.figure() ext = [self.a[0], self.b[0], self.a[1], self.b[1]] - #plt.imshow(D, origin = 'lower', extent=ext) + plt.imshow(D, origin = 'lower', extent=ext) p = self.G.vertex_properties["pos"].get_2d_array(range(2)).T plt.scatter(p[:,0], p[:,1], color='r') plt.scatter(self.CoM[0], self.CoM[1], marker='*') @@ -180,8 +180,8 @@ class Polygon_mass: # plt.plot((pts[segs[i][0]][0], pts[segs[i][1]][0]), (pts[segs[i][0]][1], pts[segs[i][1]][1]), color='b') plt.gca().set_title(str(self.polygon.area)) - for e in self.torque: - plt.quiver(e[2][0], e[2][1], e[1][0], e[1][1], color='r') +# for e in self.torque: +# plt.quiver(e[2][0], e[2][1], e[1][0], e[1][1], color='r') #tri = Delaunay(np.asarray(self.polygon.exterior.coords.xy).T) #tri = triangulate(mesh, 'pq20a' + str(self.polygon.area/100.0)+'D') #delaunay_plot_2d(tri) @@ -259,7 +259,7 @@ class Polygon_mass: # #nlist = c.trace(level, level, 0) # #segs = nlist[:len(nlist)//2] #self.polygon = Polygon(pts) - #self.plot_graph(D, x, y) + self.plot_graph(D, x, y) @@ -684,8 +684,8 @@ def gen_Eades(G, masses, M = 10): for j in masses: j.translate(0.001) -def onion_springs(G, masses, min_length): - for v in G.vertices(): +#def onion_springs(G, masses, min_length): +# for v in G.vertices(): -- libgit2 0.21.4