def add_segmentation_ssdf(basedir, ptcode, ctcode, cropname, seeds, model, graphname, s2=None, modelname='modelavgreg', stentType=None, params=None): """ Add a model to an existing ssdf but separate from the existing graph s2 = ssdf of existing model to add new segmentation graph in ssdf graphname = name of new graph to save in ssdf """ if s2 is None: s2 = loadmodel(basedir, ptcode, ctcode, cropname, modelname) # unpacks to graph s2['params'+graphname] = params s2['stentType'+graphname] = stentType # Store model if model is not None: # step 2 and 3 were performed otherwise NoneType s2['model'+graphname] = model s2['seeds'+graphname] = seeds else: # store seeds as model s2['model'+graphname] = seeds.copy() s2['seeds'+graphname] = seeds # pack all graphs to ssdf for save for key in dir(s2): if key.startswith('model'): s2[key] = s2[key].pack() if key.startswith('seeds'): s2[key] = s2[key].pack() # Save filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, modelname) ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk in {} as {}.'.format(basedir, filename) )
def showModel3d(basedir,ptcode, ctcode, cropname='ring', showVol='MIP', showmodel=True, graphname='model', **kwargs): """ show model and vol in 3d by mip iso or 2D graphname 'all' draws all graph models stored in s, if multiple """ s = loadmodel(basedir, ptcode, ctcode, cropname, modelname='modelavgreg') vol = loadvol(basedir, ptcode, ctcode, cropname, what='avgreg').vol # figure f = vv.figure(); vv.clf() f.position = 0.00, 22.00, 1920.00, 1018.00 a = vv.gca() a.axis.axisColor = 1,1,1 a.axis.visible = False a.bgcolor = 0,0,0 a.daspect = 1, 1, -1 t = show_ctvolume(vol, axis=a, showVol=showVol, removeStent=False, climEditor=True, **kwargs) label = pick3d(a, vol) vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') if showmodel: if graphname == 'all': for key in dir(s): if key.startswith('model'): s[key].Draw(mc='b', mw = 5, lc='g', alpha = 0.5) else: s[graphname].Draw(mc='b', mw = 5, lc='g', alpha = 0.5) vv.title('Model for LSPEAS %s - %s' % (ptcode[8:], ctcode)) # f.eventKeyDown.Bind(lambda event: _utils_GUI.RotateView(event, [a], axishandling=False )) f.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event, [a]) ) return f, a, label, s
def make_model_dynamic(basedir, ptcode, ctcode, cropname, what='avgreg'): """ Read deforms and model to make model dynamic, ie, add deforms to edges and nodes in the graph """ # Load deforms s = loadvol(basedir, ptcode, ctcode, cropname, 'deforms') deformkeys = [] for key in dir(s): if key.startswith('deform'): deformkeys.append(key) deforms = [s[key] for key in deformkeys] deforms = [pirt.DeformationFieldBackward(*fields) for fields in deforms] paramsreg = s.params # Load model s = loadmodel(basedir, ptcode, ctcode, cropname, 'model'+what) for key in dir(s): if key.startswith('model'): model = s[key] # Combine ... incorporate_motion_nodes(model, deforms, s.origin) # adds deforms PointSets incorporate_motion_edges(model, deforms, s.origin) # adds deforms PointSets s[key] = model.pack() # also pack seeds before save if key.startswith('seeds'): s[key] = s[key].pack() # Save back filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'model'+what) s.paramsreg = paramsreg ssdf.save(os.path.join(basedir, ptcode, filename), s) print('saved dynamic to disk in {} as {}.'.format(basedir, filename) )
def model2mesh(basedir,savedir,ptcode,ctcode,cropname,modelname='modelavgreg'): from stentseg.stentdirect.stentgraph import create_mesh # formats that can be saved to: .obj .stl .ssdf .bsdf filename = '%s_%s_%s_%s.stl' % (ptcode, ctcode, cropname, modelname) # Load the stent model and mesh s = loadmodel(basedir, ptcode, ctcode, cropname, modelname) model = s.model mesh = create_mesh(model, 0.4) # Param is thickness (with 0.4 -> ~0.75mm diam) mesh._vertices[:,-1] *= -1 # flip z, negative in original dicom mesh._normals[:,-1] *= -1 # flip also normals to change front face and back face along vv.meshWrite(os.path.join(savedir, filename),mesh)
def loadvolmodel(basedir, ptcode, ctcode1, cropname, modelname, nstruts=8, ringpart=False): """ load vol and model """ s1 = loadmodel(basedir, ptcode, ctcode1, cropname, modelname) model = s1.model models1 = [] for ringname in ringnames: model1 = s1[ringname] if ringpart: models = get_model_struts(model1, nstruts=nstruts) modelRs = get_model_rings(models[2]) # model_R1R2 model1 = modelRs[ringpart - 1] # R1 or R2 models1.append(model1) vol1 = loadvol(basedir, ptcode, ctcode1, cropname, 'avgreg').vol return vol1, models1, model
def add_segmentation_graph(basedir, ptcode, ctcode, cropname, seeds, model, s2=None, graphname='', modelname='modelavgreg'): """ add segmentation to an existing graph s2 = ssdf of existing segmentation model to add graph to this model graphname = model is default storename for model but can also be modelbranch for example if this was used in add_segmentation_ssdf """ if s2 is None: s2 = loadmodel(basedir, ptcode, ctcode, cropname, modelname) # unpacks graphold = s2['model'+graphname] seedsold = s2['seeds'+graphname] # add seeds graph seedsold.add_nodes_from(seeds.nodes(data=True)) # including attributes if any # add nodes and edges to graph model if model is not None: # step 2 and 3 were performed otherwise NoneType graphold.add_nodes_from(model.nodes(data=True)) graphold.add_edges_from(model.edges(data=True)) else: # store seeds with model graphold.add_nodes_from(seeds.nodes(data=True)) # Store model s2['model'+graphname] = graphold s2['seeds'+graphname] = seedsold # pack all graphs to ssdf for save for key in dir(s2): if key.startswith('model'): s2[key] = s2[key].pack() if key.startswith('seeds'): s2[key] = s2[key].pack() # Save filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, modelname) ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk in {} as {}.'.format(basedir, filename) )
# Load deforms s = loadvol(basedir, ptcode, ctcode, cropname, 'deforms') deformkeys = [] for key in dir(s): if key.startswith('deform'): deformkeys.append(key) deforms = [s[key] for key in deformkeys] deforms = [pirt.DeformationFieldBackward(*fields) for fields in deforms] paramsreg = s.params # Load centerline mat matName = '%s_%s_%s_%s.mat' % (ptcode, ctcode, cropname, what) centerlineMat = scipy.io.loadmat(os.path.join(basedirstl, ptcode, matName)) # Load model s = loadmodel(basedirstl, ptcode, ctcode, cropname, what) for key in dir(s): if key.startswith('model'): model = s[key] # Combine ... incorporate_motion_nodes(model, deforms, s.origin) # adds deforms PointSets incorporate_motion_edges(model, deforms, s.origin) # adds deforms PointSets # get deforms of centerline path as array assert model.number_of_edges() == 1 # cll should be 1 path centerlineEdge = model.edges()[0] # the two nodes that define the edge centerlineDeforms = model.edge[centerlineEdge[0]][ centerlineEdge[1]]['pathdeforms']
import visvis as vv from visvis import ssdf from visvis import Pointset from stentseg.utils.picker import pick3d, get_picked_seed from stentseg.utils import PointSet, _utils_GUI, visualization basedir = select_dir(os.getenv('LSPEAS_BASEDIR', ''), r'D:\LSPEAS\LSPEAS_ssdf', r'F:\LSPEAS_ssdf_BACKUP', r'G:\LSPEAS_ssdf_BACKUP') ptcode = 'LSPEAS_025' ctcode = '1month' cropname = 'ring' modelname = 'modelavgreg' s = loadmodel(basedir, ptcode, ctcode, cropname, modelname) model = s.model.copy() # Load volume s_vol = loadvol(basedir, ptcode, ctcode, cropname, 'avgreg') vol = s_vol.vol # Load deforms s_deforms = loadvol(basedir, ptcode, ctcode, cropname, 'deforms') deformkeys = [] for key in dir(s_deforms): if key.startswith('deform'): deformkeys.append(key) deforms = [s_deforms[key] for key in deformkeys] deforms = [pirt.DeformationFieldBackward(*fields) for fields in deforms]
AC.a.bgcolor = 1, 1, 1 # get start endpoints stentsStartPoints = AC.s.StartPoints stentsEndPoints = AC.s.EndPoints vesselStartPoints = AC.s_vessel.StartPoints vesselEndPoints = AC.s_vessel.EndPoints # get ppcenterlines to plot with appropriate markers and colors allcenterlines = AC.s.ppallCenterlines allcenterlinesv = AC.s_vessel.ppallCenterlines # get seedpoints segmentations s_modelvessel = loadmodel(basedir, ptcode, ctcode, 'prox', modelname='modelvesselavgreg') ppmodelvessel = points_from_nodes_in_graph(s_modelvessel.model) s_model = loadmodel(basedir, ptcode, ctcode, 'prox', modelname='modelavgreg') ppmodel = points_from_nodes_in_graph(s_model.model) # Visualize AC.a.MakeCurrent() vv.cla() # clear vol otherwise plots not visible somehow # seedpoints segmentations vv.plot(ppmodelvessel, ms='.', ls='', alpha=0.6, mw=2) vv.plot(ppmodel, ms='.', ls='', alpha=0.6, mw=2)
s = loadvol(basedir2, ptcode, ctcode, cropname, what) nrs = [1,2,4,5,7,8,10,11,13,14,16,17,19,20,22,23,25,26] FIG1 = False ## Load all rings of the limb for i in nrs: ring = 'ringR%s' %(i) filename = '%s_%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'model'+what,ring) s["ringR" + str(i)] = ssdf.load(os.path.join(basedir1, filename)) ## Visualize centerlines rings s2 = loadmodel(targetdir2, ptcode, ctcode, cropname, modelname='stentseedsavgreg') pmodel = points_from_nodes_in_graph(s2.model) if FIG1 == True: f = vv.figure(1); vv.clf() f.position = 709.00, 30.00, 1203.00, 1008.00 a1 = vv.subplot(121) show_ctvolume(s.vol, None, showVol=showVol, clim=clim0, isoTh=isoTh, removeStent=False) label = pick3d(vv.gca(), s.vol) a1.axis.visible = showAxis a1.daspect = 1,1,-1 a2 = vv.subplot(122) vv.plot(pmodel, ms='.', ls='', alpha=0.2, mw = 2) # stent seed points for i in nrs: pp = s["ringR" + str(i)].ringpoints vv.plot(pp[0],pp[1],pp[2], ms='.', ls='', mw=3, mc='c')
def __init__(self, ptcode, ctcode, basedir, showVol='mip', meshWithColors=False, motion='amplitude', clim2=(0, 2)): """ Script to show the stent model. [ nellix] """ import os import pirt import visvis as vv from stentseg.utils.datahandling import select_dir, loadvol, loadmodel from pirt.utils.deformvis import DeformableTexture3D, DeformableMesh from stentseg.stentdirect.stentgraph import create_mesh from stentseg.stentdirect import stentgraph from stentseg.utils.visualization import show_ctvolume from stentseg.motion.vis import create_mesh_with_abs_displacement import copy from stentseg.motion.dynamic import incorporate_motion_nodes, incorporate_motion_edges from lspeas.utils.ecgslider import runEcgSlider from stentseg.utils import _utils_GUI import numpy as np cropname = 'prox' # params nr = 1 # motion = 'amplitude' # amplitude or sum dimension = 'xyz' showVol = showVol # MIP or ISO or 2D or None clim0 = (0, 2000) # clim2 = (0,2) motionPlay = 9, 1 # each x ms, a step of x % s = loadvol(basedir, ptcode, ctcode, cropname, what='deforms') m = loadmodel(basedir, ptcode, ctcode, cropname, 'centerline_total_modelavgreg_deforms') v = loadmodel(basedir, ptcode, ctcode, cropname, modelname='centerline_total_modelvesselavgreg_deforms') s2 = loadvol(basedir, ptcode, ctcode, cropname, what='avgreg') vol_org = copy.deepcopy(s2.vol) s2.vol.sampling = [ vol_org.sampling[1], vol_org.sampling[1], vol_org.sampling[2] ] s2.sampling = s2.vol.sampling vol = s2.vol # merge models into one for dynamic visualization model_total = stentgraph.StentGraph() for key in dir(m): if key.startswith('model'): model_total.add_nodes_from( m[key].nodes(data=True)) # also attributes model_total.add_edges_from(m[key].edges(data=True)) for key in dir(v): if key.startswith('model'): model_total.add_nodes_from( v[key].nodes(data=True)) # also attributes model_total.add_edges_from(v[key].edges(data=True)) # Load deformations (forward for mesh) deformkeys = [] for key in dir(s): if key.startswith('deform'): deformkeys.append(key) deforms = [s[key] for key in deformkeys] deforms = [[field[::2, ::2, ::2] for field in fields] for fields in deforms] # These deforms are forward mapping. Turn into DeformationFields. # Also get the backwards mapping variants (i.e. the inverse deforms). # The forward mapping deforms should be used to deform meshes (since # the information is used to displace vertices). The backward mapping # deforms should be used to deform textures (since they are used in # interpolating the texture data). deforms_f = [pirt.DeformationFieldForward(*f) for f in deforms] deforms_b = [f.as_backward() for f in deforms_f] # Create mesh if meshWithColors: try: modelmesh = create_mesh_with_abs_displacement(model_total, radius=0.7, dim=dimension, motion=motion) except KeyError: print('Centerline model has no pathdeforms so we create them') # use unsampled deforms deforms2 = [s[key] for key in deformkeys] # deforms as backward for model deformsB = [ pirt.DeformationFieldBackward(*fields) for fields in deforms2 ] # set sampling to original # for i in range(len(deformsB)): # deformsB[i]._field_sampling = tuple(s.sampling) # not needed because we use unsampled deforms # Combine ... incorporate_motion_nodes(model_total, deformsB, s2.origin) convert_paths_to_PointSet(model_total) incorporate_motion_edges(model_total, deformsB, s2.origin) convert_paths_to_ndarray(model_total) modelmesh = create_mesh_with_abs_displacement(model_total, radius=0.7, dim=dimension, motion=motion) else: modelmesh = create_mesh(model_total, 0.7, fullPaths=True) ## Start vis f = vv.figure(nr) vv.clf() if nr == 1: f.position = 8.00, 30.00, 944.00, 1002.00 else: f.position = 968.00, 30.00, 944.00, 1002.00 a = vv.gca() a.axis.axisColor = 1, 1, 1 a.axis.visible = False a.bgcolor = 0, 0, 0 a.daspect = 1, 1, -1 t = vv.volshow(vol, clim=clim0, renderStyle=showVol, axes=a) vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') if meshWithColors: if dimension == 'xyz': dim = '3D' vv.title( 'Model for chEVAS %s (color-coded %s of movement in %s in mm)' % (ptcode[8:], motion, dim)) else: vv.title('Model for chEVAS %s' % (ptcode[8:])) colorbar = True # Create deformable mesh dm = DeformableMesh(a, modelmesh) # in x,y,z dm.SetDeforms(*[list(reversed(deform)) for deform in deforms_f]) # from z,y,x to x,y,z if meshWithColors: dm.clim = clim2 dm.colormap = vv.CM_JET #todo: use colormap Viridis or Magma as JET is not linear (https://bids.github.io/colormap/) if colorbar: vv.colorbar() colorbar = False 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% dm.motionSplineType = 'B-spline' dm.motionAmplitude = 0.5 ## run ecgslider ecg = runEcgSlider(dm, f, a, motionPlay)
def __init__(self, ptcode, ctcode, StartPoints, EndPoints, basedir, modelname='modelavgreg'): """ with start and endpoints provided, calculate centerline and save as ssdf in basedir as model and dynamic model """ #todo: name of dynamic model is now deforms, unclear, should be dynamic #import numpy as np import visvis as vv import numpy as np import os import copy from stentseg.utils import PointSet, _utils_GUI from stentseg.utils.centerline import (find_centerline, points_from_nodes_in_graph, points_from_mesh, smooth_centerline) from stentseg.utils.datahandling import loadmodel, loadvol from stentseg.utils.visualization import show_ctvolume from stentseg.utils.picker import pick3d stentnr = len(StartPoints) cropname = 'prox' what = modelname what_vol = 'avgreg' vismids = True m = loadmodel(basedir, ptcode, ctcode, cropname, what) s = loadvol(basedir, ptcode, ctcode, cropname, what_vol) s.vol.sampling = [s.sampling[1], s.sampling[1], s.sampling[2]] s.sampling = s.vol.sampling start1 = StartPoints.copy() ends = EndPoints.copy() from stentseg.stentdirect import stentgraph ppp = points_from_nodes_in_graph(m.model) allcenterlines = [] # for pp allcenterlines_nosmooth = [] # for pp centerlines = [] # for stentgraph nodes_total = stentgraph.StentGraph() for j in range(stentnr): if j == 0 or not start1[j] == ends[j - 1]: # if first stent or when stent did not continue with this start point nodes = stentgraph.StentGraph() centerline = PointSet(3) # empty # Find main centerline # if j > 3: # for stent with midpoints # centerline1 = find_centerline(ppp, start1[j], ends[j], step= 1, # ndist=10, regfactor=0.5, regsteps=10, verbose=False) #else: centerline1 = find_centerline(ppp, start1[j], ends[j], step=1, ndist=10, regfactor=0.5, regsteps=1, verbose=False) # centerline1 is a PointSet print('Centerline calculation completed') # ========= Maaike ======= smoothfactor = 15 # Mirthe used 2 or 4 # check if cll continued here from last end point if not j == 0 and start1[j] == ends[j - 1]: # yes we continued ppart = centerline1[: -1] # cut last but do not cut first point as this is midpoint else: # do not use first points, as they are influenced by user selected points ppart = centerline1[1:-1] for p in ppart: centerline.append(p) # if last stent or stent does not continue with next start-endpoint if j == stentnr - 1 or not ends[j] == start1[j + 1]: # store non-smoothed for vis allcenterlines_nosmooth.append(centerline) pp = smooth_centerline(centerline, n=smoothfactor) # add pp to list allcenterlines.append(pp) # list with PointSet per centerline self.allcenterlines = allcenterlines # add pp as nodes for i, p in enumerate(pp): p_as_tuple = tuple(p.flat) nodes.add_node(p_as_tuple) nodes_total.add_node(p_as_tuple) # add pp as one edge so that pathpoints are in fixed order pstart = tuple(pp[0].flat) pend = tuple(pp[-1].flat) nodes.add_edge(pstart, pend, path=pp) nodes_total.add_edge(pstart, pend, path=pp) # add final centerline nodes model to list centerlines.append(nodes) # ========= Maaike ======= ## Store segmentation to disk # Build struct s2 = vv.ssdf.new() s2.sampling = s.sampling s2.origin = s.origin s2.stenttype = m.stenttype s2.croprange = m.croprange for key in dir(m): if key.startswith('meta'): suffix = key[4:] s2['meta' + suffix] = m['meta' + suffix] s2.what = what s2.params = s.params #reg s2.paramsseeds = m.params s2.stentType = 'nellix' s2.StartPoints = StartPoints s2.EndPoints = EndPoints # keep centerlines as pp also [Maaike] s2.ppallCenterlines = allcenterlines for k in range(len(allcenterlines)): suffix = str(k) pp = allcenterlines[k] s2['ppCenterline' + suffix] = pp s3 = copy.deepcopy(s2) s3['model'] = nodes_total.pack() # Store model for each centerline for j in range(len(centerlines)): suffix = str(j) model = centerlines[j] s2['model' + suffix] = model.pack() # Save model with seperate centerlines. filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'centerline_' + what) vv.ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk as {}.'.format(filename)) # Save model with combined centerlines filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'centerline_total_' + what) vv.ssdf.save(os.path.join(basedir, ptcode, filename), s3) print('saved to disk as {}.'.format(filename)) # remove intermediate centerline points # start1 = map(tuple, start1) # ends = map(tuple, ends) startpoints_clean = copy.deepcopy(start1) endpoints_clean = copy.deepcopy(ends) duplicates = list(set(start1) & set(ends)) for i in range(len(duplicates)): startpoints_clean.remove(duplicates[i]) endpoints_clean.remove(duplicates[i]) #Visualize f = vv.figure(10) vv.clf() a1 = vv.subplot(121) a1.daspect = 1, 1, -1 vv.plot(ppp, ms='.', ls='', alpha=0.6, mw=2) for j in range(len(startpoints_clean)): vv.plot(PointSet(list(startpoints_clean[j])), ms='.', ls='', mc='g', mw=20) # startpoint green vv.plot(PointSet(list(endpoints_clean[j])), ms='.', ls='', mc='r', mw=20) # endpoint red for j in range(len(allcenterlines)): vv.plot(allcenterlines[j], ms='.', ls='', mw=10, mc='y') vv.title('Centerlines and seed points') vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') # for j in range(len(allcenterlines_nosmooth)): # vv.plot(allcenterlines_nosmooth[j], ms='o', ls='', mw=10, mc='c', alpha=0.6) a2 = vv.subplot(122) a2.daspect = 1, 1, -1 vv.plot(ppp, ms='.', ls='', alpha=0.6, mw=2) # vv.volshow(s.vol, clim=clim, renderStyle = 'mip') t = show_ctvolume(s.vol, axis=a2, showVol='ISO', clim=(0, 2500), isoTh=250, removeStent=False, climEditor=True) label = pick3d(vv.gca(), s.vol) for j in range(len(startpoints_clean)): vv.plot(PointSet(list(startpoints_clean[j])), ms='.', ls='', mc='g', mw=20, alpha=0.6) # startpoint green vv.plot(PointSet(list(endpoints_clean[j])), ms='.', ls='', mc='r', mw=20, alpha=0.6) # endpoint red for j in range(len(allcenterlines)): vv.plot(allcenterlines[j], ms='o', ls='', mw=10, mc='y', alpha=0.6) # show midpoints (e.g. duplicates) if vismids: for p in duplicates: vv.plot(p[0], p[1], p[2], mc='m', ms='o', mw=10, alpha=0.6) a2.axis.visible = False vv.title('Centerlines and seed points') a1.camera = a2.camera f.eventKeyDown.Bind( lambda event: _utils_GUI.RotateView(event, [a1, a2])) f.eventKeyDown.Bind( lambda event: _utils_GUI.ViewPresets(event, [a1, a2])) # Pick node for midpoint to redo get_centerline self.pickedCLLpoint = _utils_GUI.Event_pick_graph_point( nodes_total, s.vol, label, nodesOnly=True) # x,y,z # use key p to select point #=============================================================================== vv.figure(11) vv.gca().daspect = 1, 1, -1 t = show_ctvolume(s.vol, showVol='ISO', clim=(0, 2500), isoTh=250, removeStent=False, climEditor=True) label2 = pick3d(vv.gca(), s.vol) for j in range(len(startpoints_clean)): vv.plot(PointSet(list(startpoints_clean[j])), ms='.', ls='', mc='g', mw=20, alpha=0.6) # startpoint green vv.plot(PointSet(list(endpoints_clean[j])), ms='.', ls='', mc='r', mw=20, alpha=0.6) # endpoint red vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') #=============================================================================== ## Make model dynamic (and store/overwrite to disk) import pirt from stentseg.motion.dynamic import incorporate_motion_nodes, incorporate_motion_edges # Load deforms filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'deforms') s1 = vv.ssdf.load(os.path.join(basedir, ptcode, filename)) deformkeys = [] for key in dir(s1): if key.startswith('deform'): deformkeys.append(key) deforms = [s1[key] for key in deformkeys] deforms = [ pirt.DeformationFieldBackward(*fields) for fields in deforms ] for i in range(len(deforms)): deforms[i]._field_sampling = tuple(s1.sampling) paramsreg = s1.params # Load model s2 = loadmodel(basedir, ptcode, ctcode, cropname, 'centerline_' + what) s3 = loadmodel(basedir, ptcode, ctcode, cropname, 'centerline_total_' + what) # Combine ... for key in dir(s2): if key.startswith('model'): incorporate_motion_nodes(s2[key], deforms, s.origin) incorporate_motion_edges(s2[key], deforms, s.origin) model = s2[key] s2[key] = model.pack() # Combine ... for key in dir(s3): if key.startswith('model'): incorporate_motion_nodes(s3[key], deforms, s.origin) incorporate_motion_edges(s3[key], deforms, s.origin) model = s3[key] s3[key] = model.pack() # Save s2.paramsreg = paramsreg filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'centerline_' + what + '_deforms') vv.ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk as {}.'.format(filename)) # Save s3.paramsreg = paramsreg filename = '%s_%s_%s_%s.ssdf' % ( ptcode, ctcode, cropname, 'centerline_total_' + what + '_deforms') vv.ssdf.save(os.path.join(basedir, ptcode, filename), s3) print('saved to disk as {}.'.format(filename))
modelname = 'modelavgreg' # default for stents # modelname = 'modelvesselavgreg' foo = _Get_Centerline(ptcode,ctcode,StartPoints,EndPoints, basedir, modelname=modelname) # MK: start=distal points # loads prox_avgreg (reg) and prox_modelavgreg (segm) # saves centerline_modelavgreg and centerline_total_modelavgreg; also with _deforms as dynamic centerline # in centerline we have all centerlines but separate graphs; in centerline_total merged in one graph allcenterlines = foo.allcenterlines # list with PointSet per centerline print('centerline: done') ## IDENTIFY CENTERLINES FOR ANALYSIS if False: from stentseg.utils.centerline import points_from_nodes_in_graph modelname = 'centerline_modelavgreg_deforms' # modelname = 'centerline_modelvesselavgreg_deforms' s = loadmodel(basedir, ptcode, ctcode, 'prox', modelname=modelname) from nellix.identify_centerlines import identifyCenterlines a, s2 = identifyCenterlines(s, ptcode,ctcode,basedir,modelname,showVol='MIP') ## MOTION ANALYSIS CENTERLINES if False: import os from stentseg.utils.datahandling import select_dir, loadmodel, loadvol from stentseg.utils.picker import pick3d ptcodes = [ # 'chevas_01', # 'chevas_02', # 'chevas_03', # 'chevas_04',
ptcode = 'chevas_09_thin' ctcode = '12months' phases = range(10) # all 10 phases showmodelavgreg = True showvol = True # get vol for reference s = loadvol(basedir, ptcode, ctcode, 'prox', what='avgreg') # set sampling for cases where this was not stored correctly s.vol.sampling = [s.sampling[1], s.sampling[1], s.sampling[2]] vol = s.vol s_modelcll = loadmodel(basedir, ptcode, ctcode, 'prox', modelname='centerline_total_modelavgreg_deforms') # get graph modelcll = s_modelcll.model s_modelcll_vessel = loadmodel(basedir, ptcode, ctcode, 'prox', modelname='centerline_modelvesselavgreg_deforms') # get graph models = [] for key in s_modelcll_vessel: if key.startswith('model'): cllv = s_modelcll_vessel[key]
r'C:\Users\Maaike\SURFdrive\UTdrive\LSPEAS\Analysis\Landmark Validation\phantom_article\ssdf') # Select location .mat file matsave = select_dir(r'D:\Profiles\koenradesma\SURFdrive\UTdrive\LSPEAS\Analysis\Landmark Validation\phantom_article\mat', r'C:\Users\Maaike\SURFdrive\UTdrive\LSPEAS\Analysis\Landmark Validation\phantom_article\mat') # Select dataset to select landmarks ptcode = 'LSPEAS_020' # 002_6months, 008_12months, 011_discharge, 17_1month, 20_discharge, 25_12months ctcode = 'discharge' cropname = 'stent' # use stent crops observer = 'obs1' # =========== ALGORITHM PHASES / AVGREG =============== ## Load dynamic landmark model and export to mat file s2 = loadmodel(os.path.join(dirsave,observer), ptcode, ctcode, cropname, 'landmarksavgreg') landmarks = s2.landmarksavgreg # # landmarks with deforms # deformslandmark = [] # for i in range(len(landmarks.nodes())): # point = landmarks.nodes()[i] # u = landmarks.node[point] # deformslandmark.append(u) # print(deformslandmark) # Calculate algorithm coordinates with avgreg & deforms algorithmpoints = [] algorithmnumbers =[] algtranslationx = []
xrenal2, yrenal2, zrenal2 = 171, 165.1, 39.5 renal2 = PointSet(list((xrenal2, yrenal2, zrenal2))) # renal_left, renal_right = foo.readRenalsExcel(sheet_renals_obs, ptcode, ctcode1) # renal1 = renal_left ## Load (dynamic) stent models, vessel, ct # Load static CT image to add as reference s = loadvol(basedir, ptcode, ctcode1, cropname, 'avgreg') vol1 = s.vol if ctcode2: s = loadvol(basedir, ptcode, ctcode2, cropname, 'avgreg') vol2 = s.vol # load stent model s2 = loadmodel(basedir, ptcode, ctcode1, cropname, modelname) model1 = s2.model modelmesh1 = create_mesh(model1, meshradius) if ctcode2: s2 = loadmodel(basedir, ptcode, ctcode2, cropname, modelname) model2 = s2.model modelmesh2 = create_mesh(model2, meshradius) # Load vessel mesh (output Mimics) vessel1 = loadmesh(basedirstl, ptcode, vesselname1) #inverts Z if ctcode2: vessel2 = loadmesh(basedirstl, ptcode, vesselname2) #inverts Z # get pointset from STL ppvessel1 = points_from_mesh(vessel1, invertZ=False) # removes duplicates if ctcode2: ppvessel2 = points_from_mesh(vessel2, invertZ=False) # removes duplicates
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)