diff --git a/hexrd/ui/indexing/fit_grains_options_dialog.py b/hexrd/ui/indexing/fit_grains_options_dialog.py index 6f9d1d668..590484654 100644 --- a/hexrd/ui/indexing/fit_grains_options_dialog.py +++ b/hexrd/ui/indexing/fit_grains_options_dialog.py @@ -17,6 +17,7 @@ class FitGrainsOptionsDialog(QObject): accepted = Signal() rejected = Signal() + grains_table_modified = Signal() def __init__(self, grains_table, parent=None): super().__init__(parent) @@ -43,6 +44,7 @@ def __init__(self, grains_table, parent=None): view = self.ui.grains_table_view view.data_model = self.data_model view.material = self.material + view.can_modify_grains = True ok_button = self.ui.button_box.button(QDialogButtonBox.Ok) ok_button.setText('Fit Grains') @@ -84,6 +86,9 @@ def setup_connections(self): HexrdConfig().materials_dict_modified.connect(self.update_materials) + self.data_model.grains_table_modified.connect( + self.on_grains_table_modified) + def all_widgets(self): """Only includes widgets directly related to config parameters""" widgets = [ @@ -338,3 +343,7 @@ def set_working_dir(self): if d: self.spots_path = d + + def on_grains_table_modified(self): + self.grains_table = self.data_model.full_grains_table + self.grains_table_modified.emit() diff --git a/hexrd/ui/indexing/fit_grains_results_dialog.py b/hexrd/ui/indexing/fit_grains_results_dialog.py index 345192501..08b1b14ab 100644 --- a/hexrd/ui/indexing/fit_grains_results_dialog.py +++ b/hexrd/ui/indexing/fit_grains_results_dialog.py @@ -70,6 +70,11 @@ def __init__(self, data, material=None, parent=None): self.load_cmaps() self.reset_glyph_size(update_plot=False) + self.add_extra_data_columns() + + self.setup_gui() + + def add_extra_data_columns(self): # Add columns for equivalent strain and hydrostatic strain eqv_strain = np.zeros(self.num_grains) hydrostatic_strain = np.zeros(self.num_grains) @@ -82,8 +87,6 @@ def __init__(self, data, material=None, parent=None): self.data = np.hstack((self.data, eqv_strain[:, np.newaxis])) self.data = np.hstack((self.data, hydrostatic_strain[:, np.newaxis])) - self.setup_gui() - def setup_gui(self): self.update_selectors() self.setup_plot() @@ -313,6 +316,9 @@ def setup_connections(self): self.ui.convert_strain_to_stress.toggled.connect( self.convert_strain_to_stress_toggled) + self.data_model.grains_table_modified.connect( + self.on_grains_table_modified) + def setup_plot(self): # Create the figure and axes to use canvas = FigureCanvas(Figure(tight_layout=True)) @@ -465,6 +471,7 @@ def setup_tableview(self): # Update the variables on the table view view.data_model = self.data_model view.material = self.material + view.can_modify_grains = True def show(self): self.ui.show() @@ -571,6 +578,12 @@ def reset_glyph_size(self, update_plot=True): def draw_idle(self): self.canvas.draw_idle() + def on_grains_table_modified(self): + # Update our grains table + self.data = self.data_model.full_grains_table + self.add_extra_data_columns() + self.update_plot() + if __name__ == '__main__': from PySide2.QtCore import QCoreApplication diff --git a/hexrd/ui/indexing/grains_table_model.py b/hexrd/ui/indexing/grains_table_model.py index af216dcdc..53702f280 100644 --- a/hexrd/ui/indexing/grains_table_model.py +++ b/hexrd/ui/indexing/grains_table_model.py @@ -1,11 +1,13 @@ import numpy as np -from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt +from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt, Signal class GrainsTableModel(QAbstractTableModel): """Model for viewing grains""" + grains_table_modified = Signal() + def __init__(self, grains_table, excluded_columns=None, parent=None): super().__init__(parent) self.full_grains_table = grains_table @@ -23,6 +25,9 @@ def __init__(self, grains_table, excluded_columns=None, parent=None): self.excluded_columns = excluded_columns if excluded_columns else [] + self.regenerate_grains_table() + + def regenerate_grains_table(self): self.grains_table = self.full_grains_table[:, self.included_columns] self.headers = [self.full_headers[x] for x in self.included_columns] @@ -51,8 +56,37 @@ def rowCount(self, parent=QModelIndex()): return len(self.grains_table) + def removeRows(self, row, count, parent): + while count > 0: + self.full_grains_table = np.delete(self.full_grains_table, row, + axis=0) + count -= 1 + + self.regenerate_grains_table() + + return True + # Custom methods + def delete_grains(self, grain_ids): + any_modified = False + for grain_id in grain_ids: + to_delete = np.where(self.full_grains_table[:, 0] == grain_id)[0] + if to_delete.size == 0: + continue + + self.remove_rows(to_delete) + any_modified = True + + if any_modified: + self.grains_table_modified.emit() + + def remove_rows(self, rows): + for row in rows: + self.beginRemoveRows(QModelIndex(), row, row) + self.removeRow(row) + self.endRemoveRows() + @property def included_columns(self): return [i for i in range(len(self.full_headers)) diff --git a/hexrd/ui/indexing/grains_table_view.py b/hexrd/ui/indexing/grains_table_view.py index 99551a7e4..e08422c54 100644 --- a/hexrd/ui/indexing/grains_table_view.py +++ b/hexrd/ui/indexing/grains_table_view.py @@ -2,7 +2,7 @@ from PySide2.QtCore import QSortFilterProxyModel, Qt, Signal from PySide2.QtGui import QCursor -from PySide2.QtWidgets import QMenu, QTableView +from PySide2.QtWidgets import QMenu, QMessageBox, QTableView from hexrd.ui.async_runner import AsyncRunner from hexrd.ui.hexrd_config import HexrdConfig @@ -27,6 +27,7 @@ def __init__(self, parent=None): self.material = None self.pull_spots_allowed = True + self.can_modify_grains = False self._data_model = None self._tolerances = [] self.selected_tol_id = -1 @@ -47,6 +48,10 @@ def add_actions(d): if self.can_run_pull_spots: add_actions({'Visualize Spots': self.pull_spots}) + if self.can_modify_grains and self.num_selected_grains > 0: + suffix = 's' if self.num_selected_grains > 1 else '' + add_actions({f'Delete Grain{suffix}': self.delete_selected_grains}) + if not actions: return super().contextMenuEvent(event) @@ -98,6 +103,10 @@ def selected_grains(self): return self.grains_table[grain_ids] + @property + def num_selected_grains(self): + return len(self.selected_grain_ids) + @property def can_run_pull_spots(self): return ( @@ -127,6 +136,10 @@ def tolerances(self): def tolerances(self, v): self._tolerances = v + @property + def num_grains(self): + return len(self.data_model.grains_table) + def select_tolerance_id(self): tolerances = self.tolerances if len(tolerances) == 1: @@ -150,6 +163,16 @@ def select_tolerance_id(self): self.selected_tol_id = dialog.selected_row return True + def delete_selected_grains(self): + if self.num_selected_grains == self.num_grains: + # Don't let the user delete all of the grains + msg = 'Cannot delete all grains' + print(msg) + QMessageBox.critical(self, 'HEXRD', msg) + return + + self.data_model.delete_grains(self.selected_grain_ids) + def pull_spots(self): if not self.select_tolerance_id(): # User canceled diff --git a/hexrd/ui/indexing/run.py b/hexrd/ui/indexing/run.py index cbb831a77..f158ec7c9 100644 --- a/hexrd/ui/indexing/run.py +++ b/hexrd/ui/indexing/run.py @@ -400,6 +400,12 @@ def view_fit_grains_options(self): dialog = FitGrainsOptionsDialog(self.grains_table, self.parent) dialog.accepted.connect(self.fit_grains_options_accepted) dialog.rejected.connect(self.clear) + + def on_grains_table_modified(): + # Update our grains table + self.grains_table = dialog.grains_table + + dialog.grains_table_modified.connect(on_grains_table_modified) self.fit_grains_options_dialog = dialog dialog.show()