Example #1
0
    
    t1 = vv.Label(a, 'Edge ctvalue: ', fontSize=11, color='c')
    t1.position = 0.1, 5, 0.5, 20  # x (frac w), y, w (frac), h
    t1.bgcolor = None
    t1.visible = False
    t2 = vv.Label(a, 'Edge cost: ', fontSize=11, color='c')
    t2.position = 0.1, 25, 0.5, 20
    t2.bgcolor = None
    t2.visible = False
    t3 = vv.Label(a, 'Edge length: ', fontSize=11, color='c')
    t3.position = 0.1, 45, 0.5, 20
    t3.bgcolor = None
    t3.visible = False
    
    #Add clickable nodes
    node_points = _utils_GUI.interactive_node_points(model)
    
    selected_nodes = list()
    # Bind event handlers
    f.eventKeyDown.Bind(on_key)
    for node_point in node_points:
        node_point.eventDoubleClick.Bind(lambda event: _utils_GUI.select_node(event, selected_nodes) )
    print('')
    print('UP/DOWN = show/hide nodes')
    print('ENTER   = show edge and attribute values [select 2 nodes]')
    print('DELETE  = remove edge [select 2 nodes]')
    print('CTRL    = replace intially created ringparts')
    print('')

    # Get ring parts
    ringparts(ringpart=ringpart)
