diff --git a/jdaviz/configs/default/plugins/export/export.py b/jdaviz/configs/default/plugins/export/export.py index d9fde7c269..100b71c24f 100644 --- a/jdaviz/configs/default/plugins/export/export.py +++ b/jdaviz/configs/default/plugins/export/export.py @@ -46,7 +46,6 @@ class Export(PluginTemplateMixin, ViewerSelectMixin, SubsetSelectMixin, # feature flag for cone support dev_dataset_support = Bool(False).tag(sync=True) # when enabling: add entries to docstring - dev_subset_support = Bool(False).tag(sync=True) # when enabling: add entries to docstring dev_plot_support = Bool(False).tag(sync=True) # when enabling: add entries to docstring dev_multi_support = Bool(False).tag(sync=True) # when enabling: add entries to docstring @@ -56,6 +55,9 @@ class Export(PluginTemplateMixin, ViewerSelectMixin, SubsetSelectMixin, viewer_format_items = List().tag(sync=True) viewer_format_selected = Unicode().tag(sync=True) + subset_format_items = List().tag(sync=True) + subset_format_selected = Unicode().tag(sync=True) + filename = Unicode().tag(sync=True) # For Cubeviz movie. @@ -89,6 +91,12 @@ def __init__(self, *args, **kwargs): selected='viewer_format_selected', manual_options=viewer_format_options) + subset_format_options = ['fits', 'reg'] + self.subset_format = SelectPluginComponent(self, + items='subset_format_items', + selected='subset_format_selected', + manual_options=subset_format_options) + # default selection: self.dataset._default_mode = 'empty' self.table._default_mode = 'empty' @@ -104,12 +112,11 @@ def user_api(self): # TODO: backwards compat for save_figure, save_movie, # i_start, i_end, movie_fps, movie_filename # TODO: expose export method once API is finalized - expose = ['viewer', 'viewer_format', 'table', 'filename', 'export'] + expose = ['viewer', 'viewer_format', 'table', 'filename', 'export', + 'subset'] if self.dev_dataset_support: expose += ['dataset'] - if self.dev_subset_support: - expose += ['subset'] if self.dev_plot_support: expose += ['plot'] if self.dev_multi_support: @@ -163,8 +170,6 @@ def export(self, filename=None, show_dialog=None): """ if self.dataset.selected is not None and len(self.dataset.selected): raise NotImplementedError("dataset export not yet supported") - if self.subset.selected is not None and len(self.subset.selected): - raise NotImplementedError("subset export not yet supported") if self.plot.selected is not None and len(self.plot.selected): raise NotImplementedError("plot export not yet supported") if self.multiselect: @@ -187,10 +192,20 @@ def export(self, filename=None, show_dialog=None): self.save_movie(viewer, filename, filetype) else: self.save_figure(viewer, filename, filetype, show_dialog=show_dialog) + elif len(self.table.selected): if not filename.endswith("csv"): filename += ".csv" self.table.selected_obj.export_table(filename) + + elif len(self.subset.selected): + selected_subset_label = self.subset.selected + filetype = self.subset_format.selected + if len(filename): + if not filename.endswith(filetype): + filename += f".{filetype}" + self.save_subset_as_region(selected_subset_label, filename) + else: raise ValueError("nothing selected for export") @@ -202,6 +217,7 @@ def vue_export_from_ui(self, *args, **kwargs): f"Export failed with: {e}", sender=self, color="error")) def save_figure(self, viewer, filename=None, filetype="png", show_dialog=False): + if filetype == "png": if filename is None or show_dialog: viewer.figure.save_png(str(filename) if filename is not None else None) @@ -384,6 +400,39 @@ def save_movie(self, viewer, filename, filetype, i_start=None, i_end=None, fps=N return filename + def save_subset_as_region(self, selected_subset_label, filename): + """ + Save a subset to file as a `Region` object in the working directory. + Currently only enabled for non-composite spatial subsets. Can be saved + as a `.fits` or `.reg` file. If link type is currently set to 'pixel', + then a pixel region will be saved. If link type is 'wcs', then a sky + region will be saved. If a file with the same name already exists in the + working directory, it will be overwriten. + """ + + # type of region saved depends on link type + link_type = getattr(self.app, '_link_type', None) + + region = self.app.get_subsets(subset_name=selected_subset_label, + include_sky_region=link_type=='wcs') + + if len(region) > 1: + raise NotImplementedError("Export not yet supported for composite subsets.") + + region = region[0][f'{"sky_" if link_type=="wcs" else ""}region'] + + try: + region.write(filename, overwrite=True) + except Exception as e: + self.hub.broadcast(SnackbarMessage( + f"{selected_subset_label} failed to export to {str(filename)}: {e}", + sender=self, color="error")) + finally: + self.hub.broadcast(SnackbarMessage( + f"{selected_subset_label} exported to {str(filename)}", + sender=self, color="success")) + + def vue_interrupt_recording(self, *args): # pragma: no cover self.movie_interrupt = True # TODO: this will need updating when batch/multiselect support is added diff --git a/jdaviz/configs/default/plugins/export/export.vue b/jdaviz/configs/default/plugins/export/export.vue index f5b8fab88c..d367134d75 100644 --- a/jdaviz/configs/default/plugins/export/export.vue +++ b/jdaviz/configs/default/plugins/export/export.vue @@ -89,7 +89,7 @@ -