napari-micromanager icon indicating copy to clipboard operation
napari-micromanager copied to clipboard

Setup error in loading MM config file

Open jacopoabramo opened this issue 4 years ago • 5 comments

Hi everyone. I've tried to install this plugin on my setup but I've got some errors popping up after loading the .cfg file.

Steps to reproduce

  • Select the following MM config file:
# Generated by Configurator on Wed Oct 27 15:31:13 CEST 2021

# Reset
Property,Core,Initialize,0

# Devices
Device,COM3,SerialManager,COM3
Device,MicroDrive XY Stage,MCL_MicroDrive,MicroDrive XY Stage
Device,MicroDrive Z Stage,MCL_MicroDrive,MicroDrive Z Stage
Device,MCL NanoDrive Z Stage,MCL_NanoDrive,MCL NanoDrive Z Stage
Device,iBeamSmartCW,Toptica_iBeamSmartCW,iBeamSmartCW

# Pre-init settings for devices
Property,MicroDrive XY Stage,EncodersPresent,No
Property,MicroDrive Z Stage,EncodersPresent,No
Property,iBeamSmartCW,Description,iBeam smart Laser Controller
Property,iBeamSmartCW,Port,COM3

# Pre-init settings for COM ports
Property,COM3,AnswerTimeout,500.0000
Property,COM3,BaudRate,115200
Property,COM3,DTR,Disable
Property,COM3,DataBits,8
Property,COM3,DelayBetweenCharsMs,0.0000
Property,COM3,Fast USB to Serial,Disable
Property,COM3,Handshaking,Off
Property,COM3,Parity,None
Property,COM3,StopBits,1
Property,COM3,Verbose,1

# Hub (parent) references

# Initialize
Property,Core,Initialize,1

# Delays

# Focus directions
FocusDirection,MicroDrive Z Stage,0
FocusDirection,MCL NanoDrive Z Stage,0

# Roles
Property,Core,Focus,MCL NanoDrive Z Stage
Property,Core,AutoShutter,1

# Camera-synchronized devices

# Labels

# Configuration presets
# Group: Channel

# Group: System
# Preset: Startup



# PixelSize settings
  • Click "Load"

Traceback

RuntimeError                              Traceback (most recent call last)
~\AppData\Local\Programs\Python\Python39\lib\site-packages\micromanager_gui\main_window.py in _on_system_configuration_loaded(self=)
    252 
    253     def _on_system_configuration_loaded(self):
--> 254         self._refresh_camera_options()
        self._refresh_camera_options = >
    255         self._refresh_objective_options()
    256         self._refresh_channel_list()

~\AppData\Local\Programs\Python\Python39\lib\site-packages\micromanager_gui\main_window.py in _refresh_camera_options(self=)
    224     def _refresh_camera_options(self):
    225         cam_device = self._mmc.getCameraDevice()
--> 226         cam_props = self._mmc.getDevicePropertyNames(cam_device)
        cam_props = undefined
        self._mmc.getDevicePropertyNames = 
        cam_device = ''
    227         if "Binning" in cam_props:
    228             bin_opts = self._mmc.getAllowedPropertyValues(cam_device, "Binning")

~\AppData\Local\Programs\Python\Python39\lib\site-packages\Pyro5\client.py in __call__(self=, *args=('',), **kwargs={})
    474         for attempt in range(self.__max_retries + 1):
    475             try:
--> 476                 return self.__send(self.__name, args, kwargs)
        self.__send = 
        self.__name = 
        args = ('',)
        kwargs = {}
    477             except (errors.ConnectionClosedError, errors.TimeoutError):
    478                 # only retry for recoverable network errors

~\AppData\Local\Programs\Python\Python39\lib\site-packages\Pyro5\client.py in _pyroInvoke(self=, methodname='getDevicePropertyNames', vargs=('',), kwargs={}, flags=0, objectId='pymmcore_plus.CMMCorePlus')
    241                     return _StreamResultIterator(streamId, self)
    242                 if msg.flags & protocol.FLAGS_EXCEPTION:
--> 243                     raise data  # if you see this in your traceback, you should probably inspect the remote traceback as well
        data = RuntimeError('No device with label ""')
    244                 else:
    245                     return data

RuntimeError: No device with label ""

Setup

napari: 0.4.12
 Platform: Windows-10-10.0.19043-SP0
Python: 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64 bit (AMD64)]
Qt: 5.15.2
PyQt5: 5.15.5
NumPy: 1.21.2
SciPy: 1.7.1
Dask: 2021.09.1
VisPy: 0.9.2

OpenGL:
- GL version: 4.6.0 - Build 27.20.100.9127
- MAX_TEXTURE_SIZE: 16384

Screens:
- screen 1: resolution 1920x1080, scale 1.0

Plugins:
- console: 0.0.4
- micromanager: 0.0.1rc3
- napari-live-recording: 0.1.5
- scikit-image: 0.4.12
- svg: 0.1.5

Am I doing something wrong?

jacopoabramo avatar Oct 29 '21 08:10 jacopoabramo

Hi @jacopoabramo, and thanks for trying it out :)

Am I doing something wrong?

nope! you've just exposed one of the incorrect assumptions that we made so far, which is that the config would have a camera device (in our _refresh_camera_options method). We could/should "fix" this specific issue pretty easily by just making sure to try/catch the call to self._mmc.getDevicePropertyNames(cam_device) ...

however, this kinda points to a broader issue for your specific use case at the moment (thinking about your image.sc post)... which is that napari-micromanager is, at this point, still just trying to get the basic use case of a GUI-control for a camera and conventional scope. As mentioned over there, for now, I suspect that you'll want to go a bit lower-level and use the core object provided by pymmcore-plus.

