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.
- PYMEcs/Acquire/Actions/__init__.py +0 -0
- PYMEcs/Acquire/Actions/custom.py +167 -0
- PYMEcs/Acquire/Hardware/LPthreadedSimple.py +248 -0
- PYMEcs/Acquire/Hardware/LPthreadedSimpleSim.py +246 -0
- PYMEcs/Acquire/Hardware/NikonTiFlaskServer.py +45 -0
- PYMEcs/Acquire/Hardware/NikonTiFlaskServerT.py +59 -0
- PYMEcs/Acquire/Hardware/NikonTiRESTClient.py +73 -0
- PYMEcs/Acquire/Hardware/NikonTiSim.py +35 -0
- PYMEcs/Acquire/Hardware/__init__.py +0 -0
- PYMEcs/Acquire/Hardware/driftTrackGUI.py +329 -0
- PYMEcs/Acquire/Hardware/driftTrackGUI_n.py +472 -0
- PYMEcs/Acquire/Hardware/driftTracking.py +424 -0
- PYMEcs/Acquire/Hardware/driftTracking_n.py +433 -0
- PYMEcs/Acquire/Hardware/fakeCamX.py +15 -0
- PYMEcs/Acquire/Hardware/offsetPiezoRESTCorrelLog.py +38 -0
- PYMEcs/Acquire/__init__.py +0 -0
- PYMEcs/Analysis/MBMcollection.py +552 -0
- PYMEcs/Analysis/MINFLUX.py +280 -0
- PYMEcs/Analysis/MapUtils.py +77 -0
- PYMEcs/Analysis/NPC.py +1176 -0
- PYMEcs/Analysis/Paraflux.py +218 -0
- PYMEcs/Analysis/Simpler.py +81 -0
- PYMEcs/Analysis/Sofi.py +140 -0
- PYMEcs/Analysis/__init__.py +0 -0
- PYMEcs/Analysis/decSofi.py +211 -0
- PYMEcs/Analysis/eventProperties.py +50 -0
- PYMEcs/Analysis/fitDarkTimes.py +569 -0
- PYMEcs/Analysis/objectVolumes.py +20 -0
- PYMEcs/Analysis/offlineTracker.py +130 -0
- PYMEcs/Analysis/stackTracker.py +180 -0
- PYMEcs/Analysis/timeSeries.py +63 -0
- PYMEcs/Analysis/trackFiducials.py +186 -0
- PYMEcs/Analysis/zerocross.py +91 -0
- PYMEcs/IO/MINFLUX.py +851 -0
- PYMEcs/IO/NPC.py +117 -0
- PYMEcs/IO/__init__.py +0 -0
- PYMEcs/IO/darkTimes.py +19 -0
- PYMEcs/IO/picasso.py +219 -0
- PYMEcs/IO/tabular.py +11 -0
- PYMEcs/__init__.py +0 -0
- PYMEcs/experimental/CalcZfactor.py +51 -0
- PYMEcs/experimental/FRC.py +338 -0
- PYMEcs/experimental/ImageJROItools.py +49 -0
- PYMEcs/experimental/MINFLUX.py +1537 -0
- PYMEcs/experimental/NPCcalcLM.py +560 -0
- PYMEcs/experimental/Simpler.py +369 -0
- PYMEcs/experimental/Sofi.py +78 -0
- PYMEcs/experimental/__init__.py +0 -0
- PYMEcs/experimental/binEventProperty.py +187 -0
- PYMEcs/experimental/chaining.py +23 -0
- PYMEcs/experimental/clusterTrack.py +179 -0
- PYMEcs/experimental/combine_maps.py +104 -0
- PYMEcs/experimental/eventProcessing.py +93 -0
- PYMEcs/experimental/fiducials.py +323 -0
- PYMEcs/experimental/fiducialsNew.py +402 -0
- PYMEcs/experimental/mapTools.py +271 -0
- PYMEcs/experimental/meas2DplotDh5view.py +107 -0
- PYMEcs/experimental/mortensen.py +131 -0
- PYMEcs/experimental/ncsDenoise.py +158 -0
- PYMEcs/experimental/onTimes.py +295 -0
- PYMEcs/experimental/procPoints.py +77 -0
- PYMEcs/experimental/pyme2caml.py +73 -0
- PYMEcs/experimental/qPAINT.py +965 -0
- PYMEcs/experimental/randMap.py +188 -0
- PYMEcs/experimental/regExtraCmaps.py +11 -0
- PYMEcs/experimental/selectROIfilterTable.py +72 -0
- PYMEcs/experimental/showErrs.py +51 -0
- PYMEcs/experimental/showErrsDh5view.py +58 -0
- PYMEcs/experimental/showShiftMap.py +56 -0
- PYMEcs/experimental/snrEvents.py +188 -0
- PYMEcs/experimental/specLabeling.py +51 -0
- PYMEcs/experimental/splitRender.py +246 -0
- PYMEcs/experimental/testChannelByName.py +36 -0
- PYMEcs/experimental/timedSpecies.py +28 -0
- PYMEcs/experimental/utils.py +31 -0
- PYMEcs/misc/ExtraCmaps.py +177 -0
- PYMEcs/misc/__init__.py +0 -0
- PYMEcs/misc/configUtils.py +169 -0
- PYMEcs/misc/guiMsgBoxes.py +27 -0
- PYMEcs/misc/mapUtils.py +230 -0
- PYMEcs/misc/matplotlib.py +136 -0
- PYMEcs/misc/rectsFromSVG.py +182 -0
- PYMEcs/misc/shellutils.py +1110 -0
- PYMEcs/misc/utils.py +205 -0
- PYMEcs/misc/versionCheck.py +20 -0
- PYMEcs/misc/zcInfo.py +90 -0
- PYMEcs/pyme_warnings.py +4 -0
- PYMEcs/recipes/__init__.py +0 -0
- PYMEcs/recipes/base.py +75 -0
- PYMEcs/recipes/localisations.py +2380 -0
- PYMEcs/recipes/manipulate_yaml.py +83 -0
- PYMEcs/recipes/output.py +177 -0
- PYMEcs/recipes/processing.py +247 -0
- PYMEcs/recipes/simpler.py +290 -0
- PYMEcs/version.py +2 -0
- pyme_extra-1.0.4.post0.dist-info/METADATA +114 -0
- pyme_extra-1.0.4.post0.dist-info/RECORD +101 -0
- pyme_extra-1.0.4.post0.dist-info/WHEEL +5 -0
- pyme_extra-1.0.4.post0.dist-info/entry_points.txt +3 -0
- pyme_extra-1.0.4.post0.dist-info/licenses/LICENSE +674 -0
- pyme_extra-1.0.4.post0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float, Bool
|
|
3
|
+
from traitsui.api import View, Item, Group
|
|
4
|
+
from traitsui.menu import OKButton, CancelButton, OKCancelButtons
|
|
5
|
+
|
|
6
|
+
class ChannelSelector(HasTraits):
|
|
7
|
+
clist = List([])
|
|
8
|
+
Channel = Enum(values='clist')
|
|
9
|
+
|
|
10
|
+
traits_view = View(Group(Item(name = 'Channel')),
|
|
11
|
+
title = 'Select Channel',
|
|
12
|
+
buttons = OKCancelButtons
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
def add_keys(self,chans):
|
|
16
|
+
for chan in chans:
|
|
17
|
+
if chan not in self.clist:
|
|
18
|
+
self.clist.append(chan)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TimeSelector(HasTraits):
|
|
22
|
+
clist = List([])
|
|
23
|
+
Channel = Enum(values='clist')
|
|
24
|
+
FromTime = Float()
|
|
25
|
+
ToTime = Float()
|
|
26
|
+
FilterEvents = Bool(False)
|
|
27
|
+
|
|
28
|
+
traits_view = View(Group(Item(name = 'Channel'),
|
|
29
|
+
Item(name = 'FromTime'),
|
|
30
|
+
Item(name = 'ToTime'),
|
|
31
|
+
Item(name = 'FilterEvents')),
|
|
32
|
+
title = 'Select Channel',
|
|
33
|
+
buttons = OKCancelButtons
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def add_keys(self,chans):
|
|
37
|
+
for chan in chans:
|
|
38
|
+
if chan not in self.clist:
|
|
39
|
+
self.clist.append(chan)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TimeBlock(HasTraits):
|
|
43
|
+
BlockSize = Int(100)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ExtraColumns:
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
def __init__(self, visFr):
|
|
51
|
+
self.visFr = visFr
|
|
52
|
+
self.pipeline = visFr.pipeline
|
|
53
|
+
|
|
54
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
55
|
+
'Add random value column',
|
|
56
|
+
self.OnRandMap,
|
|
57
|
+
helpText='the added random value column can be used to select a fraction of all events')
|
|
58
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
59
|
+
'Add time block choice column',
|
|
60
|
+
self.OnTimeBlocks,
|
|
61
|
+
helpText='the added column can be used to select blocks of frames as even or odd numbered blocks')
|
|
62
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
63
|
+
'Select 50% of events from even numbered time blocks - EVEN',
|
|
64
|
+
self.OnSelectTB1,
|
|
65
|
+
helpText='select half of all events for FRC - even numbered time blocks')
|
|
66
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
67
|
+
'Select 50% of events from from odd numbered time blocks - ODD',
|
|
68
|
+
self.OnSelectTB2,
|
|
69
|
+
helpText='select half of all events for FRC - second half')
|
|
70
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
71
|
+
'Select 50% of events from random value column - half 1',
|
|
72
|
+
self.OnSelectHalf1,
|
|
73
|
+
helpText='select half of all events for FRC - first half')
|
|
74
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
75
|
+
'Select 50% of events from random value column - half 2',
|
|
76
|
+
self.OnSelectHalf2,
|
|
77
|
+
helpText='select half of all events for FRC - second half')
|
|
78
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
79
|
+
'Add channel based time selection column',
|
|
80
|
+
self.OnTimeSelectChannel,
|
|
81
|
+
helpText='the added column can be used to select a time window of events of a specific colour, filter tsel_channel in range (0.5,2)')
|
|
82
|
+
visFr.AddMenuItem('Experimental>Deprecated>ExtraColumns',
|
|
83
|
+
'Add channel based random fraction selection column',
|
|
84
|
+
self.OnRandomSelectChannel,
|
|
85
|
+
helpText='the added column can be used to select a fraction of events of a specific colour by random sub-sampling, filter rand_channel in range (-.1,fraction)')
|
|
86
|
+
|
|
87
|
+
def OnRandMap(self, event=None):
|
|
88
|
+
self.pipeline.selectedDataSource.setMapping('randVal','0*x+np.random.rand(x.size)')
|
|
89
|
+
self.pipeline.Rebuild()
|
|
90
|
+
|
|
91
|
+
def OnTimeBlocks(self, event=None):
|
|
92
|
+
tb = TimeBlock()
|
|
93
|
+
if tb.configure_traits(kind='modal'):
|
|
94
|
+
psd = self.pipeline.selectedDataSource
|
|
95
|
+
blockSel = np.mod((psd['t']/tb.BlockSize).astype('int'),2)
|
|
96
|
+
# self.pipeline.selectedDataSource.setMapping('timeBlock',"np.mod((t/%d).astype('int'),2)" % tb.BlockSize)
|
|
97
|
+
self.pipeline.selectedDataSource.addColumn('timeBlock',blockSel)
|
|
98
|
+
self.pipeline.Rebuild()
|
|
99
|
+
|
|
100
|
+
def OnSelectTB1(self, event=None):
|
|
101
|
+
if 'timeBlock' not in self.pipeline.keys():
|
|
102
|
+
print('Need randVal property, call "Add random value column" first')
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
self.pipeline.filterKeys['timeBlock'] = (-0.1,0.5)
|
|
106
|
+
self.pipeline.Rebuild()
|
|
107
|
+
self.visFr.CreateFoldPanel()
|
|
108
|
+
|
|
109
|
+
def OnSelectTB2(self, event=None):
|
|
110
|
+
if 'timeBlock' not in self.pipeline.keys():
|
|
111
|
+
print('Need randVal property, call "Add random value column" first')
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
self.pipeline.filterKeys['timeBlock'] = (0.5,1.5)
|
|
115
|
+
self.pipeline.Rebuild()
|
|
116
|
+
self.visFr.CreateFoldPanel()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def OnSelectHalf1(self, event=None):
|
|
120
|
+
if 'randVal' not in self.pipeline.keys():
|
|
121
|
+
print('Need randVal property, call "Add random value column" first')
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
self.pipeline.filterKeys['randVal'] = (-0.1,0.4999)
|
|
125
|
+
self.pipeline.Rebuild()
|
|
126
|
+
self.visFr.CreateFoldPanel()
|
|
127
|
+
|
|
128
|
+
def OnSelectHalf2(self, event=None):
|
|
129
|
+
if 'randVal' not in self.pipeline.keys():
|
|
130
|
+
print('Need randVal property, call "Add random value column" first')
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
self.pipeline.filterKeys['randVal'] = (0.5,1.1)
|
|
134
|
+
self.pipeline.Rebuild()
|
|
135
|
+
self.visFr.CreateFoldPanel()
|
|
136
|
+
|
|
137
|
+
def OnTimeSelectChannel(self, event=None):
|
|
138
|
+
pipeline = self.pipeline
|
|
139
|
+
if pipeline.selectedDataSource is None:
|
|
140
|
+
return
|
|
141
|
+
if len(pipeline.colourFilter.getColourChans()) < 1:
|
|
142
|
+
return
|
|
143
|
+
timeSelector = TimeSelector()
|
|
144
|
+
timeSelector.add_keys(pipeline.colourFilter.getColourChans())
|
|
145
|
+
if timeSelector.configure_traits(kind='modal'):
|
|
146
|
+
psd = pipeline.selectedDataSource
|
|
147
|
+
tall = np.ones_like(psd['x'], dtype='float')
|
|
148
|
+
tsel = (psd['t'] >= timeSelector.FromTime) * (psd['t'] <= timeSelector.ToTime)
|
|
149
|
+
|
|
150
|
+
dispColor = pipeline.colourFilter.currentColour
|
|
151
|
+
pipeline.colourFilter.setColour(timeSelector.Channel)
|
|
152
|
+
idx = pipeline.filter.Index.copy()
|
|
153
|
+
idx[idx] = pipeline.colourFilter.index
|
|
154
|
+
tall[idx] = tsel[idx]
|
|
155
|
+
pipeline.colourFilter.setColour(dispColor)
|
|
156
|
+
pipeline.selectedDataSource.addColumn('tselect_%s' % timeSelector.Channel,tall)
|
|
157
|
+
if timeSelector.FilterEvents:
|
|
158
|
+
self.pipeline.filterKeys['tselect_%s' % timeSelector.Channel] = (0.5,2.0)
|
|
159
|
+
pipeline.Rebuild()
|
|
160
|
+
self.visFr.CreateFoldPanel()
|
|
161
|
+
|
|
162
|
+
def OnRandomSelectChannel(self, event=None):
|
|
163
|
+
pipeline = self.pipeline
|
|
164
|
+
if pipeline.selectedDataSource is None:
|
|
165
|
+
return
|
|
166
|
+
if len(pipeline.colourFilter.getColourChans()) < 1:
|
|
167
|
+
return
|
|
168
|
+
chanSelector = ChannelSelector()
|
|
169
|
+
chanSelector.add_keys(pipeline.colourFilter.getColourChans())
|
|
170
|
+
if chanSelector.configure_traits(kind='modal'):
|
|
171
|
+
psd = pipeline.selectedDataSource
|
|
172
|
+
eall = np.zeros_like(psd['x'], dtype='float')
|
|
173
|
+
erand = np.random.rand(eall.size)
|
|
174
|
+
|
|
175
|
+
dispColor = pipeline.colourFilter.currentColour
|
|
176
|
+
pipeline.colourFilter.setColour(chanSelector.Channel)
|
|
177
|
+
idx = pipeline.filter.Index.copy()
|
|
178
|
+
idx[idx] = pipeline.colourFilter.index
|
|
179
|
+
eall[idx] = erand[idx]
|
|
180
|
+
pipeline.colourFilter.setColour(dispColor)
|
|
181
|
+
pipeline.selectedDataSource.addColumn('rand_%s' % chanSelector.Channel,eall)
|
|
182
|
+
pipeline.Rebuild()
|
|
183
|
+
self.visFr.CreateFoldPanel()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def Plug(visFr):
|
|
187
|
+
'''Plugs this module into the gui'''
|
|
188
|
+
visFr.extraCols = ExtraColumns(visFr)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import PYMEcs.misc.ExtraCmaps
|
|
2
|
+
|
|
3
|
+
# this module hijacks the plugin system to run colour map registration
|
|
4
|
+
# at startup of visgui, dsviewer
|
|
5
|
+
|
|
6
|
+
# I am exploring the alternative option to do this via the startup console script
|
|
7
|
+
# which has the advantage of doing this at startup for dsviewer which is an issue otherwise
|
|
8
|
+
|
|
9
|
+
def Plug(arg):
|
|
10
|
+
# registerCmaps()
|
|
11
|
+
pass
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from PYME.recipes.tablefilters import FilterTable
|
|
3
|
+
import wx
|
|
4
|
+
|
|
5
|
+
def selectWithDialog(choices, message='select image from list', caption='Selection'):
|
|
6
|
+
dlg = wx.SingleChoiceDialog(None, message, caption, choices, wx.CHOICEDLG_STYLE)
|
|
7
|
+
if dlg.ShowModal() == wx.ID_OK:
|
|
8
|
+
item = dlg.GetStringSelection()
|
|
9
|
+
else:
|
|
10
|
+
item = None
|
|
11
|
+
dlg.Destroy()
|
|
12
|
+
return item
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SelectROIFT:
|
|
16
|
+
def __init__(self, visFr):
|
|
17
|
+
self.visFr = visFr
|
|
18
|
+
|
|
19
|
+
visFr.AddMenuItem('Experimental>View', "Add ROI FilterTable module from selection", self.OnSelROIFT)
|
|
20
|
+
visFr.AddMenuItem('Experimental>View', "Add ROI FilterTable module from image", self.OnImROIFT)
|
|
21
|
+
|
|
22
|
+
def OnSelROIFT(self, event):
|
|
23
|
+
try:
|
|
24
|
+
#old glcanvas
|
|
25
|
+
x0, y0 = self.visFr.glCanvas.selectionStart[0:2]
|
|
26
|
+
x1, y1 = self.visFr.glCanvas.selectionFinish[0:2]
|
|
27
|
+
except AttributeError:
|
|
28
|
+
#new glcanvas
|
|
29
|
+
x0, y0 = self.visFr.glCanvas.selectionSettings.start[0:2]
|
|
30
|
+
x1, y1 = self.visFr.glCanvas.selectionSettings.finish[0:2]
|
|
31
|
+
|
|
32
|
+
filters = {}
|
|
33
|
+
filters['x'] = [float(min(x0, x1)), float(max(x0, x1))] # must ensure all values are eventually scalars to avoid issue with recipe yaml output
|
|
34
|
+
filters['y'] = [float(min(y0, y1)), float(max(y0, y1))] # ditto
|
|
35
|
+
|
|
36
|
+
recipe = self.visFr.pipeline.recipe
|
|
37
|
+
ftable = FilterTable(recipe, inputName=self.visFr.pipeline.selectedDataSourceKey,
|
|
38
|
+
outputName='selectedROI', filters=filters)
|
|
39
|
+
if not ftable.configure_traits(kind='modal'):
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
recipe.add_module(ftable)
|
|
43
|
+
recipe.execute()
|
|
44
|
+
|
|
45
|
+
def OnImROIFT(self, event):
|
|
46
|
+
from PYME.DSView import dsviewer
|
|
47
|
+
selection = selectWithDialog(list(dsviewer.openViewers.keys()))
|
|
48
|
+
if selection is not None:
|
|
49
|
+
img = dsviewer.openViewers[selection].image
|
|
50
|
+
else:
|
|
51
|
+
return
|
|
52
|
+
if img.mdh.getOrDefault('Filter.Keys',None) is None:
|
|
53
|
+
logger.debug('no Filter.Keys in image metadata')
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
filters = {}
|
|
57
|
+
filters['x'] = list(img.mdh['Filter.Keys']['x'])
|
|
58
|
+
filters['y'] = list(img.mdh['Filter.Keys']['y'])
|
|
59
|
+
|
|
60
|
+
recipe = self.visFr.pipeline.recipe
|
|
61
|
+
ftable = FilterTable(recipe, inputName=self.visFr.pipeline.selectedDataSourceKey,
|
|
62
|
+
outputName='selectedROI', filters=filters)
|
|
63
|
+
if not ftable.configure_traits(kind='modal'):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
recipe.add_module(ftable)
|
|
67
|
+
recipe.execute()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def Plug(visFr):
|
|
71
|
+
"""Plugs this module into the gui"""
|
|
72
|
+
SelectROIFT(visFr)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import wx
|
|
2
|
+
from wx.lib.dialogs import ScrolledMessageDialog
|
|
3
|
+
from PYMEcs.misc.guiMsgBoxes import Warn
|
|
4
|
+
|
|
5
|
+
def isDarwin():
|
|
6
|
+
import os
|
|
7
|
+
from sys import platform
|
|
8
|
+
return platform == "darwin"
|
|
9
|
+
|
|
10
|
+
class ShowErr:
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self, visFr):
|
|
15
|
+
self.visFr = visFr
|
|
16
|
+
self.txtwin = None
|
|
17
|
+
visFr.AddMenuItem('Experimental', 'Errors in scrolled message dialog\tCtrl+E', self.OnErrScrolledDialog)
|
|
18
|
+
|
|
19
|
+
def getLogFileName(self, pidoffset = -1):
|
|
20
|
+
import os
|
|
21
|
+
pid = int(os.getpid()) + pidoffset
|
|
22
|
+
return os.path.join('/tmp','visgui-%d.tmp' % pid)
|
|
23
|
+
|
|
24
|
+
def OnErrScrolledDialog(self, event=None):
|
|
25
|
+
if not isDarwin():
|
|
26
|
+
Warn(None,'aborting: functionality only available on mac','Error')
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
ok = False
|
|
30
|
+
import os.path
|
|
31
|
+
fname = self.getLogFileName(pidoffset = -1)
|
|
32
|
+
if os.path.isfile(fname):
|
|
33
|
+
ok = True
|
|
34
|
+
else:
|
|
35
|
+
fname = self.getLogFileName(pidoffset = 0)
|
|
36
|
+
if os.path.isfile(fname):
|
|
37
|
+
ok = True
|
|
38
|
+
else:
|
|
39
|
+
Warn(None,'aborting: cannot find log file, tried %s and %s' % (self.getLogFileName(pidoffset = -1),
|
|
40
|
+
self.getLogFileName(pidoffset = 0)))
|
|
41
|
+
if ok:
|
|
42
|
+
with open(fname,"r") as f:
|
|
43
|
+
txt = "\n".join(f.readlines())
|
|
44
|
+
dlg = ScrolledMessageDialog(self.visFr, txt, "VisGUI Error Output", size=(900,400),
|
|
45
|
+
style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE )
|
|
46
|
+
dlg.ShowModal()
|
|
47
|
+
dlg.Destroy()
|
|
48
|
+
|
|
49
|
+
def Plug(visFr):
|
|
50
|
+
"""Plugs this module into the gui"""
|
|
51
|
+
visFr.showErr = ShowErr(visFr)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import wx
|
|
2
|
+
from wx.lib.dialogs import ScrolledMessageDialog
|
|
3
|
+
from PYMEcs.misc.guiMsgBoxes import Warn
|
|
4
|
+
|
|
5
|
+
from PYMEcs.misc.versionCheck import PYMEversionCheck
|
|
6
|
+
try:
|
|
7
|
+
from PYME.DSView.modules._base import Plugin
|
|
8
|
+
except ImportError:
|
|
9
|
+
PYMEversionCheck('PluginClass')
|
|
10
|
+
|
|
11
|
+
def isDarwin():
|
|
12
|
+
import os
|
|
13
|
+
from sys import platform
|
|
14
|
+
return platform == "darwin"
|
|
15
|
+
|
|
16
|
+
class ShowErr(Plugin):
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
def __init__(self, dsviewer):
|
|
21
|
+
|
|
22
|
+
Plugin.__init__(self, dsviewer)
|
|
23
|
+
|
|
24
|
+
self.txtwin = None
|
|
25
|
+
dsviewer.AddMenuItem('Experimental', 'Errors in scrolled message dialog\tCtrl+E', self.OnErrScrolledDialog)
|
|
26
|
+
|
|
27
|
+
def getLogFileName(self, pidoffset = -1):
|
|
28
|
+
import os
|
|
29
|
+
pid = int(os.getpid()) + pidoffset
|
|
30
|
+
return os.path.join('/tmp','dh5view-%d.tmp' % pid)
|
|
31
|
+
|
|
32
|
+
def OnErrScrolledDialog(self, event=None):
|
|
33
|
+
if not isDarwin():
|
|
34
|
+
Warn(None,'aborting: functionality only available on mac','Error')
|
|
35
|
+
return
|
|
36
|
+
ok = False
|
|
37
|
+
import os.path
|
|
38
|
+
fname = self.getLogFileName(pidoffset = -1)
|
|
39
|
+
if os.path.isfile(fname):
|
|
40
|
+
ok = True
|
|
41
|
+
else:
|
|
42
|
+
fname = self.getLogFileName(pidoffset = 0)
|
|
43
|
+
if os.path.isfile(fname):
|
|
44
|
+
ok = True
|
|
45
|
+
else:
|
|
46
|
+
Warn(None,'aborting: cannot find log file, tried %s and %s' % (self.getLogFileName(pidoffset = -1),
|
|
47
|
+
self.getLogFileName(pidoffset = 0)))
|
|
48
|
+
if ok:
|
|
49
|
+
with open(fname,"r") as f:
|
|
50
|
+
txt = "\n".join(f.readlines())
|
|
51
|
+
dlg = ScrolledMessageDialog(self.dsviewer, txt, "VisGUI Error Output", size=(900,400),
|
|
52
|
+
style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE )
|
|
53
|
+
dlg.ShowModal()
|
|
54
|
+
dlg.Destroy()
|
|
55
|
+
|
|
56
|
+
def Plug(dsviewer):
|
|
57
|
+
"""Plugs this module into the gui"""
|
|
58
|
+
return ShowErr(dsviewer)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import logging
|
|
3
|
+
logger = logging.getLogger(__file__)
|
|
4
|
+
|
|
5
|
+
# note: to turn this into a standalone shiftmap display tool, add code to open a shiftfield:
|
|
6
|
+
# import PYME.Acquire.Hardware.splitter as sp
|
|
7
|
+
# dx2,dy2 = sp.LoadShiftField(h5file_or_sf_file)
|
|
8
|
+
#
|
|
9
|
+
# if it is purely a shiftfield file then we have to supply some additional info, e.g. voxelsizes
|
|
10
|
+
# and ROI size for the splitter
|
|
11
|
+
|
|
12
|
+
class ShowMap:
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, visFr):
|
|
17
|
+
self.visFr = visFr
|
|
18
|
+
self.pipeline = visFr.pipeline
|
|
19
|
+
|
|
20
|
+
visFr.AddMenuItem('Experimental>ShiftMap', 'Show Shiftmap', self.OnShowShiftMap,
|
|
21
|
+
helpText='Show a shiftmap from metadata info')
|
|
22
|
+
visFr.AddMenuItem('Experimental>ShiftMap', 'Shiftmap as image', self.OnShiftMapAsImage,
|
|
23
|
+
helpText='Show a shiftmap from metadata info and display as image')
|
|
24
|
+
|
|
25
|
+
def OnShowShiftMap(self, event=None):
|
|
26
|
+
from PYME.Analysis.points import twoColour, twoColourPlot
|
|
27
|
+
mdh = self.pipeline.mdh
|
|
28
|
+
vs = [mdh['voxelsize.x']*1e3, mdh['voxelsize.y']*1e3, mdh['voxelsize.z']*1e3]
|
|
29
|
+
dx = mdh.getEntry('chroma.dx')
|
|
30
|
+
dy = mdh.getEntry('chroma.dy')
|
|
31
|
+
|
|
32
|
+
shape = mdh['Splitter.Channel0ROI'][2:]
|
|
33
|
+
|
|
34
|
+
twoColourPlot.PlotShiftField2(dx,dy,shape,vs)
|
|
35
|
+
|
|
36
|
+
def OnShiftMapAsImage(self, event=None):
|
|
37
|
+
mdh = self.pipeline.mdh
|
|
38
|
+
voxelsize = [mdh['voxelsize.x']*1e3, mdh['voxelsize.y']*1e3, mdh['voxelsize.z']*1e3]
|
|
39
|
+
spx = mdh.getEntry('chroma.dx')
|
|
40
|
+
spy = mdh.getEntry('chroma.dy')
|
|
41
|
+
|
|
42
|
+
shape = mdh['Splitter.Channel0ROI'][2:]
|
|
43
|
+
xi, yi = np.meshgrid(np.arange(0, shape[0]*voxelsize[0], 100), np.arange(0, shape[1]*voxelsize[1], 100))
|
|
44
|
+
xin = xi.ravel()
|
|
45
|
+
yin = yi.ravel()
|
|
46
|
+
dx = spx.ev(xin[:], yin[:]).reshape(xi.shape)
|
|
47
|
+
dy = spy.ev(xin[:], yin[:]).reshape(xi.shape)
|
|
48
|
+
|
|
49
|
+
from PYME.DSView.dsviewer import View3D
|
|
50
|
+
image = np.stack([dx[::-1, :],dy[::-1, :]],axis=-1)
|
|
51
|
+
View3D(image, parent=self.visFr, titleStub='ShiftMap')
|
|
52
|
+
|
|
53
|
+
def Plug(visFr):
|
|
54
|
+
"""Plugs this module into the gui"""
|
|
55
|
+
visFr.showShiftMap = ShowMap(visFr)
|
|
56
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from PYMEcs.misc.guiMsgBoxes import Warn
|
|
3
|
+
import wx
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
def populate_fresults_wholep(fitMod,pipeline,bgzero=True):
|
|
7
|
+
r = np.zeros(pipeline['x'].size, fitMod.fresultdtype)
|
|
8
|
+
for k in pipeline.keys():
|
|
9
|
+
f = k.split('_')
|
|
10
|
+
if len(f) == 1:
|
|
11
|
+
try:
|
|
12
|
+
r[f[0]] = pipeline[k]
|
|
13
|
+
except ValueError:
|
|
14
|
+
pass
|
|
15
|
+
elif len(f) == 2:
|
|
16
|
+
try:
|
|
17
|
+
r[f[0]][f[1]] = pipeline[k]
|
|
18
|
+
except ValueError:
|
|
19
|
+
pass
|
|
20
|
+
elif len(f) == 3:
|
|
21
|
+
try:
|
|
22
|
+
r[f[0]][f[1]][f[2]] = pipeline[k]
|
|
23
|
+
except ValueError:
|
|
24
|
+
pass
|
|
25
|
+
else:
|
|
26
|
+
raise RuntimeError('more fields than expected: %d' % len(f))
|
|
27
|
+
|
|
28
|
+
if bgzero:
|
|
29
|
+
r['fitResults']['bg'] = 0
|
|
30
|
+
r['fitResults']['br'] = 0
|
|
31
|
+
|
|
32
|
+
return r
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
from PYME.IO.MetaDataHandler import NestedClassMDHandler
|
|
36
|
+
def genFitImage(fitMod,fr,mdh,psfname=None):
|
|
37
|
+
mdh2 = NestedClassMDHandler(mdh)
|
|
38
|
+
if psfname is not None:
|
|
39
|
+
mdh2['PSFFile'] = psfname
|
|
40
|
+
fitim = fitMod.genFitImage(fr,mdh2)
|
|
41
|
+
|
|
42
|
+
return fitim
|
|
43
|
+
|
|
44
|
+
def get_photons(fitim,mdh):
|
|
45
|
+
nph = fitim.sum()*mdh.getEntry('Camera.ElectronsPerCount')/mdh.getEntry('Camera.TrueEMGain')
|
|
46
|
+
return nph
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def nPhotons(fitMod,fr,mdh,psfname=None,nmax=100,progressBar=None,updateStep=100):
|
|
50
|
+
mdh2 = NestedClassMDHandler(mdh)
|
|
51
|
+
if psfname is not None:
|
|
52
|
+
mdh2['PSFFile'] = psfname
|
|
53
|
+
npoints = min(fr.shape[0],nmax)
|
|
54
|
+
nph = np.zeros((npoints))
|
|
55
|
+
us = int(updateStep)
|
|
56
|
+
for i in range(npoints):
|
|
57
|
+
nph[i] = get_photons(genFitImage(fitMod,fr[i],mdh2,psfname=None), mdh2)
|
|
58
|
+
if (progressBar is not None) and ((i % us) == 0):
|
|
59
|
+
progressBar.Update(100.0*i/float(npoints))
|
|
60
|
+
wx.Yield()
|
|
61
|
+
return nph
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# you may need a lot more imports depending what functionality your require in your plugin
|
|
65
|
+
class SNRcalculator:
|
|
66
|
+
"""
|
|
67
|
+
A plugin, very simple to demonstrate the concept. Also providing a simple
|
|
68
|
+
measure of some kind of SNR, the formula used is probably debatable.
|
|
69
|
+
For example, low background estimates cause very high SNRs which may or may not
|
|
70
|
+
be reasonable given the uncertainty in determining the background etc
|
|
71
|
+
"""
|
|
72
|
+
def __init__(self, visFr):
|
|
73
|
+
self.visFr = visFr
|
|
74
|
+
self.pipeline = visFr.pipeline
|
|
75
|
+
|
|
76
|
+
visFr.AddMenuItem('Experimental>ExtraColumns', 'Add SNR property', self.OnAddSNR,
|
|
77
|
+
helpText='Add an event property that provides some measure of SNR for events (from background and amplitude)')
|
|
78
|
+
visFr.AddMenuItem('Experimental>Biplane', 'Add Biplane nPhotons', self.OnAddnphBPlane,
|
|
79
|
+
helpText='Add nPhotons for Biplane fitting')
|
|
80
|
+
visFr.AddMenuItem('Experimental>Biplane', 'Plot Biplane zErrors', self.OnPlotErrBPlane,
|
|
81
|
+
helpText='Plot Biplane fitting z-errors')
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def OnAddSNR(self, event=None):
|
|
85
|
+
"""
|
|
86
|
+
this function adds an 'SNR' property to events - there could be some discussion how that is actually best calculated
|
|
87
|
+
"""
|
|
88
|
+
from PYMEcs.recipes import localisations
|
|
89
|
+
|
|
90
|
+
if False: # this way does not make a special recipe module but uses the generic Mapping module and adds a few columns
|
|
91
|
+
from PYME.IO import tabular
|
|
92
|
+
from PYME.recipes import tablefilters
|
|
93
|
+
# the original formula was very adhoc
|
|
94
|
+
# we have now changed to a different way
|
|
95
|
+
# here we use an approach derived from a formula from Tang et al,
|
|
96
|
+
# Scientific Reports | 5:11073 | DOi: 10.1038/srep11073
|
|
97
|
+
mdh = self.pipeline.mdh
|
|
98
|
+
pipeline = self.pipeline
|
|
99
|
+
# there is an issue if we don't have the nPhotons property FIXME!
|
|
100
|
+
nph = self.pipeline['nPhotons']
|
|
101
|
+
bgraw = self.pipeline['fitResults_background']
|
|
102
|
+
bgph = np.clip((bgraw)*mdh['Camera.ElectronsPerCount']/mdh.getEntry('Camera.TrueEMGain'),1,None)
|
|
103
|
+
|
|
104
|
+
npixroi = (2*mdh.getOrDefault('Analysis.ROISize',5) + 1)**2
|
|
105
|
+
snr = 1.0/npixroi * np.clip(nph,0,None)/np.sqrt(bgph)
|
|
106
|
+
#dirty copy of the pipeline output
|
|
107
|
+
|
|
108
|
+
recipe = pipeline.recipe
|
|
109
|
+
mapp = tablefilters.Mapping(recipe,inputName=pipeline.selectedDataSourceKey,
|
|
110
|
+
outputName='snr')
|
|
111
|
+
recipe.add_module(mapp)
|
|
112
|
+
recipe.execute()
|
|
113
|
+
|
|
114
|
+
snrmap = recipe.namespace['snr']
|
|
115
|
+
snrmap.addColumn('SNR', snr)
|
|
116
|
+
snrmap.addColumn('backgroundPhotons',bgph)
|
|
117
|
+
|
|
118
|
+
else:
|
|
119
|
+
recipe = self.pipeline.recipe
|
|
120
|
+
snr = localisations.SnrCalculation(recipe,inputName=self.pipeline.selectedDataSourceKey,
|
|
121
|
+
outputName='snr')
|
|
122
|
+
recipe.add_module(snr)
|
|
123
|
+
recipe.execute()
|
|
124
|
+
|
|
125
|
+
self.pipeline.selectDataSource('snr')
|
|
126
|
+
|
|
127
|
+
self.pipeline.Rebuild()
|
|
128
|
+
#self.visFr.CreateFoldPanel() # we should not need this anymore
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def OnAddnphBPlane(self, event=None):
|
|
132
|
+
"""
|
|
133
|
+
this function adds nPhoton property to events for biplane
|
|
134
|
+
"""
|
|
135
|
+
fdialog = wx.FileDialog(None, 'Please select PSF to use ...',
|
|
136
|
+
#defaultDir=os.path.split(self.image.filename)[0],
|
|
137
|
+
wildcard='PSF Files|*.psf|TIFF files|*.tif', style=wx.FD_OPEN)
|
|
138
|
+
succ = fdialog.ShowModal()
|
|
139
|
+
if (succ == wx.ID_OK):
|
|
140
|
+
psfn = filename = fdialog.GetPath()
|
|
141
|
+
mdh = self.pipeline.mdh
|
|
142
|
+
pipeline = self.pipeline
|
|
143
|
+
if mdh.getEntry('Analysis.FitModule') not in ['SplitterFitInterpBNR']:
|
|
144
|
+
Warn('Plugin works only for Biplane analysis')
|
|
145
|
+
return
|
|
146
|
+
fitMod = __import__('PYME.localization.FitFactories.' +
|
|
147
|
+
self.pipeline.mdh.getEntry('Analysis.FitModule'),
|
|
148
|
+
fromlist=['PYME', 'localization', 'FitFactories'])
|
|
149
|
+
fr = populate_fresults_wholep(fitMod, pipeline)
|
|
150
|
+
progress = wx.ProgressDialog("calculating photon numbers",
|
|
151
|
+
"calculating...", maximum=100, parent=None,
|
|
152
|
+
style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
|
|
153
|
+
nph = nPhotons(fitMod, fr, mdh, psfname=psfn, nmax=1e6,
|
|
154
|
+
progressBar=progress, updateStep = 100)
|
|
155
|
+
progress.Destroy()
|
|
156
|
+
self.pipeline.addColumn('nPhotons', nph)
|
|
157
|
+
self.pipeline.addColumn('fitResults_background', pipeline['fitResults_bg']+pipeline['fitResults_br'])
|
|
158
|
+
self.pipeline.addColumn('sig',float(137.0)+np.zeros_like(pipeline['x'])) # this one is a straight kludge for mortensenError
|
|
159
|
+
self.pipeline.Rebuild()
|
|
160
|
+
self.visFr.CreateFoldPanel()
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def OnPlotErrBPlane(self, event=None):
|
|
164
|
+
mdh = self.pipeline.mdh
|
|
165
|
+
pipeline = self.pipeline
|
|
166
|
+
if mdh.getEntry('Analysis.FitModule') not in ['SplitterFitInterpBNR']:
|
|
167
|
+
Warn('Plugin works only for Biplane analysis')
|
|
168
|
+
return
|
|
169
|
+
bgraw = pipeline['fitResults_bg']+pipeline['fitResults_br']
|
|
170
|
+
bgph = bgraw * pipeline.mdh.getEntry('Camera.ElectronsPerCount')/pipeline.mdh.getEntry('Camera.TrueEMGain')
|
|
171
|
+
|
|
172
|
+
import matplotlib.pyplot as plt
|
|
173
|
+
plt.figure()
|
|
174
|
+
plt.scatter(pipeline['nPhotons'],pipeline['fitError_z0'],s=10,c=bgph)
|
|
175
|
+
plt.colorbar()
|
|
176
|
+
plt.xlim(0,None)
|
|
177
|
+
plt.xlabel('Photons')
|
|
178
|
+
plt.ylabel('z error (nm)')
|
|
179
|
+
|
|
180
|
+
# example use after adding the nPhotons entry:
|
|
181
|
+
# def bg(pipeline):
|
|
182
|
+
# return (pipeline['fitResults_bg']+pipeline['fitResults_br'])*pipeline.mdh.getEntry('Camera.ElectronsPerCount')/pipeline.mdh.getEntry('Camera.TrueEMGain')
|
|
183
|
+
# scatter(pipeline['nPhotons'],pipeline['fitError_z0'],s=10,c=bg(pipeline))
|
|
184
|
+
# colorbar()
|
|
185
|
+
|
|
186
|
+
def Plug(visFr):
|
|
187
|
+
"""Plugs this module into the gui"""
|
|
188
|
+
visFr.snrCalc = SNRcalculator(visFr)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from PYMEcs.recipes.localisations import ClusterTimeRange, ValidClumps
|
|
3
|
+
from PYME.recipes.tablefilters import FilterTable
|
|
4
|
+
from PYME.recipes.localisations import DBSCANClustering
|
|
5
|
+
|
|
6
|
+
class SpecLabeling:
|
|
7
|
+
def __init__(self, visFr):
|
|
8
|
+
self.visFr = visFr
|
|
9
|
+
|
|
10
|
+
visFr.AddMenuItem('Experimental>Corrections', "Filter specific labeling (DNA-PAINT)", self.OnSpecFilter)
|
|
11
|
+
visFr.AddMenuItem('Experimental>Corrections', "Apply specific labeling to non-clumped data (DNA-PAINT)", self.OnSpecFilterNC)
|
|
12
|
+
|
|
13
|
+
def OnSpecFilter(self, event):
|
|
14
|
+
from PYMEcs.recipes import localisations
|
|
15
|
+
recipe = self.visFr.pipeline.recipe
|
|
16
|
+
bigLimit = 1e6 # size for filters big enough to capture everything
|
|
17
|
+
|
|
18
|
+
# check 'coalesced' is available
|
|
19
|
+
recipe.add_module(DBSCANClustering(recipe,inputName='coalesced', outputName='dbscanClustered', columns=['x', 'y'],
|
|
20
|
+
searchRadius=50, minClumpSize=3, clumpColumnName='dbscanClumpID'))
|
|
21
|
+
filters={'dbscanClumpID' : [0.5,1e6]}
|
|
22
|
+
recipe.add_module(FilterTable(recipe, inputName='dbscanClustered',
|
|
23
|
+
outputName='validCluster', filters={'dbscanClumpID' : [0.5,bigLimit]}))
|
|
24
|
+
|
|
25
|
+
recipe.add_module(ClusterTimeRange(recipe, inputName='validCluster',
|
|
26
|
+
outputName='withTrange', IDkey='dbscanClumpID'))
|
|
27
|
+
recipe.add_module(FilterTable(recipe, inputName='withTrange',
|
|
28
|
+
outputName='specLabeling', filters={'trange' : [2500,bigLimit]}))
|
|
29
|
+
|
|
30
|
+
recipe.execute()
|
|
31
|
+
self.visFr.pipeline.selectDataSource('specLabeling')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def OnSpecFilterNC(self, event):
|
|
35
|
+
from PYMEcs.recipes import localisations
|
|
36
|
+
recipe = self.visFr.pipeline.recipe
|
|
37
|
+
|
|
38
|
+
recipe.add_module(ValidClumps(inputName='with_clumps',
|
|
39
|
+
inputValid='specLabeling',
|
|
40
|
+
outputName='with_validClumps'))
|
|
41
|
+
recipe.add_module(FilterTable(recipe, inputName='with_validClumps',
|
|
42
|
+
outputName='specLabelingNC', filters={'validID' : [0.5,1.5]}))
|
|
43
|
+
recipe.add_module(FilterTable(recipe, inputName='with_validClumps',
|
|
44
|
+
outputName='nonSpecNC', filters={'validID' : [-0.5,0.5]}))
|
|
45
|
+
recipe.execute()
|
|
46
|
+
self.visFr.pipeline.selectDataSource('specLabelingNC')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def Plug(visFr):
|
|
50
|
+
"""Plugs this module into the gui"""
|
|
51
|
+
SpecLabeling(visFr)
|