def as_ctrait(thandler): if hasattr(thandler, 'as_ctrait'): return thandler.as_ctrait() if hasattr(thandler, 'aType'): ttype = thandler.aType elif hasattr(thandler, 'aClass'): ttype = thandler.aClass else: ttype = thandler if isinstance(ttype, type): if ttype.__name__ == 'str': ttype = traits.Str() elif ttype.__name__ == 'bytes': ttype = traits.Bytes() elif ttype.__name__ == 'unicode': ttype = traits.Unicode() #else: #ttype = ttype() if hasattr(ttype, 'as_ctrait'): ttype = ttype.as_ctrait() return ttype
class Signal1DCalibration(SpanSelectorInSignal1D): left_value = t.Float(t.Undefined, label='New left value') right_value = t.Float(t.Undefined, label='New right value') offset = t.Float() scale = t.Float() units = t.Unicode() def __init__(self, signal): super(Signal1DCalibration, self).__init__(signal) if signal.axes_manager.signal_dimension != 1: raise SignalDimensionError( signal.axes_manager.signal_dimension, 1) self.units = self.axis.units self.scale = self.axis.scale self.offset = self.axis.offset self.last_calibration_stored = True def _left_value_changed(self, old, new): if self.span_selector is not None and \ self.span_selector.range is None: return else: self._update_calibration() def _right_value_changed(self, old, new): if self.span_selector.range is None: return else: self._update_calibration() def _update_calibration(self, *args, **kwargs): # If the span selector or the new range values are not defined do # nothing if np.isnan(self.ss_left_value) or np.isnan(self.ss_right_value) or\ t.Undefined in (self.left_value, self.right_value): return lc = self.axis.value2index(self.ss_left_value) rc = self.axis.value2index(self.ss_right_value) self.offset, self.scale = self.axis.calibrate( (self.left_value, self.right_value), (lc, rc), modify_calibration=False) def apply(self): if np.isnan(self.ss_left_value) or np.isnan(self.ss_right_value): _logger.warning("Select a range by clicking on the signal figure " "and dragging before pressing Apply.") return elif self.left_value is t.Undefined or self.right_value is t.Undefined: _logger.warning("Select the new left and right values before " "pressing apply.") return axis = self.axis axis.scale = self.scale axis.offset = self.offset axis.units = self.units self.span_selector_switch(on=False) self.signal._replot() self.span_selector_switch(on=True) self.last_calibration_stored = True
class SubSet(_traits.HasTraits): '''FIXME: deprecated by Level''' id = _traits.Str() name = _traits.Unicode() # Index label list row_selector = _traits.List() # col_selector = _traits.List(_traits.Int()) gr_style = VisualStyle()
class Signal1DCalibration(SpanSelectorInSignal1D): left_value = t.Float(label='New left value') right_value = t.Float(label='New right value') offset = t.Float() scale = t.Float() units = t.Unicode() view = tu.View(tu.Group( 'left_value', 'right_value', tu.Item('ss_left_value', label='Left', style='readonly'), tu.Item('ss_right_value', label='Right', style='readonly'), tu.Item(name='offset', style='readonly'), tu.Item(name='scale', style='readonly'), 'units', ), handler=CalibrationHandler, buttons=[OKButton, OurApplyButton, CancelButton], kind='live', title='Calibration parameters') def __init__(self, signal): super(Signal1DCalibration, self).__init__(signal) if signal.axes_manager.signal_dimension != 1: raise SignalDimensionError(signal.axes_manager.signal_dimension, 1) self.units = self.axis.units self.last_calibration_stored = True def _left_value_changed(self, old, new): if self.span_selector is not None and \ self.span_selector.range is None: messages.information('Please select a range in the spectrum figure' 'by dragging the mouse over it') return else: self._update_calibration() def _right_value_changed(self, old, new): if self.span_selector.range is None: messages.information('Please select a range in the spectrum figure' 'by dragging the mouse over it') return else: self._update_calibration() def _update_calibration(self, *args, **kwargs): if self.left_value == self.right_value: return lc = self.axis.value2index(self.ss_left_value) rc = self.axis.value2index(self.ss_right_value) self.offset, self.scale = self.axis.calibrate( (self.left_value, self.right_value), (lc, rc), modify_calibration=False)
class DataSet(_traits.HasTraits): '''Data set for holding one matrix and associated metadata The reccomended access methods as properties for the DataSet object: * id: An identity string that is unique for each object * display_name: An human friendly name that for the datataset * kind: The data set type * missing_data: Boolean value indicatin if the data set have "holes" * n_vars: Number of variables * n_objs: Number of objects * var_n: List containing variable names * obj_n: List containing object names * values: The matrix values as an 2D Numpy array * mat: The matrix as an Pandas DataFrame ''' mat = _traits.Instance(_pd.DataFrame, ()) _id = _traits.Int() id = _traits.Property() new_id = _itr.count(start=101).next display_name = _traits.Unicode('Unnamed data set') kind = _traits.Enum(DS_TYPES) # FIXME: Only color style = _traits.Instance('VisualStyle', ()) # Example: {'species': [SubSet, SubSet], 'location': [SubSet, SubSet]} # Column subsets subs = _traits.Dict(_traits.Unicode, _traits.List) # Row subsets rsubs = _traits.Dict(_traits.Unicode, _traits.List) row_factors = _traits.List() col_factors = _traits.List() # FIXME: This data set has missing data # do you want to do somthing about it? # * throw rows/cols with missing data # * do imputation missing_data = _traits.Property(_traits.Bool) n_vars = _traits.Property() n_objs = _traits.Property() var_n = _traits.Property() obj_n = _traits.Property() values = _traits.Property() # FIXME: This is a dubious solution matcat = _traits.Instance(_pd.DataFrame) valuescat = _traits.Property() def _get_values(self): if self.missing_data: return _np.ma.masked_invalid(self.mat.values) else: return self.mat.values def _make_matcat(self): matcat = self.mat.copy() for cn, ssl in self.subs.items(): cs = _pd.Series(index=self.mat.index) for ss in ssl: cs[list(ss.row_selector)] = ss.id matcat[cn] = cs for cn, ssl in self.rsubs.items(): cs = _pd.Series(index=self.mat.index) for ss in ssl: cs[list(ss.row_selector)] = ss.id matcat[cn] = cs self.matcat = matcat def _get_valuescat(self): try: return self.matcat.values except AttributeError: # self._make_matcat() return self.matcat.values def _get_n_vars(self): return self.mat.shape[1] def _get_n_objs(self): return self.mat.shape[0] def _get_var_n(self): return list(self.mat.columns) def _get_obj_n(self): return list(self.mat.index) def __id_default(self): return DataSet.new_id() def __eq__(self, other): return self.id == other def __ne__(self, other): return self.id != other def _get_id(self): return str(self._id) def _get_missing_data(self): # FIXME: I must look more into this try: return _np.any(_np.isnan(self.mat.values)) except TypeError: return False def get_subset_groups(self): return self.subs.keys() def get_subsets(self, group): return self.subs[group] def get_subset_rows(self, subset): ''' Return a subset from given subset id''' return self.mat.loc[list(subset.row_selector)] def copy(self, transpose=False): new = self.clone_traits(traits=['display_name', 'kind', 'style', 'subs']) if transpose: tmp = self.mat.copy() new.mat = tmp.transpose() else: new.mat = self.mat.copy() return new
class Factor(_traits.HasTraits): '''Represent different factors as independent variables FIXME: is the order of levels important, the uniqueness? looks more like a mapping type than a sequences type ''' name = _traits.Unicode() levels = _traits.Dict(_traits.Unicode, Level) # Can be used to check if this can be used for a given dataset size = _traits.Property() _size = _traits.Int() default_ds_axis = _traits.Enum(("row", "col")) def __init__(self, name, size, *levels, **kwargs): '''Create a factor object name: The factor name levels: none, one or several level objects check_idx: check index strategy; no, toss_overlaping ''' check_idx = kwargs.pop('check_idx', "no") super(Factor, self).__init__(name=name, size=size, **kwargs) for level in levels: self.add_level(level, check_idx) def add_level(self, level, check_idx="no"): '''Add level level: a level object check_idx: "no", "toss_overlaping", "excpet_overlapping", "return_overlapping" ''' self.name_check(level.name) self.bound_check(level.selector) if check_idx == "no": self.levels[level.name] = level elif check_idx == "toss_overlaping": self.toss_overlaping(level) self.levels[level.name] = level else: msg = "Not valid value for check_idx: {0}".format(check_idx) raise ValueError(msg) def name_check(self, new_name): if new_name in self.levels: msg = "Level name collision. Name: {0} already exist in factor: {1}".format( new_name, self.name) raise ValueError(msg) def bound_check(self, selector): if self.size <= max(selector): msg = "Index in level out of bounds" raise IndexError(msg) def toss_overlaping(self, level): ''' FIXME: This will mainpulate an existing object. Is that unproblematic? ''' existing_idx = [] for lv in self.levels.itervalues(): existing_idx.extend(lv.selector) exist = set(existing_idx) unique = set(level.selector).difference(exist) level.selector = list(unique) def get_values(self, dataset, name, axis=None): '''Return numpy subarray ''' idx = self.levels[name].selector if axis is not None: if axis == 0: return dataset.mat.values[idx,:] elif axis == 1: return dataset.mat.values[:,idx] raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": return dataset.mat.values[idx,:] else: return dataset.mat.values[:,idx] def get_labels(self, dataset, name, axis=None): '''Return list of selected labels ''' idx = self.levels[name].selector if axis is not None: if axis == 0: return dataset.mat.index[idx] elif axis == 1: return dataset.mat.columns[idx] raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": return dataset.mat.index[idx] else: return dataset.mat.columns[idx] def _get_all_leveled(self): '''The index combined from all the levels ''' return list(_itr.chain.from_iterable([lv.selector for lv in self.levels.itervalues()])) def get_combined_levels_subset(self, dataset, axis=None): '''Return numpy subarray ''' sub_ds = dataset.copy() idx = self._get_all_leveled() if axis is not None: if axis == 0: sub_ds.mat = dataset.mat.iloc[idx,:] return sub_ds elif axis == 1: sub_ds.mat = dataset.mat.iloc[:,idx] return sub_ds raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": sub_ds.mat = dataset.mat[idx,:] return sub_ds else: sub_ds.mat = dataset.mat[:,idx] return sub_ds def get_combined_levels_values(self, dataset, axis=None): '''Return numpy subarray ''' idx = self._get_all_leveled() if axis is not None: if axis == 0: return dataset.mat.values[idx,:] elif axis == 1: return dataset.mat.values[:,idx] raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": return dataset.mat.values[idx,:] else: return dataset.mat.values[:,idx] def get_combined_levels_labels(self, dataset, axis=None): '''Return list of all selected labels ''' idx = self._get_all_leveled() if axis is not None: if axis == 0: return dataset.mat.index[idx] elif axis == 1: return dataset.mat.columns[idx] raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": return dataset.mat.index[idx] else: return dataset.mat.columns[idx] def _get_nonleveled(self, dataset, axis): '''The indexes for a dataset that is not in a level ''' lvs = self._get_all_leveled() return list(set(range(dataset.mat.shape[axis])).difference(set(lvs))) def get_rest_values(self, dataset, axis=None): '''Return numpy subarray ''' if axis is not None: if axis == 0: idx = self._get_nonleveled(dataset, 0) return dataset.mat.values[idx,:] elif axis == 1: idx = self._get_nonleveled(dataset, 1) return dataset.mat.values[:,idx] raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": idx = self._get_nonleveled(dataset, 0) return dataset.mat.values[idx,:] else: idx = self._get_nonleveled(dataset, 1) return dataset.mat.values[:,idx] def get_rest_labels(self, dataset, axis=None): '''Return list of not selected labels ''' if axis is not None: if axis == 0: idx = self._get_nonleveled(dataset, 0) return dataset.mat.index[idx] elif axis == 1: idx = self._get_nonleveled(dataset, 1) return dataset.mat.columns[idx] raise ValueError('Illegale value for axis') else: if self.default_ds_axis == "row": idx = self._get_nonleveled(dataset, 0) return dataset.mat.index[idx] else: idx = self._get_nonleveled(dataset, 1) return dataset.mat.columns[idx] def __len__(self): return len(self.levels) # def __getitem__(self, key): # pass # def __setitem__(self, key, value): # pass # def __iter__(self): # pass def _set_size(self, sz): self._size = sz def _get_size(self): return self._size
class Level(_traits.HasTraits): '''Represent a level in a factor If we have gender as a factor, the levels can be for instance male or female. If we have a age group factor, the levels can bel for instance 1, 2, 3. ''' # Require name name = _traits.Unicode() # Accept list of integers or numpy vector (1 dim array) that we convert to list selector = _traits.List(_traits.Int) # Autoasign unique style if style is not explicit specified # style = VisualStyle() color = ColorTrait() def __init__(self, idx, name, color=None): '''Create level group idx: list of numerical indexes to make selection from matrix name: name for this group style: color tuple (r, g, b, a) to color this level in plots ''' self.selector = list(idx) self.name = name if color is None: self.color = from_palette() else: self.color = color def get_values(self, dataset, axis=0): '''Get selected row or columns values dataset: the dataset to get from axis: 0 - vertical, columns labels, 1 - horizontal, row labels ''' if axis == 0: return dataset.mat[self.selector,:] elif axis == 1: return dataset.mat[:,self.selector] raise ValueError('Illegale value for axis') def get_labels(self, dataset, axis=0): '''Get selected row or columns labels dataset: the dataset to get from axis: 0 - vertical, columns labels, 1 - horizontal, row labels ''' if axis == 0: return dataset.mat.index[self.selector] elif axis == 1: return dataset.mat.columns[:,self.selector] raise ValueError('Illegale value for axis') def __eq__(self, other): return self.name == other.name def __ne__(self, other): return self.name != other.name