Example #2
0
def on_key(event):
    global node_points 
    if event.key == vv.KEY_DOWN:
        # hide nodes and labels
        t1.visible, t2.visible, t3.visible = False, False, False
        t4.visible, t5.visible, t6.visible = False, False, False
        for node_point in node_points:
            node_point.visible = False
    if event.key == vv.KEY_UP:
        # show nodes and labels
        t1.visible, t2.visible, t3.visible = True, True, True
        t4.visible, t5.visible, t6.visible = True, True, True
        for node_point in node_points:
            node_point.visible = True
    if event.text == 'n':
        # add clickable point: point on graph closest to picked point (SHIFT+R-click )
        view = a.GetView()
        for node_point in node_points:
            node_point.visible = False
        snapOut = _utils_GUI.snap_picked_point_to_graph(model, vol, label) # x,y,z
        pickedOnGraph = snapOut[0]
        n1, n2 = snapOut[1]
        pickedOnGraphIndex = snapOut[2]
        pickedOnGraphDeforms = model.edge[n1][n2]['pathdeforms'][pickedOnGraphIndex]
        model.add_node(pickedOnGraph, deforms=pickedOnGraphDeforms)
        node_points = _utils_GUI.interactive_node_points(model, scale=0.7)
        _utils_GUI.node_points_callbacks(node_points, selected_nodes, t0=t0)
        # visualize
        # pickedOnGraph_sphere = vv.solidSphere(translation = (pickedOnGraph), scaling = (scale,scale,scale))
        point = vv.plot(pickedOnGraph[0], pickedOnGraph[1], pickedOnGraph[2], 
                        mc = 'y', ms = 'o', mw = 9, alpha=0.5)
        a.SetView(view)
    if event.key == vv.KEY_ENTER:
        assert len(selected_nodes) == 2 or 3 or 4
        # Node_to_node analysis
        if len(selected_nodes) == 2:
            # get nodes
            selectn1 = selected_nodes[0].node
            selectn2 = selected_nodes[1].node
            # get index of nodes which are in fixed order
            n1index = selected_nodes[0].nr
            n2index = selected_nodes[1].nr
            nindex = [n1index, n2index]
            # get deforms of nodes
            n1Deforms = model.node[selectn1]['deforms']
            n2Deforms = model.node[selectn2]['deforms']
            # get pulsatility
            output = point_to_point_pulsatility(selectn1, n1Deforms, selectn2, n2Deforms)
            # update labels
            t1.text = '\b{Node pair}: %i - %i' % (nindex[0], nindex[1])
            t2.text = 'Node-to-node Min: %1.2f mm' % output[0][0]
            t3.text = 'Node-to-node Max: %1.2f mm' % output[4][0]
            t4.text = 'Node-to-node Median: %1.2f mm' % output[2]
            t5.text = 'Node-to-node Q1 and Q3: %1.2f | %1.2f mm' % (output[1], output[3])
            t6.text = '\b{Node-to-node Pulsatility: %1.2f mm}' % (output[5][0] )
            t1.visible, t2.visible, t3.visible = True, True, True
            t4.visible, t5.visible, t6.visible = True, True, True
            # Store output including index/nr of nodes
            output.insert(0, [n1index]) # at the start
            output.insert(1, [n2index])
            output[8].insert(0, [n1index])
            output[9].insert(0, [n2index])
            if output not in storeOutput:
                storeOutput.append(output)
        # Midpoint_to_node analysis
        if len(selected_nodes)== 3:
            # find the edge selected to get midpoint
            selected_nodes2 = selected_nodes.copy()
            for node1 in selected_nodes:
                selected_nodes2.remove(node1) # check combination once and not to self
                for node2 in selected_nodes2:
                    if model.has_edge(node1.node, node2.node):
                        # get midpoint of edge and its deforms
                        output = get_midpoint_deforms_edge(model, node1.node, node2.node)
                        break  # edge found, to first for loop
            # get index of nodepair and midpoint and its deforms
            nodepair1 = output[0]
            midpoint1IndexPath = output[1]
            midpoint1 = output[2]
            midpoint1Deforms = output[3]
            # get node
            for i, node in enumerate(selected_nodes):
                if node.nr not in nodepair1:
                    n3 = node
                    break
            # get deforms for node
            n3Deforms = model.node[n3.node]['deforms']
            # get pulsatility
            # first selected first in output
            if i > 0: # single node was not selected first
                output2 = point_to_point_pulsatility(midpoint1, 
                            midpoint1Deforms, n3.node, n3Deforms)
            else:
                output2 = point_to_point_pulsatility(n3.node, n3Deforms,
                            midpoint1, midpoint1Deforms)
            # visualize midpoint
            view = a.GetView()
            point = vv.plot(midpoint1[0], midpoint1[1], midpoint1[2], 
                            mc = 'm', ms = 'o', mw = 8, alpha=0.5)
            a.SetView(view)
            # update labels
            t1.text = '\b{Node pairs}: (%i %i) - (%i)' % (nodepair1[0],nodepair1[1],n3.nr)
            t2.text = 'Midpoint-to-node Min: %1.2f mm' % output2[0][0]
            t3.text = 'Midpoint-to-node Max: %1.2f mm' % output2[4][0]
            t4.text = 'Midpoint-to-node Median: %1.2f mm' % output2[2]
            t5.text = 'Midpoint-to-node Q1 and Q3: %1.2f | %1.2f mm' % (output2[1], output2[3])
            t6.text = '\b{Midpoint-to-node Pulsatility: %1.2f mm}' % (output2[5][0])
            t1.visible, t2.visible, t3.visible = True, True, True
            t4.visible, t5.visible, t6.visible = True, True, True
            # Store output including index nodes
            if i > 0:
                output2.insert(0, nodepair1) # at the start
                output2.insert(1, [n3.nr])
                output2[8].insert(0, midpoint1IndexPath)
                output2[9].insert(0, [n3.nr])
            else:
                output2.insert(0, [n3.nr]) # at the start
                output2.insert(1, nodepair1)
                output2[8].insert(0, [n3.nr])
                output2[9].insert(0, midpoint1IndexPath)
            if output2 not in storeOutput:
                storeOutput.append(output2)
        # Midpoint_to_midpoint analysis
        if len(selected_nodes) == 4:
            outputs = list()
            # get midpoints for the two edges
            # get nodepairs from order selected
            for i in (0,2):
                n1 = selected_nodes[i].node
                n2 = selected_nodes[i+1].node
                assert model.has_edge(n1, n2)
                # get midpoint of edge and its deforms
                output = get_midpoint_deforms_edge(model, n1, n2)
                midpoint = output[2]
                # store for both edges
                outputs.append(output)
                # visualize midpoint
                view = a.GetView()
                point = vv.plot(midpoint[0], midpoint[1], midpoint[2], 
                                mc = 'm', ms = 'o', mw = 8, alpha=0.5)
                a.SetView(view)
            assert len(outputs) == 2 # two midpoints should be found
            # get midpoints and deforms
            nodepair1 = outputs[0][0]
            midpoint1IndexPath = outputs[0][1]
            midpoint1 = outputs[0][2]
            midpoint1Deforms = outputs[0][3]
            nodepair2 = outputs[1][0]
            midpoint2IndexPath = outputs[1][1]
            midpoint2 = outputs[1][2]
            midpoint2Deforms = outputs[1][3]
            # get pulsatility midp to midp
            output2 = point_to_point_pulsatility(midpoint1, 
                                midpoint1Deforms, midpoint2, midpoint2Deforms)
            # # get max pulsatility between points on the paths
            # outputmaxP.append(edge_to_edge_max_pulsatility(model, nodepair1, nodepair2))
            # update labels
            t1.text = '\b{Node pairs}: (%i %i) - (%i %i)' % (nodepair1[0], nodepair1[1],
                                                            nodepair2[0], nodepair2[1])
            t2.text = 'Midpoint-to-midpoint Min: %1.2f mm' % output2[0][0]
            t3.text = 'Midpoint-to-midpoint Max: %1.2f mm' % output2[4][0]
            t4.text = 'Midpoint-to-midpoint Median: %1.2f mm' % output2[2]
            t5.text = 'Midpoint-to-midpoint Q1 and Q3: %1.2f | %1.2f mm' % (output2[1], output2[3])
            t6.text = '\b{Midpoint-to-midpoint Pulsatility: %1.2f mm}' % (output2[5][0])
            t1.visible, t2.visible, t3.visible = True, True, True
            t4.visible, t5.visible, t6.visible = True, True, True
            # Store output including nodepairs of the midpoints
            output2.insert(0, nodepair1) # indices at the start
            output2.insert(1, nodepair2)
            output2[8].insert(0, midpoint1IndexPath)
            output2[9].insert(0, midpoint2IndexPath)
            if output2 not in storeOutput:
                storeOutput.append(output2)
        # Visualize analyzed nodes and deselect
        for node in selected_nodes:
            node.faceColor = (0,1,0,0.8) #  # make green when analyzed
        selected_nodes.clear()
    if event.key == vv.KEY_ESCAPE:
        # FINISH, STORE TO EXCEL
        # visualize
        view = a.GetView()
        t = vv.volshow(vol, clim=clim, renderStyle='mip')
        # show mesh of model without deform coloring
        modelmesh = create_mesh(model, 0.4)  # Param is thickness
        m = vv.mesh(modelmesh)
        m.faceColor = (0,1,0,1) # green
        a.SetView(view)
        # Store to EXCEL
        storeOutputToExcel(storeOutput,exceldir)
        for node_point in node_points:
            node_point.visible = False # show that store is ready
