PYME-extra 1.0.4.post0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. PYMEcs/Acquire/Actions/__init__.py +0 -0
  2. PYMEcs/Acquire/Actions/custom.py +167 -0
  3. PYMEcs/Acquire/Hardware/LPthreadedSimple.py +248 -0
  4. PYMEcs/Acquire/Hardware/LPthreadedSimpleSim.py +246 -0
  5. PYMEcs/Acquire/Hardware/NikonTiFlaskServer.py +45 -0
  6. PYMEcs/Acquire/Hardware/NikonTiFlaskServerT.py +59 -0
  7. PYMEcs/Acquire/Hardware/NikonTiRESTClient.py +73 -0
  8. PYMEcs/Acquire/Hardware/NikonTiSim.py +35 -0
  9. PYMEcs/Acquire/Hardware/__init__.py +0 -0
  10. PYMEcs/Acquire/Hardware/driftTrackGUI.py +329 -0
  11. PYMEcs/Acquire/Hardware/driftTrackGUI_n.py +472 -0
  12. PYMEcs/Acquire/Hardware/driftTracking.py +424 -0
  13. PYMEcs/Acquire/Hardware/driftTracking_n.py +433 -0
  14. PYMEcs/Acquire/Hardware/fakeCamX.py +15 -0
  15. PYMEcs/Acquire/Hardware/offsetPiezoRESTCorrelLog.py +38 -0
  16. PYMEcs/Acquire/__init__.py +0 -0
  17. PYMEcs/Analysis/MBMcollection.py +552 -0
  18. PYMEcs/Analysis/MINFLUX.py +280 -0
  19. PYMEcs/Analysis/MapUtils.py +77 -0
  20. PYMEcs/Analysis/NPC.py +1176 -0
  21. PYMEcs/Analysis/Paraflux.py +218 -0
  22. PYMEcs/Analysis/Simpler.py +81 -0
  23. PYMEcs/Analysis/Sofi.py +140 -0
  24. PYMEcs/Analysis/__init__.py +0 -0
  25. PYMEcs/Analysis/decSofi.py +211 -0
  26. PYMEcs/Analysis/eventProperties.py +50 -0
  27. PYMEcs/Analysis/fitDarkTimes.py +569 -0
  28. PYMEcs/Analysis/objectVolumes.py +20 -0
  29. PYMEcs/Analysis/offlineTracker.py +130 -0
  30. PYMEcs/Analysis/stackTracker.py +180 -0
  31. PYMEcs/Analysis/timeSeries.py +63 -0
  32. PYMEcs/Analysis/trackFiducials.py +186 -0
  33. PYMEcs/Analysis/zerocross.py +91 -0
  34. PYMEcs/IO/MINFLUX.py +851 -0
  35. PYMEcs/IO/NPC.py +117 -0
  36. PYMEcs/IO/__init__.py +0 -0
  37. PYMEcs/IO/darkTimes.py +19 -0
  38. PYMEcs/IO/picasso.py +219 -0
  39. PYMEcs/IO/tabular.py +11 -0
  40. PYMEcs/__init__.py +0 -0
  41. PYMEcs/experimental/CalcZfactor.py +51 -0
  42. PYMEcs/experimental/FRC.py +338 -0
  43. PYMEcs/experimental/ImageJROItools.py +49 -0
  44. PYMEcs/experimental/MINFLUX.py +1537 -0
  45. PYMEcs/experimental/NPCcalcLM.py +560 -0
  46. PYMEcs/experimental/Simpler.py +369 -0
  47. PYMEcs/experimental/Sofi.py +78 -0
  48. PYMEcs/experimental/__init__.py +0 -0
  49. PYMEcs/experimental/binEventProperty.py +187 -0
  50. PYMEcs/experimental/chaining.py +23 -0
  51. PYMEcs/experimental/clusterTrack.py +179 -0
  52. PYMEcs/experimental/combine_maps.py +104 -0
  53. PYMEcs/experimental/eventProcessing.py +93 -0
  54. PYMEcs/experimental/fiducials.py +323 -0
  55. PYMEcs/experimental/fiducialsNew.py +402 -0
  56. PYMEcs/experimental/mapTools.py +271 -0
  57. PYMEcs/experimental/meas2DplotDh5view.py +107 -0
  58. PYMEcs/experimental/mortensen.py +131 -0
  59. PYMEcs/experimental/ncsDenoise.py +158 -0
  60. PYMEcs/experimental/onTimes.py +295 -0
  61. PYMEcs/experimental/procPoints.py +77 -0
  62. PYMEcs/experimental/pyme2caml.py +73 -0
  63. PYMEcs/experimental/qPAINT.py +965 -0
  64. PYMEcs/experimental/randMap.py +188 -0
  65. PYMEcs/experimental/regExtraCmaps.py +11 -0
  66. PYMEcs/experimental/selectROIfilterTable.py +72 -0
  67. PYMEcs/experimental/showErrs.py +51 -0
  68. PYMEcs/experimental/showErrsDh5view.py +58 -0
  69. PYMEcs/experimental/showShiftMap.py +56 -0
  70. PYMEcs/experimental/snrEvents.py +188 -0
  71. PYMEcs/experimental/specLabeling.py +51 -0
  72. PYMEcs/experimental/splitRender.py +246 -0
  73. PYMEcs/experimental/testChannelByName.py +36 -0
  74. PYMEcs/experimental/timedSpecies.py +28 -0
  75. PYMEcs/experimental/utils.py +31 -0
  76. PYMEcs/misc/ExtraCmaps.py +177 -0
  77. PYMEcs/misc/__init__.py +0 -0
  78. PYMEcs/misc/configUtils.py +169 -0
  79. PYMEcs/misc/guiMsgBoxes.py +27 -0
  80. PYMEcs/misc/mapUtils.py +230 -0
  81. PYMEcs/misc/matplotlib.py +136 -0
  82. PYMEcs/misc/rectsFromSVG.py +182 -0
  83. PYMEcs/misc/shellutils.py +1110 -0
  84. PYMEcs/misc/utils.py +205 -0
  85. PYMEcs/misc/versionCheck.py +20 -0
  86. PYMEcs/misc/zcInfo.py +90 -0
  87. PYMEcs/pyme_warnings.py +4 -0
  88. PYMEcs/recipes/__init__.py +0 -0
  89. PYMEcs/recipes/base.py +75 -0
  90. PYMEcs/recipes/localisations.py +2380 -0
  91. PYMEcs/recipes/manipulate_yaml.py +83 -0
  92. PYMEcs/recipes/output.py +177 -0
  93. PYMEcs/recipes/processing.py +247 -0
  94. PYMEcs/recipes/simpler.py +290 -0
  95. PYMEcs/version.py +2 -0
  96. pyme_extra-1.0.4.post0.dist-info/METADATA +114 -0
  97. pyme_extra-1.0.4.post0.dist-info/RECORD +101 -0
  98. pyme_extra-1.0.4.post0.dist-info/WHEEL +5 -0
  99. pyme_extra-1.0.4.post0.dist-info/entry_points.txt +3 -0
  100. pyme_extra-1.0.4.post0.dist-info/licenses/LICENSE +674 -0
  101. pyme_extra-1.0.4.post0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,965 @@
