def test_one_center_em(self): em_band = (490e-9, 497e-9, 500e-9, 503e-9, 510e-9) em_bands = ((650e-9, 660e-9, 675e-9, 678e-9, 680e-9), (780e-9, 785e-9, 790e-9, 800e-9, 812e-9), (1034e-9, 1080e-9, 1100e-9, 1200e-9, 1500e-9)) # Excitation band should be smaller than the emission band used in_exp = [ ((em_band, (490e-9, 510e-9)), fluo.get_center(em_band)), # only one band ((em_bands, (490e-9, 497e-9, 500e-9, 503e-9, 510e-9)), fluo.get_center(em_bands[0])), # smallest above 500nm ((em_bands, (690e-9, 697e-9, 700e-9, 703e-9, 710e-9)), fluo.get_center(em_bands[1])), # smallest above 700nm ((em_bands, (790e-9, 797e-9, 800e-9, 803e-9, 810e-9)), fluo.get_center(em_bands[2])), # smallest above 800nm ((em_bands[0:2], (790e-9, 797e-9, 800e-9, 803e-9, 810e-9)), fluo.get_center(em_bands[1])), # biggest # Try with a pass-through ((em_band, BAND_PASS_THROUGH), 500e-9), ((em_bands, BAND_PASS_THROUGH), 1100e-9), # biggest # ((BAND_PASS_THROUGH, (490e-9, 510e-9)), BAND_PASS_THROUGH), ] for args, exp in in_exp: out = fluo.get_one_center_em(*args) self.assertEqual( exp, out, "Failed while running with %s and got %s" % (args, out))
def test_one_center_ex(self): ex_band = (490e-9, 497e-9, 500e-9, 503e-9, 510e-9) ex_bands = ((650e-9, 660e-9, 675e-9, 678e-9, 680e-9), (780e-9, 785e-9, 790e-9, 800e-9, 812e-9), (1034e-9, 1080e-9, 1100e-9, 1200e-9, 1500e-9)) # Excitation band should be smaller than the emission band used in_exp = [((ex_band, (490e-9, 510e-9)), fluo.get_center(ex_band)), # only one band ((ex_bands, (490e-9, 497e-9, 500e-9, 503e-9, 510e-9)), fluo.get_center(ex_bands[0])), # nothing fitting, but should pick the smallest ((ex_bands, (690e-9, 697e-9, 700e-9, 703e-9, 710e-9)), fluo.get_center(ex_bands[0])), # biggest below 700nm ((ex_bands, (790e-9, 797e-9, 800e-9, 803e-9, 810e-9)), fluo.get_center(ex_bands[1])), # biggest below 800nm ] for args, exp in in_exp: out = fluo.get_one_center_ex(*args) self.assertEqual(exp, out, "Failed while running with %s and got %s" % (args, out))
def test_center(self): in_exp = [ ((490e-9, 510e-9), 500e-9), # 2-float band ((490e-9, 497e-9, 500e-9, 503e-9, 510e-9), 500e-9), # 5-float band (((490e-9, 510e-9), (820e-9, 900e-9)), (500e-9, 860e-9) ) # multi-band ] for inp, exp in in_exp: out = fluo.get_center(inp) self.assertEqual( exp, out, "Failed while running with %s and got %s" % (inp, out)) # Special case for "pass-through": any number > 0 is fine out = fluo.get_center(BAND_PASS_THROUGH) self.assertGreaterEqual(out, 0)
def test_center(self): in_exp = [((490e-9, 510e-9), 500e-9), # 2-float band ((490e-9, 497e-9, 500e-9, 503e-9, 510e-9), 500e-9), # 5-float band (((490e-9, 510e-9), (820e-9, 900e-9)), (500e-9, 860e-9)) # multi-band ] for inp, exp in in_exp: out = fluo.get_center(inp) self.assertEqual(exp, out, "Failed while running with %s and got %s" % (inp, out))
def _weight_stream(stream): """ Defines how much a stream is of priority (should be done first) for acquisition. stream (acq.stream.Stream): a stream to weight returns (number): priority (the higher the more it should be done first) """ if isinstance(stream, (FluoStream, ScannedFluoMDStream)): # Fluorescence ASAP to avoid bleaching if isinstance(stream, ScannedFluoMDStream): # Just take one of the streams, to keep things "simple" stream = stream.streams[0] # If multiple fluorescence acquisitions: prefer the long emission # wavelengths first because there is no chance their emission light # affects the other dyes (and which could lead to a little bit of # bleaching). ewl_center = fluo.get_center(stream.emission.value) if isinstance(ewl_center, collections.Iterable): # multi-band filter, so fallback to guess based on excitation xwl_center = fluo.get_center(stream.excitation.value) if isinstance(ewl_center, collections.Iterable): # also unguessable => just pick one "randomly" ewl_bonus = ewl_center[0] else: ewl_bonus = xwl_center + 50e-6 # add 50nm as guesstimate for emission else: ewl_bonus = ewl_center # normally, between 0 and 1 return 100 + ewl_bonus elif isinstance(stream, OpticalStream): return 90 # any other kind of optical after fluorescence elif isinstance(stream, ScannedRemoteTCStream): return 85 # Stream for FLIM acquisition with time correlator elif isinstance(stream, EMStream): return 50 # can be done after any light elif isinstance(stream, (SEMCCDMDStream, SEMMDStream, SEMTemporalMDStream)): return 40 # after standard (=survey) SEM elif isinstance(stream, OverlayStream): return 10 # after everything (especially after SEM and optical) else: logging.debug("Unexpected stream of type %s", stream.__class__.__name__) return 0
def test_center(self): in_exp = [ ((490e-9, 510e-9), 500e-9), # 2-float band ((490e-9, 497e-9, 500e-9, 503e-9, 510e-9), 500e-9), # 5-float band (((490e-9, 510e-9), (820e-9, 900e-9)), (500e-9, 860e-9) ) # multi-band ] for inp, exp in in_exp: out = fluo.get_center(inp) self.assertEqual( exp, out, "Failed while running with %s and got %s" % (inp, out))
def test_one_center_ex(self): ex_band = (490e-9, 497e-9, 500e-9, 503e-9, 510e-9) ex_bands = ((650e-9, 660e-9, 675e-9, 678e-9, 680e-9), (780e-9, 785e-9, 790e-9, 800e-9, 812e-9), (1034e-9, 1080e-9, 1100e-9, 1200e-9, 1500e-9)) # Excitation band should be smaller than the emission band used in_exp = [ ((ex_band, (490e-9, 510e-9)), fluo.get_center(ex_band)), # only one band ((ex_bands, (490e-9, 497e-9, 500e-9, 503e-9, 510e-9)), fluo.get_center(ex_bands[0]) ), # nothing fitting, but should pick the smallest ((ex_bands, (690e-9, 697e-9, 700e-9, 703e-9, 710e-9)), fluo.get_center(ex_bands[0])), # biggest below 700nm ((ex_bands, (790e-9, 797e-9, 800e-9, 803e-9, 810e-9)), fluo.get_center(ex_bands[1])), # biggest below 800nm ] for args, exp in in_exp: out = fluo.get_one_center_ex(*args) self.assertEqual( exp, out, "Failed while running with %s and got %s" % (args, out))
def _weight_stream(stream): """ Defines how much a stream is of priority (should be done first) for acquisition. stream (acq.stream.Stream): a stream to weight returns (number): priority (the higher the more it should be done first) """ if isinstance(stream, FluoStream): # Fluorescence ASAP to avoid bleaching # If multiple fluorescence acquisitions: prefer the long emission # wavelengths first because there is no chance their emission light # affects the other dyes (and which could lead to a little bit of # bleaching). ewl_center = fluo.get_center(stream.emission.value) if isinstance(ewl_center, collections.Iterable): # multi-band filter, so fallback to guess based on excitation xwl_center = fluo.get_center(stream.excitation.value) if isinstance(ewl_center, collections.Iterable): # also unguessable => just pick one "randomly" ewl_bonus = ewl_center[0] else: ewl_bonus = xwl_center + 50e-6 # add 50nm as guesstimate for emission else: ewl_bonus = ewl_center # normally, between 0 and 1 return 100 + ewl_bonus elif isinstance(stream, OpticalStream): return 90 # any other kind of optical after fluorescence elif isinstance(stream, EMStream): return 50 # can be done after any light elif isinstance(stream, (SEMCCDMDStream, SEMMDStream)): return 40 # after standard (=survey) SEM elif isinstance(stream, OverlayStream): return 10 # after everything (especially after SEM and optical) else: logging.debug("Unexpected stream of type %s", stream.__class__.__name__) return 0
def __init__(self, name, detector, dataflow, emitter, em_filter): """ name (string): user-friendly name of this stream detector (Detector): the detector which has the dataflow dataflow (Dataflow): the dataflow from which to get the data emitter (Light): the HwComponent to modify the light excitation filter (Filter): the HwComponent to modify the emission light filtering """ CameraStream.__init__(self, name, detector, dataflow, emitter) self._em_filter = em_filter # Emission and excitation are based on the hardware capacities. # For excitation, compared to the hardware, only one band at a time can # be selected. The difficulty comes to pick the default value. The best # would be to use the current hardware value, but if the light is off # there is no default value. In that case, we pick the emission value # and try to pick a compatible excitation value: the first excitation # wavelength below the emission. However, the emission value might also # be difficult to know if there is a multi-band filter. In that case we # just pick the lowest value. # TODO: once the streams have their own version of the hardware settings # and in particular light.power, it should be possible to turn off the # light just by stopping the power, and so leaving the emissions as is. em_choices = em_filter.axes["band"].choices.copy() # convert any list into tuple, as lists cannot be put in a set for k, v in em_choices.items(): em_choices[k] = conversion.ensureTuple(v) # invert the dict, to directly convert the emission to the position value self._emission_to_idx = dict((v, k) for k, v in em_choices.items()) cur_pos = em_filter.position.value["band"] current_em = em_choices[cur_pos] if isinstance(current_em[0], collections.Iterable): # if multiband => pick the first one em_band = current_em[0] else: em_band = current_em center_em = fluo.get_center(em_band) exc_choices = set(emitter.spectra.value) current_exc = self._get_current_excitation() if current_exc is None: # pick the closest below the current emission current_exc = min(exc_choices, key=lambda b: b[2]) # default to the smallest for b in exc_choices: # Works because exc_choices only contains 5-float tuples if (b[2] < center_em and center_em - b[2] < center_em - current_exc[2]): current_exc = b logging.debug("Guessed excitation is %s, based on emission %s", current_exc, current_em) self.excitation = model.VAEnumerated(current_exc, choices=exc_choices, unit="m") self.excitation.subscribe(self.onExcitation) # The wavelength band on the out path (set when emission changes) self.emission = model.VAEnumerated(current_em, choices=set(em_choices.values()), unit="m") self.emission.subscribe(self.onEmission) # colouration of the image default_tint = conversion.wave2rgb(center_em) self.tint = model.ListVA(default_tint, unit="RGB") # 3-tuple R,G,B self.tint.subscribe(self.onTint)
def __init__(self, name, detector, dataflow, emitter, em_filter, **kwargs): """ name (string): user-friendly name of this stream detector (Detector): the detector which has the dataflow dataflow (Dataflow): the dataflow from which to get the data emitter (Light): the HwComponent to modify the light excitation em_filter (Filter): the HwComponent to modify the emission light filtering """ super(FluoStream, self).__init__(name, detector, dataflow, emitter, **kwargs) self._em_filter = em_filter # Emission and excitation are based on the hardware capacities. # For excitation, compared to the hardware, only one band at a time can # be selected. The difficulty comes to pick the default value. The best # would be to use the current hardware value, but if the light is off # there is no default value. In that case, we pick the emission value # and try to pick a compatible excitation value: the first excitation # wavelength below the emission. However, the emission value might also # be difficult to know if there is a multi-band filter. In that case we # just pick the lowest value. # TODO: once the streams have their own version of the hardware settings # and in particular light.power, it should be possible to turn off the # light just by stopping the power, and so leaving the emissions as is. em_choices = em_filter.axes["band"].choices.copy() # convert any list into tuple, as lists cannot be put in a set for k, v in em_choices.items(): em_choices[k] = conversion.ensure_tuple(v) # invert the dict, to directly convert the emission to the position value self._emission_to_idx = {v: k for k, v in em_choices.items()} cur_pos = em_filter.position.value["band"] current_em = em_choices[cur_pos] if isinstance(current_em[0], collections.Iterable): # if multiband => pick the first one em_band = current_em[0] else: em_band = current_em center_em = fluo.get_center(em_band) exc_choices = set(emitter.spectra.value) current_exc = self._get_current_excitation() if current_exc is None: # pick the closest below the current emission current_exc = min(exc_choices, key=lambda b: b[2]) # default to the smallest for b in exc_choices: # Works because exc_choices only contains 5-float tuples if (b[2] < center_em and center_em - b[2] < center_em - current_exc[2]): current_exc = b logging.debug("Guessed excitation is %s, based on emission %s", current_exc, current_em) self.excitation = model.VAEnumerated(current_exc, choices=exc_choices, unit="m") self.excitation.subscribe(self.onExcitation) # The wavelength band on the out path (set when emission changes) self.emission = model.VAEnumerated(current_em, choices=set(em_choices.values()), unit="m") self.emission.subscribe(self.onEmission) # colouration of the image self.tint.value = conversion.wave2rgb(center_em)