Example #3
0
    t5.position = 0.1, 125, 0.5, 20
    t5.bgcolor = None
    t5.visible = False
    t6 = vv.Label(a, '\b{Node-to-node Pulsatility: }', fontSize=11, color='c')
    t6.position = 0.1, 145, 0.5, 20
    t6.bgcolor = None
    t6.visible = False
    
    # Initialize output variable to store pulsatility analysis
    storeOutput = list()
    # outputmaxP = list()
    selected_nodes = list()
    
    # Add clickable nodes
    scale = 0.7
    node_points = _utils_GUI.interactive_node_points(model, scale=0.7)
    
    
    # Bind event handlers
    fig.eventKeyDown.Bind(on_key)
    _utils_GUI.node_points_callbacks(node_points, selected_nodes, t0=t0) # bind callback functions to node points
    fig.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event) )
    
    # Print user instructions
    print('')
    print('n = add node to click from graph point closest to [picked point]')
    print('Enter = get distance between selected nodes and/or midpoints')
    print('Esc = finish analysis, STORE TO EXCEL desktop')
    print('x = axis invisible/visible')

Example #4
0
def on_key(event):
    """KEY commands for user interaction
        'UP/DOWN  = show/hide nodes'
        'DELETE   = remove edge [select 2 nodes] or pop node [select 1 node] '
                   'or remove seed in nodes1 closest to [picked point]'
        'p = remove seeds posterior (y-axis) to [picked point] (use for spine seeds)'
        'o = remove seeds anterior (y-axis) to [picked point]'
        'i = remove seeds proximal (z-axis) to [picked point]'
        'k = remove seeds distal (z-axis) to [picked point]'
        'l = remove seeds left (x-axis) to [picked point]'
        'j = remove seeds right (x-axis) to [picked point]'
        'ALT   = clean graph: remove residual clusters, pop, corner'
        'PageUp= protect node closest to picked point in nodes1 axes, no pop
        'n = add [picked point] (SHIFT+R-click) as seed'
        '1 = redo step 1; 2 = redo step 2; 3 = redo step 3'
        'z/x/a/d = axis invisible/visible/rotate'
    """
    global label
    global node_points
    global sd
    if event.key == vv.KEY_DOWN:
        # hide nodes
        t1.visible = False
        t2.visible = False
        t3.visible = False
        if 'node_points' in globals():
            for node_point in node_points:
                node_point.visible = False
    if event.key == vv.KEY_UP:
        # show nodes
        if 'node_points' in globals():
            for node_point in node_points:
                node_point.visible = True
    if event.key == vv.KEY_DELETE:
        if len(selected_nodes) == 0:
            # remove node closest to picked point
            node = _utils_GUI.snap_picked_point_to_graph(sd._nodes1, vol, label, nodesOnly=True)
            sd._nodes1.remove_node(node)
            view = a1.GetView()
            a1.Clear()
            label = DrawModelAxes(vol, sd._nodes1, a1, clim=clim, showVol=showVol, removeStent=False)
            a1.SetView(view)    
        if len(selected_nodes) == 2:
            # remove edge
            select1 = selected_nodes[0].node
            select2 = selected_nodes[1].node
            c = sd._nodes3.edge[select1][select2]['cost']
            ct = sd._nodes3.edge[select1][select2]['ctvalue']
            path = sd._nodes3.edge[select1][select2]['path']
            l = stentgraph._edge_length(sd._nodes3, select1, select2)
            sd._nodes3.remove_edge(select1, select2)
            stentgraph.pop_nodes(sd._nodes3) # pop residual nodes
            # Visualize removed edge, show keys and deselect nodes
            selected_nodes[1].faceColor = 'b'
            selected_nodes[0].faceColor = 'b'
            selected_nodes.clear()
            t1.text = 'Edge ctvalue: \b{%1.2f HU}' % ct
            t2.text = 'Edge cost: \b{%1.7f }' % c
            t3.text = 'Edge length: \b{%1.2f mm}' % l
            t1.visible = True
            t2.visible = True
            t3.visible = True
            view = a3.GetView()
            pp = Pointset(path)
            line = vv.solidLine(pp, radius = 0.2)
            line.faceColor = 'r'
            a3.SetView(view)
        if len(selected_nodes) == 1:
            # pop node
            select1 = selected_nodes[0].node
            stentgraph._pop_node(sd._nodes3, select1) # asserts degree == 2
            selected_nodes[0].faceColor = 'w'
            selected_nodes.clear()
    if event.key == vv.KEY_ALT:
        # ALT will FINISH model
        stentgraph.prune_clusters(sd._nodes3, 3) #remove residual nodes/clusters
        stentgraph.pop_nodes(sd._nodes3)
        stentgraph.add_corner_nodes(sd._nodes3, th=sd._params.graph_angleVector, angTh=sd._params.graph_angleTh)
        # Create mesh and visualize
        view = a3.GetView()
        a3.Clear()
        DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol, lc='g', mw=8, lw=0.2)
        # _utils_GUI.vis_spared_edges(sd._nodes3)
        a3.SetView(view)
        print('----DO NOT FORGET TO SAVE THE MODEL TO DISK; RUN _SAVE_SEGMENTATION----')
    if event.text == 'n':
        # add picked seed to nodes_1
        coord2 = get_picked_seed(vol, label)
        sd._nodes1.add_node(tuple(coord2))
        view = a1.GetView()
        point = vv.plot(coord2[0], coord2[1], coord2[2], mc= 'b', ms = 'o', mw= 8, alpha=0.5, axes=a1)
        a1.SetView(view)
    if event.key == vv.KEY_PAGEUP:
        # protect node from pop
        pickedNode = _utils_GUI.snap_picked_point_to_graph(sd._nodes1, vol, label, nodesOnly=True) 
        sd._nodes1.add_node(pickedNode, nopop = True)
        sd._nodes2.add_node(pickedNode, nopop = True)
        view = a1.GetView()
        point = vv.plot(pickedNode[0], pickedNode[1], pickedNode[2], mc= 'y', ms = 'o', mw= 8, alpha=0.5, axes=a1)
        a1.SetView(view)
        # now rerun step 3
    if event.text == 'p':
        # remove false seeds posterior to picked point, e.g. for spine
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a2, label, 
            clim, location='posterior', showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, 
            clim, location='posterior', showVol=showVol)
    if event.text == 'o':
        # remove seeds prox to selected point
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, 
            clim, location='anterior', showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, 
            clim, location='anterior', showVol=showVol)
    if event.text == 'i':
        # remove seeds prox to selected point
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, 
            clim, location='proximal', showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, 
            clim, location='proximal', showVol=showVol)
    if event.text == 'k':
        # remove seeds dist to selected point
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, 
            clim, location='distal', showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, 
            clim, location='distal', showVol=showVol)
    if event.text == 'l':
        # remove seeds left to selected point
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, 
            clim, location='left', showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, 
            clim, location='left', showVol=showVol)
    if event.text == 'j':
        # remove seeds right to selected point
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, 
            clim, location='right', showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, 
            clim, location='right', showVol=showVol)
    if event.text == '1':
        # redo step1
        view = a1.GetView()
        a1.Clear(); a2.Clear(); a3.Clear()
        sd._params = p
        sd.Step1()
        label = DrawModelAxes(vol, sd._nodes1, a1, clim=clim, showVol=showVol, removeStent=False) # lc, mc
        a1.SetView(view)
    if event.text == '2':
        # redo step2
        view = a2.GetView()
        a2.Clear(); a3.Clear()
        sd._params = p
        sd.Step2()
        DrawModelAxes(vol, sd._nodes2, a2, clim=clim, showVol=showVol,removeStent=False)
        a2.SetView(view)
    if event.text == '3':
        # redo step3
        view = a3.GetView()
        a3.Clear()
        sd._params = p
        sd.Step3(cleanNodes=True)
        DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol,removeStent=False)
        node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6)
        _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False)
        a3.SetView(view)
