diff --git a/nmrpy/data_objects.py b/nmrpy/data_objects.py index a0eb6bf..ddf3c98 100644 --- a/nmrpy/data_objects.py +++ b/nmrpy/data_objects.py @@ -361,8 +361,8 @@ def identities(self): @identities.setter def identities(self, identities): if identities is not None: - if not Fid._is_flat_iter(identities): - raise AttributeError("identitites must be a flat iterable") + # if not Fid._is_flat_iter(identities): + # raise AttributeError("identitites must be a flat iterable") if not all(isinstance(i, str) for i in identities): raise AttributeError("identities must be strings") self._identitites = numpy.array(identities) @@ -931,6 +931,12 @@ def clear_ranges(self): """ self.ranges = None + def clear_identitites(self): + """ + Clear identities stored in :attr:`~nmrpy.data_objects.Fid.identities`. + """ + self.identities = None + def baseliner(self): """ Instantiate a baseline-correction GUI widget. Right-click-dragging @@ -1403,18 +1409,20 @@ def plot_deconv(self, **kwargs): def assign_identities(self): """ - Instantiate a identity-assignment GUI widget. Select a range from dropdown menu containing - :attr:`~nmrpy.data_objects.Fid.ranges`. Select a species from second dropdown menu - containing species defined in EnzymeML. When satisfied with assignment, press Assign button - to apply. + Instantiate a identity-assignment GUI widget. Select peaks from + dropdown menu containing :attr:`~nmrpy.data_objects.Fid.peaks`. + Attach a species to the selected peak from second dropdown menu + containing species defined in EnzymeML. When satisfied with + assignment, press Assign button to apply. """ - widget_title = "Assign identitiy for {}".format(self.id) + widget_title = "Assign identities for {}".format(self.id) self._assigner_widget = IdentityAssigner(fid=self, title=widget_title) def clear_identities(self): """ - Clear assigned identities stored in :attr:`~nmrpy.data_objects.Fid.identities`. + Clear assigned identities stored in + :attr:`~nmrpy.data_objects.Fid.identities`. """ self.identities = None @@ -2342,6 +2350,26 @@ def save_data(self, file_format: str, filename=None, overwrite=False): with open(filename, "w") as f: f.write(model) + def assign_identities(self): + """ + Instantiate a identity-assignment GUI widget. Select a FID by + its ID from the combobox. Select peaks from dropdown menu + containing :attr:`~nmrpy.data_objects.Fid.peaks`. Attach a + species to the selected peak from second dropdown menu + containing species defined in EnzymeML. When satisfied with + assignment, press Assign button to apply. + """ + + self._assigner_widget = IdentityRangeAssigner(fid_array=self) + + def clear_identities(self): + """ + Clear assigned identities stored in + :attr:`~nmrpy.data_objects.Fid.identities`. + """ + for fid in self.get_fids(): + fid.identities = None + class Importer(Base): def __init__(self, *args, **kwargs): diff --git a/nmrpy/plotting.py b/nmrpy/plotting.py index 1ba0bb1..fa2fb70 100644 --- a/nmrpy/plotting.py +++ b/nmrpy/plotting.py @@ -11,7 +11,15 @@ from matplotlib.widgets import Cursor from matplotlib.backend_bases import NavigationToolbar2, Event -from ipywidgets import FloatText, Output, VBox, Dropdown, Label, Button +from ipywidgets import ( + FloatText, + Output, + VBox, + Dropdown, + Label, + Button, + Combobox, +) from IPython.display import display import asyncio @@ -1381,11 +1389,9 @@ def __init__(self, fid, title): self.fid = fid self.title = title self.selected_values = {} - if fid.data is [] or fid.data is None: - raise ValueError("data must exist.") if fid.peaks is [] or fid.peaks is None: raise RuntimeError( - f"`fid.peaks` are required but still empty. Please either assign them manually or using the `peakpicker` method." + f"`fid.peaks` is required but still empty. Please either assign them manually or using the `peakpicker` method." ) # Create the label widget for the title @@ -1452,6 +1458,9 @@ def on_save_button_click(b): print("\nSaved selections:") for key, value in self.selected_values.items(): print(f"{key}: {value}") + self.fid.identities = [ + value for value in self.selected_values.values() + ] # Attach the function to the save button's click event save_button.on_click(on_save_button_click) @@ -1472,7 +1481,130 @@ def on_save_button_click(b): class IdentityRangeAssigner: - ... + """Wow, such documentation. + for fid in [self.fids[i] for i in self.fid_number]: + """ + + def __init__(self, fid_array): + self.fid_array = fid_array + self.fids = fid_array.get_fids() + self.selected_fid = None + self.selected_values = {} + for fid in self.fids: + if fid.peaks is [] or fid.peaks is None: + raise RuntimeError( + f"`fid.peaks` is required but still empty. Please either assign them manually or using the `peakpicker` method." + ) + + # Create the label widget for the title + title_label = Label(value="Assign identities for all FIDs") + + # Create the combobox for the selection of the FID ID + combobox = Combobox( + options=[fid.id for fid in self.fids], + description="Select FID to base entire array on:", + layout={"width": "max-content"}, + style={"description_width": "initial"}, + ) + + # Create the dropdown widget for the peaks + peak_dropdown = Dropdown( + options=[], + description="Select a peak:", + layout={"width": "max-content"}, + style={"description_width": "initial"}, + disabled=True, + ) + + # Create the dropdown widget for the species + species_dropdown = Dropdown( + options=[], + description="Select a species:", + layout={"width": "max-content"}, + style={"description_width": "initial"}, + disabled=True, + ) + + # Create the button to save selection to dict + save_button = Button( + description="Save selection", icon="file-arrow-down", disabled=True + ) + + # Create an output widget to display the selection + selection_output = Output() + + # Define a method to handle selection in combobox + def on_combobox_change(event): + if event["type"] == "change" and event["name"] == "value": + selected_option = event["new"] + if selected_option in combobox.options: + peak_dropdown.disabled = False + self.selected_fid = self.fid_array.get_fid(selected_option) + peak_dropdown.options = [ + str(peak) for peak in self.selected_fid.peaks + ] + + # Attach the method to the combobox's change event: + combobox.observe(on_combobox_change) + + # Define a method to handle the peak dropdown's change event + def on_peak_dropdown_change(event): + if event["type"] == "change" and event["name"] == "value": + selected_option = event["new"] + if selected_option != "": + species_dropdown.options = [ + "3PG", + "2PG", + "Phosphate", + "TEP", + "PEP", + ] + species_dropdown.disabled = False + save_button.disabled = False + + # Attach the method to the dropdown's change event + peak_dropdown.observe(on_peak_dropdown_change) + + # Define a method to handle the species dropdown's change event + def on_species_dropdown_change(event): + if event["type"] == "change" and event["name"] == "value": + selected_option = event["new"] + if selected_option != "": + new_key = peak_dropdown.value + self.selected_values[new_key] = selected_option + + # Attach the function to the second dropdown's change event + species_dropdown.observe(on_species_dropdown_change) + + # Define a function to handle the save button click event + def on_save_button_click(b): + with selection_output: + selection_output.clear_output(wait=True) + print("\nSaved selections:") + for key, value in self.selected_values.items(): + print(f"{key}: {value}") + for fid in self.fids: + fid.identities = [ + value for value in self.selected_values.values() + ] + + # Attach the function to the save button's click event + save_button.on_click(on_save_button_click) + + # Create a container for both the title and the dropdown + container = VBox( + [ + title_label, + combobox, + peak_dropdown, + species_dropdown, + save_button, + selection_output, + ] + ) + + # Display the container + display(container) class DataTraceSelector: