Exemplo n.º 1
0
    def __init__(self, vol, a_transversal, a_coronal, a_sagittal, a_text):

        # Create text objects
        self._labelx = vv.Label(a_text)
        self._labely = vv.Label(a_text)
        self._labelz = vv.Label(a_text)
        self._labelx.position = 10, 10
        self._labely.position = 10, 30
        self._labelz.position = 10, 50

        # Create Finish button
        self._finished = False
        self._but = vv.PushButton(a_text)
        self._but.position = 10, 80
        self._but.text = 'Finish'

        # Get short name for sampling
        if isinstance(vol, Aarray):
            self._sam = sam = vol.sampling
        else:
            self._sam = None
            sam = (1, 1, 1)

        # Calculate mips and deal with anisotropy
        mipz = np.max(vol, 0)
        mipz = Aarray(mipz, (sam[1], sam[2]))
        mipy = np.max(vol, 1)
        mipy = Aarray(mipy, (sam[0], sam[2]))
        mipx = np.max(vol, 2)
        mipx = Aarray(mipx, (sam[0], sam[1]))

        # Display the mips
        vv.imshow(mipz, axes=a_transversal)
        vv.imshow(mipy, axes=a_coronal)
        vv.imshow(mipx, axes=a_sagittal)

        # Initialize range objects
        self._range_transversal = RangeWobject2D(a_transversal, mipz)
        self._range_coronal = RangeWobject2D(a_coronal, mipy)
        self._range_sagittal = RangeWobject2D(a_sagittal, mipx)

        # Get list of all range wobjects
        self._rangeWobjects = [
            self._range_transversal, self._range_coronal, self._range_sagittal
        ]

        # Bind events
        fig = a_text.GetFigure()
        fig.eventClose.Bind(self._OnFinish)
        self._but.eventPress.Bind(self._OnFinish)
        for r in self._rangeWobjects:
            r.eventRangeUpdated.Bind(self._OnRangeUpdated)

        # Almost done
        self._SetTexts()
Exemplo n.º 2
0
def add_label(text,
              pos,
              angle=0,
              fontName=None,
              fontSize=9,
              color='k',
              bgcolor=None,
              axes=None):
    '''
    Adds a label inside the axes. Returns the Label object.
    Parameters:
    text    - String. The text of the label
    pos     - Tuple with two numbers. The (x,y) position of the label with origin
              at the upper left corner.
    angle   - Float or int. The rotation of the label in degrees.
    fontname- String. Either 'mono', 'sans' or 'serif'.
    fontSize- Int. Size of the text. Default 9.
    color   - A 3-tuple or a character in 'rgbycmkw', etc that defines text color.
              Default 'k' (black).
    bgcolor - Background color. See color. Default None.
    axes    - Axes wherein the label is placed. If None then the current axes is
              chosen.
    '''
    if axes is None:
        axes = vv.gca()
    label = vv.Label(axes, text, fontName, fontSize, color)
    label.position = pos
    label.bgcolor = bgcolor
    label.textAngle = angle
    return label
Exemplo n.º 3
0
 def __init__(self, im, grid_sampling=40):
     
     # Store image
     self._im = im
     
     # Setup visualization
     self._fig = fig = vv.figure()
     self._a1 = a1 = vv.subplot(231);
     self._a2 = a2 = vv.subplot(232);
     self._a3 = a3 = vv.subplot(233);
     self._a4 = a4 = vv.subplot(234);
     self._a5 = a5 = vv.subplot(235);
     self._a6 = a6 = vv.subplot(236);
     
     # Text objects
     self._text1 = vv.Label(fig)
     self._text1.position = 5, 2
     self._text2 = vv.Label(fig)
     self._text2.position = 5, 20
     
     # Move axes 
     a1.parent.position = 0.0, 0.1, 0.33, 0.45
     a2.parent.position = 0.33, 0.1, 0.33, 0.45
     a3.parent.position = 0.66, 0.1, 0.33, 0.45
     a4.parent.position = 0.0, 0.55, 0.33, 0.45
     a5.parent.position = 0.33, 0.55, 0.33, 0.45
     a6.parent.position = 0.66, 0.55, 0.33, 0.45
     
     # Correct axes, share camera
     cam = vv.cameras.TwoDCamera()
     for a in [a1, a2, a3, a4, a5, a6]:
         a.axis.visible = False
         a.camera = cam
     
     # Show images
     im0 = im*0
     self._t1 = vv.imshow(im, axes=a1)
     self._t2 = vv.imshow(im, axes=a2)
     self._t3 = vv.imshow(im, axes=a3)
     self._t4 = vv.imshow(im0, axes=a4)
     self._t5 = vv.imshow(im0, axes=a5)
     self._t6 = vv.imshow(im0, axes=a6)
     
     # Init pointsets
     self._pp1 = Pointset(2)
     self._pp2 = Pointset(2)
     self._active = None
     self._lines = []
     
     # Init lines to show all deformations
     tmp = vv.Pointset(2)        
     self._line1 = vv.plot(tmp, ls='', ms='.', mc='c', axes=a2)
     self._line2 = vv.plot(tmp, ls='+', lc='c', lw='2', axes=a2)
     
     # Init grid properties
     self._sampling = grid_sampling
     self._levels = 5
     self._multiscale = True
     self._injective = 0.5
     self._frozenedge = 1
     self._forward = True
     
     # Init grid
     self.DeformationField = DeformationFieldForward
     self._field1 = self.DeformationField(FieldDescription(self._im))
     self._field2 = self.DeformationField(FieldDescription(self._im))
     
     # Bind to events
     a2.eventMouseDown.Bind(self.on_down)
     a2.eventMouseUp.Bind(self.on_up)
     a2.eventMotion.Bind(self.on_motion)
     fig.eventKeyDown.Bind(self.on_key_down)
     #a1.eventDoubleClick.Bind(self.OnDone)
     
     # Apply
     self.apply()
Exemplo n.º 4
0
 f.position = 968.00, 30.00,  944.00, 1002.00
 a = vv.gca()
 show_ctvolume(vol, model, showVol=showVol, clim=clim0, isoTh=isoTh)
 model.Draw(mc='b', mw = 10, lc='g')
 vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)')
 vv.title('Analysis for model LSPEAS %s  -  %s' % (ptcode[7:], ctcode))
 a.axis.axisColor= 1,1,1
 a.bgcolor= 0,0,0
 a.daspect= 1, 1, -1  # z-axis flipped
 a.axis.visible = showAxis
 
 # Initialize labels GUI
 from visvis import Pointset
 from stentseg.stentdirect import stentgraph
 
 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)
 