1
+ from __future__ import print_function
2
+
3
+ import wx
4
+ import numpy as np
5
+ import sys
6
+ from scipy import ndimage
7
+ from PYMEcs.misc.guiMsgBoxes import Warn
8
+ from PYME.recipes import tablefilters
9
+ from PYMEcs.Analysis import fitDarkTimes
10
+
11
+ import logging
12
+ logger = logging.getLogger(__file__)
13
+
14
+ from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float, Bool
15
+ from traitsui.api import View, Item, Group
16
+ from traitsui.menu import OKButton, CancelButton, OKCancelButtons
17
+
18
+ class KeyChoice(HasTraits):
19
+ clist = List([])
20
+ Key = Enum(values='clist')
21
+
22
+ traits_view = View(
23
+ 'Key',
24
+ title = 'Select Measure',
25
+ resizable = True,
26
+ buttons = OKCancelButtons
27
+ )
28
+
29
+ def add_keys(self,chans):
30
+ for chan in chans:
31
+ if chan not in self.clist:
32
+ self.clist.append(chan)
33
+
34
+
35
+ class myCChoice(HasTraits):
36
+ clist = List([])
37
+ RatioChannel1 = Enum(values='clist')
38
+ RatioChannel2 = Enum(values='clist')
39
+ Channel1Calibration = Float(1.0)
40
+ Channel2Calibration = Float(1.0)
41
+
42
+ traits_view = View(Group(Item(name = 'RatioChannel1'),
43
+ Item(name = 'Channel1Calibration'),
44
+ Item('_'),
45
+ Item(name = 'RatioChannel2'),
46
+ Item(name = 'Channel2Calibration'),
47
+ label = 'Select Channels and Calibration',
48
+ show_border = True),
49
+ buttons = OKCancelButtons)
50
+
51
+ cal_view = View(Group(Item(name = 'Channel1Calibration'),
52
+ Item('_'),
53
+ Item(name = 'Channel2Calibration'),
54
+ label = 'Select Calibration',
55
+ show_border = True),
56
+ buttons = OKCancelButtons)
57
+
58
+ one_view = View(Group(Item(name = 'RatioChannel1'),
59
+ Item(name = 'Channel1Calibration'),
60
+ label = 'Select Channel and Calibration',
61
+ show_border = True),
62
+ buttons = OKCancelButtons)
63
+
64
+ def add_channels(self,chans):
65
+ for chan in chans:
66
+ if chan not in self.clist:
67
+ self.clist.append(chan)
68
+
69
+
70
+ class TimedSpecies(HasTraits):
71
+ Species1 = CStr()
72
+ Species1FromTime = Float()
73
+ Species1ToTime = Float()
74
+
75
+ Species2 = CStr()
76
+ Species2FromTime = Float()
77
+ Species2ToTime = Float()
78
+
79
+ Species3 = CStr()
80
+ Species3FromTime = Float()
81
+ Species3ToTime = Float()
82
+
83
+
84
+ traits_view = View(Group(Item(name = 'Species1'),
85
+ Item(name = 'Species1FromTime'),
86
+ Item(name = 'Species1ToTime'),
87
+ Item('_'),
88
+ Item(name = 'Species2'),
89
+ Item(name = 'Species2FromTime'),
90
+ Item(name = 'Species2ToTime'),
91
+ Item('_'),
92
+ Item(name = 'Species3'),
93
+ Item(name = 'Species3FromTime'),
94
+ Item(name = 'Species3ToTime'),
95
+ label = 'Specify Timed Species',
96
+ show_border = True),
97
+ buttons = OKCancelButtons)
98
+
99
+ def getSpeciesDescriptor(self):
100
+ speclist = {}
101
+ if self.Species1: # empty strings will be ignored
102
+ speclist[self.Species1] = (self.Species1FromTime,
103
+ self.Species1ToTime)
104
+ if self.Species2: # empty strings will be ignored
105
+ speclist[self.Species2] = (self.Species2FromTime,
106
+ self.Species2ToTime)
107
+ if self.Species3: # empty strings will be ignored
108
+ speclist[self.Species3] = (self.Species3FromTime,
109
+ self.Species3ToTime)
110
+
111
+ logger.info('speclist is ' + repr(speclist))
112
+ return speclist
113
+
114
+ def uniqueByID(ids,column):
115
+ uids, idx = np.unique(ids, return_index=True)
116
+ ucol = column[idx]
117
+ valid = uids > 0
118
+ return uids[valid], ucol[valid]
119
+
120
+ def selectWithDialog(choices, message='select image from list', caption='Selection'):
121
+ dlg = wx.SingleChoiceDialog(None, message, caption, list(choices), wx.CHOICEDLG_STYLE)
122
+ if dlg.ShowModal() == wx.ID_OK:
123
+ item = dlg.GetStringSelection()
124
+ else:
125
+ item = None
126
+ dlg.Destroy()
127
+ return item
128
+
129
+ def unique_name(stem,names):
130
+ if stem not in names:
131
+ return stem
132
+ for i in range(1,11):
133
+ stem2 = "%s%d" % (stem,i)
134
+ if stem2 not in names:
135
+ return stem2
136
+
137
+ return stem2 # here we just give up and accept a duplicate name
138
+
139
+
140
+ class QPCalc:
141
+ """
142
+
143
+ """
144
+ def __init__(self, visFr):
145
+ self.visFr = visFr
146
+ self.pipeline = visFr.pipeline
147
+ self.qpMeasurements = {}
148
+ self.fitSettings = fitDarkTimes.FitSettings()
149
+ self.useTau = 2 # we change to using the proper histogram for fitting
150
+ if self.useTau == 1:
151
+ self.tausrc = {
152
+ 'tau' : 'tau1',
153
+ 'tauerr' : 'tau1err',
154
+ 'chisq' : 'chisqr1'}
155
+ elif self.useTau == 2:
156
+ self.tausrc = {
157
+ 'tau' : 'tau2',
158
+ 'tauerr' : 'tau2err',
159
+ 'chisq' : 'chisqr2'}
160
+ else:
161
+ raise RuntimeError("Invalid useTau mode %d (must be 1 or 2)" % self.useTau)
162
+
163
+
164
+ visFr.AddMenuItem('Experimental>qPAINT', "From Image - Set driftpars",self.OnSetDriftPars)
165
+ visFr.AddMenuItem('Experimental>qPAINT', "From Image - Set ROI clipping",self.OnClipFromImage)
166
+ visFr.AddMenuItem('Experimental>qPAINT', "From Image - Set objectIDs",self.OnGetIDsfromImage)
167
+ visFr.AddMenuItem('Experimental>qPAINT', "From Image - Get Areas by ID",self.OnAreaFromLabels)
168
+ visFr.AddMenuItem('Experimental>qPAINT', "Qindex - Measure object ID dark times",self.OnMeasureTau2)
169
+ visFr.AddMenuItem('Experimental>qPAINT', "All in 1 go: select Image, set drift, IDs, measure qindex, areas",
170
+ self.OnSelectImgAndProcess)
171
+
172
+ visFr.AddMenuItem('Experimental>qPAINT', itemType='separator') #--------------------------
173
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - set timed species by Dialog",self.OnTimedSpecies)
174
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - set timed species from image",self.OnTimedSpeciesFromImage)
175
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - qIndex by channel",self.OnChannelMeasureTau)
176
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - Merge Channel Measures", self.OnMergeChannelMeasures)
177
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - Calculate Channel Ratios", self.OnChannelMeasurementRatios)
178
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - calibrate channel qIndices (Pseudo test function)",self.OnChannelCalibrate)
179
+ visFr.AddMenuItem('Experimental>qPAINT', "Multicolour - in 1 go: select Image, set drift, IDs, areas, species, qIndex & merge & ratio",
180
+ self.OnSelectImgAndProcessMulticol)
181
+
182
+ visFr.AddMenuItem('Experimental>qPAINT', itemType='separator') #--------------------------
183
+ visFr.AddMenuItem('Experimental>qPAINT', 'Points based: Set objectIDs by DBSCAN clumping', self.OnClumpObjects,
184
+ helpText='Calculate objectID using DBSCAN algorithm')
185
+ visFr.AddMenuItem('Experimental>qPAINT', "Points based: Measure object ID volumes (area if 2D) by convex hull",self.OnMeasureVol)
186
+
187
+ visFr.AddMenuItem('Experimental>qPAINT', itemType='separator') #--------------------------
188
+ visFr.AddMenuItem('Experimental>qPAINT', "Darktime distribution of selected events\tCtrl+T",self.OnDarkT)
189
+ visFr.AddMenuItem('Experimental>qPAINT', "Select Fit Settings",self.OnFitSettings)
190
+ visFr.AddMenuItem('Experimental>qPAINT', "Calibrate a qIndex (or any column)",self.OnQindexCalibrate)
191
+ visFr.AddMenuItem('Experimental>qPAINT', "Ratio two qIndices (or any two columns)",self.OnQindexRatio)
192
+
193
+ visFr.AddMenuItem('Experimental>qPAINT', itemType='separator') #--------------------------
194
+ visFr.AddMenuItem('Experimental>qPAINT', "Plot histogram of one data column",self.OnGeneralHist)
195
+ visFr.AddMenuItem('Experimental>qPAINT', "Scatter plot by ID",self.OnScatterByID)
196
+ visFr.AddMenuItem('Experimental>qPAINT', "Image of qPAINT measure from label image",self.OnLabelLookupByID)
197
+ visFr.AddMenuItem('Experimental>qPAINT', "Load Measurements",self.OnLoadMeasurements)
198
+ visFr.AddMenuItem('Experimental>qPAINT', "Save Measurements",self.OnSaveMeasurements)
199
+
200
+
201
+ def OnClumpObjects(self, event=None):
202
+ """
203
+ Runs sklearn DBSCAN clustering algorithm on pipeline filtered results using the GUI defined in the DBSCAN
204
+ recipe module.
205
+
206
+ Args are user defined through GUI
207
+ searchRadius: search radius for clustering
208
+ minClumpSize: number of points within eps required for a given point to be considered a core point
209
+
210
+ This version is generally used to identify clumps identifying fiduciaries and therefore the
211
+ default searchRadius is set fairly generous.
212
+ """
213
+ from PYMEcs.recipes import localisations
214
+
215
+ clumper = localisations.DBSCANClustering(minClumpSize = 20, searchRadius = 20.0)
216
+ if clumper.configure_traits(kind='modal'):
217
+ namespace = {clumper.inputName: self.pipeline}
218
+ clumper.execute(namespace)
219
+
220
+ self.pipeline.addColumn('objectID', namespace[clumper.outputName]['dbscanClumpID'])
221
+
222
+ def OnGetIDsfromImage(self, event, img=None):
223
+ from PYME.DSView import dsviewer
224
+
225
+ pipeline = self.pipeline
226
+
227
+ if img is None:
228
+ selection = selectWithDialog(dsviewer.openViewers.keys())
229
+ if selection is not None:
230
+ img = dsviewer.openViewers[selection].image
231
+
232
+ if img is not None:
233
+ with_ids = unique_name('with_ids',pipeline.dataSources.keys())
234
+ valid_ids = unique_name('valid_ids',pipeline.dataSources.keys())
235
+ recipe = pipeline.recipe
236
+ mapp = tablefilters.Mapping(recipe,inputName=pipeline.selectedDataSourceKey,
237
+ outputName=with_ids)
238
+ recipe.add_module(mapp)
239
+ recipe.execute()
240
+
241
+ withIDs = recipe.namespace[with_ids]
242
+
243
+ pixX = np.round((pipeline['x'] - img.imgBounds.x0 )/img.pixelSize).astype('i')
244
+ pixY = np.round((pipeline['y'] - img.imgBounds.y0 )/img.pixelSize).astype('i')
245
+
246
+ ind = (pixX < img.data.shape[0])*(pixY < img.data.shape[1])*(pixX >= 0)*(pixY >= 0)
247
+
248
+ ids = np.zeros_like(pixX)
249
+ #assume there is only one channel
250
+ ids[ind] = img.data[:,:,:,0].squeeze()[pixX[ind], pixY[ind]].astype('i')
251
+
252
+ numPerObject, b = np.histogram(ids, np.arange(ids.max() + 1.5) + .5)
253
+
254
+ withIDs.addColumn('objectID', ids)
255
+ withIDs.addColumn('NEvents', numPerObject[ids-1])
256
+
257
+ recipe.add_module(tablefilters.FilterTable(recipe,inputName=with_ids, outputName=valid_ids,
258
+ filters={'objectID' : [.5, sys.maxsize]}))
259
+ recipe.execute()
260
+
261
+ pipeline.selectDataSource(valid_ids)
262
+ pipeline.Rebuild()
263
+
264
+
265
+ def OnCopyDS(self, event=None):
266
+ """
267
+
268
+ """
269
+ from PYMEcs.recipes.localisations import CopyMapped
270
+ recipe = self.pipeline.recipe
271
+ CM = CopyMapped(recipe, inputName=self.pipeline.selectedDataSourceKey,
272
+ outputName='%s-copy' % self.pipeline.selectedDataSourceKey)
273
+ if CM.configure_traits(kind='modal'):
274
+ recipe.add_module(CM)
275
+ recipe.execute()
276
+ self.pipeline.selectDataSource(CM.outputName)
277
+
278
+ self.visFr.RefreshView()
279
+ self.visFr.CreateFoldPanel()
280
+
281
+
282
+ def OnSetDriftPars(self, event, img=None):
283
+ from PYME.DSView import dsviewer
284
+
285
+ if img is None:
286
+ selection = selectWithDialog(dsviewer.openViewers.keys())
287
+ if selection is not None:
288
+ img = dsviewer.openViewers[selection].image
289
+
290
+ if img is not None:
291
+ dpn = self.visFr.driftPane
292
+ dpn.tXExpr.SetValue(img.mdh['DriftCorrection.ExprX'])
293
+ dpn.tYExpr.SetValue(img.mdh['DriftCorrection.ExprY'])
294
+ dpn.tZExpr.SetValue(img.mdh['DriftCorrection.ExprZ'])
295
+ dpn.OnDriftExprChange(None)
296
+ destp = dpn.dp.driftCorrParams
297
+ srcp = img.mdh['DriftCorrection.Parameters']
298
+ for key in destp.keys():
299
+ if key.startswith(('a','b')):
300
+ destp[key] = srcp[key]
301
+ dpn.OnDriftApply(None)
302
+ dpn.OnDriftExprChange(None)
303
+
304
+ def OnTimedSpecies(self, event):
305
+ # a reworked version that uses a simpler TraitsUI interface
306
+ timedSpecies = TimedSpecies()
307
+ if timedSpecies.configure_traits(kind='modal'):
308
+ from PYME.LMVis import renderers
309
+ speclist = timedSpecies.getSpeciesDescriptor()
310
+ if len(speclist.keys())>0:
311
+ # not sure if this should be Source.TimedSpecies or just TimedSpecies
312
+ #renderers.renderMetadataProviders.append(lambda mdh:
313
+ # mdh.setEntry('Source.TimedSpecies', speclist))
314
+
315
+ pipeline = self.visFr.pipeline
316
+ pipeline.mdh.setEntry('TimedSpecies', speclist)
317
+ if pipeline.selectedDataSource is not None:
318
+ pipeline.selectedDataSource.setMapping('ColourNorm', '1.0 + 0*t')
319
+ for species in speclist.keys():
320
+ pipeline.selectedDataSource.setMapping('p_%s' % species,
321
+ '(t>= %d)*(t<%d)' % speclist[species])
322
+ pipeline.Rebuild()
323
+ # self.visFr.RegenFilter()
324
+ self.visFr.CreateFoldPanel()
325
+
326
+
327
+ def OnClipFromImage(self, event, img=None):
328
+ from PYME.DSView import dsviewer
329
+
330
+ if img is None:
331
+ selection = selectWithDialog(list(dsviewer.openViewers.keys()))
332
+ if selection is not None:
333
+ img = dsviewer.openViewers[selection].image
334
+
335
+ if img is not None:
336
+ if img.mdh.getOrDefault('Filter.Keys',None) is None:
337
+ logger.debug('no Filter.Keys in image metadata')
338
+ return
339
+ try:
340
+ self.pipeline.filterKeys['x'] = img.mdh['Filter.Keys']['x']
341
+ except:
342
+ logger.debug('cannot read or set filterKeys x-component')
343
+ return
344
+ try:
345
+ self.pipeline.filterKeys['y'] = img.mdh['Filter.Keys']['y']
346
+ except:
347
+ logger.debug('cannot read or set filterKeys y-component')
348
+ return
349
+
350
+ self.pipeline.Rebuild()
351
+ #self.visFr.RegenFilter()
352
+ self.visFr.CreateFoldPanel()
353
+
354
+
355
+ def OnTimedSpeciesFromImage(self, event, img=None):
356
+ from PYME.DSView import dsviewer
357
+
358
+ if img is None:
359
+ selection = selectWithDialog(dsviewer.openViewers.keys())
360
+ if selection is not None:
361
+ img = dsviewer.openViewers[selection].image
362
+
363
+ if img is not None:
364
+ # somewhat weired condition as sometimes TimeSpecies becomes None in the root namespce
365
+ if img.mdh.getOrDefault('TimedSpecies',None) is not None:
366
+ logger.debug('setting timed species from root level')
367
+ timedSpecies = img.mdh['TimedSpecies']
368
+ elif 'Source.TimedSpecies' in img.mdh.keys():
369
+ logger.debug('setting timed species from source level')
370
+ timedSpecies = img.mdh['Source.TimedSpecies']
371
+ logger.debug('time species is %s' % repr(timedSpecies))
372
+ else:
373
+ return
374
+ pipeline = self.visFr.pipeline
375
+ if pipeline.selectedDataSource is not None:
376
+ pipeline.selectedDataSource.setMapping('ColourNorm', '1.0 + 0*t')
377
+ # there are a couple different formats for timedSpecies, so check which one it is
378
+ try:
379
+ specs = timedSpecies.keys()
380
+ isdict = True
381
+ except AttributeError:
382
+ isdict = False
383
+ if isdict:
384
+ for species in timedSpecies.keys():
385
+ pipeline.selectedDataSource.setMapping('p_%s' % species,
386
+ '(t>= %d)*(t<%d)' % timedSpecies[species])
387
+ else:
388
+ for entry in timedSpecies:
389
+ pipeline.selectedDataSource.setMapping('p_%s' % entry['name'],
390
+ '(t>= %d)*(t<%d)' % (entry['t_start'],entry['t_end']))
391
+ # FIXME: (1) append if exists, (2) assigning to mdh ok?
392
+ pipeline.selectedDataSource.mdh['TimedSpecies'] = timedSpecies
393
+ self.visFr.pipeline.Rebuild()
394
+ self.visFr.CreateFoldPanel()
395
+
396
+
397
+ def OnAreaFromLabels(self, event, img=None):
398
+ from PYME.DSView import dsviewer
399
+
400
+ if img is None:
401
+ selection = selectWithDialog(dsviewer.openViewers.keys())
402
+ if selection is not None:
403
+ img = dsviewer.openViewers[selection].image
404
+
405
+ if img is not None:
406
+ from PYME.recipes.measurement import Measure2D
407
+
408
+ # execute the measure2D module as a mini-recipe
409
+ MeasureIt = Measure2D(measureContour=False)
410
+ namespace = {MeasureIt.inputLabels: img, MeasureIt.inputIntensity: img}
411
+ MeasureIt.execute(namespace)
412
+ # save the measurements for further use
413
+ self.qpMeasurements['area'] = namespace[MeasureIt.outputName]
414
+
415
+ meas = self.qpMeasurements['area']
416
+ # currently the scale of areas is in 1000 nm^2
417
+ areas = meas['area'] * float(img.mdh['voxelsize.x'])*float(img.mdh['voxelsize.y'])*1e3
418
+
419
+ # add the area info to the qPAINT measures already available
420
+ for chan in (self.pipeline.colourFilter.getColourChans() + ['Everything']):
421
+ if chan in self.qpMeasurements.keys():
422
+ # here we copy the area over, other 2D measures could be similarly copied
423
+ self.qpMeasurements[chan].addNewColumnByID(meas['label'], 'area', areas)
424
+
425
+ # make a new objAreas column for the pipeline
426
+ # 1st we are making a lookup table
427
+ # for areas by label index in abyl
428
+ labels = meas['label'].astype('int')
429
+ abyl = np.zeros(labels.max()+1) # make it long enough to hold all labels present
430
+ abyl[labels] = areas
431
+ objIDs = self.pipeline['objectID'].astype('int')
432
+ objAreas = np.zeros_like(objIDs,dtype='float')
433
+ # now look up the area values by addressing into our lookup table abyl
434
+ objAreas[objIDs>0] = abyl[objIDs[objIDs>0]]
435
+ # enter the new column into the pipeline
436
+ self.pipeline.addColumn('objArea',objAreas)
437
+
438
+ def OnMeasureTau2(self, event):
439
+
440
+ pipeline = self.pipeline
441
+ #idCol = 'objectID'
442
+ idCol = self.fitSettings.IDcolumn
443
+ measure = fitDarkTimes.measureObjectsByID2(pipeline, idname=idCol, settings=self.fitSettings)
444
+ self.qpMeasurements[pipeline.selectedDataSourceKey] = {'Everything' : measure}
445
+
446
+ newcols = fitDarkTimes.retrieveMeasuresForIDs2(measure,pipeline[idCol])
447
+
448
+ qp_measured = unique_name('qp_measured',pipeline.dataSources.keys())
449
+ recipe = pipeline.recipe
450
+ mapp = tablefilters.Mapping(recipe,inputName=pipeline.selectedDataSourceKey,
451
+ outputName=qp_measured)
452
+ recipe.add_module(mapp)
453
+ recipe.execute()
454
+
455
+ qpm = recipe.namespace[qp_measured]
456
+
457
+ for sourceCol in newcols.keys():
458
+ qpm.addColumn("qp_%s" % sourceCol,newcols[sourceCol])
459
+
460
+ def OnMeasureTau(self, event):
461
+
462
+ # chans = self.pipeline.colourFilter.getColourChans()
463
+
464
+ ids = np.unique(self.pipeline['objectID'].astype('int'))
465
+ idsnz = ids[ids > 0]
466
+ pipeline = self.pipeline
467
+
468
+ measure = fitDarkTimes.measureObjectsByID(self.pipeline, set(idsnz))
469
+ self.qpMeasurements['Everything'] = measure
470
+
471
+ # mapping from measurements column name to new pipeline column name to add
472
+ colmapNames = {
473
+ 'tau1':'taudark',
474
+ 'NDarktimes':'NDarktimes',
475
+ 'qindex1':'qIndex',
476
+ 'tau1err':'taudark_error',
477
+ 'chisqr1':'taudark_chisq2'}
478
+
479
+ newcols = fitDarkTimes.retrieveMeasuresForIDs(measure,pipeline['objectID'],
480
+ columns=colmapNames.keys())
481
+ for sourceCol in colmapNames.keys():
482
+ pipeline.addColumn(colmapNames[sourceCol],newcols[sourceCol])
483
+
484
+ # pipeline.Rebuild()
485
+
486
+ def OnChannelMeasureTau(self, event, chan=None, mapMeasuresToEvents=True):
487
+
488
+ if chan is None:
489
+ chan = selectWithDialog(self.pipeline.colourFilter.getColourChans(), message='select channel')
490
+ if chan is None:
491
+ return
492
+
493
+ pipeline = self.pipeline
494
+ dispColor = self.pipeline.colourFilter.currentColour
495
+
496
+ # make sure we get our IDs when everything is present -
497
+ # otherwise colourfiltering can create an issue with some IDs not present
498
+ # in some channels
499
+ pipeline.colourFilter.setColour('Everything')
500
+ ids = np.unique(pipeline['objectID'].astype('int'))
501
+ idsnz = ids[ids > 0]
502
+
503
+ pipeline.colourFilter.setColour(chan)
504
+
505
+ tausrc = self.tausrc
506
+ self.qpMeasurements[chan] = fitDarkTimes.measureObjectsByID(pipeline, set(idsnz), sigDefocused=165.0)
507
+ qmc = self.qpMeasurements[chan]
508
+ fitDarkTimes.makeRatio(qmc, 'qIndex', 100.0, qmc[tausrc['tau']])
509
+ fitDarkTimes.makeRatio(qmc, 'NTauDiff', np.abs(qmc['tau1']-qmc['tau2']), qmc['tau2'])
510
+
511
+ if mapMeasuresToEvents:
512
+ # switch back to all channels
513
+ pipeline.colourFilter.setColour('Everything')
514
+ colmapNames = {
515
+ tausrc['tau'] : 'taudark_%s' % chan,
516
+ tausrc['tauerr'] : 'taudark_error_%s' % chan,
517
+ tausrc['chisq'] : 'taudark_chisq2_%s' % chan,
518
+ 'NDarktimes' : 'NDarktimes_%s' % chan,
519
+ 'qIndex' : 'qIndex_%s' % chan,
520
+ 'NEvents' : 'NEvents_%s' % chan,
521
+ 'NDefocusedFrac' : 'NDefocusedFrac_%s' % chan,
522
+ 'NTauDiff' : 'NTauDiff_%s' % chan
523
+ }
524
+
525
+ newcols = fitDarkTimes.retrieveMeasuresForIDs(self.qpMeasurements[chan],pipeline['objectID'],
526
+ columns=colmapNames.keys())
527
+ for sourceCol in colmapNames.keys():
528
+ pipeline.addColumn(colmapNames[sourceCol],newcols[sourceCol])
529
+
530
+ # restore original display settings
531
+ pipeline.colourFilter.setColour(dispColor)
532
+
533
+
534
+ def OnMergeChannelMeasures(self, event):
535
+ if len(self.pipeline.colourFilter.getColourChans()) > 0:
536
+ channels = self.pipeline.colourFilter.getColourChans()
537
+ if np.all([chan in self.qpMeasurements.keys() for chan in channels]):
538
+ mergedMeas = fitDarkTimes.mergeChannelMeasurements(channels,[self.qpMeasurements[chan] for chan in channels])
539
+ self.qpMeasurements['Everything'] = mergedMeas
540
+
541
+
542
+ def OnChannelMeasurementRatios(self, event=None, channels=None, cals=None):
543
+ from PYME.recipes.traits import HasTraits, Enum, Float
544
+
545
+ if not len(self.pipeline.colourFilter.getColourChans()) > 0:
546
+ return
547
+
548
+ if channels is None:
549
+ chans = self.pipeline.colourFilter.getColourChans()
550
+ cChoice = myCChoice()
551
+ cChoice.add_channels(chans)
552
+ if cChoice.configure_traits(kind='modal'):
553
+ channels = (cChoice.Channel1, cChoice.Channel2)
554
+ cals = (cChoice.Channel1Calibration,cChoice.Channel2Calibration)
555
+
556
+ # here if cancel from configure_traits
557
+ if channels is None:
558
+ return
559
+
560
+ if ('Everything' in self.qpMeasurements):
561
+ fitDarkTimes.mergedMeasurementsRatios(self.qpMeasurements['Everything'],
562
+ channels[0], channels[1], cals[0], cals[1])
563
+
564
+ def chanName(key,chan):
565
+ return '%s_%s' % (key,chan)
566
+
567
+ pipeline = self.pipeline
568
+ dispColor = pipeline.colourFilter.currentColour
569
+ pipeline.colourFilter.setColour('Everything')
570
+
571
+ tausrc = self.tausrc
572
+ colmapNames = {
573
+ tausrc['tau']: 'taudark',
574
+ 'NDarktimes': 'NDarktimes',
575
+ 'qIndex': 'qIndex',
576
+ 'qIndexC': 'qIndexC',
577
+ tausrc['tauerr']: 'taudark',
578
+ tausrc['chisq']: 'taudark_chisq2',
579
+ 'qDensity': 'qDensity',
580
+ 'qDensityC': 'qDensityC'}
581
+
582
+ for chan in channels:
583
+ cmapChan = { chanName(key,chan) : chanName(value,chan) for key, value in colmapNames.items()}
584
+ newcols = fitDarkTimes.retrieveMeasuresForIDs(self.qpMeasurements['Everything'],pipeline['objectID'],
585
+ columns=cmapChan.keys())
586
+ for sourceCol in cmapChan.keys():
587
+ if cmapChan[sourceCol] not in pipeline.keys():
588
+ pipeline.addColumn(cmapChan[sourceCol],newcols[sourceCol])
589
+
590
+ for ratioName in ['qRatio','qRatioC']:
591
+ ratiokey = '%s_%svs%s' % (ratioName,channels[0],channels[1])
592
+ newcol = fitDarkTimes.retrieveMeasuresForIDs(self.qpMeasurements['Everything'],pipeline['objectID'],
593
+ columns=[ratiokey])
594
+ pipeline.addColumn(ratiokey, newcol[ratiokey])
595
+
596
+ meas = self.qpMeasurements['Everything']
597
+ chisq_chan1 = meas[chanName(self.tausrc['chisq'],channels[0])]
598
+ chisq_chan2 = meas[chanName(self.tausrc['chisq'],channels[0])]
599
+ ratioChisq = 'qRatio_chisq2'
600
+ fitDarkTimes.makeSum(meas,ratioChisq,chisq_chan1,chisq_chan2)
601
+ newcol = fitDarkTimes.retrieveMeasuresForIDs(self.qpMeasurements['Everything'],pipeline['objectID'],
602
+ columns=[ratioChisq])
603
+ pipeline.addColumn(ratioChisq, newcol[ratioChisq])
604
+
605
+ # restore original display settings
606
+ pipeline.colourFilter.setColour(dispColor)
607
+
608
+ def OnChannelCalibrate(self, event, channels=None):
609
+ # currently just an interface test function
610
+
611
+ chans = ['ryrtest','jphtest']
612
+ if channels is None:
613
+ cChoice = myCChoice()
614
+ cChoice.add_channels(chans)
615
+ if cChoice.configure_traits(view='one_view', kind='modal'):
616
+ channels = (cChoice.RatioChannel1, cChoice.RatioChannel2)
617
+ cals = (cChoice.Channel1Calibration,cChoice.Channel2Calibration)
618
+
619
+
620
+ def OnSelectImgAndProcess(self, event):
621
+ from PYME.DSView import dsviewer
622
+ selection = selectWithDialog(dsviewer.openViewers.keys())
623
+ if selection is not None:
624
+ img = dsviewer.openViewers[selection].image
625
+ self.OnSetDriftPars(None,img=img)
626
+ self.OnGetIDsfromImage(None,img=img)
627
+ self.OnMeasureTau(None)
628
+ # areas last so that qpMeasures get the area info
629
+ self.OnAreaFromLabels(None,img=img)
630
+
631
+
632
+ def OnLabelLookupByID(self, event):
633
+ from PYME.DSView import dsviewer, ViewIm3D
634
+ import PYME.IO.image as im
635
+
636
+ if ('Everything' in self.qpMeasurements):
637
+ meas = self.qpMeasurements['Everything']
638
+ selection = selectWithDialog(dsviewer.openViewers.keys())
639
+ if selection is None:
640
+ return
641
+ keyChoice = KeyChoice()
642
+ keyChoice.add_keys(sorted(meas.keys()))
643
+ if not keyChoice.configure_traits(kind='modal'):
644
+ return
645
+
646
+ labelimg = dsviewer.openViewers[selection].image
647
+ labels = labelimg.data[:,:,:].squeeze()
648
+ measures = meas.lookupByID(labels,keyChoice.Key)
649
+ newimg = im.ImageStack(measures, titleStub = 'Measure %s' % (keyChoice.Key))
650
+ newimg.mdh.copyEntriesFrom(labelimg.mdh)
651
+ newimg.mdh['Parent'] = labelimg.filename
652
+ newimg.mdh['Processing.qpMeasure'] = keyChoice.Key
653
+
654
+ ViewIm3D(newimg, mode='visGUI', title='Measure %s' % (keyChoice.Key),
655
+ glCanvas=self.visFr.glCanvas, parent=self.visFr)
656
+
657
+
658
+ def OnSelectImgAndProcessMulticol(self, event):
659
+ from PYME.DSView import dsviewer
660
+
661
+ selection = selectWithDialog(dsviewer.openViewers.keys())
662
+ if selection is None:
663
+ return
664
+
665
+ img = dsviewer.openViewers[selection].image
666
+ self.OnTimedSpeciesFromImage(None,img=img)
667
+
668
+ # get channel ratio info
669
+ if len(self.pipeline.colourFilter.getColourChans()) > 0:
670
+ chans = self.pipeline.colourFilter.getColourChans()
671
+ cChoice = myCChoice()
672
+ cChoice.add_channels(chans)
673
+ if cChoice.configure_traits(kind='modal'):
674
+ channels = (cChoice.RatioChannel1, cChoice.RatioChannel2)
675
+ cals = (cChoice.Channel1Calibration,cChoice.Channel2Calibration)
676
+ else:
677
+ channels = None
678
+ cals = None
679
+
680
+ prog = wx.ProgressDialog("Process Multicolour Data", "Setting Drift...", 100,
681
+ style=wx.PD_ELAPSED_TIME | wx.PD_AUTO_HIDE)
682
+ prog.Update(15)
683
+ self.OnSetDriftPars(None,img=img)
684
+
685
+ prog.Update(40,"Setting IDs...")
686
+ self.OnGetIDsfromImage(None,img=img)
687
+
688
+ prog.Update(50,"Calculating qIndices...")
689
+ for chan in self.pipeline.colourFilter.getColourChans():
690
+ self.OnChannelMeasureTau(None,chan=chan)
691
+
692
+ prog.Update(85,"Calculating Areas and Ratios...")
693
+ # areas last so that qpMeasures get the area info
694
+ self.OnAreaFromLabels(None,img=img)
695
+ self.OnMergeChannelMeasures(None)
696
+
697
+ prog.Update(95,"Nearly Done")
698
+ if channels is not None:
699
+ self.OnChannelMeasurementRatios(None,channels=channels,cals=cals)
700
+ prog.Update(100)
701
+ prog.Destroy()
702
+
703
+ def OnMeasureVol(self, event):
704
+ from PYMEcs.recipes import localisations
705
+ # fixme: this is currently 2D only but allows straightforward extension to 3D
706
+ VolMeasurer = localisations.ObjectVolume()
707
+ if VolMeasurer.configure_traits(kind='modal'):
708
+ # we call this with the pipeline to allow filtering etc
709
+ namespace = {VolMeasurer.inputName: self.pipeline}
710
+ VolMeasurer.execute(namespace)
711
+ # FIXME: scaling factor is correct for 2D only
712
+ self.pipeline.addColumn('volume', namespace[VolMeasurer.outputName]['volume']/1e3) # area in 1000 nm^2
713
+
714
+
715
+ def OnGeneralHist(self, event):
716
+ from PYMEcs.recipes import localisations
717
+ from PYME.recipes.base import ModuleCollection
718
+
719
+ rec = ModuleCollection()
720
+
721
+ HistByID = localisations.HistByID(rec)
722
+ rec.namespace = {HistByID.inputName: self.pipeline}
723
+ if HistByID.configure_traits(kind='modal'):
724
+ # we call this with the pipeline to allow filtering etc
725
+ HistByID.execute(rec.namespace)
726
+
727
+
728
+ def OnQindexCalibrate(self, event):
729
+ from PYMEcs.recipes import localisations
730
+ from PYME.recipes.base import ModuleCollection
731
+
732
+ rec = ModuleCollection()
733
+ QIScaler = localisations.QindexScale(rec)
734
+
735
+ # we call this with the pipeline to allow filtering etc
736
+ rec.namespace = {QIScaler.inputName: self.pipeline}
737
+ if QIScaler.configure_traits(kind='modal'):
738
+ QIScaler.execute(rec.namespace)
739
+ self.pipeline.addColumn(QIScaler.newKey, rec.namespace[QIScaler.outputName][QIScaler.newKey])
740
+
741
+ def OnQindexRatio(self, event):
742
+ from PYMEcs.recipes import localisations
743
+ from PYME.recipes.base import ModuleCollection
744
+
745
+ rec = ModuleCollection()
746
+ QIRatio = localisations.QindexRatio(rec)
747
+
748
+ # we call this with the pipeline to allow filtering etc
749
+ rec.namespace = {QIRatio.inputName: self.pipeline}
750
+ if QIRatio.configure_traits(kind='modal'):
751
+ QIRatio.execute(rec.namespace)
752
+ self.pipeline.addColumn(QIRatio.qIndexRatio, rec.namespace[QIRatio.outputName][QIRatio.qIndexRatio])
753
+
754
+ def OnScatterByID(self, event):
755
+ from PYMEcs.recipes import localisations
756
+ from PYME.recipes.base import ModuleCollection
757
+
758
+ rec = ModuleCollection()
759
+ ScatterbyID = localisations.ScatterbyID(rec)
760
+ rec.namespace = {ScatterbyID.inputName: self.pipeline}
761
+ if ScatterbyID.configure_traits(kind='modal'):
762
+ # we call this with the pipeline to allow filtering etc
763
+ ScatterbyID.execute(rec.namespace)
764
+
765
+ def OnSaveMeasurements(self,event):
766
+ from PYME.recipes import runRecipe
767
+ from PYMEcs.IO.darkTimes import saveDarkTimesCSV
768
+ import os.path
769
+ import yaml
770
+
771
+ if len(self.qpMeasurements.keys()) > 0:
772
+ filename = wx.FileSelector('Save all measurements (select basename)...',
773
+ wildcard="CSV files (*.csv)|*.csv|Excell files (*.xlsx)|*.xlsx|HDF5 files (*.hdf)|*.hdf",
774
+ flags = wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
775
+
776
+ if not filename == '':
777
+ base, ext = os.path.splitext(filename)
778
+ for ds in self.qpMeasurements.keys():
779
+ for chan in self.qpMeasurements[ds]:
780
+ qpm = self.qpMeasurements[ds][chan]
781
+ runRecipe.saveOutput(qpm['measures'], base + '_' + ds + '_' + chan + ext)
782
+ saveDarkTimesCSV(qpm['measures']['objectID'],qpm['darkTimes'],
783
+ base + '_' + ds + '_' + chan + '_' + 'dts.csv')
784
+ saveDarkTimesCSV(qpm['measures']['objectID'],qpm['times'],
785
+ base + '_' + ds + '_' + chan + '_' + 'times.csv')
786
+ with open(base + '_' + ds + '_' + chan + '_' + 'state.yaml', 'w') as stream:
787
+ yaml.dump(qpm['state'], stream)
788
+
789
+ def OnLoadMeasurements(self,event):
790
+ import PYMEcs.IO.tabular as tb
791
+ import os.path
792
+
793
+ filename = wx.FileSelector('Load measurements (select basename)...',
794
+ wildcard="CSV files (*.csv)|*.csv",
795
+ flags = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
796
+
797
+ if not filename == '':
798
+ self.qpMeasurements['Everything'] = tb.tabularFromCSV(filename)
799
+
800
+
801
+ def OnFitSettings(self,event):
802
+ self.fitSettings.configure_traits(kind='modal')
803
+
804
+ def OnDarkT(self,event):
805
+ try:
806
+ from StringIO import StringIO ## for Python 2
807
+ except ImportError:
808
+ from io import StringIO ## for Python 3
809
+
810
+
811
+ visFr = self.visFr
812
+ pipeline = visFr.pipeline
813
+ mdh = pipeline.mdh
814
+
815
+ NTMIN = 5
816
+ maxPts = 1e5
817
+
818
+ ## STEP 1: Extract times of relevant events, preprocess as needed and get darktimes from that (dtg)
819
+
820
+ tc, dtg, nevents, nevents_corrected, usingClumpIndex, usingTminTmax = \
821
+ fitDarkTimes.extractEventTimes(pipeline,
822
+ useTminTmax = (self.fitSettings.coalescedProcessing == 'useTminTmaxIfAvailable'),
823
+ return_modes=True)
824
+
825
+ ## STEP 2: from the extracted times get the actual darktimes
826
+
827
+ # determine darktime from gaps and reject zeros (no real gaps)
828
+ #dts = tc[1:]-tc[0:-1]-1
829
+ #dtg = dts[dts>0]
830
+ nts = dtg.size
831
+
832
+ ## STEP 3: fit the dark time distribution
833
+
834
+ if nts > NTMIN:
835
+ # now make a cumulative histogram from these
836
+ cumux,cumuy = fitDarkTimes.cumuhist(dtg)
837
+ binctrs,hc,binctrsg,hcg = fitDarkTimes.cumuhistBinnedLog(dtg,dlog=0.05,return_good=True)
838
+ binctrsCoarse,hcCoarse,binctrsgCoarse,hcgCoarse, hCoarse = fitDarkTimes.cumuhistBinnedLog(dtg,dlog=0.2,return_hist=True,return_good=True)
839
+
840
+ # fit theoretical distributions
841
+ from scipy.optimize import curve_fit
842
+
843
+ try:
844
+ tau1, tau1err, chisqr, tau1est = fitDarkTimes.fitTaus(binctrs,hc,return_tau1est=True)
845
+ logger.info("fitTaus: tau1 %f, tau1err %f, chisq %.1g, tau1est %f" % (tau1, tau1err, chisqr, tau1est))
846
+ except RuntimeError:
847
+ logger.warn("fitting tau value from histogram failed")
848
+ tau1ok = False
849
+ else:
850
+ tau1ok = True
851
+
852
+ try:
853
+ tau1c, tau1errc, chisqrc, tau1estc = fitDarkTimes.fitTaus(cumux,cumuy,return_tau1est=True)
854
+ logger.info("fitTaus: tau1 %f, tau1err %f, chisq %.1g, tau1est %f" % (tau1c, tau1errc, chisqrc, tau1estc))
855
+ except RuntimeError:
856
+ logger.warn("fitting tau value from cumulative dist failed")
857
+ tau1cok = False
858
+ else:
859
+ tau1cok = True
860
+
861
+ try:
862
+ tau1m, tau2m, atau1m, tau1errm, tau2errm, atau1errm, chisqrm = fitDarkTimes.fitTaus(binctrs,hc,
863
+ fitTau2=not self.fitSettings.Tau2Constant,
864
+ tau2const=self.fitSettings.Tau2FixedValue)
865
+ logger.info("fitTaus: tau1 %f, tau2 %f, atau1 %f, tau1err %f, tau2err %f, atau1err %f, chisq %.1g" %
866
+ (tau1m, tau2m, atau1m, tau1errm, tau2errm, atau1errm, chisqrm))
867
+ except RuntimeError:
868
+ logger.warn("fitting two tau values failed")
869
+ tau1mok = False
870
+ else:
871
+ tau1mok = True
872
+
873
+ ## STEP 4: plotting and reporting
874
+
875
+ import matplotlib.pyplot as plt
876
+
877
+ def safepltshow():
878
+ try:
879
+ plt.show()
880
+ except RuntimeError:
881
+ pass
882
+
883
+ # make a string with info
884
+ outstr = StringIO()
885
+
886
+ if usingClumpIndex:
887
+ if usingTminTmax:
888
+ print("events: %d (raw clumpSize: %d), dark times: %d (using clumpIndices + Tmin & Tmax)"
889
+ % (nevents_corrected,nevents,nts),file=outstr)
890
+ else:
891
+ print("events: %d (from clumpSize), dark times: %d (using clumpIndices)"
892
+ % (nevents,nts),file=outstr)
893
+ else:
894
+ print("events: %d, dark times: %d" % (nevents,nts),file=outstr)
895
+
896
+ print("darktime: %.1f+-%d (%.1f+-%d) frames - chisqr %.2g (%.2g)"
897
+ % (tau1c,tau1errc,
898
+ tau1,tau1err,
899
+ chisqrc,chisqr),file=outstr)
900
+ if tau1mok:
901
+ print("darktime: tau1 %.1f+-%d, tau2 %.1f+-%d"
902
+ % (tau1m, tau1errm, tau2m, tau2errm),file=outstr)
903
+ if tau1mok:
904
+ print("amplitudes: (a %.2f+-%.2f, b %.2f) - chisqr %.2g"
905
+ % (atau1m,atau1errm, 1-atau1m,chisqrm),file=outstr)
906
+ print("darktime: starting estimates: %.1f (%.1f)" % (tau1estc,tau1est),file=outstr)
907
+ print("qunits: %.2f (%.2f)" % (100.0/tau1c, 100.0/tau1),file=outstr)
908
+
909
+ labelstr = outstr.getvalue()
910
+
911
+ # plot data and fitted curves
912
+ plt.figure()
913
+ plt.subplot(211)
914
+ plt.plot(cumux,cumuy,'o')
915
+ if tau1cok: plt.plot(cumux,fitDarkTimes.cumuexpfit(cumux,tau1c))
916
+
917
+ plt.plot(binctrs,hc,'o')
918
+ if tau1ok: plt.plot(binctrs,fitDarkTimes.cumuexpfit(binctrs,tau1))
919
+
920
+ if tau1mok: plt.plot(binctrs,fitDarkTimes.cumumultiexpfit(binctrs,tau1m,tau2m,atau1m),'--')
921
+
922
+ plt.ylim(-0.2,1.2)
923
+ plt.subplot(212)
924
+ plt.semilogx(cumux,cumuy,'o')
925
+ if tau1cok: plt.semilogx(cumux,fitDarkTimes.cumuexpfit(cumux,tau1c))
926
+ plt.semilogx(binctrs,hc,'o')
927
+ if tau1ok: plt.semilogx(binctrs,fitDarkTimes.cumuexpfit(binctrs,tau1))
928
+
929
+ if tau1mok: plt.semilogx(binctrs,fitDarkTimes.cumumultiexpfit(binctrs,tau1m,tau2m,atau1m),'--')
930
+
931
+ plt.ylim(-0.2,1.2)
932
+ safepltshow()
933
+
934
+ plt.annotate(labelstr, xy=(0.5, 0.1), xycoords='axes fraction',
935
+ fontsize=10)
936
+
937
+ plt.figure()
938
+ plt.subplot(211)
939
+ if True:
940
+ plt.semilogx(cumux,cumuy,'o',color='darkblue')
941
+ if tau1ok: plt.semilogx(binctrs,fitDarkTimes.cumuexpfit(binctrs,tau1))
942
+ if tau1mok: plt.semilogx(binctrs,fitDarkTimes.cumumultiexpfit(binctrs,tau1m,tau2m,atau1m),'--')
943
+ plt.ylim(-0.2,1.2)
944
+ plt.annotate(labelstr, xy=(0.5, 0.1), xycoords='axes fraction',
945
+ fontsize=10)
946
+ else:
947
+ plt.semilogx(binctrsCoarse, hCoarse, 'o')
948
+
949
+ plt.subplot(212)
950
+ plt.semilogx(binctrs,hc,'go')
951
+ plt.semilogx(binctrsg,hcg,'bo')
952
+ if tau1ok: plt.semilogx(binctrs,fitDarkTimes.cumuexpfit(binctrs,tau1))
953
+ if tau1mok: plt.semilogx(binctrs,fitDarkTimes.cumumultiexpfit(binctrs,tau1m,tau2m,atau1m),'--',color='orange')
954
+
955
+ plt.ylim(-0.2,1.2)
956
+ safepltshow()
957
+
958
+ else:
959
+ Warn(None, 'not enough data points, only found %d dark times (need at least %d)' % (nts,NTMIN), 'Error')
960
+
961
+
962
+ def Plug(visFr):
963
+ """Plugs this module into the gui"""
964
+ visFr.qPAINTCalc = QPCalc(visFr)
965
+