|
34 | 34 | from cdl.core.gui import actionhandler, objectmodel, objectview |
35 | 35 | from cdl.core.gui.roieditor import TypeROIEditor |
36 | 36 | from cdl.core.model.base import ( |
| 37 | + ANN_KEY, |
| 38 | + ROI_KEY, |
37 | 39 | ResultProperties, |
38 | 40 | ResultShape, |
39 | 41 | TypeObj, |
@@ -247,6 +249,18 @@ def create_resultdata_dict(objs: list[SignalObj | ImageObj]) -> dict[str, Result |
247 | 249 | return rdatadict |
248 | 250 |
|
249 | 251 |
|
| 252 | +class PasteMetadataParam(gds.DataSet): |
| 253 | + """Paste metadata parameters""" |
| 254 | + |
| 255 | + keep_roi = gds.BoolItem(_("Regions of interest"), default=True) |
| 256 | + keep_resultshapes = gds.BoolItem(_("Result shapes"), default=False).set_pos(col=1) |
| 257 | + keep_annotations = gds.BoolItem(_("Annotations"), default=True) |
| 258 | + keep_resultproperties = gds.BoolItem(_("Result properties"), default=False).set_pos( |
| 259 | + col=1 |
| 260 | + ) |
| 261 | + keep_other = gds.BoolItem(_("Other metadata"), default=True) |
| 262 | + |
| 263 | + |
250 | 264 | class BaseDataPanel(AbstractPanel, Generic[TypeObj, TypeROI, TypeROIEditor]): |
251 | 265 | """Object handling the item list, the selected item properties and plot""" |
252 | 266 |
|
@@ -535,15 +549,60 @@ def duplicate_object(self) -> None: |
535 | 549 |
|
536 | 550 | def copy_metadata(self) -> None: |
537 | 551 | """Copy object metadata""" |
538 | | - obj_cpy = self.objview.get_sel_objects()[0].copy() |
539 | | - obj_cpy.delete_results() # Remove all object-specific analysis results |
540 | | - self.__metadata_clipboard = obj_cpy.metadata |
541 | | - |
542 | | - def paste_metadata(self) -> None: |
| 552 | + obj = self.objview.get_sel_objects()[0] |
| 553 | + self.__metadata_clipboard = obj.metadata.copy() |
| 554 | + new_pref = obj.short_id + "_" |
| 555 | + for key, value in obj.metadata.items(): |
| 556 | + if ResultShape.match(key, value): |
| 557 | + mshape = ResultShape.from_metadata_entry(key, value) |
| 558 | + if not re.match(obj.PREFIX + r"[0-9]{3}[\s]*", mshape.title): |
| 559 | + # Handling additional result (e.g. diameter) |
| 560 | + for a_key, a_value in obj.metadata.items(): |
| 561 | + if isinstance(a_key, str) and a_key.startswith(mshape.title): |
| 562 | + self.__metadata_clipboard.pop(a_key) |
| 563 | + self.__metadata_clipboard[new_pref + a_key] = a_value |
| 564 | + mshape.title = new_pref + mshape.title |
| 565 | + # Handling result shape |
| 566 | + self.__metadata_clipboard.pop(key) |
| 567 | + self.__metadata_clipboard[mshape.key] = value |
| 568 | + |
| 569 | + def paste_metadata(self, param: PasteMetadataParam | None = None) -> None: |
543 | 570 | """Paste metadata to selected object(s)""" |
| 571 | + if param is None: |
| 572 | + param = PasteMetadataParam( |
| 573 | + _("Paste metadata"), |
| 574 | + comment=_( |
| 575 | + "Select what to keep from the clipboard.<br><br>" |
| 576 | + "Result shapes and annotations, if kept, will be merged with " |
| 577 | + "existing ones. <u>All other metadata will be replaced</u>." |
| 578 | + ), |
| 579 | + ) |
| 580 | + if not param.edit(parent=self.parent()): |
| 581 | + return |
| 582 | + metadata = {} |
| 583 | + if param.keep_roi and ROI_KEY in self.__metadata_clipboard: |
| 584 | + metadata[ROI_KEY] = self.__metadata_clipboard[ROI_KEY] |
| 585 | + if param.keep_annotations and ANN_KEY in self.__metadata_clipboard: |
| 586 | + metadata[ANN_KEY] = self.__metadata_clipboard[ANN_KEY] |
| 587 | + if param.keep_resultshapes: |
| 588 | + for key, value in self.__metadata_clipboard.items(): |
| 589 | + if ResultShape.match(key, value): |
| 590 | + metadata[key] = value |
| 591 | + if param.keep_resultproperties: |
| 592 | + for key, value in self.__metadata_clipboard.items(): |
| 593 | + if ResultProperties.match(key, value): |
| 594 | + metadata[key] = value |
| 595 | + if param.keep_other: |
| 596 | + for key, value in self.__metadata_clipboard.items(): |
| 597 | + if ( |
| 598 | + not ResultShape.match(key, value) |
| 599 | + and not ResultProperties.match(key, value) |
| 600 | + and key not in (ROI_KEY, ANN_KEY) |
| 601 | + ): |
| 602 | + metadata[key] = value |
544 | 603 | sel_objects = self.objview.get_sel_objects(include_groups=True) |
545 | 604 | for obj in sorted(sel_objects, key=lambda obj: obj.short_id, reverse=True): |
546 | | - obj.metadata.update(self.__metadata_clipboard) |
| 605 | + obj.update_metadata_from(metadata) |
547 | 606 | # We have to do a manual refresh in order to force the plot handler to update |
548 | 607 | # all plot items, even the ones that are not visible (otherwise, image masks |
549 | 608 | # would not be updated after pasting the metadata: see issue #123) |
@@ -1324,8 +1383,8 @@ class PlotResultParam(gds.DataSet): |
1324 | 1383 | x.append(index) |
1325 | 1384 | else: |
1326 | 1385 | i_xaxis = rdata.xlabels.index(param.xaxis) |
1327 | | - x.append(float(result.shown_array[mask, i_xaxis])) |
1328 | | - y.append(float(result.shown_array[mask, i_yaxis])) |
| 1386 | + x.append(result.shown_array[mask, i_xaxis][0]) |
| 1387 | + y.append(result.shown_array[mask, i_yaxis][0]) |
1329 | 1388 | self.__add_result_signal( |
1330 | 1389 | x, y, f"{title}{roi_suffix}", param.xaxis, param.yaxis |
1331 | 1390 | ) |
|
0 commit comments