Exemplo n.º 5
0
    def __init__(self,
                 dirsave,
                 ptcode,
                 ctcode,
                 cropname,
                 s,
                 what='phases',
                 axes=None,
                 **kwargs):
        """ s is struct from loadvol
        """

        self.fig = vv.figure(1)
        vv.clf()
        self.fig.position = 0.00, 29.00, 1680.00, 973.00
        self.defaultzoom = 0.025  # check current zoom with foo.ax.GetView()
        self.what = what
        self.ptcode = ptcode
        self.dirsave = dirsave
        self.ctcode = ctcode
        self.cropname = cropname
        if self.what == 'phases':
            self.phase = 0
        else:
            self.phase = self.what  # avgreg
        # self.vol = s.vol0
        self.s = s  # s with vol(s)
        self.s_landmarks = vv.ssdf.new()
        self.graph = stentgraph.StentGraph()
        self.points = []  # selected points
        self.nodepoints = []
        self.pointindex = 0  # for selected points
        try:
            self.vol = s.vol0  # when phases
        except AttributeError:
            self.vol = s.vol  # when avgreg

        self.ax = vv.subplot(121)
        self.axref = vv.subplot(122)

        self.label = DrawModelAxes(self.vol,
                                   ax=self.ax)  # label of clicked point
        self.axref.bgcolor = 0, 0, 0
        self.axref.visible = False

        # create axis for buttons
        a_select = vv.Wibject(self.ax)  # on self.ax or fig?
        a_select.position = 0.55, 0.7, 0.6, 0.5  # x, y, w, h

        # Create text objects
        self._labelcurrentIndexT = vv.Label(a_select)  # for text title
        self._labelcurrentIndexT.position = 125, 180
        self._labelcurrentIndexT.text = ' Total selected ='
        self._labelcurrentIndex = vv.Label(a_select)
        self._labelcurrentIndex.position = 225, 180

        # Create Select button
        self._select = False
        self._butselect = vv.PushButton(a_select)
        self._butselect.position = 10, 150
        self._butselect.text = 'Select'

        # Create Back button
        self._back = False
        self._butback = vv.PushButton(a_select)
        self._butback.position = 125, 150
        self._butback.text = 'Undo'

        # Create Next/Save button
        self._finished = False
        self._butclose = vv.PushButton(a_select)
        self._butclose.position = 10, 230
        self._butclose.text = 'Next/Save'

        # # Create Save landmarks button
        # self._save = False
        # self._butsave = vv.PushButton(a_select)
        # self._butsave.position = 125,230
        # self._butsave.text = 'Save|Finished'

        # Create Reset-View button
        self._resetview = False
        self._butresetview = vv.PushButton(a_select)
        self._butresetview.position = 10, 180
        self._butresetview.text = 'Default Zoom'  # back to default zoom

        # bind event handlers
        self.fig.eventClose.Bind(self._onFinish)
        self._butclose.eventPress.Bind(self._onFinish)
        self._butselect.eventPress.Bind(self._onSelect)
        self._butback.eventPress.Bind(self._onBack)
        self._butresetview.eventPress.Bind(self._onView)
        # self._butsave.eventPress.Bind(self._onSave)

        self._updateTextIndex()
        self._updateTitle()
Exemplo n.º 6
0
 
 fig = vv.figure(); vv.clf()
 fig.position = 9.00, 30.00,  944.00, 1002.00
 a = vv.gca()
 label = DrawModelAxes(vol, model, a, getLabel=True, clim=clim, showVol=showVol, mw=10)
 vv.title('Model for LSPEAS %s  -  %s' % (ptcode[7:], ctcode))
 viewAP = {'zoom': 0.006,'fov': 0.0,
 'daspect': (1.0, 1.0, -1.0),
 'azimuth': 0.0,
 'roll': 0.0}
 
 # Set view
 # a.SetView(viewAP)
 
 # Initialize labels
 t0 = vv.Label(a, '\b{Node nr|location}: ', fontSize=11, color='w')
 t0.position = 0.1, 25, 0.5, 20  # x (frac w), y, w (frac), h
 t0.bgcolor = None
 t0.visible = True
 t1 = vv.Label(a, '\b{Nodepair}: ', fontSize=11, color='w')
 t1.position = 0.1, 45, 0.5, 20  # x (frac w), y, w (frac), h
 t1.bgcolor = None
 t1.visible = False
 t2 = vv.Label(a, 'Node-to-node Min: ', fontSize=11, color='w')
 t2.position = 0.1, 65, 0.5, 20
 t2.bgcolor = None
 t2.visible = False
 t3 = vv.Label(a, 'Node-to-node Max: ', fontSize=11, color='w')
 t3.position = 0.1, 85, 0.5, 20
 t3.bgcolor = None
 t3.visible = False