Example #5
0
fig.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event, [a1, a2, a3], keyboard=['6', '7', '8', '9', '0']) )
fig.eventKeyDown.Bind(lambda event: _utils_GUI.RotateView(event, [a1, a2, a3]) )

# Print user instructions
print('')
print('n = add [picked point] (SHIFT+R-click) as seed')
print('PageUp = protect node closest to picked point in nodes1 axes, no pop')
print('p = remove seeds posterior (y-axis) to [picked point] (use for spine seeds)')
print('o = remove seeds anterior (y-axis) to [picked point]')
print('i = remove seeds cranial (z-axis) to [picked point]')
print('k = remove seeds caudal (z-axis) to [picked point]')
print('l = remove seeds left (x-axis) to [picked point]')
print('j = remove seeds right (x-axis) to [picked point]')
print('1 = redo step 1; 2 = redo step 2; 3 = redo step 3')
print('x and a/d = axis invisible/visible and rotate')

if guiRemove==True:
        # Add clickable nodes to remove edges
        node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6)
        _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False)
        print('UP/DOWN = show/hide nodes')
        print('DELETE  = remove edge [select 2 nodes] or pop node [select 1 node] '
               'or remove seed in nodes1 closest to [picked point]')
        print('ALT  = SHOW RESULT after remove clusters, pop, corner')
        print('')
