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,107 @@
1
+ from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float
2
+
3
+ class clusterParam(HasTraits):
4
+ Ryrminsize = Float(1.0)
5
+
6
+ class Meas2DPlotter:
7
+ """
8
+
9
+ """
10
+ def __init__(self, dsviewer):
11
+ self.dsviewer = dsviewer
12
+ dsviewer.AddMenuItem('Experimental>Meas2D', 'Plot cluster measurements', self.OnPlotClust)
13
+ dsviewer.AddMenuItem('Experimental>Meas2D', 'Plot per cluster colocalisation', self.OnClusterColoc)
14
+ self.clusterPar = clusterParam() # initialise parameter selector
15
+
16
+
17
+ def OnPlotClust(self, event=None):
18
+ nodata = False
19
+ try:
20
+ pipeline = self.dsviewer.pipeline
21
+ except AttributeError:
22
+ nodata = True
23
+ else:
24
+ if 'area' not in pipeline.keys():
25
+ nodata = True
26
+ if nodata:
27
+ print('no area column found - returning')
28
+ return
29
+
30
+ if not self.clusterPar.configure_traits(kind='modal'):
31
+ return
32
+
33
+ mdh = self.dsviewer.image.mdh
34
+ vx = 1e3*mdh['voxelsize.x']
35
+ vy = 1e3*mdh['voxelsize.y']
36
+ RyRsz = 900.0 # RyR footprint in nm
37
+ ryrmin = self.clusterPar.Ryrminsize # minimal size of cluster to check
38
+
39
+ ryrsall = pipeline['area']*vx*vy/RyRsz
40
+ ryrs = ryrsall[ryrsall > ryrmin]
41
+ ryrmean = ryrs.mean()
42
+
43
+ import matplotlib.pyplot as plt
44
+ # plot data and fitted curves
45
+ plt.figure()
46
+ plt.hist(ryrs, bins=20)
47
+ plt.xlabel('RyRs')
48
+ plt.ylabel('Frequency')
49
+ plt.title('RyR size distribution (mean %.1f RyRs, %d clusters)' % (ryrmean,ryrs.shape[0]))
50
+ plt.show()
51
+
52
+ def OnClusterColoc(self, event=None):
53
+ nodata = False
54
+ try:
55
+ pipeline = self.dsviewer.pipeline
56
+ except AttributeError:
57
+ nodata = True
58
+ else:
59
+ if 'area' not in pipeline.keys():
60
+ nodata = True
61
+ if 'mean_intensity' not in pipeline.keys():
62
+ nodata = True
63
+ if nodata:
64
+ print('no area column found - returning')
65
+ return
66
+
67
+ if not self.clusterPar.configure_traits(kind='modal'):
68
+ return
69
+
70
+ mdh = self.dsviewer.image.mdh
71
+ vx = 1e3*mdh['voxelsize.x']
72
+ vy = 1e3*mdh['voxelsize.y']
73
+ RyRsz = 900.0 # RyR footprint in nm
74
+ ryrmin = self.clusterPar.Ryrminsize # minimal size of cluster to check
75
+
76
+ ryrs = pipeline['area']*vx*vy/RyRsz
77
+ ryrgtmin = ryrs > ryrmin
78
+
79
+ import matplotlib.pyplot as plt
80
+ import numpy as np
81
+ plt.figure()
82
+ plt.scatter(ryrs[ryrgtmin],pipeline['mean_intensity'][ryrgtmin],
83
+ facecolors='lightgray', edgecolors='black')
84
+ plt.xlabel('RyRs')
85
+ plt.ylabel('fractional coloc')
86
+ plt.title('area fraction of IP3R in RyR clusters')
87
+ plt.ylim(0,1)
88
+
89
+ fracs1 = pipeline['mean_intensity'][ryrgtmin]
90
+ meanclc = fracs1.mean()
91
+ #print('mean fraction colocalising per cluster (RyRs>5): %.2f' % meanclc)
92
+
93
+ positive1 = (fracs1 > 0.05).sum()/float(fracs1.shape[0])
94
+ #print('fraction with positive staining: %.2f' % positive1)
95
+
96
+ plt.figure()
97
+ #mbins = np.arange(0,10,1.0)/10.0
98
+ h0 = plt.hist(pipeline['mean_intensity'][ryrgtmin],bins=10)
99
+ plt.title('mean coloc frac %.2f, cluster frac positive %.2f' % (meanclc,positive1))
100
+ plt.xlabel('coloc fraction per cluster')
101
+ plt.ylabel('frequency')
102
+ plt.show()
103
+
104
+
105
+ def Plug(dsviewer):
106
+ """Plugs this module into the gui"""
107
+ dsviewer.meas2Dplt = Meas2DPlotter(dsviewer)
@@ -0,0 +1,131 @@
1
+ import numpy as np
2
+ # you may need a lot more imports depending what functionality your require in your plugin
3
+
4
+ from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float
5
+ #from traitsui.api import View, Item, Group
6
+ #from traitsui.menu import OKButton, CancelButton, OKCancelButtons
7
+
8
+ from PYMEcs.misc.guiMsgBoxes import Warn
9
+ import PYMEcs.misc.shellutils as su
10
+
11
+ class PlotOptions(HasTraits):
12
+ plotMode = Enum(('Compare with and without background',
13
+ 'Colour errors by photon number',
14
+ 'Scatter Density Plot',
15
+ 'Plot z errors (colour by photon number)'))
16
+
17
+ # We use the formula (S30) from Mortensen et al, 2010 [1] which provides a nice closed-form expression for the localisation error;
18
+ # note that this is likely a lower bound on actual error due to simplifying model assumptions (no read noise etc)
19
+
20
+ # Reference
21
+
22
+ # 1. Optimized localization analysis for single-molecule tracking and super-resolution microscopy.
23
+ # Kim I Mortensen, L Stirling Churchman, James A Spudich, and Henrik Flyvbjerg.
24
+ # Nat Meth, 2017 vol. 18 (5) pp. 377-381.
25
+ # http://www.nature.com/doifinder/10.1038/nmeth.1447
26
+
27
+ class MortensenFormula:
28
+ """
29
+ A plugin that calculates errors according to the Mortensen formula using photon number and background
30
+ estimates that event analysis has provided.
31
+ """
32
+ def __init__(self, visFr):
33
+ self.visFr = visFr
34
+ self.pipeline = visFr.pipeline
35
+ self.plotOptions = PlotOptions()
36
+
37
+ visFr.AddMenuItem('Experimental>ExtraColumns>Errors', 'Add Mortensen Formula', self.OnAddMort,
38
+ helpText='Add an event property that provides an estimate by the Mortensen Formula (from background and amplitude)')
39
+ visFr.AddMenuItem('Experimental>ExtraColumns>Errors', 'Plot Mortensen Error', self.OnPlotMort,
40
+ helpText='Scatterplot estimate by the Mortensen Formula')
41
+
42
+
43
+ def OnAddMort(self, event=None):
44
+ """
45
+ this function adds a 'mortensenError' property to events - there could be some discussion how that is actually best calculated
46
+ """
47
+ import math
48
+ mdh = self.pipeline.mdh
49
+ # the formula below is very adhoc
50
+ # I am not even sure this is remotely correct nor the best way
51
+ # so use only as a basis for experimentation and/or better plugins
52
+ N = self.pipeline['nPhotons']
53
+ # we think we do not need to subtract the camera offset
54
+ Nb = mdh['Camera.ElectronsPerCount'] * np.maximum(0,self.pipeline['fitResults_background'] / mdh['Camera.TrueEMGain'])
55
+ a = 1e3*mdh['voxelsize.x']
56
+ siga = np.sqrt(self.pipeline['sig']**2+a*a/12.0)
57
+
58
+ emort = siga /np.sqrt(N) * np.sqrt(16.0/9.0 + 8*math.pi*siga*siga*Nb/(N*a*a))
59
+ emort_nobg = siga /np.sqrt(N) * np.sqrt(16.0/9.0)
60
+
61
+ cb = 1.0*Nb/N
62
+ self.pipeline.addColumn('cb_estimate', cb)
63
+ self.pipeline.addColumn('mortensenError',emort)
64
+ self.pipeline.addColumn('mortensenErrorNoBG',emort_nobg)
65
+ self.pipeline.addColumn('backgroundPhotons',Nb)
66
+
67
+ self.pipeline.Rebuild()
68
+ self.visFr.CreateFoldPanel() # to make, for example, new columns show up in filter column selections
69
+
70
+
71
+ def OnPlotMort(self, event=None):
72
+ import matplotlib.pyplot as plt
73
+ pipeline = self.pipeline
74
+
75
+ err = pipeline['mortensenError']
76
+ err1 = np.percentile(err,1)
77
+ err99 = np.percentile(err,99)
78
+
79
+ errnbg = pipeline['mortensenErrorNoBG']
80
+ errnbg1 = np.percentile(errnbg,1)
81
+ errnbg99 = np.percentile(errnbg,99)
82
+
83
+ popt = self.plotOptions
84
+ if popt.configure_traits(kind='modal'):
85
+ if popt.plotMode == 'Compare with and without background':
86
+ plt.figure()
87
+ ebg = plt.scatter(pipeline['error_x'],pipeline['mortensenError'],
88
+ c='g',alpha=0.5)
89
+ enobg = plt.scatter(pipeline['error_x'],pipeline['mortensenErrorNoBG'],
90
+ c='r',alpha=0.5)
91
+ plt.legend((ebg,enobg),('error with bg','error assuming zero bg'))
92
+ plt.plot([errnbg1,err99],[errnbg1,err99])
93
+ plt.xlabel('Fit error x')
94
+ plt.ylabel('Error from Mortensen Formula')
95
+ elif popt.plotMode == 'Colour errors by photon number':
96
+ nph = pipeline['nPhotons']
97
+ nph5 = np.percentile(nph,5)
98
+ nph95 = np.percentile(nph,95)
99
+ plt.figure()
100
+ plt.scatter(pipeline['error_x'],pipeline['mortensenError'],
101
+ c=nph,vmin=nph5,vmax=nph95,cmap=plt.cm.jet)
102
+ plt.plot([err1,err99],[err1,err99])
103
+ plt.xlabel('Fit error x')
104
+ plt.ylabel('Error from Mortensen Formula')
105
+ plt.title('error coloured with nPhotons')
106
+ plt.colorbar()
107
+ elif popt.plotMode == 'Scatter Density Plot':
108
+ plt.figure()
109
+ su.scatterdens(pipeline['error_x'],pipeline['mortensenError'],
110
+ subsample=0.2, xlabel='Fit error x',
111
+ ylabel='Error from Mortensen Formula',s=20)
112
+ plt.plot([err1,err99],[err1,err99])
113
+ elif popt.plotMode == 'Plot z errors (colour by photon number)':
114
+ if 'fitError_z0' not in pipeline.keys():
115
+ Warn('No z error - works only with fitError_z0 property')
116
+ return
117
+ nph = pipeline['nPhotons']
118
+ nph5 = np.percentile(nph,5)
119
+ nph95 = np.percentile(nph,95)
120
+ plt.figure()
121
+ plt.scatter(pipeline['fitError_z0'],pipeline['mortensenError'],
122
+ c=nph,vmin=nph5,vmax=nph95,cmap=plt.cm.jet)
123
+ plt.plot([err1,err99],[err1,err99])
124
+ plt.xlabel('Fit error z')
125
+ plt.ylabel('Error from Mortensen Formula')
126
+ plt.title('error coloured with nPhotons')
127
+ plt.colorbar()
128
+
129
+ def Plug(visFr):
130
+ """Plugs this module into the gui"""
131
+ visFr.mortForm = MortensenFormula(visFr)
@@ -0,0 +1,158 @@
1
+ from PYME.DSView import ViewIm3D
2
+ from PYME.localization.remFitBuf import CameraInfoManager
3
+
4
+ # the NCS functionality needs the pyNCS in the path, either linked
5
+ # into the PYMEcs.Analysis directory (e.g. via symlink) or as pyNCS in the PYTHONPATH
6
+ # the code can be obtained from https://github.com/HuanglabPurdue/NCS,
7
+ # in the python3-6 directory
8
+ # my testing shows that the implementation runs fine under python-2.7
9
+ try:
10
+ import PYMEcs.Analysis.pyNCS.denoisetools as ncs
11
+ except ImportError:
12
+ try:
13
+ import pyNCS.denoisetools as ncs
14
+ except ImportError:
15
+ ncs = None
16
+
17
+ from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float
18
+ from traitsui.api import View, Item, Group
19
+ from traitsui.menu import OKButton, CancelButton, OKCancelButtons
20
+
21
+ from PYMEcs.misc.guiMsgBoxes import Warn
22
+
23
+ from PYMEcs.misc.mapUtils import check_mapexists
24
+
25
+ class ncsSelect(HasTraits):
26
+ winSize = Enum(64,128,256)
27
+ Rs = Int(8) # IMPORTANT: looks like the pyncs code assumes Rs is a divider of the imgsz (see imagsz2 below)!!
28
+ Lambda_nm = Float(690) # emission wavelength
29
+ NA = Float(1.49) # objective NA
30
+ iterations = Int(15)
31
+ alpha = Float(0.2)
32
+
33
+ class ncsDenoiser:
34
+ """
35
+ GUI class to supply various map tools
36
+ """
37
+ def __init__(self, dsviewer):
38
+ self.dsviewer = dsviewer
39
+ self.do = dsviewer.do
40
+ self.image = dsviewer.image
41
+ self.ncsSel = ncsSelect() # by making it part of the object we retain parameters across invocations
42
+ self.ci = CameraInfoManager()
43
+
44
+ dsviewer.AddMenuItem('Experimental',
45
+ 'NCS denoising of small square ROI',
46
+ self.OnNCSDenoise)
47
+
48
+ def OnNCSDenoise(self, event=None):
49
+ ncsSel = self.ncsSel
50
+ if not ncsSel.configure_traits(kind='modal'):
51
+ return
52
+
53
+ mdh = self.image.mdh
54
+ img = self.image.data[:,:, self.do.zp, 0].squeeze() # current frame
55
+
56
+ # code below from pyncs.addnoise
57
+ # I is presumably average photon number; bg is background photons/pixel
58
+ # idealimg = np.abs(normimg)*I+bg
59
+ # poissonimg = np.random.poisson(idealimg)
60
+
61
+ # UNITS: scmosimg (ADUs) = electrons * [gain-as-ADU/electrons / flatfield] + readnoise(ADUs) + offset
62
+ # from which follows gain_for_pyNCS = [gain-as-ADU/electrons / flatfield]
63
+ # scmosimg = poissonimg*gainmap + np.sqrt(varmap)*np.random.randn(R,R)
64
+ # scmosimg += offset
65
+
66
+ if check_mapexists(mdh,'dark') is None:
67
+ Warn(None, 'ncsimage: no dark map found')
68
+ return
69
+ else:
70
+ dark = self.ci.getDarkMap(mdh)
71
+
72
+ if check_mapexists(mdh,'variance') is None:
73
+ Warn(None, 'ncsimage: no variance map found')
74
+ return
75
+ else:
76
+ # we need to convert to units of ADU^2
77
+ variance = self.ci.getVarianceMap(mdh)/(mdh['Camera.ElectronsPerCount']**2)
78
+
79
+ if check_mapexists(mdh,'flatfield') is None:
80
+ gain = 1.0/mdh['Camera.ElectronsPerCount']*np.ones_like(variance)
81
+ else:
82
+ # code above argues we need to divide by flatfield
83
+ gain = 1.0/(mdh['Camera.ElectronsPerCount']*self.ci.getFlatfieldMap(mdh))
84
+
85
+ # the slice code needs a little bit of further checking
86
+ isz = ncsSel.winSize
87
+ imshape = img.shape
88
+ xstart = self.do.xp - isz/2
89
+ if xstart < 0:
90
+ xstart = imshape[0]/2 - isz/2
91
+ ystart = self.do.yp - isz/2
92
+ if ystart < 0:
93
+ ystart = imshape[1]/2 - isz/2
94
+
95
+ sliceSquare = np.s_[xstart:xstart+isz,ystart:ystart+isz] # either on crosshairs or in the centre
96
+ roi = [[xstart,xstart+isz],[ystart,ystart+isz],[self.do.zp,self.do.zp]]
97
+
98
+ var_sl = variance[sliceSquare]
99
+ dark_sl = dark[sliceSquare]
100
+ gain_sl = gain[sliceSquare]
101
+
102
+ # next few lines from NCSdemo_experiment which show how raw cmos data is pre-corrected
103
+ # apply gain and offset correction
104
+ # N = subims.shape[0]
105
+ # imsd = (subims-np.tile(suboffset,(N,1,1)))/np.tile(subgain,(N,1,1))
106
+ # imsd[imsd<=0] = 1e-6
107
+
108
+ # therefore this needs to be in photoelectrons
109
+ imgcorr = mdh['Camera.ElectronsPerCount']*self.ci.correctImage(mdh, img)
110
+ imgc_sl = imgcorr[sliceSquare].squeeze()
111
+
112
+ imgc_sl_T = imgc_sl[:,:,None].transpose((2,0,1))
113
+ ret = np.clip(imgc_sl_T,1e-6,None,out=imgc_sl_T) # clip inplace at 1e-6
114
+
115
+ Rs = ncsSel.Rs # IMPORTANT: looks like the pyncs code assumes Rs is a divider of the imgsz (see imagsz2 below)!!
116
+ Pixelsize = mdh['voxelsize.x']
117
+ Lambda = ncsSel.Lambda_nm / 1e3 # emission wavelength
118
+ NA = ncsSel.NA # objective NA
119
+ iterationN = ncsSel.iterations
120
+ alpha = ncsSel.alpha
121
+
122
+ if ncs is not None:
123
+ out = ncs.reducenoise(Rs,imgc_sl_T,var_sl,gain_sl,isz,Pixelsize,NA,Lambda,alpha,iterationN)
124
+ else:
125
+ out = imgc_sl_T # no reduction performed
126
+
127
+ # now we need code to show this image and make it possible to save that
128
+ disp_img = np.dstack([imgc_sl_T.squeeze(), out.squeeze()])
129
+ im = ImageStack(disp_img, titleStub = '%d pixel crop of Frame %d denoised' % (isz,self.do.zp))
130
+ im.mdh.copyEntriesFrom(mdh)
131
+
132
+ # NCS parameters and crop info
133
+ im.mdh['Parent'] = self.image.filename
134
+ im.mdh['Processing.Units'] = 'PhotoElectrons'
135
+ im.mdh['Processing.Type'] = 'NCS Denoising'
136
+ im.mdh['Processing.NCS.alpha'] = ncsSel.alpha
137
+ im.mdh['Processing.NCS.iterations'] = ncsSel.iterations
138
+ im.mdh['Processing.NCS.Rs'] = ncsSel.Rs
139
+ im.mdh['Processing.NCS.LambdaNM'] = ncsSel.Lambda_nm
140
+ im.mdh['Processing.NCS.NA'] = ncsSel.NA
141
+ im.mdh['Processing.CropROI'] = roi
142
+ im.mdh['Processing.Comment'] = 'First frame: original (photoelectrons), second frame: denoised'
143
+
144
+ vx, vy, vz = self.image.voxelsize
145
+ ox, oy, oz = self.image.origin
146
+ im.mdh['Origin.x'] = ox + roi[0][0]*vx
147
+ im.mdh['Origin.y'] = oy + roi[1][0]*vy
148
+ im.mdh['Origin.z'] = oz
149
+
150
+ if self.dsviewer.mode == 'visGUI':
151
+ mode = 'visGUI'
152
+ else:
153
+ mode = 'lite'
154
+
155
+ dv = ViewIm3D(im, mode=mode, glCanvas=self.dsviewer.glCanvas, parent=wx.GetTopLevelParent(self.dsviewer))
156
+
157
+ def Plug(dsviewer):
158
+ dsviewer.ncsDenoiser = ncsDenoiser(dsviewer)
@@ -0,0 +1,295 @@
1
+ import wx
2
+ import numpy as np
3
+ import sys
4
+ from scipy import ndimage
5
+ from PYMEcs.misc.guiMsgBoxes import Warn, Info
6
+
7
+ from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float
8
+ from traitsui.api import View, Item, Group
9
+ from traitsui.menu import OKButton, CancelButton, OKCancelButtons
10
+
11
+
12
+ import logging
13
+ logger = logging.getLogger(__file__)
14
+
15
+ class propertyChoice(HasTraits):
16
+ clist = List([])
17
+ EventProperty = Enum(values='clist')
18
+
19
+ traits_view = View(Group(Item(name = 'EventProperty'),
20
+ show_border = True),
21
+ buttons = OKCancelButtons)
22
+
23
+ def add_channels(self,chans):
24
+ for chan in chans:
25
+ if chan not in self.clist:
26
+ self.clist.append(chan)
27
+
28
+
29
+ class onTimer:
30
+ """
31
+
32
+ """
33
+ def __init__(self, visFr):
34
+ self.visFr = visFr
35
+ self.pipeline = visFr.pipeline
36
+
37
+ visFr.AddMenuItem('Experimental>Event Processing',
38
+ "onTimes from selected coalesced events",
39
+ self.OnTimes,
40
+ helpText='analyse the on time distribution of events in a region - needs the coalesced data source with nFrames event property')
41
+ visFr.AddMenuItem('Experimental>Event Processing',
42
+ "plot time series of clumps",
43
+ self.OnPlotClumps,
44
+ helpText='plots the time course of the selected events in a "single channel trace" - needs the clumpIndex event property')
45
+ visFr.AddMenuItem('Experimental>Event Processing',
46
+ "plot time series of event property",
47
+ self.OnPlotProperty,
48
+ helpText='plots a time series of the selected events in a "single channel trace" - using a user chosen event property')
49
+ visFr.AddMenuItem('Experimental>Event Processing',
50
+ "plot time gating from selected events\tCtrl+G",
51
+ self.OnPlotTser,
52
+ helpText='plots the time series of gating of detected molecules from the selected group of events')
53
+ visFr.AddMenuItem('Experimental>Event Processing',
54
+ "Event density in ROI\tCtrl+D",
55
+ self.OnEvtDensity,
56
+ helpText='calculate the event density (events/unit area) in the current ROI/image area')
57
+
58
+
59
+ def OnEvtDensity(self,event):
60
+ from PYMEcs.Analysis.eventProperties import evtDensity, getarea
61
+ visFr = self.visFr
62
+ pipeline = visFr.pipeline
63
+
64
+ dens, intens1, intens2, trange = evtDensity(pipeline)
65
+ area = getarea(pipeline)
66
+
67
+ if dens is None:
68
+ Warn(visFr,'area too small (%.2f um^2)' % (area))
69
+ else:
70
+ infostr = \
71
+ """
72
+ Event density: %.1f events/um^2
73
+ Norm. intens.: %.1f events/um^2/5K-fr
74
+ Norm. intens.: %.1f events/(20um)^2/fr
75
+ Number of Events: %d events
76
+ Area probed: %.2f um^2
77
+ Time range: %.2fK frames""" % (dens, intens1, intens2, dens*area, area, trange/1e3)
78
+ Info(visFr,infostr)
79
+
80
+
81
+ def OnPlotTser(self,event):
82
+ from PYMEcs.misc.shellutils import plotserpipeline
83
+
84
+ visFr = self.visFr
85
+ pipeline = visFr.pipeline
86
+ mdh = pipeline.mdh
87
+
88
+ t = pipeline['t']
89
+ maxPts = 1e4
90
+ if len(t) > maxPts:
91
+ Warn(None,'aborting darktime analysis: too many events, current max is %d' % maxPts)
92
+ return
93
+
94
+ p = pipeline
95
+
96
+ # if we have coalesced events use this info
97
+ if ('tmin' in pipeline.keys()) and ('tmax' in pipeline.keys()):
98
+ tmin = pipeline['tmin']
99
+ tmax = pipeline['tmax']
100
+ tc = np.arange(tmin[0],tmax[0]+1)
101
+ for i in range(1,tmin.shape[0]):
102
+ tc = np.append(tc,np.arange(tmin[i],tmax[i]+1))
103
+ tc.sort()
104
+ else:
105
+ tc = t
106
+
107
+ startn = pipeline.selectedDataSource['t'].min()
108
+ endn = pipeline.selectedDataSource['t'].max()
109
+
110
+ tt, v = plotserpipeline(tc, np.ones_like(tc))
111
+
112
+ # add points to start from beginning of series
113
+ tt2 = np.append([startn,tt[0],tt[0]],tt)
114
+ v2 = np.append([0,0,1],v)
115
+ # add points to go to end of series
116
+ tt2 = np.append(tt2,[tt[-1],tt[-1],endn])
117
+ v2 = np.append(v2,[1,0,0])
118
+
119
+ import matplotlib.pyplot as plt
120
+ # plot data and fitted curves
121
+ plt.figure()
122
+ plt.plot(tt2,v2)
123
+ plt.show()
124
+ plt.xlim(startn,endn)
125
+
126
+ def OnTimes(self,event):
127
+ import StringIO
128
+ from PYMEcs.Analysis import fitDarkTimes
129
+
130
+ visFr = self.visFr
131
+ pipeline = visFr.pipeline
132
+ mdh = pipeline.mdh
133
+
134
+ NTMIN = 5
135
+ maxPts = 1e5
136
+ t = pipeline['t']
137
+ if len(t) > maxPts:
138
+ Warn(None,'aborting analysis: too many events, current max is %d' % maxPts)
139
+ return
140
+ x = pipeline['x']
141
+ y = pipeline['y']
142
+
143
+ # determine darktime from gaps and reject zeros (no real gaps)
144
+
145
+ try:
146
+ dtg = pipeline['nFrames']
147
+ except KeyError:
148
+ Warn(None,'aborting analysis: could not find "nFrames" property, needs "Coalesced" Data Source','Error')
149
+ return
150
+
151
+ nts = dtg.shape[0]
152
+
153
+ if nts > NTMIN:
154
+ # now make a cumulative histogram from these
155
+ cumux,cumuy = fitDarkTimes.cumuhist(dtg)
156
+ binctrs,hc,binctrsg,hcg = fitDarkTimes.cumuhistBinned(dtg)
157
+
158
+ bbx = (x.min(),x.max())
159
+ bby = (y.min(),y.max())
160
+ voxx = 1e3*mdh['voxelsize.x']
161
+ voxy = 1e3*mdh['voxelsize.y']
162
+ bbszx = bbx[1]-bbx[0]
163
+ bbszy = bby[1]-bby[0]
164
+
165
+ # fit theoretical distributions
166
+ popth,pcovh,popt,pcov = (None,None,None,None)
167
+ if nts > NTMIN:
168
+ from scipy.optimize import curve_fit
169
+
170
+ idx = (np.abs(hcg - 0.63)).argmin()
171
+ tauesth = binctrsg[idx]
172
+ popth,pcovh,infodicth,errmsgh,ierrh = curve_fit(fitDarkTimes.cumuexpfit,binctrs,hc, p0=(tauesth),full_output=True)
173
+ chisqredh = ((hc - infodicth['fvec'])**2).sum()/(hc.shape[0]-1)
174
+ idx = (np.abs(cumuy - 0.63)).argmin()
175
+ tauest = cumux[idx]
176
+ popt,pcov,infodict,errmsg,ierr = curve_fit(fitDarkTimes.cumuexpfit,cumux,cumuy, p0=(tauest),full_output=True)
177
+ chisqred = ((cumuy - infodict['fvec'])**2).sum()/(nts-1)
178
+
179
+ import matplotlib.pyplot as plt
180
+ # plot data and fitted curves
181
+ plt.figure()
182
+ plt.subplot(211)
183
+ plt.plot(cumux,cumuy,'o')
184
+ plt.plot(cumux,fitDarkTimes.cumuexpfit(cumux,popt[0]))
185
+ plt.plot(binctrs,hc,'o')
186
+ plt.plot(binctrs,fitDarkTimes.cumuexpfit(binctrs,popth[0]))
187
+ plt.ylim(-0.2,1.2)
188
+ plt.subplot(212)
189
+ plt.semilogx(cumux,cumuy,'o')
190
+ plt.semilogx(cumux,fitDarkTimes.cumuexpfit(cumux,popt[0]))
191
+ plt.semilogx(binctrs,hc,'o')
192
+ plt.semilogx(binctrs,fitDarkTimes.cumuexpfit(binctrs,popth[0]))
193
+ plt.ylim(-0.2,1.2)
194
+ plt.show()
195
+
196
+ outstr = StringIO.StringIO()
197
+
198
+ analysis = {
199
+ 'Nevents' : t.shape[0],
200
+ 'Ndarktimes' : nts,
201
+ 'filterKeys' : pipeline.filterKeys.copy(),
202
+ 'darktimes' : (popt[0],popth[0]),
203
+ 'darktimeErrors' : (np.sqrt(pcov[0][0]),np.sqrt(pcovh[0][0]))
204
+ }
205
+
206
+ #if not hasattr(self.visFr,'analysisrecord'):
207
+ # self.visFr.analysisrecord = []
208
+ # self.visFr.analysisrecord.append(analysis)
209
+
210
+ print >>outstr, "events: %d, on times: %d" % (t.shape[0],nts)
211
+ print >>outstr, "region: %d x %d nm (%d x %d pixel)" % (bbszx,bbszy,bbszx/voxx,bbszy/voxy)
212
+ print >>outstr, "centered at %d,%d (%d,%d pixels)" % (x.mean(),y.mean(),x.mean()/voxx,y.mean()/voxy)
213
+ print >>outstr, "ontime: %.1f+-%d (%.1f+-%d) frames - chisqr %.2f (%.2f)" % (popt[0],np.sqrt(pcov[0][0]),
214
+ popth[0],np.sqrt(pcovh[0][0]),
215
+ chisqred,chisqredh)
216
+ print >>outstr, "ontime: starting estimates: %.1f (%.1f)" % (tauest,tauesth)
217
+ print >>outstr, "qunits: %.2f (%.2f), mean on time: %.2f" % (100.0/popt[0], 100.0/popth[0], dtg.mean())
218
+
219
+ labelstr = outstr.getvalue()
220
+ plt.annotate(labelstr, xy=(0.5, 0.1), xycoords='axes fraction',
221
+ fontsize=10)
222
+ else:
223
+ Warn(None, 'not enough data points, only found %d on times (need at least %d)' % (nts,NTMIN), 'Error')
224
+
225
+ def OnPlotClumps(self,event):
226
+ import PYMEcs.Analysis.timeSeries as ts
227
+ try:
228
+ ci = self.pipeline['clumpIndex']
229
+ except KeyError:
230
+ Warn(None,'aborting analysis: could not find "clumpIndex" property','Error')
231
+ return
232
+ t = self.pipeline['t']
233
+
234
+ maxPts = 1e4
235
+ if len(t) > maxPts:
236
+ Warn(None,'aborting analysis: too many events, current max is %d' % maxPts)
237
+ return
238
+
239
+ ts.plotClumpSeries(t, ci)
240
+
241
+ def tserFromPipeline(self,key,base=0):
242
+ # t is on integer times assumed (from pipeline)
243
+ # val is the corresponding value
244
+ t = self.pipeline['t']
245
+ val = self.pipeline[key]
246
+
247
+ tmin = t.min()
248
+ tmax = t.max()
249
+ tstart = tmin-1
250
+ tend = tmax + 1
251
+ tlen = tend-tstart+1
252
+
253
+ to = t-tstart
254
+ tidx = np.argsort(to)
255
+ tos = to[tidx]
256
+ vs = val[tidx]
257
+
258
+ tvalid = np.zeros((tlen))
259
+ tvalid[tos] = 1
260
+
261
+ vals = np.zeros((tlen))
262
+ vals[tos] = vs
263
+
264
+ tup = tos[1:][(tos[1:]-tos[:-1] > 1)]
265
+ tvalid[tup-1] = 1
266
+ vals[tup-1] = base
267
+
268
+ tdown = tos[:-1][(tos[1:]-tos[:-1] > 1)]
269
+ tvalid[tdown+1] = 1
270
+ vals[tdown+1] = base
271
+
272
+ tplot = tvalid.nonzero()[0]
273
+ vplot = vals[tplot]
274
+
275
+ return (tplot+tstart,vplot)
276
+
277
+
278
+ def OnPlotProperty(self,event):
279
+ pChoice = propertyChoice()
280
+ pChoice.add_channels(sorted(self.pipeline.keys()))
281
+ if pChoice.configure_traits(kind='modal'):
282
+ t,prop = self.tserFromPipeline(pChoice.EventProperty)
283
+ if t.shape[0] > 2e4:
284
+ Warn(None,'aborting analysis: too many events, current max is %d' % 2e4)
285
+ return
286
+ import matplotlib.pyplot as plt
287
+ plt.figure()
288
+ plt.plot(t,prop)
289
+ plt.xlabel('Frame Number')
290
+ plt.ylabel(pChoice.EventProperty)
291
+ plt.show()
292
+
293
+ def Plug(visFr):
294
+ """Plugs this module into the gui"""
295
+ visFr.onTimer = onTimer(visFr)