Exemplo n.º 7
0
    def __init__(self,
                 vol,
                 a_transversal,
                 a_coronal,
                 a_sagittal,
                 a_MIP,
                 a_text,
                 nr_of_stents,
                 clim=None):
        self.nr_of_stents = nr_of_stents
        self.f = vv.gcf()
        self.vol = vol

        # Create empty list of endpoints
        self.endpoints = []
        self.endpoints = ['xx,yy,zz'] * nr_of_stents * 2
        self.endpointsindex = 0

        # Create text objects
        self._labelcurrent = vv.Label(a_text)
        self._labelx = vv.Label(a_text)
        self._labelxslice = vv.Label(a_text)
        self._labely = vv.Label(a_text)
        self._labelyslice = vv.Label(a_text)
        self._labelz = vv.Label(a_text)
        self._labelzslice = vv.Label(a_text)
        self._labelcurrent.position = -250, 10
        self._labelx.position = -250, 35
        self._labelxslice.position = -200, 35
        self._labely.position = -250, 55
        self._labelyslice.position = -200, 55
        self._labelz.position = -250, 75
        self._labelzslice.position = -200, 75

        self._labelendpointstext = []
        self._labelendpointstext.append(vv.Label(a_text))
        self._labelendpointstext[0].position = 100, -5
        self._labelendpointstext.append(vv.Label(a_text))
        self._labelendpointstext[1].position = 230, -5
        for i in range(2, self.nr_of_stents + 2):
            self._labelendpointstext.append(vv.Label(a_text))
            self._labelendpointstext[i].position = 40, 15 + (20 * (i - 2))

        self._labelendpoints = []
        for i in range(0, self.nr_of_stents * 2, 2):
            self._labelendpoints.append(vv.Label(a_text))
            self._labelendpoints[i].position = 100, 15 + (20 * (i / 2)), 50, 20
            self._labelendpoints.append(vv.Label(a_text))
            self._labelendpoints[i + 1].position = 230, 15 + (20 *
                                                              (i / 2)), 50, 20

        # Create Select button
        self._select = False
        self._butselect = vv.PushButton(a_text)
        self._butselect.position = -110, 150
        self._butselect.text = 'Select'

        # Create Back button
        self._back = False
        self._butback = vv.PushButton(a_text)
        self._butback.position = 10, 150
        self._butback.text = 'Back'

        # Create Close button
        self._finished = False
        self._butclose = vv.PushButton(a_text)
        self._butclose.position = -50, 180
        self._butclose.text = 'Finish'

        # Get short name for sampling
        if isinstance(vol, Aarray):
            self._sam = sam = vol.sampling
        else:
            self._sam = None
            sam = (1, 1, 1)

        # Display the slices and 3D MIP
        self.b1 = VolViewer(vol, 0, axes=a_transversal, clim=clim)
        self.b2 = VolViewer(vol, 1, axes=a_coronal, clim=clim)
        self.b3 = VolViewer(vol, 2, axes=a_sagittal, clim=clim)

        renderstyle = 'mip'
        a_MIP.daspect = 1, 1, -1
        self.b4 = vv.volshow(vol,
                             clim=(0, 2500),
                             renderStyle=renderstyle,
                             axes=a_MIP)
        c = vv.ClimEditor(a_MIP)
        c.position = (10, 50)

        # set axis settings
        for a in [a_transversal, a_coronal, a_sagittal, a_MIP]:
            a.bgcolor = [0, 0, 0]
            a.axis.visible = False
            a.showAxis = True

        # get current slice number
        Zslice = self.b1.GetCurrentSlice()
        Yslice = self.b2.GetCurrentSlice()
        Xslice = self.b3.GetCurrentSlice()
        size = vol.shape

        # create lines for position of x,y and z slices
        origin = vol.origin
        Zrange = (origin[0], (size[0] * sam[0]) + origin[0])
        Xrange = (origin[1], (size[1] * sam[1]) + origin[1])
        Yrange = (origin[2], (size[2] * sam[2]) + origin[2])

        self.l11 = vv.Line(a_transversal, [(Yslice, Xrange[0]),
                                           (Yslice, Xrange[1])])
        self.l12 = vv.Line(a_transversal, [(Yrange[0], Xslice),
                                           (Yrange[1], Xslice)])

        self.l21 = vv.Line(a_coronal, [(Zslice, Zrange[0]),
                                       (Zslice, Zrange[1])])
        self.l22 = vv.Line(a_coronal, [(Yrange[0], Xslice),
                                       (Yrange[1], Xslice)])

        self.l31 = vv.Line(a_sagittal, [(Zslice, Zrange[0]),
                                        (Zslice, Zrange[1])])
        self.l32 = vv.Line(a_sagittal, [(Xrange[0], Yslice),
                                        (Xrange[1], Yslice)])

        # change color of the lines
        for i in [self.l11, self.l12, self.l21, self.l22, self.l31, self.l32]:
            i.lc = 'g'

        # create a point in the MIP figure for the current position
        self.mippoint = vv.Line(a_MIP, [(Zslice, Xslice, Yslice)])
        self.mippoint.ms = 'o'
        self.mippoint.mw = 5
        self.mippoint.mc = 'g'
        self.mippoint.alpha = 0.9

        # Get list of all range wobjects
        self._volviewers = [self.b1, self.b2, self.b3]

        # Bind events
        fig = a_text.GetFigure()
        fig.eventClose.Bind(self._OnFinish)
        self._butclose.eventPress.Bind(self._OnFinish)
        self._butselect.eventPress.Bind(self._OnSelect)
        self._butback.eventPress.Bind(self._OnBack)

        for r in self._volviewers:
            r.eventPositionUpdate.Bind(self._OnMouseClickAxis)
        for s in range(len(self._labelendpoints)):
            self._labelendpoints[s].eventMouseDown.Bind(
                self._OnMouseClickEndpoint)

        # Almost done
        self._SetTexts()
        self.updatePosition()
Exemplo n.º 8
0
import visvis as vv

# Create figure and figure
fig = vv.figure()
a = vv.cla()
a.cameraType = '2d'
a.daspectAuto = True
a.SetLimits((0, 8), (-1, 10))

# Create text inside the axes
vv.Text(a, 'These are texts living in the scene:', 1, 3)
vv.Text(a, 'Text can be made \b{bold} easil\by!', 1, 2)
vv.Text(a, 'Text can be made \i{italic} easil\iy!', 1, 1)

# Create text labels
label0 = vv.Label(a, 'These are texts in widget coordinates:')
label0.position = 10, 20
label1 = vv.Label(a, 'Sub_{script} and super^{script} are easy as pi^2.')
label1.position = 10, 40
label2 = vv.Label(a, u'You can use many Unicode characters: \\u0183 = \u0183')
label2.position = 10, 60
label3 = vv.Label(
    a, 'And can use many Latex like commands: \\alpha \\Alpha' +
    '\\approx, \sigma, \pi, ')
label3.position = 10, 80

for label in [label0, label1, label2, label3]:
    label.bgcolor = (0.5, 1, 0.5)
    label.position.w = 400

# Enter main loop
Exemplo n.º 9
0
# Initialize 2D view
axes2 = vv.Axes(vv.gcf())
axes2.position = 0.65, 0.05, 0.3, 0.4
axes2.daspectAuto = False
axes2.camera = '2d'
axes2.axis.showGrid = True
axes2.axis.axisColor = 'k'

# Initialize axes to put widgets and labels in
container = vv.Wibject(vv.gcf())
container.position = 0.65, 0.5, 0.3, 0.5

