def test_remove_column(self): mc = MarkedColumns() mc.add_y(4) mc.add_x(3) ec = ErrorColumn(column=2, related_y_column=6) mc.add_y_err(ec) self.assertEqual(1, len(mc.as_x)) self.assertEqual(1, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) mc.remove(4) self.assertEqual(0, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) self.assertEqual(1, len(mc.as_x)) mc.remove(3) self.assertEqual(0, len(mc.as_x)) self.assertEqual(0, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) mc.remove(2) self.assertEqual(0, len(mc.as_x)) self.assertEqual(0, len(mc.as_y)) self.assertEqual(0, len(mc.as_y_err))
def test_remove_column(self): mc = MarkedColumns() mc.add_y(4) mc.add_x(3) ec = ErrorColumn(column=2, related_y_column=6, label_index=0) mc.add_y_err(ec) self.assertEqual(1, len(mc.as_x)) self.assertEqual(1, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) mc.remove(4) self.assertEqual(0, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) self.assertEqual(1, len(mc.as_x)) mc.remove(3) self.assertEqual(0, len(mc.as_x)) self.assertEqual(0, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) mc.remove(2) self.assertEqual(0, len(mc.as_x)) self.assertEqual(0, len(mc.as_y)) self.assertEqual(0, len(mc.as_y_err))
def test_build_labels_y_with_only_some_having_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y_err(ErrorColumn(2,1)) expected = [(0, '[Y0]'), (1, '[Y1]'), (2, '[Y1_YErr]')] self.assertEqual(expected, mc.build_labels())
def test_fail_to_add_yerr_for_another_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) mc.add_y_err(ErrorColumn(1, 0)) expected = [(0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]'), (1, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) self.assertRaises(ValueError, lambda: mc.add_y_err(ErrorColumn(0, 1)))
def test_fail_to_add_yerr_for_another_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) mc.add_y_err(ErrorColumn(1, 0, 0)) expected = [(0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]'), (1, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) self.assertRaises(ValueError, lambda: mc.add_y_err(ErrorColumn(0, 1, 2)))
def test_build_labels_y_and_yerr_change_middle(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) # change one of the columns to YErr mc.add_y_err(ErrorColumn(1, 0)) expected = [(0, '[Y0]'), (2, '[Y1]'), (1, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) # change the last Y column to YErr mc.add_y_err(ErrorColumn(2, 0)) expected = [(0, '[Y0]'), (2, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels())
def test_build_labels_y_and_yerr_change_middle(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) # change one of the columns to YErr mc.add_y_err(ErrorColumn(1, 0, 0)) expected = [(0, '[Y0]'), (2, '[Y1]'), (1, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) # change the last Y column to YErr mc.add_y_err(ErrorColumn(2, 0, 0)) expected = [(0, '[Y0]'), (2, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels())
def test_build_labels_y_and_yerr_change_first(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) # change one of the columns to YErr mc.add_y_err(ErrorColumn(0, 1, 1)) # note: the first column is being set -> this decreases the label index of all columns to its right by 1 expected = [(1, '[Y0]'), (2, '[Y1]'), (0, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) # change the last Y column to YErr mc.add_y_err(ErrorColumn(2, 1, 0)) expected = [(1, '[Y0]'), (2, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels())
def test_build_labels_y_and_yerr_change_first(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) # change one of the columns to YErr mc.add_y_err(ErrorColumn(0, 1)) # note: the first column is being set -> this decreases the label index of all columns to its right by 1 expected = [(1, '[Y0]'), (2, '[Y1]'), (0, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) # change the last Y column to YErr mc.add_y_err(ErrorColumn(2, 1)) expected = [(1, '[Y0]'), (2, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels())
def test_find_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) mc.add_y_err(ErrorColumn(4, 1, 1)) expected = {1: 4} self.assertEqual(expected, mc.find_yerr([1])) # Replace the Y column, which has an associated YErr. This should remove the YErr as well mc.add_y_err(ErrorColumn(1, 3, 1)) expected = {3: 1} self.assertEqual(expected, mc.find_yerr([0, 1, 2, 3])) mc.add_y_err(ErrorColumn(4, 2, 1)) expected = {2: 4, 3: 1} self.assertEqual(expected, mc.find_yerr([0, 1, 2, 3]))
def test_find_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) mc.add_y_err(ErrorColumn(4, 1)) expected = {1: 4} self.assertEqual(expected, mc.find_yerr([1])) # Replace the Y column, which has an associated YErr. This should remove the YErr as well mc.add_y_err(ErrorColumn(1, 3)) expected = {3: 1} self.assertEqual(expected, mc.find_yerr([0, 1, 2, 3])) mc.add_y_err(ErrorColumn(4, 2)) expected = {2: 4, 3: 1} self.assertEqual(expected, mc.find_yerr([0, 1, 2, 3]))
def test_build_labels_x_y(self): # TODO test this edge case: mark all columns Y, remove one that is not the last one! mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) # note that the max Y label number will decrease as more Y columns are being changed to X expected = [(0, '[Y0]'), (1, '[Y1]'), (2, '[Y2]'), (3, '[Y3]')] self.assertEqual(expected, mc.build_labels()) expected = [(1, '[X0]'), (0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]')] mc.add_x(1) self.assertEqual(expected, mc.build_labels()) expected = [(1, '[X0]'), (3, '[X1]'), (0, '[Y0]'), (2, '[Y1]')] mc.add_x(3) self.assertEqual(expected, mc.build_labels())
def test_build_labels_x_y_and_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) mc.add_y_err(ErrorColumn(1, 0)) expected = [(0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]'), (1, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) expected = [(1, '[X0]'), (0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]')] mc.add_x(1) self.assertEqual(expected, mc.build_labels()) expected = [(1, '[X0]'), (2, '[Y0]'), (3, '[Y1]'), (0, '[Y1_YErr]')] mc.add_y_err(ErrorColumn(0, 3)) self.assertEqual(expected, mc.build_labels())
def test_build_labels_x_y_and_yerr(self): mc = MarkedColumns() mc.add_y(0) mc.add_y(1) mc.add_y(2) mc.add_y(3) mc.add_y_err(ErrorColumn(1, 0, 0)) expected = [(0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]'), (1, '[Y0_YErr]')] self.assertEqual(expected, mc.build_labels()) expected = [(1, '[X0]'), (0, '[Y0]'), (2, '[Y1]'), (3, '[Y2]')] mc.add_x(1) self.assertEqual(expected, mc.build_labels()) expected = [(1, '[X0]'), (2, '[Y0]'), (3, '[Y1]'), (0, '[Y1_YErr]')] mc.add_y_err(ErrorColumn(0, 3, 2)) self.assertEqual(expected, mc.build_labels())
def test_changing_y_to_none_removes_associated_yerr_columns(self): """ Test to check if a first column is marked as Y, a second column YErr is associated with it, but then the first one is changed to X - the YErr mark should be removed """ mc = MarkedColumns() mc.add_y(4) ec = ErrorColumn(column=2, related_y_column=4, label_index=0) mc.add_y_err(ec) # check that we have both a Y col and an associated YErr self.assertEqual(1, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) mc.remove(4) # changing the column to NONE should have removed it from X, Y and YErr self.assertEqual(0, len(mc.as_x)) self.assertEqual(0, len(mc.as_y)) self.assertEqual(0, len(mc.as_y_err))
def test_changing_y_to_x_removes_associated_yerr_columns(self): """ Test to check if a first column is marked as Y, a second column YErr is associated with it, but then the first one is changed to X - the YErr mark should be removed """ mc = MarkedColumns() mc.add_y(4) ec = ErrorColumn(column=2, related_y_column=4) mc.add_y_err(ec) # check that we have both a Y col and an associated YErr self.assertEqual(1, len(mc.as_y)) self.assertEqual(1, len(mc.as_y_err)) mc.add_x(4) # changing the column to X should have removed it from Y and Yerr self.assertEqual(1, len(mc.as_x)) self.assertEqual(0, len(mc.as_y)) self.assertEqual(0, len(mc.as_y_err)) # check setting the column back to Y does not automatically reinstate the error column mc.add_y(4) self.assertEqual(1, len(mc.as_y)) self.assertEqual(0, len(mc.as_y_err))
class TableWorkspaceDisplayModel: SPECTRUM_PLOT_LEGEND_STRING = '{}-{}' BIN_PLOT_LEGEND_STRING = '{}-bin-{}' ALLOWED_WORKSPACE_TYPES = [PeaksWorkspace, TableWorkspace] @classmethod def supports(cls, ws): """ Checks that the provided workspace is supported by this display. :param ws: Workspace to be checked for support :raises ValueError: if the workspace is not supported """ if not any(isinstance(ws, allowed_type) for allowed_type in cls.ALLOWED_WORKSPACE_TYPES): raise ValueError("The workspace type is not supported: {0}".format(ws)) def __init__(self, ws): """ Initialise the model with the workspace :param ws: Workspace to be used for providing data :raises ValueError: if the workspace is not supported """ self.supports(ws) self.ws = ws self.ws_num_rows = self.ws.rowCount() self.ws_num_cols = self.ws.columnCount() self.marked_columns = MarkedColumns() self._original_column_headers = self.get_column_headers() # loads the types of the columns for col in range(self.ws_num_cols): plot_type = self.ws.getPlotType(col) if plot_type == TableWorkspaceColumnTypeMapping.X: self.marked_columns.add_x(col) elif plot_type == TableWorkspaceColumnTypeMapping.Y: self.marked_columns.add_y(col) elif plot_type == TableWorkspaceColumnTypeMapping.YERR: # mark YErrs only if there are any columns that have been marked as Y # if there are none then do not mark anything as YErr if len(self.marked_columns.as_y) > len(self.marked_columns.as_y_err): # Assume all the YErrs are associated with the first available (no other YErr has it) Y column. # There isn't a way to know the correct Y column, as that information is not stored # in the table workspace - the original table workspace does not associate Y errors # columns with specific Y columns err_for_column = self.marked_columns.as_y[len(self.marked_columns.as_y_err)] label = str(len(self.marked_columns.as_y_err)) self.marked_columns.add_y_err(ErrorColumn(col, err_for_column, label)) def _get_v3d_from_str(self, string): if '[' in string and ']' in string: string = string[1:-1] if ',' in string: return V3D(*[float(x) for x in string.split(',')]) else: raise ValueError("'{}' is not a valid V3D string.".format(string)) def original_column_headers(self): return self._original_column_headers[:] def build_current_labels(self): return self.marked_columns.build_labels() def get_name(self): return self.ws.name() def get_column_headers(self): return self.ws.getColumnNames() def get_column(self, index): return self.ws.column(index) def get_number_of_rows(self): return self.ws_num_rows def get_number_of_columns(self): return self.ws_num_cols def get_column_header(self, index): return self.get_column_headers()[index] def is_peaks_workspace(self): return isinstance(self.ws, PeaksWorkspace) def set_cell_data(self, row, col, data, is_v3d): # if the cell contains V3D data, construct a V3D object # from the string to that it can be properly set if is_v3d: data = self._get_v3d_from_str(data) # The False stops the replace workspace ADS event from being triggered # The replace event causes the TWD model to be replaced, which in turn # deletes the previous table item objects, however this happens # at the same time as we are trying to locally update the data in the # item object itself, which causes a Qt exception that the object has # already been deleted and a crash self.ws.setCell(row, col, data, notify_replace=False) def workspace_equals(self, workspace_name): return self.ws.name() == workspace_name def delete_rows(self, selected_rows): DeleteTableRows(self.ws, selected_rows) def get_statistics(self, selected_columns): stats = StatisticsOfTableWorkspace(self.ws, selected_columns) return stats def sort(self, column_index, sort_ascending): column_name = self.ws.getColumnNames()[column_index] if self.is_peaks_workspace(): SortPeaksWorkspace(InputWorkspace=self.ws, OutputWorkspace=self.ws, ColumnNameToSortBy=column_name, SortAscending=sort_ascending) else: SortTableWorkspace(InputWorkspace=self.ws, OutputWorkspace=self.ws, Columns=column_name, Ascending=sort_ascending)
class TableWorkspaceDisplayModel: SPECTRUM_PLOT_LEGEND_STRING = '{}-{}' BIN_PLOT_LEGEND_STRING = '{}-bin-{}' EDITABLE_COLUMN_NAMES = ['h', 'k', 'l'] ALLOWED_WORKSPACE_TYPES = [ITableWorkspace] @classmethod def supports(cls, ws: ITableWorkspace): """ Checks that the provided workspace is supported by this display. :param ws: Workspace to be checked for support :raises ValueError: if the workspace is not supported """ if not any( isinstance(ws, allowed_type) for allowed_type in cls.ALLOWED_WORKSPACE_TYPES): raise ValueError( "The workspace type is not supported: {0}".format(ws)) def __init__(self, ws: ITableWorkspace): """ Initialise the model with the workspace :param ws: Workspace to be used for providing data :raises ValueError: if the workspace is not supported """ self.supports(ws) self.ws: ITableWorkspace = ws self.ws_num_rows = self.ws.rowCount() self.ws_num_cols = self.ws.columnCount() self.marked_columns = MarkedColumns() self._original_column_headers = self.get_column_headers() # loads the types of the columns for col in range(self.ws_num_cols): plot_type = self.ws.getPlotType(col) if plot_type == TableWorkspaceColumnTypeMapping.X: self.marked_columns.add_x(col) elif plot_type == TableWorkspaceColumnTypeMapping.Y: self.marked_columns.add_y(col) elif plot_type == TableWorkspaceColumnTypeMapping.YERR: err_for_column = self.ws.getLinkedYCol(col) if err_for_column >= 0: self.marked_columns.add_y_err( ErrorColumn(col, err_for_column)) def _get_v3d_from_str(self, string): if '[' in string and ']' in string: string = string[1:-1] if ',' in string: return V3D(*[float(x) for x in string.split(',')]) else: raise ValueError("'{}' is not a valid V3D string.".format(string)) def original_column_headers(self): return self._original_column_headers[:] def build_current_labels(self): return self.marked_columns.build_labels() def get_name(self): return self.ws.name() def get_column_headers(self): return self.ws.getColumnNames() def get_column(self, index): return self.ws.column(index) def get_cell(self, row, column): return self.ws.cell(row, column) def get_number_of_rows(self): return self.ws_num_rows def get_number_of_columns(self): return self.ws_num_cols def get_column_header(self, index): return self.get_column_headers()[index] def is_editable_column(self, icol): if self.is_peaks_workspace(): return self.ws.getColumnNames()[icol] in self.EDITABLE_COLUMN_NAMES else: return not self.ws.isColumnReadOnly(icol) def is_peaks_workspace(self): return isinstance(self.ws, IPeaksWorkspace) def set_cell_data(self, row, col, data, is_v3d): if self.is_peaks_workspace(): p = self.ws.getPeak(row) if self.ws.getColumnNames()[col] == "h": p.setH(data) elif self.ws.getColumnNames()[col] == "k": p.setK(data) elif self.ws.getColumnNames()[col] == "l": p.setL(data) else: # if the cell contains V3D data, construct a V3D object # from the string to that it can be properly set if is_v3d: data = self._get_v3d_from_str(data) # The False stops the replace workspace ADS event from being triggered # The replace event causes the TWD model to be replaced, which in turn # deletes the previous table item objects, however this happens # at the same time as we are trying to locally update the data in the # item object itself, which causes a Qt exception that the object has # already been deleted and a crash self.ws.setCell(row, col, data, notify_replace=False) def workspace_equals(self, workspace_name): return self.ws.name() == workspace_name def delete_rows(self, selected_rows): from mantid.simpleapi import DeleteTableRows DeleteTableRows(self.ws, selected_rows) def get_statistics(self, selected_columns): from mantid.simpleapi import StatisticsOfTableWorkspace stats = StatisticsOfTableWorkspace(self.ws, selected_columns) return stats def sort(self, column_index, sort_ascending): from mantid.simpleapi import SortPeaksWorkspace, SortTableWorkspace column_name = self.ws.getColumnNames()[column_index] if self.is_peaks_workspace(): SortPeaksWorkspace(InputWorkspace=self.ws, OutputWorkspace=self.ws, ColumnNameToSortBy=column_name, SortAscending=sort_ascending) else: SortTableWorkspace(InputWorkspace=self.ws, OutputWorkspace=self.ws, Columns=column_name, Ascending=sort_ascending) def set_column_type(self, col, type, linked_col_index=-1): self.ws.setPlotType(col, type, linked_col_index)
class TableWorkspaceDisplayModel: SPECTRUM_PLOT_LEGEND_STRING = '{}-{}' BIN_PLOT_LEGEND_STRING = '{}-bin-{}' ALLOWED_WORKSPACE_TYPES = [PeaksWorkspace, TableWorkspace] @classmethod def supports(cls, ws): """ Checks that the provided workspace is supported by this display. :param ws: Workspace to be checked for support :raises ValueError: if the workspace is not supported """ if not any( isinstance(ws, allowed_type) for allowed_type in cls.ALLOWED_WORKSPACE_TYPES): raise ValueError( "The workspace type is not supported: {0}".format(ws)) def __init__(self, ws): """ Initialise the model with the workspace :param ws: Workspace to be used for providing data :raises ValueError: if the workspace is not supported """ self.supports(ws) self.ws = ws self.ws_num_rows = self.ws.rowCount() self.ws_num_cols = self.ws.columnCount() self.marked_columns = MarkedColumns() self._original_column_headers = self.get_column_headers() # loads the types of the columns for col in range(self.ws_num_cols): plot_type = self.ws.getPlotType(col) if plot_type == TableWorkspaceColumnTypeMapping.X: self.marked_columns.add_x(col) elif plot_type == TableWorkspaceColumnTypeMapping.Y: self.marked_columns.add_y(col) elif plot_type == TableWorkspaceColumnTypeMapping.YERR: # mark YErrs only if there are any columns that have been marked as Y # if there are none then do not mark anything as YErr if len(self.marked_columns.as_y) > len( self.marked_columns.as_y_err): # Assume all the YErrs are associated with the first available (no other YErr has it) Y column. # There isn't a way to know the correct Y column, as that information is not stored # in the table workspace - the original table workspace does not associate Y errors # columns with specific Y columns err_for_column = self.marked_columns.as_y[len( self.marked_columns.as_y_err)] label = str(len(self.marked_columns.as_y_err)) self.marked_columns.add_y_err( ErrorColumn(col, err_for_column, label)) def _get_v3d_from_str(self, string): if '[' in string and ']' in string: string = string[1:-1] if ',' in string: return V3D(*[float(x) for x in string.split(',')]) else: raise ValueError("'{}' is not a valid V3D string.".format(string)) def original_column_headers(self): return self._original_column_headers[:] def build_current_labels(self): return self.marked_columns.build_labels() def get_name(self): return self.ws.name() def get_column_headers(self): return self.ws.getColumnNames() def get_column(self, index): return self.ws.column(index) def get_number_of_rows(self): return self.ws_num_rows def get_number_of_columns(self): return self.ws_num_cols def get_column_header(self, index): return self.get_column_headers()[index] def is_peaks_workspace(self): return isinstance(self.ws, PeaksWorkspace) def set_cell_data(self, row, col, data, is_v3d): # if the cell contains V3D data, construct a V3D object # from the string to that it can be properly set if is_v3d: data = self._get_v3d_from_str(data) # The False stops the replace workspace ADS event from being triggered # The replace event causes the TWD model to be replaced, which in turn # deletes the previous table item objects, however this happens # at the same time as we are trying to locally update the data in the # item object itself, which causes a Qt exception that the object has # already been deleted and a crash self.ws.setCell(row, col, data, notify_replace=False) def workspace_equals(self, workspace_name): return self.ws.name() == workspace_name def delete_rows(self, selected_rows): DeleteTableRows(self.ws, selected_rows) def get_statistics(self, selected_columns): stats = StatisticsOfTableWorkspace(self.ws, selected_columns) return stats def sort(self, column_index, sort_ascending): column_name = self.ws.getColumnNames()[column_index] if self.is_peaks_workspace(): SortPeaksWorkspace(InputWorkspace=self.ws, OutputWorkspace=self.ws, ColumnNameToSortBy=column_name, SortAscending=sort_ascending) else: SortTableWorkspace(InputWorkspace=self.ws, OutputWorkspace=self.ws, Columns=column_name, Ascending=sort_ascending)