else:
    # Bind event handlers but do not make node_points
    print('DELETE = remove seed in nodes1 closest to [picked point]')
    print('')

Example #6
0
def on_key(event):
    """KEY commands for user interaction
        'UP/DOWN  = show/hide nodes'
        'DELETE   = remove edge [select 2 nodes] or pop node [select 1 node] '
                   'or remove seed in nodes1 closest to [picked point]'
        'PageDown = remove graph posterior (y-axis) to [picked point] (use for spine seeds)'
        'ALT      = clean graph: remove residual clusters, pop, corner'
        'CTRL+SHIFT = add [picked point] (SHIFT+R-click) as seed'
    """
    global label
    global node_points
    global sd
    if event.key == vv.KEY_DOWN:
        # hide nodes
        t1.visible = False
        t2.visible = False
        t3.visible = False
        for node_point in node_points:
            node_point.visible = False
    if event.key == vv.KEY_UP:
        # show nodes
        for node_point in node_points:
            node_point.visible = True
    if event.key == vv.KEY_DELETE:
        if len(selected_nodes) == 0:
            # remove node closest to picked point
            node = _utils_GUI.snap_picked_point_to_graph(sd._nodes1,
                                                         vol,
                                                         label,
                                                         nodesOnly=True)
            sd._nodes1.remove_node(node)
            view = a1.GetView()
            a1.Clear()
            label = DrawModelAxes(vol,
                                  sd._nodes1,
                                  a1,
                                  clim=clim,
                                  showVol=showVol,
                                  removeStent=False)
            a1.SetView(view)
        if len(selected_nodes) == 2:
            # remove edge
            select1 = selected_nodes[0].node
            select2 = selected_nodes[1].node
            c = sd._nodes3.edge[select1][select2]['cost']
            ct = sd._nodes3.edge[select1][select2]['ctvalue']
            path = sd._nodes3.edge[select1][select2]['path']
            l = stentgraph._edge_length(sd._nodes3, select1, select2)
            sd._nodes3.remove_edge(select1, select2)
            stentgraph.pop_nodes(sd._nodes3)  # pop residual nodes
            # Visualize removed edge, show keys and deselect nodes
            selected_nodes[1].faceColor = 'b'
            selected_nodes[0].faceColor = 'b'
            selected_nodes.clear()
            t1.text = 'Edge ctvalue: \b{%1.2f HU}' % ct
            t2.text = 'Edge cost: \b{%1.7f }' % c
            t3.text = 'Edge length: \b{%1.2f mm}' % l
            t1.visible = True
            t2.visible = True
            t3.visible = True
            view = a3.GetView()
            pp = Pointset(path)
            line = vv.solidLine(pp, radius=0.2)
            line.faceColor = 'r'
            # a3.SetView(view)
        if len(selected_nodes) == 1:
            # pop node
            select1 = selected_nodes[0].node
            stentgraph._pop_node(sd._nodes3, select1)  # asserts degree == 2
            selected_nodes[0].faceColor = 'w'
            selected_nodes.clear()
    if event.key == vv.KEY_ALT:
        # ALT will FINISH model
        stentgraph.prune_clusters(sd._nodes3,
                                  3)  #remove residual nodes/clusters
        stentgraph.pop_nodes(sd._nodes3)
        stentgraph.add_corner_nodes(sd._nodes3,
                                    th=sd._params.graph_angleVector,
                                    angTh=sd._params.graph_angleTh)
        # Create mesh and visualize
        view = a3.GetView()
        a3.Clear()
        DrawModelAxes(vol,
                      sd._nodes3,
                      a3,
                      meshColor=meshColor,
                      clim=clim,
                      showVol=showVol,
                      lc='b',
                      mw=8,
                      lw=0.2)
        _utils_GUI.vis_spared_edges(sd._nodes3)
        a3.SetView(view)
        print(
            '----DO NOT FORGET TO SAVE THE MODEL TO DISK; RUN _SAVE_SEGMENTATION----'
        )
    if event.text == 'n':
        # add picked seed to nodes_1
        coord2 = get_picked_seed(vol, label)
        sd._nodes1.add_node(tuple(coord2))
        view = a1.GetView()
        point = vv.plot(coord2[0],
                        coord2[1],
                        coord2[2],
                        mc='b',
                        ms='o',
                        mw=8,
                        alpha=0.5,
                        axes=a1)
        a1.SetView(view)
    if event.text == 'p':
        # protect node from pop
        pickedNode = _utils_GUI.snap_picked_point_to_graph(sd._nodes1,
                                                           vol,
                                                           label,
                                                           nodesOnly=True)
        sd._nodes1.add_node(pickedNode, nopop=True)
        sd._nodes2.add_node(pickedNode, nopop=True)
        view = a1.GetView()
        point = vv.plot(pickedNode[0],
                        pickedNode[1],
                        pickedNode[2],
                        mc='y',
                        ms='o',
                        mw=8,
                        alpha=0.5,
                        axes=a1)
        a1.SetView(view)
        # now rerun step 3
    if event.key == vv.KEY_PAGEDOWN:
        # remove false seeds posterior to picked point, e.g. for spine
        try:
            _utils_GUI.remove_nodes_by_selected_point(sd._nodes3,
                                                      vol,
                                                      a3,
                                                      label,
                                                      clim,
                                                      showVol=showVol)
        except ValueError:  # false nodes already cleaned by Step3
            pass
        _utils_GUI.remove_nodes_by_selected_point(sd._nodes2,
                                                  vol,
                                                  a2,
                                                  label,
                                                  clim,
                                                  showVol=showVol)
        label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1,
                                                          vol,
                                                          a1,
                                                          label,
                                                          clim,
                                                          showVol=showVol)
    if event.text == '1':
        # redo step1
        view = a1.GetView()
        a1.Clear()
        a2.Clear()
        a3.Clear()
        sd._params = p
        sd.Step1()
        label = DrawModelAxes(vol,
                              sd._nodes1,
                              a1,
                              clim=clim,
                              showVol=showVol,
                              removeStent=False)  # lc, mc
        a1.SetView(view)
    if event.text == '2':
        # redo step2 and 3
        view = a2.GetView()
        a2.Clear()
        a3.Clear()
        sd._params = p
        sd.Step2()
        sd.Step3(cleanNodes=cleanNodes)
        DrawModelAxes(vol,
                      sd._nodes2,
                      a2,
                      clim=clim,
                      showVol=showVol,
                      removeStent=False)
        DrawModelAxes(vol,
                      sd._nodes3,
                      a3,
                      meshColor=meshColor,
                      clim=clim,
                      showVol=showVol,
                      removeStent=False)
        a2.SetView(view)
    if event.text == '3':
        view = a3.GetView()
        a3.Clear()
        sd._params = p
        sd.Step3(cleanNodes=cleanNodes)
        DrawModelAxes(vol,
                      sd._nodes3,
                      a3,
                      meshColor=meshColor,
                      clim=clim,
                      showVol=showVol,
                      removeStent=False)
        node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6)
        _utils_GUI.node_points_callbacks(node_points,
                                         selected_nodes,
                                         pick=False)
        a3.SetView(view)

    if event.text == 's':
        # SAVE SEGMENTATION
        # make centerline points of segmentation
        paths_as_pp = points_from_edges_in_graph(sd._nodes3, type='order')
        ringpoints = paths_as_pp[0].T
        # Get graph model
        model = sd._nodes3
        seeds = sd._nodes1
        Draw = sd.Draw
        # Build struct
        s2 = vv.ssdf.new()
        # We do not need croprange, but keep for reference
        s2.sampling = s.sampling
        s2.origin = s.origin
        s2.stenttype = s.stenttype
        s2.croprange = s.croprange
        for key in dir(s):
            if key.startswith('meta'):
                suffix = key[4:]
                s2['meta' + suffix] = s['meta' + suffix]
        s2.what = what
        s2.params = p
        s2.stentType = stentType
        # Store model
        s2.model = model.pack()
        s2.seeds = seeds.pack()
        s2.Draw = Draw
        s2.ringpoints = ringpoints
        #s2.mesh = ssdf.new()
        # Save
        savedir = select_dir(
            r'C:\Users\Gebruiker\Google Drive\Afstuderen\Rings')
        filename = '%s_%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname,
                                            'model' + what, ring)
        ssdf.save(os.path.join(savedir, filename), s2)
        print('saved to disk in {} as {}.'.format(savedir, filename))