diff --git a/GraphCanvas.py b/GraphCanvas.py index 38b4743..cece411 100644 --- a/GraphCanvas.py +++ b/GraphCanvas.py @@ -13,6 +13,7 @@ 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 +import copy import numpy as np import math @@ -91,7 +92,6 @@ class GraphCanvas(scene.SceneCanvas): self.moving = False self.moving_cluster = False self.selection = False - n = 10 ne = 10 #Init dummy structures @@ -209,6 +209,9 @@ 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 + print(self.context.config) def on_timer(self, event): #get the temporary positions of the vertices (and edges) @@ -285,7 +288,7 @@ class GraphCanvas(scene.SceneCanvas): self.program_s.bind(self.vbo_s) self.program_e_s.bind(self.vbo_cluster_lines) - self.update() + self.refresh() """ Function that recolors vertices based on the selected statistic @@ -306,7 +309,7 @@ class GraphCanvas(scene.SceneCanvas): self.vbo = gloo.VertexBuffer(self.data) self.program.bind(self.vbo) #self.program_e.bind(self.vbo) - self.update() + self.refresh() def update_color_buffers(self): color = self.G.vertex_properties["RGBA"].get_2d_array(range(4)).T @@ -352,7 +355,7 @@ class GraphCanvas(scene.SceneCanvas): self.vbo = gloo.VertexBuffer(self.data) self.program.bind(self.vbo) #self.program_e.bind(self.vbo) - self.update() + self.refresh() """ @@ -461,7 +464,7 @@ class GraphCanvas(scene.SceneCanvas): self.vbo_line = gloo.VertexBuffer(self.line_data) self.program.bind(self.vbo) self.program_e.bind(self.vbo_line) - self.update() + self.refresh() """ Sets the edge color based on the the cluster the vertices belongs to @@ -480,10 +483,10 @@ class GraphCanvas(scene.SceneCanvas): Test function that only binds the buffer """ def gen_vertex_vbo_minimalist(self): - self.update() + self.refresh() self.vbo.set_data(self.data) self.program.bind(self.vbo) - self.update() + self.refresh() """ Helper function that generates the framebuffer object that stores the vertices @@ -540,7 +543,7 @@ class GraphCanvas(scene.SceneCanvas): self.program_s.bind(self.vbo_s) if DEBUG: print(self.view) - self.update() + self.refresh() """ Helper function that creates colored "block" lines based on the edges @@ -898,7 +901,7 @@ class GraphCanvas(scene.SceneCanvas): # self.program_s.bind(self.vbo_s) # if DEBUG: # print(self.view) -# self.update() +# self.refresh() """ @@ -928,12 +931,59 @@ class GraphCanvas(scene.SceneCanvas): #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) + + + + #add colormap G.vertex_properties["RGBA"] = nwt.Network.map_property_to_color(G, G.vertex_properties["clusters"]) @@ -1072,7 +1122,7 @@ class GraphCanvas(scene.SceneCanvas): self.program_s.bind(self.vbo_s) if DEBUG: print(self.view) - self.update() + self.refresh() """ Loads the data G and generates all the buffers necessary as well as performs @@ -1143,7 +1193,7 @@ class GraphCanvas(scene.SceneCanvas): self.program_s.bind(self.vbo_s) if DEBUG: print(self.view) - self.update() + self.refresh() """ Function that changes and redraws the buffer during a resize event. @@ -1165,7 +1215,20 @@ 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 + #self._u + #self._update_pending = True + #app.Canvas.update(self) + #super(scene.SceneCanvas, self).update() #This forces redrawd + """ + refreshes the canvas and forces the redraw. A workaround for issue in + vispy 0.6.3 + """ + def refresh(self): + self.update() + app.Canvas.update(self) # """ # A function to animate from one layout to another layout given a new G. @@ -1259,7 +1322,7 @@ class GraphCanvas(scene.SceneCanvas): # print(self.color_dict[tuple(color)]) #reset the original buffer - self.update() + self.refresh() #Return the element under the click. if clusters == False: @@ -1343,7 +1406,7 @@ class GraphCanvas(scene.SceneCanvas): def update_vbo(self): self.vbo = gloo.VertexBuffer(self.data) self.program.bind(self.vbo) - self.update() + self.refresh() def update_vertex_alpha(self, vertex, alpha): temp = self.G.vertex_properties["RGBA"][vertex] @@ -1605,7 +1668,7 @@ class GraphCanvas(scene.SceneCanvas): self.program_e.bind(self.vbo_line) #self.program.draw('points') self.location = event.pos - self.update() + self.refresh() elif(self.moving == True and self.moving_cluster == True): if(len(self.c_id) < 2): #Project into GLSpace and get before and after move coordinates @@ -1640,7 +1703,7 @@ class GraphCanvas(scene.SceneCanvas): self.vbo_s = gloo.VertexBuffer(self.clusters) self.program_s.bind(self.vbo_s) self.update_cluster_line_vbo() - self.update() + self.refresh() else: @@ -1660,7 +1723,7 @@ class GraphCanvas(scene.SceneCanvas): self.program_s['u_view'] = self.view self.program_e_s['u_view'] = self.view self.location = event.pos - self.update() + self.refresh() """ Handles the mouse wheel zoom event. @@ -1687,4 +1750,4 @@ class GraphCanvas(scene.SceneCanvas): self.program_s['u_view'] = self.view self.program_e_s['u_view'] = self.view #print(event.delta[1]) - self.update() + self.refresh() diff --git a/GraphWidget.py b/GraphWidget.py index 6ce1b88..1de24fa 100644 --- a/GraphWidget.py +++ b/GraphWidget.py @@ -7,7 +7,7 @@ Created on Mon Aug 5 15:42:19 2019 """ from GraphCanvas import GraphCanvas -from pyqtgraph.Qt import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtGui, QtWidgets import network_dep as nwt import numpy as np @@ -19,14 +19,16 @@ Initializes the entire QTlayout and sets the mouse press events. These are connected to the slots such that each is processes by this class and the class it wraps. """ -class GraphWidget(QtGui.QWidget): +#class GraphWidget(QtGui.QWidget): +class GraphWidget(QtWidgets.QWidget): select = QtCore.pyqtSignal(list) def __init__(self): super(GraphWidget, self).__init__() - box = QtGui.QVBoxLayout(self) + box = QtWidgets.QVBoxLayout(self) self.resize(500,500) self.setLayout(box) self.canvas = GraphCanvas() + self.setUpdatesEnabled(True) #self.canvas.create_native() box.addWidget(self.canvas.native) self.color = True @@ -37,8 +39,9 @@ class GraphWidget(QtGui.QWidget): 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.canvas.events. #self.show() + #self.repaint() """ Handles the right click mouse event at the QWidget level. @@ -49,11 +52,16 @@ class GraphWidget(QtGui.QWidget): The context menu level actions are also coded in this section of the code. """ def on_mouse_press(self, event): + self.canvas.set_current(event) if event.button == 2: if self.canvas.view[0][0] >= 0.0010: + self.canvas.update() c_id = self.canvas.get_clicked_id(event) + self.canvas.update() else: + self.canvas.update() c_id = self.canvas.get_clicked_id(event, clusters=True) + self.canvas.update() #right click if(c_id == None): menu = QtWidgets.QMenu(self) @@ -178,15 +186,16 @@ class GraphWidget(QtGui.QWidget): Handles the mouse double click event. Pass-through function. """ + def on_mouse_double_click(self, 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 - nG = nwt.Network.gen_new_fd_layout(self.canvas.G) +# old_pos = self.canvas.G.vertex_properties["pos"].get_2d_array(range(3)).T +# nG = nwt.Network.gen_new_fd_layout(self.canvas.G) # def animate(self, new_G): # - new_pos = nG.vertex_properties["pos"].get_2d_array(range(3)).T - self.canvas.animate(old_pos, new_pos) +# new_pos = nG.vertex_properties["pos"].get_2d_array(range(3)).T +# self.canvas.animate(old_pos, new_pos) """ Handles the mouse release event. diff --git a/GuiVisPy_tube.py b/GuiVisPy_tube.py index 86cdf9c..908918f 100644 --- a/GuiVisPy_tube.py +++ b/GuiVisPy_tube.py @@ -7,35 +7,39 @@ Created on Thu Jan 31 15:29:40 2019 `""" from vispy import app - +import vispy import network_dep as nwt -from pyqtgraph.Qt import QtCore, QtGui, QtWidgets -import pyqtgraph as pg +#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') +#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 = QtGui.QApplication([]) +appMain = QtWidgets.QApplication([]) +#QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts, True) ##Define a toplevel Widget -top = QtGui.QWidget() +top = QtWidgets.QWidget() top.resize(900, 900) @@ -46,7 +50,7 @@ fibers.canvas.create_native() #plt = hist.addPlot() -layout = QtGui.QGridLayout() +layout = QtWidgets.QGridLayout() graph = GraphWidget() graph.canvas.create_native() @@ -54,14 +58,15 @@ graph.connect(fibers) fibers.connect(graph) #initialize the layout -layout.addWidget(graph, 0, 0, 2, 3) -layout.addWidget(fibers, 0, 2, 2, 3) +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) top.setLayout(layout) + top.show() @@ -95,8 +100,8 @@ G, bbl, bbu = load_nwt("/home/pavel/Documents/Python/GraphGuiQt/network_4.nwt") #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) +#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()) @@ -109,10 +114,12 @@ graph.canvas.set_data(G, bbl, bbu) fibers.canvas.set_data(G, bbl, bbu, 16) #fibers.draw_all(G, center, fibers, graph, node_tex) graph.set_g_view(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_() - + #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/TubeCanvas.py b/TubeCanvas.py index 4ecd8da..a6fc59e 100644 --- a/TubeCanvas.py +++ b/TubeCanvas.py @@ -10,7 +10,7 @@ Created on Mon Aug 5 15:56:47 2019 Class that extends the vispy SceneCanvas to draw 3D tubes """ -from vispy import gloo, scene +from vispy import gloo, scene, app from vispy.gloo import set_viewport, set_state, clear, set_blend_color, context from vispy.gloo import gl from vispy.util.transforms import perspective, translate, rotate, scale @@ -47,6 +47,7 @@ class TubeDraw(scene.SceneCanvas): self.cylinder_data = np.zeros(5*5, dtype=[('a_position', np.float32, 3), ('a_normal', np.float32, 3), ('a_fg_color', np.float32, 4), + ('a_selection', np.float32, 1), #('a_linewidth', np.float32, 1), ]) self.triangle_data = np.random.randint(size=(5, 3), low=0, @@ -82,6 +83,8 @@ class TubeDraw(scene.SceneCanvas): self.program['u_eye'] = self.camera self.program['u_up'] = self.up self.program['u_target'] = np.asarray([0., 0., 0.], dtype=np.float32) +# self.bb = np.ones((26, 3), dtype=np.float32) +# self.program['u_bb'] = self.bb @@ -170,6 +173,10 @@ class TubeDraw(scene.SceneCanvas): self.projection = perspective(90.0, self.physical_size[0]/self.physical_size[1], 1.0, 1000.0) self.program['u_projection'] = self.projection + + def refresh(self): + self.update() + app.Canvas.update(self) #Creates a cylinder around ever segment in the microvascular network. def gen_cylinder_vbo(self, G, num_sides = 32): i = 0 @@ -417,7 +424,8 @@ class TubeDraw(scene.SceneCanvas): #gloo.set_depth_func('lequal') #clear(color='white', depth=True) #print(gloo.wrappers.get_gl_configuration()) - self.update() + self.refresh() + #print(self.canvas.edge_dict[(e[1], e[0])]) #Handles the mouse wheel event, i.e., zoom def on_mouse_wheel(self, event): @@ -456,7 +464,8 @@ class TubeDraw(scene.SceneCanvas): self.program['u_eye'] = self.camera #print(self.view) #print(event.delta[1]) - self.update() + self.refresh() + @@ -534,7 +543,7 @@ class TubeDraw(scene.SceneCanvas): self.program['u_eye'] = self.camera self.program['u_up'] = self.up #self.program['u_LightPos'] = [self.camera[0], self.camera[1], self.camera[2]] - self.update() + self.refresh() #reverts the mouse state during release. def on_mouse_release(self, event): diff --git a/TubeWidget.py b/TubeWidget.py index 8a88e2c..f0521dd 100644 --- a/TubeWidget.py +++ b/TubeWidget.py @@ -11,19 +11,20 @@ Created on Mon Aug 5 15:53:16 2019 methods necessary to use the QT signals and slots API. """ -from pyqtgraph.Qt import QtCore, QtGui, QtWidgets +#from pyqtgraph.Qt import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtGui, QtWidgets from TubeCanvas import TubeDraw import numpy as np #import trimesh as tm DEBUG = False -class TubeWidget(QtGui.QWidget): +class TubeWidget(QtWidgets.QWidget): sigUpdate = QtCore.pyqtSignal(float, float, float) #Initializes the QT wrapper class. def __init__(self): super(TubeWidget, self).__init__() - box = QtGui.QVBoxLayout(self) + box = QtWidgets.QVBoxLayout(self) self.resize(500,500) self.setLayout(box) self.canvas = TubeDraw() diff --git a/graph_shaders.py b/graph_shaders.py index 8d2e0c4..9dc9265 100644 --- a/graph_shaders.py +++ b/graph_shaders.py @@ -11,7 +11,7 @@ from vispy import gloo, app, scene #shaders for drawing nodes vert = """ -#version 120 + // Uniforms // ------------------------------------ uniform float u_size; @@ -58,7 +58,7 @@ void main (void) { """ frag = """ -#version 120 + // Constants // ------------------------------------ uniform mat4 u_model; @@ -90,8 +90,9 @@ void main() { float size = v_size + 2*(v_linewidth + 1.5*v_antialias); float t = v_linewidth/2.0-v_antialias; - // The marker function needs to be linked with this shader - float r = marker(gl_PointCoord, size); + vec2 p = (gl_PointCoord.xy - vec2(0.5,0.5))*size; + float r = length(p); + r -= v_size/2; float d = abs(r) - t; if( r > (v_linewidth/3.0+v_antialias)) { @@ -103,7 +104,7 @@ void main() { float alpha = d/v_antialias; alpha = new_alpha(v_zoom_level); - gl_FragColor = mix(vec4(1,1,1,0.9), v_bg_color, max(1.0-alpha, 0.3)); + gl_FragColor = mix(vec4(1,1,1,0.9), v_bg_color, max(1.0-alpha, 0.3)); } else { @@ -132,7 +133,14 @@ void main() else gl_FragColor = vec4(gl_Color.rgb, max(1.0-alpha, 0.1)); else - gl_FragColor = mix(v_bg_color, 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, 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); + } } @@ -177,7 +185,7 @@ float new_alpha(float zoom_level) vs = """ -#version 120 + // Uniforms // ------------------------------------ @@ -215,7 +223,7 @@ void main() { """ fs = """ -#version 120 + // Varying // ------------------------------------ varying vec4 v_fg_color; diff --git a/subgraph_shaders.py b/subgraph_shaders.py index 18062a5..c47fe79 100644 --- a/subgraph_shaders.py +++ b/subgraph_shaders.py @@ -8,7 +8,6 @@ Created on Mon Aug 5 15:35:04 2019 #shaders for drawing supernodes vert_s = """ -#version 120 // Uniforms // ------------------------------------ uniform mat4 u_model; @@ -50,7 +49,6 @@ void main (void) { """ frag_s = """ -#version 120 const float pi = 3.1415926535897932384626433832795; // Varyings // ------------------------------------ @@ -99,6 +97,12 @@ void main() if(dist < 0.25) { //gl_FragColor = v_cluster_color; +// vec2 p = (gl_FragCoord.xy - v_value); +// vec3 normal = normalize(vec3(p.xy, dist)); +// 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 = vec4(max(diffuse*v_cluster_color.rgb, specular*vec3(1.0)), 1.0); gl_FragColor = vec4(v_cluster_color.rgb, n_alpha); } if(dist > 0.3 && 0.55 > dist) @@ -139,28 +143,6 @@ void main() gl_FragColor = vec4(0.93, 0.949, 0.329, n_alpha); //gl_FragColor = vec4(1.0, 1.0, 0.0, n_alpha); } - //else - //{ - // discard; - //} - -// if(angle > -pi && angle < -pi/4.0) -// { -// //gl_FragColor = vec4(0.32, 0.61, 0.93, n_alpha); -// gl_FragColor = vec4(1.0, 0.0, 0.0, n_alpha); -// } -// else if(angle > -pi/4.0 && angle < 0.0) -// { -// gl_FragColor = vec4(0.0, 1.0, 0.0, n_alpha); -// } -// else if(angle > 0.0 && angle < pi/2.0) -// { -// gl_FragColor = vec4(0.0, 0.0, 1.0, n_alpha); -// } -// else if(angle > pi/2.0 && angle < pi) -// { -// gl_FragColor = vec4(1.0, 1.0, 0.0, n_alpha); -// } } } else @@ -200,7 +182,6 @@ float new_alpha(float zoom_level) """ vs_s = """ -#version 120 // Uniforms // ------------------------------------ @@ -237,7 +218,7 @@ void main() { """ fs_s = """ -#version 120 + // Varying // ------------------------------------ varying vec4 v_fg_color; -- libgit2 0.21.4