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,27 @@
|
|
|
1
|
+
import wx
|
|
2
|
+
|
|
3
|
+
# a few simple message box utility functions
|
|
4
|
+
|
|
5
|
+
def YesNo(parent, question, caption = 'Yes or no?'):
|
|
6
|
+
dlg = wx.MessageDialog(parent, question, caption, wx.YES_NO | wx.ICON_QUESTION)
|
|
7
|
+
result = dlg.ShowModal() == wx.ID_YES
|
|
8
|
+
dlg.Destroy()
|
|
9
|
+
return result
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def Info(parent, message, caption = 'Python Microscopy Environment'):
|
|
13
|
+
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_INFORMATION)
|
|
14
|
+
dlg.ShowModal()
|
|
15
|
+
dlg.Destroy()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def Warn(parent, message, caption = 'Warning!'):
|
|
19
|
+
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_WARNING)
|
|
20
|
+
dlg.ShowModal()
|
|
21
|
+
dlg.Destroy()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def Error(parent, message, caption = 'Error!'):
|
|
25
|
+
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_ERROR)
|
|
26
|
+
dlg.ShowModal()
|
|
27
|
+
dlg.Destroy()
|
PYMEcs/misc/mapUtils.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
from PYME.localization.remFitBuf import CameraInfoManager
|
|
2
|
+
import PYME.Analysis.gen_sCMOS_maps as gmaps
|
|
3
|
+
from PYME.IO.MetaDataHandler import NestedClassMDHandler
|
|
4
|
+
from PYME.IO.image import ImageStack
|
|
5
|
+
from PYME.DSView import ViewIm3D
|
|
6
|
+
from PYME.IO.FileUtils import nameUtils
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
defaultCalibrationDir = nameUtils.getCalibrationDir('',create=False)
|
|
13
|
+
|
|
14
|
+
def defaultMapName(source, createPath=False, calibrationDir=defaultCalibrationDir):
|
|
15
|
+
resname = source.mdh.getOrDefault('Analysis.resultname',None)
|
|
16
|
+
if resname is None:
|
|
17
|
+
return None
|
|
18
|
+
|
|
19
|
+
if resname == 'mean':
|
|
20
|
+
if source.mdh.getOrDefault('Analysis.FlatField',False):
|
|
21
|
+
maptype = 'flatfield'
|
|
22
|
+
else:
|
|
23
|
+
maptype = 'dark'
|
|
24
|
+
else:
|
|
25
|
+
maptype = 'variance'
|
|
26
|
+
|
|
27
|
+
mapname = gmaps.mkDefaultPath(maptype, source.mdh, create=createPath, calibrationDir=calibrationDir)
|
|
28
|
+
return mapname
|
|
29
|
+
|
|
30
|
+
# return a list of existing camera directories that have tif files inside (assuming these are camera maps)
|
|
31
|
+
def installedCams(calibrationDir=defaultCalibrationDir):
|
|
32
|
+
from glob import glob
|
|
33
|
+
import os
|
|
34
|
+
|
|
35
|
+
camdirs = []
|
|
36
|
+
for (dirpath, dirnames, filenames) in os.walk(calibrationDir):
|
|
37
|
+
camdirs.extend(dirnames)
|
|
38
|
+
break
|
|
39
|
+
fulldirs = [os.path.join(calibrationDir,cdir) for cdir in camdirs]
|
|
40
|
+
validdirs = [cdir for cdir in fulldirs if glob(os.path.join(cdir, '*.tif'))]
|
|
41
|
+
|
|
42
|
+
return validdirs
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# source passed as PYME ImageStack
|
|
46
|
+
def install_map(source, calibrationDir=defaultCalibrationDir):
|
|
47
|
+
"""Installs a map file to a calibration directory. By default uses the system claibration directory."""
|
|
48
|
+
|
|
49
|
+
import os
|
|
50
|
+
if source.mdh.getOrDefault('Analysis.name', '') != 'mean-variance':
|
|
51
|
+
msg = 'map %s, Analysis.name is not equal to "mean-variance" - probably not a map' % source.filename
|
|
52
|
+
return msg
|
|
53
|
+
|
|
54
|
+
validROIHeight = source.mdh.getOrDefault('Analysis.valid.ROIHeight',
|
|
55
|
+
source.mdh['Camera.ROIHeight'])
|
|
56
|
+
validROIWidth = source.mdh.getOrDefault('Analysis.valid.ROIWidth',
|
|
57
|
+
source.mdh['Camera.ROIWidth'])
|
|
58
|
+
if not (validROIHeight == source.mdh['Camera.ROIHeight']
|
|
59
|
+
and validROIWidth == source.mdh['Camera.ROIWidth']):
|
|
60
|
+
msg = 'Partial (ROI based) maps cannot be installed to a calibration directory'
|
|
61
|
+
return msg
|
|
62
|
+
|
|
63
|
+
if source.mdh.getOrDefault('Analysis.isuniform', False):
|
|
64
|
+
msg = 'Uniform maps cannot be installed to ba calibration directory'
|
|
65
|
+
return msg
|
|
66
|
+
|
|
67
|
+
if source.mdh['Analysis.resultname'] == 'mean':
|
|
68
|
+
if source.mdh.getOrDefault('Analysis.FlatField',False):
|
|
69
|
+
maptype = 'flatfield'
|
|
70
|
+
else:
|
|
71
|
+
maptype = 'dark'
|
|
72
|
+
else:
|
|
73
|
+
maptype = 'variance'
|
|
74
|
+
|
|
75
|
+
mapname = gmaps.mkDefaultPath(maptype, source.mdh, create=True, calibrationDir=calibrationDir)
|
|
76
|
+
if os.path.isfile(mapname):
|
|
77
|
+
msg = 'map %s exists, not overwriting' % mapname
|
|
78
|
+
return msg
|
|
79
|
+
|
|
80
|
+
source.Save(filename=mapname)
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
# attempt to install a map in a calibration dir but check a few things
|
|
84
|
+
# 1) does it have the .tif extension?
|
|
85
|
+
# 2) can it be opened as a tiffstack
|
|
86
|
+
# 3) if all ok so far pass on to install_map which does additional checks; note that
|
|
87
|
+
# this function does not overwrite existing maps at the destination
|
|
88
|
+
def checkAndInstallMap(mapf, calibrationDir=defaultCalibrationDir):
|
|
89
|
+
import os
|
|
90
|
+
inst = 0
|
|
91
|
+
|
|
92
|
+
ext = os.path.splitext(mapf)[-1].lower()
|
|
93
|
+
if ext != ".tif":
|
|
94
|
+
msg = 'asked to install %s, not a tif extension' % mapf
|
|
95
|
+
return (inst, msg)
|
|
96
|
+
try:
|
|
97
|
+
source = ImageStack(filename=mapf)
|
|
98
|
+
except:
|
|
99
|
+
msg = 'asked to install %s, could not open as PYME ImageStack, not a map?' % mapf
|
|
100
|
+
return (inst, msg)
|
|
101
|
+
|
|
102
|
+
msg = install_map(source, calibrationDir=calibrationDir)
|
|
103
|
+
if msg is None:
|
|
104
|
+
msg = 'installed map %s in default location' % mapf
|
|
105
|
+
msg += "\n\t-> %s" % defaultMapName(source, calibrationDir=calibrationDir)
|
|
106
|
+
inst = 1
|
|
107
|
+
|
|
108
|
+
return (inst, msg)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# install maps, potentially several
|
|
112
|
+
# if fromfile is a directory attempt to install all maps below that directory
|
|
113
|
+
# if fromfile is a file, attempt to install that single file
|
|
114
|
+
def installMapsFrom(fromfile, calibrationDir=defaultCalibrationDir):
|
|
115
|
+
from glob import glob
|
|
116
|
+
import os
|
|
117
|
+
|
|
118
|
+
msgs = []
|
|
119
|
+
ntotal = 0
|
|
120
|
+
if os.path.isdir(fromfile):
|
|
121
|
+
# this is a directory, walk it
|
|
122
|
+
msgs.append("Installing maps from directory %s -> %s Folder\n" % (fromfile,calibrationDir))
|
|
123
|
+
mapfiles = [y for x in os.walk(fromfile) for y in glob(os.path.join(x[0], '*.tif'))]
|
|
124
|
+
for mapf in mapfiles:
|
|
125
|
+
ninst, msg = checkAndInstallMap(mapf, calibrationDir=calibrationDir)
|
|
126
|
+
ntotal += ninst
|
|
127
|
+
msgs.append(msg)
|
|
128
|
+
else:
|
|
129
|
+
ninst, msg = checkAndInstallMap(fromfile, calibrationDir=calibrationDir)
|
|
130
|
+
ntotal = 1
|
|
131
|
+
msgs.append(msg)
|
|
132
|
+
msgs.append("\ninstalled %d maps" % ntotal)
|
|
133
|
+
return ntotal, "\n".join(msgs)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def getInstalledMapList():
|
|
137
|
+
from glob import glob
|
|
138
|
+
import os
|
|
139
|
+
rootdir = defaultCalibrationDir
|
|
140
|
+
result = [y for x in os.walk(rootdir) for y in glob(os.path.join(x[0], '*.tif'))]
|
|
141
|
+
|
|
142
|
+
return result
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def check_mapexists(mdh, type = 'dark'):
|
|
146
|
+
import os
|
|
147
|
+
if type == 'dark':
|
|
148
|
+
id = 'Camera.DarkMapID'
|
|
149
|
+
elif type == 'variance':
|
|
150
|
+
id = 'Camera.VarianceMapID'
|
|
151
|
+
elif type == 'flatfield':
|
|
152
|
+
id = 'Camera.FlatfieldMapID'
|
|
153
|
+
else:
|
|
154
|
+
raise RuntimeError('unknown map type %s' % type)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
mPath = mdh.getOrDefault(id,'')
|
|
158
|
+
defPath = gmaps.mkDefaultPath(type,mdh,create=False)
|
|
159
|
+
if os.path.exists(mPath):
|
|
160
|
+
return mPath
|
|
161
|
+
elif os.path.exists(defPath):
|
|
162
|
+
mdh[id] = defPath
|
|
163
|
+
return defPath
|
|
164
|
+
else:
|
|
165
|
+
mdh[id] = ''
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
def mk_compositeMap(sourcemap):
|
|
169
|
+
# make new composite map using sourcemap to populate
|
|
170
|
+
# check source is a map
|
|
171
|
+
# composite map has first channel with map data, second channel is mask where map is valid
|
|
172
|
+
# returns composite map (identified by its metadata)
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
def addMap2composite(map,compMap):
|
|
176
|
+
# insert map according to valid ROI into composite map
|
|
177
|
+
# update the valid channel accordingly
|
|
178
|
+
# possibly perform a number of checks
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
def export_mapFromComposite(compMap):
|
|
182
|
+
# export a normal map from the composite map
|
|
183
|
+
# in the exported map we set the valid ROI to the whole chip area
|
|
184
|
+
# return as image?
|
|
185
|
+
pass
|
|
186
|
+
|
|
187
|
+
import os
|
|
188
|
+
|
|
189
|
+
def _getDefaultMap(ci,mdh,maptype = 'dark', return_loadedmdh = False):
|
|
190
|
+
# logic: try map in default calibration dir first
|
|
191
|
+
# if not present just return default value
|
|
192
|
+
mapname = gmaps.mkDefaultPath(maptype, mdh, create=False)
|
|
193
|
+
mdh2 = NestedClassMDHandler(mdh)
|
|
194
|
+
logger.debug("checking map file %s" % mapname)
|
|
195
|
+
|
|
196
|
+
if maptype == 'dark':
|
|
197
|
+
id = 'Camera.DarkMapID'
|
|
198
|
+
elif maptype == 'variance':
|
|
199
|
+
id = 'Camera.VarianceMapID'
|
|
200
|
+
elif maptype == 'flatfield':
|
|
201
|
+
id = 'Camera.FlatfieldMapID'
|
|
202
|
+
else:
|
|
203
|
+
raise RuntimeError('unknown map type %s' % type)
|
|
204
|
+
|
|
205
|
+
if os.path.isfile(mapname):
|
|
206
|
+
mdh2[id] = mapname
|
|
207
|
+
else:
|
|
208
|
+
mdh2[id] = ''
|
|
209
|
+
logger.debug("map file %s does not exist" % mapname)
|
|
210
|
+
|
|
211
|
+
if maptype == 'dark':
|
|
212
|
+
theMap = ci.getDarkMap(mdh2)
|
|
213
|
+
elif maptype == 'variance':
|
|
214
|
+
theMap = ci.getVarianceMap(mdh2)
|
|
215
|
+
elif maptype == 'flatfield':
|
|
216
|
+
theMap = ci.getFlatfieldMap(mdh2)
|
|
217
|
+
|
|
218
|
+
if return_loadedmdh:
|
|
219
|
+
return (theMap,mdh2)
|
|
220
|
+
else:
|
|
221
|
+
return theMap
|
|
222
|
+
|
|
223
|
+
def get_dark_default(ci,mdh):
|
|
224
|
+
return _getDefaultMap(ci,mdh,maptype = 'dark')
|
|
225
|
+
|
|
226
|
+
def get_variance_default(ci,mdh):
|
|
227
|
+
return _getDefaultMap(ci,mdh,maptype = 'variance')
|
|
228
|
+
|
|
229
|
+
def get_flatfield_default(ci,mdh):
|
|
230
|
+
return _getDefaultMap(ci,mdh,maptype = 'flatfield')
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
from numbers import Number
|
|
4
|
+
|
|
5
|
+
def figuredefaults(fontsize=10,linewidth=1.5):
|
|
6
|
+
plt.rcParams['axes.linewidth'] = linewidth
|
|
7
|
+
plt.rcParams['xtick.major.width'] = linewidth
|
|
8
|
+
plt.rcParams['ytick.major.width'] = linewidth
|
|
9
|
+
plt.rcParams['font.family']='arial'
|
|
10
|
+
plt.rcParams['font.size'] = fontsize
|
|
11
|
+
plt.rcParams['svg.fonttype'] = 'none'
|
|
12
|
+
|
|
13
|
+
def boxswarmplot(df,width=0.4,annotate_means=False,annotate_medians=False,showmeans=True,
|
|
14
|
+
meanprops=None,ax=None,swarmsize=7,swarmalpha=None,format="%.1f",
|
|
15
|
+
showpoints=True,strip=False,**kwargs):
|
|
16
|
+
import seaborn as sns
|
|
17
|
+
if meanprops is None:
|
|
18
|
+
meanprops={'marker':'o',
|
|
19
|
+
'markerfacecolor':'white',
|
|
20
|
+
'markeredgecolor':'black',
|
|
21
|
+
'markersize':'8'}
|
|
22
|
+
flierprops = dict(marker='.', markerfacecolor='none', markersize=0, linestyle='none')
|
|
23
|
+
colours = ['#72a4cdff'] * df.shape[1]
|
|
24
|
+
bp = sns.boxplot(df,boxprops={'facecolor': 'none'},width=width,showmeans=showmeans,meanprops=meanprops,ax=ax,flierprops=flierprops,**kwargs)
|
|
25
|
+
if showpoints:
|
|
26
|
+
if strip:
|
|
27
|
+
sns.stripplot(df,size=swarmsize,palette=colours,ax=ax,alpha=swarmalpha)
|
|
28
|
+
else:
|
|
29
|
+
sns.swarmplot(df,size=swarmsize,palette=colours,ax=ax,alpha=swarmalpha)
|
|
30
|
+
if annotate_medians:
|
|
31
|
+
meds = df.median().values
|
|
32
|
+
for i,xtick in enumerate(bp.get_xticks()):
|
|
33
|
+
bp.text(xtick-0.5*width-0.1,meds[i],format % meds[i],
|
|
34
|
+
horizontalalignment='center',verticalalignment='center',
|
|
35
|
+
size='x-small',color='black',weight='semibold')
|
|
36
|
+
if annotate_means:
|
|
37
|
+
means = df.mean().values
|
|
38
|
+
for i,xtick in enumerate(bp.get_xticks()):
|
|
39
|
+
bp.text(xtick+0.5*width+0.1,means[i],format % means[i],
|
|
40
|
+
horizontalalignment='center',verticalalignment='center',
|
|
41
|
+
size='x-small',color='g',weight='semibold')
|
|
42
|
+
return bp
|
|
43
|
+
|
|
44
|
+
def violinswarmplot(df,width=0.8,annotate_means=False,annotate_medians=False,
|
|
45
|
+
ax=None,swarmsize=7,swarmalpha=None,format="%.1f",strip=False,
|
|
46
|
+
annotate_width=0.4,showpoints=True,**kwargs):
|
|
47
|
+
import seaborn as sns
|
|
48
|
+
vp = sns.violinplot(df, ax=ax, color="0.95", width=width, **kwargs)
|
|
49
|
+
colours = ['#72a4cdff'] * df.shape[1]
|
|
50
|
+
if showpoints:
|
|
51
|
+
if strip:
|
|
52
|
+
sns.stripplot(df,size=swarmsize,palette=colours,ax=ax,alpha=swarmalpha, jitter=True, zorder=1)
|
|
53
|
+
else:
|
|
54
|
+
sns.swarmplot(df,size=swarmsize,palette=colours,ax=ax,alpha=swarmalpha, zorder=1)
|
|
55
|
+
|
|
56
|
+
if annotate_medians:
|
|
57
|
+
meds = df.median().values
|
|
58
|
+
for i,xtick in enumerate(vp.get_xticks()):
|
|
59
|
+
vp.text(xtick-0.5*annotate_width-0.1,meds[i],format % meds[i],
|
|
60
|
+
horizontalalignment='center',verticalalignment='center',
|
|
61
|
+
size='x-small',color='black',weight='semibold')
|
|
62
|
+
if annotate_means:
|
|
63
|
+
means = df.mean().values
|
|
64
|
+
for i,xtick in enumerate(vp.get_xticks()):
|
|
65
|
+
vp.text(xtick+0.5*annotate_width+0.1,means[i],format % means[i],
|
|
66
|
+
horizontalalignment='center',verticalalignment='center',
|
|
67
|
+
size='x-small',color='g',weight='semibold')
|
|
68
|
+
return vp
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# deprecated
|
|
72
|
+
def _scattered_boxplot(ax, x, notch=None, sym=None, vert=None, whis=None, positions=None,
|
|
73
|
+
widths=None, patch_artist=None, bootstrap=None, usermedians=None, conf_intervals=None,
|
|
74
|
+
meanline=None, showmeans=None, showcaps=None, showbox=None,
|
|
75
|
+
showfliers="unif", hide_points_within_whiskers=False,
|
|
76
|
+
boxprops=None, labels=None, flierprops=None, medianprops=None, meanprops=None,
|
|
77
|
+
capprops=None, whiskerprops=None, manage_ticks=True, autorange=False, zorder=None, *, data=None):
|
|
78
|
+
if showfliers=="classic":
|
|
79
|
+
classic_fliers=True
|
|
80
|
+
else:
|
|
81
|
+
classic_fliers=False
|
|
82
|
+
bp_dict = ax.boxplot(x, notch=notch, sym=sym, vert=vert, whis=whis, positions=positions, widths=widths,
|
|
83
|
+
patch_artist=patch_artist, bootstrap=bootstrap, usermedians=usermedians,
|
|
84
|
+
conf_intervals=conf_intervals, meanline=meanline, showmeans=showmeans, showcaps=showcaps, showbox=showbox,
|
|
85
|
+
showfliers=classic_fliers,
|
|
86
|
+
boxprops=boxprops, labels=labels, flierprops=flierprops, medianprops=medianprops, meanprops=meanprops,
|
|
87
|
+
capprops=capprops, whiskerprops=whiskerprops, manage_ticks=manage_ticks, autorange=autorange, zorder=zorder,data=data)
|
|
88
|
+
N=len(x)
|
|
89
|
+
datashape_message = ("List of boxplot statistics and `{0}` "
|
|
90
|
+
"values must have same the length")
|
|
91
|
+
# check position
|
|
92
|
+
if positions is None:
|
|
93
|
+
positions = list(np.ones_like(x))
|
|
94
|
+
elif len(positions) != N:
|
|
95
|
+
raise ValueError(datashape_message.format("positions"))
|
|
96
|
+
|
|
97
|
+
positions = np.array(positions)
|
|
98
|
+
if len(positions) > 0 and not isinstance(positions[0], Number):
|
|
99
|
+
raise TypeError("positions should be an iterable of numbers")
|
|
100
|
+
|
|
101
|
+
# width
|
|
102
|
+
if widths is None:
|
|
103
|
+
widths = [np.clip(0.15 * np.ptp(positions), 0.15, 0.5)] * N
|
|
104
|
+
elif np.isscalar(widths):
|
|
105
|
+
widths = [widths] * N
|
|
106
|
+
elif len(widths) != N:
|
|
107
|
+
raise ValueError(datashape_message.format("widths"))
|
|
108
|
+
|
|
109
|
+
if hide_points_within_whiskers:
|
|
110
|
+
import matplotlib.cbook as cbook
|
|
111
|
+
from matplotlib import rcParams
|
|
112
|
+
if whis is None:
|
|
113
|
+
whis = rcParams['boxplot.whiskers']
|
|
114
|
+
if bootstrap is None:
|
|
115
|
+
bootstrap = rcParams['boxplot.bootstrap']
|
|
116
|
+
bxpstats = cbook.boxplot_stats(x, whis=whis, bootstrap=bootstrap,
|
|
117
|
+
labels=labels, autorange=autorange)
|
|
118
|
+
for i in range(N):
|
|
119
|
+
if hide_points_within_whiskers:
|
|
120
|
+
xi=bxpstats[i]['fliers']
|
|
121
|
+
else:
|
|
122
|
+
xi=x[i]
|
|
123
|
+
if showfliers=="unif":
|
|
124
|
+
jitter=np.random.uniform(-widths[i]*0.2,widths[i]*0.2,size=np.size(xi))
|
|
125
|
+
elif showfliers=="normal":
|
|
126
|
+
jitter=np.random.normal(loc=0.0, scale=widths[i]*0.1,size=np.size(xi))
|
|
127
|
+
elif showfliers==False or showfliers=="classic":
|
|
128
|
+
return
|
|
129
|
+
else:
|
|
130
|
+
raise NotImplementedError("showfliers='"+str(showfliers)+"' is not implemented. You can choose from 'unif', 'normal', 'classic' and False")
|
|
131
|
+
|
|
132
|
+
ax.scatter(positions[i]+jitter,xi,alpha=0.2,marker="o", facecolors='none', edgecolors="k")
|
|
133
|
+
|
|
134
|
+
return bp_dict
|
|
135
|
+
|
|
136
|
+
# setattr(plt.Axes, "scattered_boxplot", scattered_boxplot)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# code for coordinate algebra, specifically rotations given by the `rotation` transform
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
|
|
6
|
+
def vlen(v):
|
|
7
|
+
return np.sqrt(v[0]**2+v[1]**2)
|
|
8
|
+
|
|
9
|
+
def rmat_ang(angle):
|
|
10
|
+
theta = np.radians(-angle)
|
|
11
|
+
# note: tests suggest that for the svg angle we use the *negative* angle for this matrix
|
|
12
|
+
c, s = np.cos(theta), np.sin(theta)
|
|
13
|
+
R = np.array(((c, -s), (s, c)))
|
|
14
|
+
return R
|
|
15
|
+
|
|
16
|
+
def vec(x,y):
|
|
17
|
+
return np.array((x,y))
|
|
18
|
+
|
|
19
|
+
def transform_rot(x,y,angle):
|
|
20
|
+
return vec(x,y).dot(rmat_ang(angle))
|
|
21
|
+
|
|
22
|
+
# the code below parses out the rectangles from an SVG
|
|
23
|
+
# all other elements are ignored
|
|
24
|
+
# for the identified rectangles the code obtains the revelant parameters by retrieveal
|
|
25
|
+
# and string conversion to float
|
|
26
|
+
|
|
27
|
+
import re
|
|
28
|
+
|
|
29
|
+
# NOTE: the argument 'svg' is assumed to be a parsed svg file
|
|
30
|
+
# obtained with something like
|
|
31
|
+
#
|
|
32
|
+
# import xml.etree.ElementTree as ET
|
|
33
|
+
# svg = ET.parse('RyR-pattern-simulation-Ashagri14-Fig1.svg')
|
|
34
|
+
def find_svgrects(svg):
|
|
35
|
+
root = svg.getroot()
|
|
36
|
+
group = root.find('{http://www.w3.org/2000/svg}g')
|
|
37
|
+
rects = group.findall('{http://www.w3.org/2000/svg}rect')
|
|
38
|
+
return rects
|
|
39
|
+
|
|
40
|
+
def parse_rect(rect):
|
|
41
|
+
# ['style', 'id', 'width', 'height', 'x', 'y', 'transform']
|
|
42
|
+
prect = {}
|
|
43
|
+
for key in ['width', 'height', 'x', 'y']:
|
|
44
|
+
prect[key] = float(rect.get(key))
|
|
45
|
+
for key in ['style', 'id']:
|
|
46
|
+
prect[key] = rect.get(key)
|
|
47
|
+
if rect.get('transform') is not None:
|
|
48
|
+
m = re.search('^rotate\(([-+]*[\d.]+)\)',rect.get('transform'))
|
|
49
|
+
if m:
|
|
50
|
+
prect['rot_angle'] = float(m.group(1))
|
|
51
|
+
return prect
|
|
52
|
+
|
|
53
|
+
def parse_rects(rects):
|
|
54
|
+
return [parse_rect(rect) for rect in rects]
|
|
55
|
+
|
|
56
|
+
# code to display parsed rectangles via matplotlib
|
|
57
|
+
# we need this to check that things work as anticipated
|
|
58
|
+
|
|
59
|
+
from matplotlib.collections import PatchCollection
|
|
60
|
+
from matplotlib.patches import Rectangle
|
|
61
|
+
|
|
62
|
+
def transformed_rect(prect):
|
|
63
|
+
angle = prect.get('rot_angle',0)
|
|
64
|
+
r_origin = list(transform_rot(prect['x'],prect['y'],angle))
|
|
65
|
+
return Rectangle(r_origin, prect['width'], prect['height'], angle=angle)
|
|
66
|
+
|
|
67
|
+
def make_matplotrects(prects):
|
|
68
|
+
mprects = [transformed_rect(prect) for prect in prects]
|
|
69
|
+
return mprects
|
|
70
|
+
|
|
71
|
+
def plot_rects(ax,matplotrects,alpha=1.0):
|
|
72
|
+
# Create patch collection with specified colour/alpha
|
|
73
|
+
pc = PatchCollection(matplotrects, facecolor='r', alpha=alpha,
|
|
74
|
+
edgecolor='black',linewidth=1.0)
|
|
75
|
+
|
|
76
|
+
# Add collection to axes
|
|
77
|
+
ax.add_collection(pc,autolim=True)
|
|
78
|
+
|
|
79
|
+
# try to fix axes limits
|
|
80
|
+
# this does not seem to work as unticipated
|
|
81
|
+
# fine to ignore for now (because it does nothing)...
|
|
82
|
+
ax._unstale_viewLim()
|
|
83
|
+
datalim = pc.get_datalim(ax.transData)
|
|
84
|
+
print(datalim.get_points())
|
|
85
|
+
points = datalim.get_points()
|
|
86
|
+
if not np.isinf(datalim.minpos).all():
|
|
87
|
+
# By definition, if minpos (minimum positive value) is set
|
|
88
|
+
# (i.e., non-inf), then min(points) <= minpos <= max(points),
|
|
89
|
+
# and minpos would be superfluous. However, we add minpos to
|
|
90
|
+
# the call so that self.dataLim will update its own minpos.
|
|
91
|
+
# This ensures that log scales see the correct minimum.
|
|
92
|
+
points = np.concatenate([points, [datalim.minpos]])
|
|
93
|
+
ax.update_datalim(points)
|
|
94
|
+
return points
|
|
95
|
+
|
|
96
|
+
# function to scale everything to be accurate in nm
|
|
97
|
+
# below we assume that rectangles should be 27 nm x 27 nm
|
|
98
|
+
def scale(prect,factor):
|
|
99
|
+
srect = prect.copy()
|
|
100
|
+
for key in ['width', 'height', 'x', 'y']:
|
|
101
|
+
srect[key] = prect[key]*factor
|
|
102
|
+
return srect
|
|
103
|
+
|
|
104
|
+
# code to get label points from scaled prect
|
|
105
|
+
def points_from_sprect(sprect,mode='default'):
|
|
106
|
+
angle = sprect.get('rot_angle',0)
|
|
107
|
+
origin = transform_rot(sprect['x'],sprect['y'],angle)
|
|
108
|
+
if mode == 'default':
|
|
109
|
+
corner_points = np.array([[3.5,3.5], [23.5,3.5], [23.5, 23.5], [3.5, 23.5]]) # anti-clock wise
|
|
110
|
+
elif mode == 'RyR-T1366':
|
|
111
|
+
corner_points = np.array([[6,5], [21.6,6.6], [20.2,22.5], [4.8,20.5]])
|
|
112
|
+
elif mode == 'RyR-T2023':
|
|
113
|
+
corner_points = np.array([[4.6,12.0], [15.5,4.8], [22.5,15.2], [11.9,22.5]])
|
|
114
|
+
elif mode == 'RyR-D4365':
|
|
115
|
+
corner_points = np.array([[2,13.2],[13.9,2.2],[25.3,14.0],[13.3,25.2]])
|
|
116
|
+
|
|
117
|
+
else:
|
|
118
|
+
raise RuntimeError('unknow RyR corner mode %s requested' % (mode))
|
|
119
|
+
# first rotate corner points
|
|
120
|
+
R = rmat_ang(sprect.get('rot_angle',0))
|
|
121
|
+
cpsr = corner_points[:,None,:].dot(R).squeeze()
|
|
122
|
+
# now shift corner points to the origin of this rect
|
|
123
|
+
scpsr = cpsr + origin[None,:]
|
|
124
|
+
return scpsr
|
|
125
|
+
|
|
126
|
+
# functions to pick points and rotate point sets for generating clusters etc
|
|
127
|
+
|
|
128
|
+
from numpy.random import default_rng
|
|
129
|
+
rng = default_rng()
|
|
130
|
+
|
|
131
|
+
def random_pick(size,p):
|
|
132
|
+
return rng.random(size) < p
|
|
133
|
+
|
|
134
|
+
def rotpts(pts,angle):
|
|
135
|
+
rotpts = []
|
|
136
|
+
for ptnum in range(pts.shape[0]):
|
|
137
|
+
rx,ry = transform_rot(pts[ptnum,0],pts[ptnum,1],angle)
|
|
138
|
+
rotpts.append([rx,ry])
|
|
139
|
+
return np.array(rotpts)
|
|
140
|
+
|
|
141
|
+
def ctrorigin(pts):
|
|
142
|
+
mxy = pts.mean(axis=0)
|
|
143
|
+
return pts - mxy[None,:]
|
|
144
|
+
|
|
145
|
+
def shftpts(pts,x,y):
|
|
146
|
+
return pts + np.array([x,y])[None,:]
|
|
147
|
+
|
|
148
|
+
def pickpts(pts,prob):
|
|
149
|
+
picked = random_pick(pts.shape[0],prob)
|
|
150
|
+
|
|
151
|
+
return pts[picked,:]
|
|
152
|
+
|
|
153
|
+
def mergeClusterlist(clist):
|
|
154
|
+
clusters = clist[0].copy()
|
|
155
|
+
for c in clist[1:]:
|
|
156
|
+
clusters = np.append(clusters,c,axis = 0)
|
|
157
|
+
return clusters
|
|
158
|
+
|
|
159
|
+
import pandas as pd
|
|
160
|
+
def pts2df(pts):
|
|
161
|
+
pymedct = {'x' : pts[:,0], 'y' : pts[:,1], 'z' : np.zeros((pts.shape[0])), 't' : np.ones((pts.shape[0]))}
|
|
162
|
+
pymedf = pd.DataFrame.from_dict(pymedct)
|
|
163
|
+
return pymedf
|
|
164
|
+
|
|
165
|
+
def pymedf_add_err(pymedf,locerr=2.0): # error in nm
|
|
166
|
+
errdf = pymedf.copy()
|
|
167
|
+
nrows = errdf.shape[0]
|
|
168
|
+
errdf['x'] += locerr*np.random.normal(size=nrows)
|
|
169
|
+
errdf['y'] += locerr*np.random.normal(size=nrows)
|
|
170
|
+
errdf['z'] += locerr*np.random.normal(size=nrows)
|
|
171
|
+
errdf['error_x'] = locerr*np.ones((nrows))
|
|
172
|
+
errdf['error_y'] = locerr*np.ones((nrows))
|
|
173
|
+
errdf['error_z'] = locerr*np.ones((nrows))
|
|
174
|
+
|
|
175
|
+
return errdf
|
|
176
|
+
|
|
177
|
+
def datasourcePick2df(ds,prob):
|
|
178
|
+
picked = random_pick(ds['x'].size,prob)
|
|
179
|
+
pymedct = {}
|
|
180
|
+
for key in ['x','y','z','error_x','error_y','error_z','t']:
|
|
181
|
+
pymedct[key] = ds[key][picked]
|
|
182
|
+
return pd.DataFrame.from_dict(pymedct)
|