I'm happy to help get you started with getting your custom camera control to show images in napari, while still being able to use mmcore for piezo and other device control. Maybe you can provide a basic workflow you're aiming for, and a little info about how you snap images with your non-mm camera?

tlambert03 avatar Oct 29 '21 12:10 tlambert03

one more thing, @fdrgsp just reminded me that we actually do catch that case in the main branch:

https://github.com/tlambert03/napari-micromanager/blob/fc3a9fb5fe8edf958ca236722d47c8f16ecb8b1b/micromanager_gui/main_window.py#L279-L281

so, you might try again from main ... or I can cut another release to pypi.

pip install -U git+https://github.com/tlambert03/napari-micromanager.git

tlambert03 avatar Oct 29 '21 13:10 tlambert03

I also just pushed a new rc to pypi... so you should be able to pip install -U napari-micromanager in about 10 mins

tlambert03 avatar Oct 29 '21 15:10 tlambert03

Hi @tlambert03 , thank you for the quick reply!

I've also read your post on image.sc, thanks for that too. I'll try to briefly explain my current situation. We have a Ximea xiB-64 camera, which - as I've explained - has some performance issues when used with Micro-Manager. To go around that, I've worked on napari-live-recording, a plugin to test new cameras and/or to use with small/quick setups. These are the controls I've implemented so far (some of them are on a development branch)

  • image snap: napari adds a layer with a snap image from the camera;
  • album snap: napari adds a layer with a snap which gradually creates a stack of images everytime you press the button;
  • live recording: napari adds a layer which is updated every 60 Hz to live-stream the camera frames;
  • recording: the camera records a stack of N frames (which can also be post-processed with a user-defined function if necessary), and then adds the recorded stack on napari

There are also some other controls integrated (at least for the Ximea camera - exposure time, bytes per pixel).

I was focusing on the last point of the list, the recording functionality, as what I wanted to achieve was something similar to a multidimensional acquisition available in Micro-Manager: provide a sets of points which moves an XY piezo stage, and after each movement capture an image. Tecnically I could write my own user-defined function to do so, but when I saw Micro-Manager being ported to napari I thought it to be easier to try and send these instructions directly to Micro-Manager, and after each movement capture an image with the live recording plugin.

I hope my explanation was clear!

EDIT: the camera snap is performed by directly using the Python APIs provided by Ximea in this case. Each camera the plugin supports is inherited from a common interface, with - at the moment - limited functionalities. So based on the user choice a new camera object is instantiated starting from the same interface. It's maybe not great but so far it's doing its job and I'm hoping to add new cameras to test it out.

jacopoabramo avatar Oct 29 '21 17:10 jacopoabramo

what I wanted to achieve was something similar to a multidimensional acquisition available in Micro-Manager: provide a sets of points which moves an XY piezo stage, and after each movement capture an image.

cool, thanks. makes sense! Let me give a high level overview of the moving parts here, which will hopefully clarify where you might start to use some of the stack here. There's three "moving parts" (and some current limitations, which I'll get to):

  • pymmcore-plus - this is a wrapper on pymmcore, that provides a number of useful things for the purpose of gui/event-driven micromanager control
    • inter-process communication via RemoteMMCore, so you don't choke up the main thread waiting for things like acquisitions, etc...
    • callbacks, re-routed from mmcore's callback system, via psygnal, so you can do stuff like
     @mmcore.propertyChanged.connect
     def prop_changed(device, prop, value):
         print(f"{device}.{prop} changed to {value!r}")
    
    • a run_mda method that acts as the multi-dimensional acquisition engine to drive scope over a set of events.
  • useq-schema - this is a backend agnostic schema for describing a sequence of microscope control events. it lets you define an experiment like this:
    mda = MDASequence(
     stage_positions=[(100, 100, 30), (200, 150, 35)],
     channels=["DAPI", "FITC"],
     time_plan={'interval': 1, 'loops': 20},
     z_plan={"range": 4, "step": 0.5},
     axis_order='tpcz',
    )
    
    it still needs a lot of work/input to make it more flexible beyond the standard 6d experiment type, but so far i've been quite happy with forcing the definition of the experiment to something static like that. note that the run_mda method in CMMCore accepts an instance of MDASequence.
  • napari-micromanager - This sits on top of those two things and basically provides a GUI for the most common things. It constructs an MDASequence based on the users interaction with the GUI, and then passes it to pymmcore-plus run_mda method. It then connects various callbacks to the core object's signals, so that it can react in the main gui. For example, after every frame in an MDA, the run_mda method emits a frameReady signal... napari-micromanager connects to that signal and shows the image in the viewer in the _on_mda_frame method.

... SO

what we'd need to do for your case is just make these three lines in run_mda more accessible, so that the user could define their own acquisition method and signals. That is, we need a hook there or something for you to call capture_image from your library.

Note: this also really should be reflected upstream in useq-schema, that is: an "acquisition event" should be more pluggable (e.g. beyond just a channel config and name)

If you want to start hacking at it, I might suggest starting just with pymmcore-plus using something like this example to build a simple experiment, and then think about how you'd want to hook into that run_mda method. (that method has always been a spot where we've planned to open up hooks, like image processing, etc... so it's a natural next step)

tlambert03 avatar Oct 29 '21 17:10 tlambert03

hey @jacopoabramo, can you let me know if this is resolved on your end? A lot has obviously changed in the meantime, but I see that you do depend on pymmcore-plus in your plugin, so don't want to close it without making sure you're good

tlambert03 avatar Jul 28 '23 12:07 tlambert03

Hi @tlambert03, sorry for the late reply - was cought up in a lot of stuff. I'll close the issue since the plugin interface to pymmcore-plus seems to be stable

jacopoabramo avatar Aug 09 '23 08:08 jacopoabramo