Skip to content

Commit 9de3502

Browse files
committed
microEye v2.3.9
Enhancements: - TIFF Viewer: - File System: Added context menu with "Reveal in Folder", "Create New Folder", and base path shortcuts. - [BUG] Localization View: Fixed issue where exporting super-resolution images would fail. - Pycro-Manager: - [BUG] GUI freeze caused by focus stabilization on `PycroStage` with Java backend (tested with FOC100). - Introduced background daemon to handle `Core` calls on a separate thread, an attempt to resolve GUI responsiveness issues. Future Updates: - Finalized Pycro-Manager Integration with XY-Stage and Focus Stabilization. - MacOS compatibility testing - Acquisition Experiments Designer tools (continued development) - 3D Localization fitting from Experimental PSF - Introduction of 2D/3D Single-Particle Tracking
1 parent d46e048 commit 9de3502

7 files changed

Lines changed: 589 additions & 380 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ The **`microEye`** is a Python toolkit for fluorescence microscopy that supports
77
This toolkit is compatible with the [hardware](#hardware) used in our microscope. For further details, refer to the [miEye microscope paper](https://doi.org/10.1016/j.ohx.2022.e00368) and [OSF project](http://doi.org/10.17605/osf.io/j2fqy).
88

99
```bash
10-
__ ____ ____ ___ ____ ___
11-
/ |/ (_)__________ / __/_ _____ _ __|_ | |_ / ( _ )
12-
/ /|_/ / / __/ __/ _ \/ _// // / -_) | |/ / __/_ _/_ <_/ _ |
13-
/_/ /_/_/\__/_/ \___/___/\_, /\__/ |___/____(_)____(_)___/
14-
/___/
10+
__ __ _ ___ ___ ____ ___
11+
| \/ (_)__ _ _ ___| __| _ ___ __ _|_ ) |__ // _ \
12+
| |\/| | / _| '_/ _ \ _| || / -_) \ V // / _ |_ \\_, /
13+
|_| |_|_\__|_| \___/___\_, \___| \_//___(_)___(_)_/
14+
|__/
1515
```
1616
1717
![Package Health](https://snyk.io/advisor/python/microEye/badge.svg)

src/microEye/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version_info = (2, 3, 8)
1+
version_info = (2, 3, 9)
22
__version__ = '.'.join(map(str, version_info))

src/microEye/analysis/multi_viewer.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,77 @@ def setupFileSystemTab(self, path):
203203
# Connect double-click signal to a method that uses QTimer
204204
self.tree.doubleClicked.connect(self._open_file)
205205

206+
# Create Tree view context menu
207+
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
208+
self.tree.customContextMenuRequested.connect(self._show_tree_context_menu)
209+
206210
# Add the File system tab contents
207211
self.imsq_pattern = QtWidgets.QLineEdit('/image_0*.ome.tif')
208212

209213
self.file_tree_layout.addWidget(QtWidgets.QLabel('Image Sequence pattern:'))
210214
self.file_tree_layout.addWidget(self.imsq_pattern)
211215
self.file_tree_layout.addWidget(self.tree)
212216

217+
def _show_tree_context_menu(self, position):
218+
index = self.tree.indexAt(position)
219+
if not index.isValid():
220+
return
221+
222+
menu = QtWidgets.QMenu()
223+
reveal_action = menu.addAction('Reveal in Explorer')
224+
new_folder_action = menu.addAction('New Folder')
225+
menu.addSeparator()
226+
227+
# Root path shortcuts
228+
root_action = menu.addAction('This PC (Root Path)')
229+
home_action = menu.addAction('Home (User Directory)')
230+
desktop_action = menu.addAction('Desktop')
231+
initial_action = menu.addAction('Initial Path')
232+
working_dir_action = menu.addAction('Working Directory')
233+
234+
action = menu.exec(self.tree.viewport().mapToGlobal(position))
235+
if action == reveal_action:
236+
path = self.model.filePath(index)
237+
folder = path if os.path.isdir(path) else os.path.dirname(path)
238+
os.startfile(folder)
239+
elif action == new_folder_action:
240+
self._create_new_folder()
241+
elif action == home_action:
242+
home = os.path.expanduser('~')
243+
self.tree.setRootIndex(self.model.index(home))
244+
elif action == desktop_action:
245+
desktop = os.path.join(os.path.expanduser('~'), 'Desktop')
246+
self.tree.setRootIndex(self.model.index(desktop))
247+
elif action == root_action:
248+
self.tree.setRootIndex(self.model.index(''))
249+
elif action == initial_action:
250+
self.tree.setRootIndex(self.model.index(self.path))
251+
elif action == working_dir_action:
252+
self.tree.setRootIndex(
253+
self.model.index(os.path.dirname(os.path.abspath(__package__)))
254+
)
255+
256+
def _create_new_folder(self):
257+
index = self.tree.currentIndex()
258+
if not index.isValid():
259+
return
260+
261+
path = self.model.filePath(index)
262+
if not os.path.isdir(path):
263+
path = os.path.dirname(path)
264+
265+
new_folder_name, ok = QtWidgets.QInputDialog.getText(
266+
self, 'New Folder', 'Enter folder name:'
267+
)
268+
if ok and new_folder_name:
269+
new_folder_path = os.path.join(path, new_folder_name)
270+
try:
271+
os.makedirs(new_folder_path)
272+
except OSError as e:
273+
QtWidgets.QMessageBox.critical(
274+
self, 'Error', f'Could not create folder: {e}'
275+
)
276+
213277
def tabifyDocks(self):
214278
# Tabify docks
215279
pass

src/microEye/analysis/viewer/localizations.py

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -285,53 +285,41 @@ def render_loc(self):
285285
ndarray or None
286286
Rendered super-res image or None.
287287
'''
288-
for idx, localizations in enumerate(self.fittingResults):
289-
if localizations is None:
290-
continue
288+
if not self.fittingResults:
289+
return
291290

292-
if len(localizations) <= 0:
293-
continue
291+
images = [None] * len(self.fittingResults)
294292

295-
render_idx = self.render_cbox.currentData()
296-
projection = self.projection_cbox.currentData()
293+
render_idx = self.render_cbox.currentData()
294+
projection = self.projection_cbox.currentData()
295+
xy_bin = self.xy_binsize.value()
296+
z_bin = self.z_binsize.value()
297+
auto_levels = self.auto_level.isChecked()
298+
299+
renderer = BaseRenderer(xy_bin, z_bin, RenderModes(render_idx))
300+
301+
for idx, localizations in enumerate(self.fittingResults):
302+
if not localizations or len(localizations) <= 0:
303+
continue
297304

298-
renderClass = BaseRenderer(
299-
self.xy_binsize.value(),
300-
self.z_binsize.value(),
301-
RenderModes(render_idx),
302-
)
303305
if 0 <= projection < 3:
304-
img = renderClass.render(
306+
rendered_img = renderer.render(
305307
Projection(projection),
306308
localizations.data[DataColumns.X],
307309
localizations.data[DataColumns.Y],
308310
localizations.data[DataColumns.Z],
309311
localizations.data[DataColumns.INTENSITY],
310312
)
311313

312-
self.setImage(
313-
img, index=idx, autoLevels=self.auto_level.isChecked()
314-
)
315-
316-
if projection == 0:
317-
self.view_box.setAspectLocked(True, 1)
318-
else:
319-
self.view_box.setAspectLocked(
320-
True, self.xy_binsize.value() / self.z_binsize.value()
321-
)
314+
aspect = 1 if projection == 0 else xy_bin / z_bin
315+
self.view_box.setAspectLocked(True, aspect)
322316
elif 3 <= projection < 6:
323-
projection -= 3
324-
325-
if projection == 0:
326-
self.view_box.setAspectLocked(True, 1)
327-
width = self.z_binsize.value()
328-
else:
329-
self.view_box.setAspectLocked(
330-
True, self.xy_binsize.value() / self.z_binsize.value()
331-
)
332-
width = self.xy_binsize.value()
317+
slice_proj = projection - 3
318+
aspect = 1 if slice_proj == 0 else xy_bin / z_bin
319+
self.view_box.setAspectLocked(True, aspect)
320+
width = z_bin if slice_proj == 0 else xy_bin
333321

334-
img = renderClass.render_slice(
322+
rendered_img = renderer.render_slice(
335323
Projection(projection),
336324
localizations.data[DataColumns.X],
337325
localizations.data[DataColumns.Y],
@@ -340,10 +328,13 @@ def render_loc(self):
340328
self.position.value(),
341329
width,
342330
)
331+
else:
332+
continue
343333

344-
self.setImage(
345-
img, index=idx, autoLevels=self.auto_level.isChecked()
346-
)
334+
self.setImage(rendered_img, index=idx, autoLevels=auto_levels)
335+
images[idx] = rendered_img
336+
337+
return images
347338

348339
def extract_z(self):
349340
'''Extract Z values from the fitting results.'''
@@ -1276,7 +1267,7 @@ def export_loc(self, filename=None):
12761267
)
12771268

12781269
if 'Super-res image' in options:
1279-
sres_img = self.render_loc()
1270+
sres_img = self.render_loc()[self.image_layers.currentIndex]
12801271
tf.imwrite(
12811272
re.sub(r'(\.h5|\.tsv)$', '_super_res.tif', filename),
12821273
sres_img,

0 commit comments

Comments
 (0)