# Create labels to show measurements
labelpool = []
for i in range(16):
    label = vv.Label(container)
    label.fontSize = 11
    label.position = 10, 100 + 25 * i, -20, 25
    labelpool.append(label)

# Initialize sliders and buttons
slider_ref = vv.Slider(container, fullRange=(1, len(centerline) - 2), value=10)
slider_ves = vv.Slider(container, fullRange=(1, len(centerline) - 2), value=10)
button_go = vv.PushButton(container, "Take all measurements (incl. volume)")
slider_ref.position = 10, 5, -20, 25
slider_ves.position = 10, 40, -20, 25
button_go.position = 10, 70, -20, 25
button_go.bgcolor = slider_ref.bgcolor = slider_ves.bgcolor = 0.8, 0.8, 1.0

# Initialize line objects for showing the plane orthogonal to centerline
slider_ref.line_plane = vv.plot([], [], [],
Exemplo n.º 10
0
def pick3d(axes, vol):
    """ Enable picking intensities in a 3D volume.

    Given an Axes object and a volume (an Aarray), will show the value,
    index and position of the voxel with maximum intentity under the
    cursor when doing a SHIFT+RIGHTCLICK. Returns the label object, so
    that it can be re-positioned.
    
    Assumptions:
    * ThreeDCamera is in use and in orthographic mode (no perspective).
    * The volume does not have any transformations w.r.t the axes,
      except for the implicit transformations defined by its sampling
      and origin.
    """
    assert hasattr(vol, 'sampling'), 'Vol must be an Aarray.'

    line = vv.plot(vv.Pointset(3),
                   ms='o',
                   mw=12,
                   lc='c',
                   mc='c',
                   alpha=0.4,
                   axesAdjust=False)
    label = vv.Label(axes)
    label.position = 0, 0, 1, 20

    @axes.eventMouseDown.Bind
    def onClick(event):
        if event.button == 2 and vv.KEY_SHIFT in event.modifiers:
            # Get clicked location in NDC
            w, h = event.owner.position.size
            x, y = 2 * event.x / w - 1, -2 * event.y / h + 1
            # Apply inverse camera transform to get two points on the clicked line
            M = np.linalg.inv(get_camera_matrix(event.owner))
            p1 = vv.Point(np.dot((x, y, -100, 1), M)[:3])
            p2 = vv.Point(np.dot((x, y, +100, 1), M)[:3])
            # Calculate center point and vector
            pm = 0.5 * (p1 + p2)
            vec = (p2 - p1).normalize()
            # Prepare for searching in two directions
            pp = [pm - vec, pm + vec]
            status = 0 if sample(vol, pm) is None else 1
            status = [status, status]
            hit = None
            max_sample = -999999
            step = min(vol.sampling)
            # Look in two directions simulaneously, search for volume, collect samples
            for i in range(10000):  # Safe while-loop
                for j in (0, 1):
                    if status[j] < 2:
                        s = sample(vol, pp[j])
                        inside = s is not None
                        if inside:
                            if s > max_sample:
                                max_sample, hit = s, pp[j]
                            if status[j] == 0:
                                status[j] = 1
                                status[
                                    not j] = 2  # stop looking in other direction
                        else:
                            if status[j] == 1:
                                status[j] = 2
                        pp[j] += (j * 2 - 1) * step * vec
                if status[0] == 2 and status[1] == 2:
                    break
            else:
                print('Warning: ray casting to collect samples did not stop'
                      )  # clicking outside the volume
            # Draw
            pp2 = vv.Pointset(3)
            text = 'No point inside volume selected.'
            if hit:
                pp2.append(hit)
                ii = vol.point_to_index(hit)
                text = 'At z=%1.1f, y=%1.1f, x=%1.1f -> X[%i, %i, %i] -> %1.2f' % (
                    hit.z, hit.y, hit.x, ii[0], ii[1], ii[2], max_sample)
            line.SetPoints(pp2)
            label.text = text
            return True  # prevent default mouse action

    return label
Exemplo n.º 11
0
t1 = vv.Text(a, 'Visvis text', 0.2, 9, 0, 'mono', 30)
t2 = vv.Text(a, '... with FreeType!', 1, 8, 0, 'serif', 12)
t3 = vv.Text(a, '... and Unicode: %s!' % hello, 1, 7)
t3 = vv.Text(
    a, '\Gamma\rho\epsilon\epsilon\kappa letters and ' +
    ' \rightarrow math \otimes symbols', 1, 6)

t2 = vv.Text(
    a, '\b{bold}, \i{italic}, and \b{\i{bolditalic}} \bfon\its' +
    ' and sup^{script} and sub_{script}', 1, 5, 0, 'serif')
t3 = vv.Text(a, 'Look, I\'m at an angle!', 1, 4)
t3.textAngle = -20
t3.fontSize = 12

# Create text labels
label1 = vv.Label(a, 'This is a Label')
label1.position = 10, 0.9
label1.bgcolor = (0.5, 1, 0.5)

## A quick brown fox jumps over the lazy dog

testText = 'A quick brown fox jumps over the lazy dog'

# Create figure and figure
fig = vv.figure()
a = vv.cla()
a.cameraType = '2d'

vv.title(testText)
# Create text labels
for i in range(20):
Exemplo n.º 12
0
        dm.clim = clim3
    dm.colormap = vv.CM_JET #todo: use colormap Viridis or Magma as JET is not linear (https://bids.github.io/colormap/)
    vv.colorbar()
else:
    dm.faceColor = 'g'

# Run mesh
a.SetLimits()
# a.SetView(viewringcrop)
dm.MotionPlay(motionPlay[0], motionPlay[1])  # (10, 0.2) = each 10 ms do a step of 20% for a phase
dm.motionSplineType = 'B-spline'
dm.motionAmplitude = 0.5  # 1 or less. For a mesh we can (more) safely increase amplitude
#todo: dm.SetValues in loop for changing color?

# Add clickable nodes
t0 = vv.Label(a, 'Node nr|location: ', fontSize=11, color='w')
t0.position = 0.01, 5, 0.5, 20
t0.bgcolor = None
t0.visible = False
if meshWithColors:
    t1 = vv.Label(a, 'Node amplitude XYZ: ', fontSize=11, color='w')
    t1.position = 0.01, 25, 0.5, 20  # x (frac w), y, w (frac), h
    t1.bgcolor = None
    t1.visible = False
    t2 = vv.Label(a, 'Node amplitude Z: ', fontSize=11, color='w')
    t2.position = 0.01, 45, 0.5, 20
    t2.bgcolor = None
    t2.visible = False
    t3 = vv.Label(a, 'Node amplitude Y: ', fontSize=11, color='w')
    t3.position = 0.01, 65, 0.5, 20
    t3.bgcolor = None
Exemplo n.º 13
0
    def __init__(self,ptcode,ctcode,allcenterlines,basedir):
        """
        Script to show the stent plus centerline model and select points on 
        centerlines for motion analysis 
        """
        import os, time
        import pirt
        import visvis as vv
        import numpy as np
        import math
        import itertools
        import xlsxwriter
        from datetime import datetime

                
        from stentseg.utils.datahandling import select_dir, loadvol, loadmodel
        from stentseg.utils.new_pointset import PointSet
        from stentseg.stentdirect.stentgraph import create_mesh
        from stentseg.motion.vis import create_mesh_with_abs_displacement
        from stentseg.utils.visualization import show_ctvolume
        from pirt.utils.deformvis import DeformableTexture3D, DeformableMesh
        from stentseg.utils import PointSet
        from stentseg.stentdirect import stentgraph
        from visvis import Pointset # for meshes
        from stentseg.stentdirect.stentgraph import create_mesh
        from visvis.processing import lineToMesh, combineMeshes
        from visvis import ssdf
        from stentseg.utils.picker import pick3d
        try:
            from PyQt4 import QtCore, QtGui # PyQt5
        except ImportError:
            from PySide import QtCore, QtGui # PySide2
        from stentseg.apps.ui_dialog import MyDialog
        from stentseg.utils.centerline import dist_over_centerline # added for Mirthe 
        import copy
        
        
        cropname = 'prox'
        
        exceldir = os.path.join(basedir,ptcode)
        
        # Load deformations and avg ct (forward for mesh)
        # centerlines combined in 1 model
        m = loadmodel(basedir, ptcode, ctcode, cropname, modelname = 'centerline_total_modelavgreg_deforms') 
        model = m.model
        # centerlines separated in a model for each centerline
        # m_sep = loadmodel(basedir, ptcode, ctcode, cropname, modelname = 'centerline_modelavgreg_deforms')
        s = loadvol(basedir, ptcode, ctcode, cropname, what='avgreg')
        vol_org = copy.deepcopy(s.vol)
        s.vol.sampling = [vol_org.sampling[1], vol_org.sampling[1], vol_org.sampling[2]]
        s.sampling = s.vol.sampling
        vol = s.vol
        
        # Start visualization and GUI
        
        fig = vv.figure(30); vv.clf()
        
        fig.position = 0.00, 30.00,  944.00, 1002.00
        a = vv.gca()
        a.axis.axisColor = 1,1,1
        a.axis.visible = True
        a.bgcolor = 0,0,0
        a.daspect = 1, 1, -1
        lim = 2500
        t = vv.volshow(vol, clim=(0, lim), renderStyle='mip')
        pick3d(vv.gca(), vol)
        b = model.Draw(mc='b', mw = 0, lc='g', alpha = 0.5)
        vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)')
        vv.title('Model for LSPEAS %s  -  %s' % (ptcode[7:], ctcode))
        
        # Add clickable nodes
        t0 = time.time()
        node_points = []
        for i, node in enumerate(sorted(model.nodes())):
            node_point = vv.solidSphere(translation = (node), scaling = (0.6,0.6,0.6))
            node_point.faceColor = 'b'
            node_point.alpha = 0.5
            node_point.visible = True
            node_point.node = node
            node_point.nr = i
            node_points.append(node_point)
        t1 = time.time()
        print('Clickable nodes created, which took %1.2f min.' % ((t1-t0)/60))
        
        # list of correctly clicked nodes
        selected_nodes_sum = set()
        
        # Initialize labels
        t0 = vv.Label(a, '\b{Node nr|location}: ', fontSize=11, color='w')
        t0.position = 0.1, 25, 0.5, 20  # x (frac w), y, w (frac), h
        t0.bgcolor = None
        t0.visible = True
        t1 = vv.Label(a, '\b{Nodepair}: ', fontSize=11, color='w')
        t1.position = 0.1, 45, 0.5, 20
        t1.bgcolor = None
        t1.visible = True
        
        # Initialize output variable to store pulsatility analysis
        storeOutput = list()
        
        
        def on_key(event): 
            if event.key == vv.KEY_ENTER:
                
                # mogenlijkheden aantal nodes 
                    # 1 voor relative beweging vanuit avg punt
                    # 2 voor onderlinge beweging tussen twee punten
                    # 3 voor hoek in punt 2 van punt 1 naar punt 3
                    
                if len(selected_nodes) == 1:
                    selectn1 = selected_nodes[0].node
                    n1index = selected_nodes[0].nr
                    n1Deforms = model.node[selectn1]['deforms']
                    output = point_pulsatility(selectn1, n1Deforms)
                    output['NodesIndex'] = [n1index]
                    
                    # Store output with name
                    dialog_output = get_index_name()
                    output['Name'] = dialog_output
                    storeOutput.append(output)
                    
                    # update labels
                    t1.text = '\b{Node}: %i' % (n1index)
                    t1.visible = True
                    print('selection of 1 node stored')

                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
                    cl_merged = append_centerlines(allcenterlines) 
                    output = point_to_point_pulsatility(cl_merged, selectn1, 
                                        n1Deforms, selectn2, n2Deforms, type='euclidian')
                    output['NodesIndex'] = nindex
                    
                    # get distance_centerline
                   
                    #dist_cl = dist_over_centerline(cl_merged, selectn1, selectn2, type='euclidian') # toegevoegd Mirthe
                    
                    #dist_cl = dist_centerline_total(cl_merged, selectn1, 
                    #                    n1Deforms, selectn2, n2Deforms, type='euclidian')
                    
                    # Store output with name
                    dialog_output = get_index_name()
                    output['Name'] = dialog_output
                    storeOutput.append(output)  
                   
                    # update labels
                    t1.text = '\b{Node pair}: %i - %i' % (nindex[0], nindex[1])
                    t1.visible = True
                    print('selection of 2 nodes stored')
                        
                if len(selected_nodes) == 3:
                    # get nodes
                    selectn1 = selected_nodes[0].node
                    selectn2 = selected_nodes[1].node
                    selectn3 = selected_nodes[2].node
                    # get index of nodes which are in fixed order
                    n1index = selected_nodes[0].nr
                    n2index = selected_nodes[1].nr
                    n3index = selected_nodes[2].nr
                    nindex = [n1index, n2index, n3index]
                    # get deforms of nodes
                    n1Deforms = model.node[selectn1]['deforms']
                    n2Deforms = model.node[selectn2]['deforms']
                    n3Deforms = model.node[selectn3]['deforms']
                    # get angulation
                    output = line_line_angulation(selectn1, 
                                        n1Deforms, selectn2, n2Deforms, selectn3, n3Deforms)
                    output['NodesIndex'] = nindex
                    
                    # Store output with name
                    dialog_output = get_index_name()
                    output['Name'] = dialog_output
                    storeOutput.append(output)
                    
                    # update labels
                    t1.text = '\b{Nodes}: %i - %i - %i' % (nindex[0], nindex[1], nindex[2])
                    t1.visible = True
                    print('selection of 3 nodes stored')
                    
                if len(selected_nodes) > 3:
                    for node in selected_nodes:
                        node.faceColor = 'b'
                    selected_nodes.clear()
                    print('to many nodes selected, select 1,2 or 3 nodes')
                if len(selected_nodes) < 1:
                    for node in selected_nodes:
                        node.faceColor = 'b'
                    selected_nodes.clear()
                    print('to few nodes selected, select 1,2 or 3 nodes')                
                
                # Visualize analyzed nodes and deselect
                for node in selected_nodes:
                    selected_nodes_sum.add(node)

                for node in selected_nodes_sum:
                    node.faceColor = 'g'  # make green when analyzed
                selected_nodes.clear()
                
            if event.key == vv.KEY_ESCAPE:
                # FINISH MODEL, STORE TO EXCEL
                
                # Store to EXCEL
                storeOutputToExcel(storeOutput, exceldir)
                vv.close(fig)
                print('output stored to excel')
     
        selected_nodes = list()
        def select_node(event):
            """ select and deselect nodes by Double Click
            """
            if event.owner not in selected_nodes:
                event.owner.faceColor = 'r'
                selected_nodes.append(event.owner)
            elif event.owner in selected_nodes:
                event.owner.faceColor = 'b'
                selected_nodes.remove(event.owner)
        
        def pick_node(event):
            nodenr = event.owner.nr
            node = event.owner.node
            t0.text = '\b{Node nr|location}: %i | x=%1.3f y=%1.3f z=%1.3f' % (nodenr,node[0],node[1],node[2])
        
        def unpick_node(event):
            t0.text = '\b{Node nr|location}: '
        
        def point_pulsatility(point1, point1Deforms):
            n1Indices = point1 + point1Deforms
            pos_combinations = list(itertools.combinations(range(len(point1Deforms)),2))
            distances = []
            for i in pos_combinations:
                v = point1Deforms[i[0]] - point1Deforms[i[1]]
                distances.append(((v[0]**2 + v[1]**2 + v[2]**2)**0.5 ))
            distances = np.array(distances)
            
            # get max distance between phases
            point_phase_max = distances.max()
            point_phase_max = [point_phase_max, [x*10 for x in (pos_combinations[list(distances).index(point_phase_max)])]]
            
            # get min distance between phases
            point_phase_min = distances.min()
            point_phase_min = [point_phase_min, [x*10 for x in (pos_combinations[list(distances).index(point_phase_min)])]]
            
            return {'point_phase_min':point_phase_min,'point_phase_max': point_phase_max, 'Node1': [point1, point1Deforms]}

        def point_to_point_pulsatility(cl, point1, point1Deforms, 
                                            point2, point2Deforms,type='euclidian'):
            
            import numpy as np
            
            n1Indices = point1 + point1Deforms
            n2Indices = point2 + point2Deforms
            # define vector between nodes
            v = n1Indices - n2Indices
            distances = ( (v[:,0]**2 + v[:,1]**2 + v[:,2]**2)**0.5 ).reshape(-1,1)
            # get min and max distance
            point_to_pointMax = distances.max()
            point_to_pointMin = distances.min()
            # add phase in cardiac cycle where min and max where found (5th = 50%)
            point_to_pointMax = [point_to_pointMax, (list(distances).index(point_to_pointMax) )*10]
            point_to_pointMin = [point_to_pointMin, (list(distances).index(point_to_pointMin) )*10]
            # get median of distances
            point_to_pointMedian = np.percentile(distances, 50) # Q2
            # median of the lower half, Q1 and upper half, Q3
            point_to_pointQ1 = np.percentile(distances, 25)
            point_to_pointQ3 = np.percentile(distances, 75)
            # Pulsatility min max distance point to point
            point_to_pointP = point_to_pointMax[0] - point_to_pointMin[0]
            # add % change to pulsatility
            point_to_pointP = [point_to_pointP, (point_to_pointP/point_to_pointMin[0])*100 ]
            
            # find index of point on cll and calculate length change cll ???
            if isinstance(cl, PointSet):
                cl = np.asarray(cl).reshape((len(cl),3))
                
            indpoint1 = np.where( np.all(cl == point1, axis=-1) )[0] # -1 counts from last to the first axis
            indpoint2 = np.where( np.all(cl == point2, axis=-1) )[0] # renal point
            n1Indices = point1 + point1Deforms
            n2Indices = point2 + point2Deforms
            
            clDeforms = []
            clpart_deformed = []
            vectors = []
            clpart = []
            d = []
            dist_cl = []   
            clpartDeforms = []
            clpart_deformed_test = []
            
            for i in range(len(cl)):
                clDeforms1 = model.node[cl[i,0], cl[i,1], cl[i,2]]['deforms']
                clDeforms.append(clDeforms1)
                clpart_deformed1 = cl[i] + clDeforms1
                clpart_deformed.append(clpart_deformed1)
            
            # clpart = cl[min(indpoint1[0], indpoint2[0]):max(indpoint1[0], indpoint2[0])+1]
            
            clpart = clpart_deformed[min(indpoint1[0], indpoint2[0]):max(indpoint1[0], indpoint2[0])+1]
            
            # for i in range(len(clpart)):
            #     clpartDeforms1 = model.node[clpart[i,0], clpart[i,1], clpart[i,2]]['deforms']
            #     clpartDeforms.append(clpartDeforms1)
            #     clpart_deformed1_test = cl[i] + clpartDeforms1
            #     clpart_deformed_test.append(clpart_deformed1_test)
                
            # for k in range(len(n1Indices)):
            #     vectors_phases = np.vstack([clpart_deformed_test[i+1][k]-clpart_deformed_test[i][k] for i in range(len(clpart)-1)])
            #     vectors.append(vectors_phases)
                
            for k in range(len(n1Indices)):
                vectors_phases = np.vstack([clpart[i+1][k]-clpart[i][k] for i in range(len(clpart)-1)])
                vectors.append(vectors_phases)
            
            for i in range(len(vectors)):
                if type == 'euclidian':
                    d1 = (vectors[i][:,0]**2 + vectors[i][:,1]**2 + vectors[i][:,2]**2)**0.5  # 3Dvector length in mm
                    d.append(d1)
                elif type == 'z':
                    d = abs(vectors[i][:,2])  # x,y,z ; 1Dvector length in mm
             
            for i in range(len(d)):
                dist = d[i].sum()
                dist_cl.append(dist)
               
            #if indpoint2 > indpoint1: # stent point proximal to renal on centerline: positive
                #dist_cl*=-1
                
            cl_min_index1 = np.argmin(dist_cl)   
            cl_min_index = cl_min_index1*10
            cl_min = min(dist_cl)
            cl_max_index1 = np.argmax(dist_cl)   
            cl_max_index = cl_max_index1*10
            cl_max = max(dist_cl)
            
            print ([dist_cl])
            print ([point1, point2])
            
            return {'point_to_pointMin': point_to_pointMin, 
            'point_to_pointQ1': point_to_pointQ1, 
            'point_to_pointMedian': point_to_pointMedian, 
            'point_to_pointQ3': point_to_pointQ3, 
            'point_to_pointMax': point_to_pointMax, 
            'point_to_pointP': point_to_pointP, 
            'Node1': [point1, point1Deforms], 
            'Node2': [point2, point2Deforms], 'distances': distances, 
            'dist_cl': dist_cl, 'cl_min_index': cl_min_index, 
            'cl_max_index': cl_max_index, 'cl_min': cl_min, 'cl_max': cl_max}
            
        
        def line_line_angulation(point1, point1Deforms, point2, point2Deforms, point3, point3Deforms):
            n1Indices = point1 + point1Deforms
            n2Indices = point2 + point2Deforms
            n3Indices = point3 + point3Deforms
            
            # get vectors
            v1 = n1Indices - n2Indices
            v2 = n3Indices - n2Indices
            
            # get angles
            angles = []
            for i in range(len(v1)):
                angles.append(math.degrees(math.acos((np.dot(v1[i],v2[i]))/
                (np.linalg.norm(v1[i])*np.linalg.norm(v2[i])))))
            angles = np.array(angles)
            
            # get all angle differences of all phases
            pos_combinations = list(itertools.combinations(range(len(v1)),2))
            angle_diff = []
            for i in pos_combinations:
                v = point1Deforms[i[0]] - point1Deforms[i[1]]
                angle_diff.append(abs(angles[i[0]] - angles[i[1]]))
            angle_diff = np.array(angle_diff)
            
            # get max angle differences
            point_angle_diff_max = angle_diff.max()
            point_angle_diff_max = [point_angle_diff_max, [x*10 for x in
            (pos_combinations[list(angle_diff).index(point_angle_diff_max)])]]
            
            # get min angle differences
            point_angle_diff_min = angle_diff.min()
            point_angle_diff_min = [point_angle_diff_min, [x*10 for x in 
            (pos_combinations[list(angle_diff).index(point_angle_diff_min)])]]
            
            return {'point_angle_diff_min':point_angle_diff_min,
            'point_angle_diff_max': point_angle_diff_max, 'angles': angles, 
            'Node1': [point1, point1Deforms], 'Node2': [point2, point2Deforms], 
            'Node3': [point3, point1Deforms]}
            
        
        def append_centerlines(allcenterlines):
            """ Merge seperated PointSet centerlines into one PointSet
            """
            # cl_merged = allcenterlines[0]
            cl_merged = PointSet(3)
            for i in range(0,len(allcenterlines)):
                for point in allcenterlines[i]:
                    cl_merged.append(point)
            return cl_merged
            
            
        def get_index_name():
                # Gui for input name
                app = QtGui.QApplication([])
                m = MyDialog()
                m.show()
                m.exec_()
                dialog_output = m.edit.text()
                return dialog_output  
            
       
        def storeOutputToExcel(storeOutput, exceldir):
            """Create file and add a worksheet or overwrite existing
            """
            # https://pypi.python.org/pypi/XlsxWriter
            workbook = xlsxwriter.Workbook(os.path.join(exceldir,'storeOutput.xlsx'))
            worksheet = workbook.add_worksheet('General')
            # set column width
            worksheet.set_column('A:A', 35)
            worksheet.set_column('B:B', 30)
            # add a bold format to highlight cells
            bold = workbook.add_format({'bold': True})
            # write title and general tab
            worksheet.write('A1', 'Output ChEVAS dynamic CT, 10 Phases', bold)
            analysisID = '%s_%s_%s' % (ptcode, ctcode, cropname)
            worksheet.write('A2', 'Filename:', bold)
            worksheet.write('B2', analysisID)
            worksheet.write('A3', 'Date and Time:', bold)
            date_time = datetime.now() #strftime("%d-%m-%Y %H:%M")
            date_format_str = 'dd-mm-yyyy hh:mm'
            date_format = workbook.add_format({'num_format': date_format_str,
                                      'align': 'left'})
            worksheet.write_datetime('B3', date_time, date_format)
            # write 'storeOutput'
            sort_index = []
            for i in range(len(storeOutput)):
                type = len(storeOutput[i]['NodesIndex'])
                sort_index.append([i, type])
            sort_index = np.array(sort_index)
            sort_index = sort_index[sort_index[:,1].argsort()]
            
            for i, n in sort_index:
                worksheet = workbook.add_worksheet(storeOutput[i]['Name'])
                worksheet.set_column('A:A', 35)
                worksheet.set_column('B:B', 20)
                worksheet.write('A1', 'Name:', bold)
                worksheet.write('B1', storeOutput[i]['Name'])
                if n == 1:
                    worksheet.write('A2', 'Type:', bold)
                    worksheet.write('B2', '1 Node')
                    
                    worksheet.write('A3', 'Minimum translation (mm, Phases)',bold)
                    worksheet.write('B3', storeOutput[i]['point_phase_min'][0])
                    worksheet.write_row('C3', list(storeOutput[i]['point_phase_min'][1]))
                    
                    worksheet.write('A4', 'Maximum translation (mm, Phases)',bold)
                    worksheet.write('B4', storeOutput[i]['point_phase_max'][0])
                    worksheet.write_row('C4', list(storeOutput[i]['point_phase_max'][1]))
                    
                    worksheet.write('A5', 'Avg node position and deformations', bold)
                    worksheet.write('B5', str(list(storeOutput[i]['Node1'][0])))
                    worksheet.write_row('C5', [str(x)for x in list(storeOutput[i]['Node1'][1])])
                    
                    worksheet.write('A6', 'Node Index Number', bold)
                    worksheet.write_row('B6', list(storeOutput[i]['NodesIndex'])) 
                                       
                elif n == 2:
                    worksheet.write('A2', 'Type:', bold)
                    worksheet.write('B2', '2 Nodes')
                    
                    worksheet.write('A3', 'Minimum distance (mm, Phases)',bold)
                    worksheet.write('B3', storeOutput[i]['point_to_pointMin'][0])
                    worksheet.write('C3', storeOutput[i]['point_to_pointMin'][1])
                    
                    worksheet.write('A4', 'Q1 distance (mm)',bold)
                    worksheet.write('B4', storeOutput[i]['point_to_pointQ1'])

                    worksheet.write('A5', 'Median distance (mm)',bold)
                    worksheet.write('B5', storeOutput[i]['point_to_pointMedian'])
                    
                    worksheet.write('A6', 'Q3 distance (mm)',bold)
                    worksheet.write('B6', storeOutput[i]['point_to_pointQ3'])
                    
                    worksheet.write('A7', 'Maximum distance (mm, phases)',bold)
                    worksheet.write('B7', storeOutput[i]['point_to_pointMax'][0])
                    worksheet.write('C7', storeOutput[i]['point_to_pointMax'][1])
                    
                    worksheet.write('A8', 'Maximum distance difference (mm)', bold)
                    worksheet.write('B8', storeOutput[i]['point_to_pointP'][0])
                    
                    worksheet.write('A9', 'Distances for each phase', bold)
                    worksheet.write_row('B9', [str(x) for x in list(storeOutput[i]['distances'])])
                    
                    worksheet.write('A10', 'Avg node1 position and deformations', bold)
                    worksheet.write('B10', str(list(storeOutput[i]['Node1'][0])))
                    worksheet.write_row('C10', [str(x) for x in list(storeOutput[i]['Node1'][1])])
                    
                    worksheet.write('A11', 'Avg node2 position and deformations', bold)
                    worksheet.write('B11', str(list(storeOutput[i]['Node2'][0])))
                    worksheet.write_row('C11', [str(x) for x in list(storeOutput[i]['Node2'][1])])
                    
                    worksheet.write('A12', 'Node Index Number', bold)
                    worksheet.write_row('B12', list(storeOutput[i]['NodesIndex'])) 
                    
                    worksheet.write('A13', 'Length centerline', bold) 
                    worksheet.write('B13', str(list(storeOutput[i]['dist_cl']))) 
                    
                    worksheet.write('A14', 'Minimum length centerline', bold) 
                    worksheet.write('B14', storeOutput[i]['cl_min']) 
                    worksheet.write('C14', storeOutput[i]['cl_min_index']) 
                    
                    worksheet.write('A15', 'Maximum length centerline', bold) 
                    worksheet.write('B15', storeOutput[i]['cl_max'])  
                    worksheet.write('C15', storeOutput[i]['cl_max_index']) 
                
                elif n == 3:
                    worksheet.write('A2', 'Type:', bold)
                    worksheet.write('B2', '3 Nodes')
                    
                    worksheet.write('A3', 'Minimum angle difference (degrees, Phases)',bold)
                    worksheet.write('B3', storeOutput[i]['point_angle_diff_min'][0])
                    worksheet.write_row('C3', list(storeOutput[i]['point_angle_diff_min'][1]))
                    
                    worksheet.write('A4', 'Maximum angle difference (degrees, Phases)',bold)
                    worksheet.write('B4', storeOutput[i]['point_angle_diff_max'][0])
                    worksheet.write_row('C4', list(storeOutput[i]['point_angle_diff_max'][1]))
                    
                    worksheet.write('A5', 'Angles for each phase (degrees)',bold)
                    worksheet.write_row('B5', list(storeOutput[i]['angles']))
                    
                    worksheet.write('A6', 'Avg node1 position and deformations', bold)
                    worksheet.write('B6', str(list(storeOutput[i]['Node1'][0])))
                    worksheet.write_row('C6', [str(x) for x in list(storeOutput[i]['Node1'][1])])
                    
                    worksheet.write('A7', 'Avg node2 position and deformations', bold)
                    worksheet.write('B7', str(list(storeOutput[i]['Node2'][0])))
                    worksheet.write_row('C7', [str(x) for x in list(storeOutput[i]['Node2'][1])])
                    
                    worksheet.write('A8', 'Avg node2 position and deformations', bold)
                    worksheet.write('B8', str(list(storeOutput[i]['Node3'][0])))
                    worksheet.write_row('C8', [str(x) for x in list(storeOutput[i]['Node3'][1])])
                    
                    worksheet.write('A9', 'Node Index Number', bold)
                    worksheet.write_row('B9', list(storeOutput[i]['NodesIndex']))   
                    
            workbook.close()
        
        # Bind event handlers
        fig.eventKeyDown.Bind(on_key)
        for node_point in node_points:
            node_point.eventDoubleClick.Bind(select_node)
            node_point.eventEnter.Bind(pick_node)
            node_point.eventLeave.Bind(unpick_node)