def test_hlog_function(self): n = 1000 _xmax = 2 ** 18 # max machine value _ymax = 10 ** 4 # max display value _xpos = np.logspace(-3, np.log10(_xmax), n) _xneg = -_xpos[::-1] _xall = np.r_[_xneg, _xpos] _ypos = np.logspace(-3, np.log10(_ymax), n) _yneg = -_ypos[::-1] _yall = np.r_[_yneg, _ypos] hlpos = hlog(_xpos) hlneg = hlog(_xneg) assert_almost_equal((hlpos[-1] - _ymax) / _ymax, 0, decimal=2) assert_almost_equal(hlpos, -hlneg[::-1]) # check symmetry # test that values get larger as b decreases hlpos10 = hlog(_xpos, b=10) self.assertTrue(np.all(hlpos10 >= hlpos)) # check that converges to tlog for large values tlpos = tlog(_xpos) i = np.where(_xpos > 1e4)[0] tlpos_large = tlpos[i] hlpos_large = hlpos10[i] d = (hlpos_large - tlpos_large) / hlpos_large assert_almost_equal(d, np.zeros(len(d)), decimal=2)
def estimate(self, experiment, subset = None): """ Estimate the bleedthrough from the single-channel controls in `controls` """ if not experiment: raise CytoflowOpError("No experiment specified") if self.num_knots < 3: raise CytoflowOpError("Need to allow at least 3 knots in the spline") self._channels = self.controls.keys() for channel in self._channels: try: tube_meta = fcsparser.parse(self.controls[channel], meta_data_only = True, reformat_meta = True) tube_channels = tube_meta["_channels_"].set_index("$PnN") except Exception as e: raise CytoflowOpError("FCS reader threw an error on tube {0}: {1}"\ .format(self.controls[channel], e.value)) for channel in self._channels: exp_v = experiment.metadata[channel]['voltage'] if not "$PnV" in tube_channels.ix[channel]: raise CytoflowOpError("Didn't find a voltage for channel {0}" "in tube {1}".format(channel, self.controls[channel])) control_v = tube_channels.ix[channel]["$PnV"] if control_v != exp_v: raise CytoflowOpError("Voltage differs for channel {0} in tube {1}" .format(channel, self.controls[channel])) self._splines = {} mesh_axes = [] for channel in self._channels: self._splines[channel] = {} try: tube_meta, tube_data = fcsparser.parse(self.controls[channel], reformat_meta = True) tube_channels = tube_meta["_channels_"].set_index("$PnN") except Exception as e: raise CytoflowOpError("FCS reader threw an error on tube {0}: {1}"\ .format(self.controls[channel], e.value)) data = tube_data.sort(channel) for af_channel in self._channels: if 'af_median' in experiment.metadata[af_channel]: data[af_channel] = data[af_channel] - \ experiment.metadata[af_channel]['af_median'] channel_min = data[channel].min() channel_max = data[channel].max() # we're going to set the knots and splines evenly across the hlog- # transformed data, so as to capture both the "linear" aspect # of near-0 and negative values, and the "log" aspect of large # values # parameterize the hlog transform r = experiment.metadata[channel]['range'] # instrument range d = np.log10(r) # maximum display scale, in decades # the transition point from linear --> log scale # use half of the log-transformed scale as "linear". b = 2 ** (np.log2(r) / 2) # the splines' knots knot_min = channel_min knot_max = channel_max hlog_knot_min, hlog_knot_max = \ hlog((knot_min, knot_max), b = b, r = r, d = d) hlog_knots = np.linspace(hlog_knot_min, hlog_knot_max, self.num_knots) knots = hlog_inv(hlog_knots, b = b, r = r, d = d) # only keep the interior knots knots = knots[1:-1] # the interpolators' mesh mesh_min = -3 * experiment.metadata[channel]['af_stdev'] mesh_max = r hlog_mesh_min, hlog_mesh_max = \ hlog((mesh_min, mesh_max), b = b, r = r, d = d) hlog_mesh_axis = \ np.linspace(hlog_mesh_min, hlog_mesh_max, self.mesh_size) mesh_axis = hlog_inv(hlog_mesh_axis, b = b, r = r, d = d) mesh_axes.append(mesh_axis) for to_channel in self._channels: from_channel = channel if from_channel == to_channel: continue self._splines[from_channel][to_channel] = \ scipy.interpolate.LSQUnivariateSpline(data[from_channel].values, data[to_channel].values, t = knots, k = 1) mesh = pandas.DataFrame(cartesian(mesh_axes), columns = [x for x in self._channels]) mesh_corrected = mesh.apply(_correct_bleedthrough, axis = 1, args = ([[x for x in self._channels], self._splines])) for channel in self._channels: chan_values = np.reshape(mesh_corrected[channel], [len(x) for x in mesh_axes]) self._interpolators[channel] = \ scipy.interpolate.RegularGridInterpolator(mesh_axes, chan_values)