Skip to content

Commit

Permalink
feat(interactive.imagetool): show dialog when data is being loaded
Browse files Browse the repository at this point in the history
  • Loading branch information
kmnhan committed Nov 22, 2024
1 parent eb75fcc commit b356fe0
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 28 deletions.
48 changes: 32 additions & 16 deletions src/erlab/interactive/imagetool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
NormalizeDialog,
RotationDialog,
)
from erlab.interactive.utils import DictMenuBar, copy_to_clipboard
from erlab.interactive.utils import DictMenuBar, copy_to_clipboard, wait_dialog
from erlab.utils.misc import _convert_to_native

if TYPE_CHECKING:
Expand All @@ -51,6 +51,9 @@

from erlab.interactive.imagetool.slicer import ArraySlicer

_ITOOL_DATA_NAME: str = "<erlab-itool-data>"
#: Name to use for the data variable in cached datasets


def _parse_input(
data: Collection[xr.DataArray | npt.NDArray]
Expand Down Expand Up @@ -274,13 +277,16 @@ def array_slicer(self) -> ArraySlicer:
return self.slicer_area.array_slicer

def to_dataset(self) -> xr.Dataset:
name = self.slicer_area.data.name
name = name if name else ""
return self.slicer_area.data.to_dataset(
name="<erlab-itool-data>", promote_attrs=False
name=_ITOOL_DATA_NAME, promote_attrs=False
).assign_attrs(
{
"state": json.dumps(self.slicer_area.state),
"title": self.windowTitle(),
"rect": self.geometry().getRect(),
"itool_state": json.dumps(self.slicer_area.state),
"itool_title": self.windowTitle(),
"itool_name": name,
"itool_rect": self.geometry().getRect(),
}
)

Expand All @@ -299,7 +305,7 @@ def to_file(self, filename: str | os.PathLike) -> None:
self.to_dataset().to_netcdf(filename, engine="h5netcdf", invalid_netcdf=True)

@classmethod
def from_dataset(self, ds: xr.Dataset) -> Self:
def from_dataset(cls, ds: xr.Dataset) -> Self:
"""Restore a window from a dataset saved using :meth:`to_dataset`.
Parameters
Expand All @@ -308,9 +314,13 @@ def from_dataset(self, ds: xr.Dataset) -> Self:
The dataset.
"""
tool = self(ds["<erlab-itool-data>"], state=json.loads(ds.attrs["state"]))
tool.setWindowTitle(ds.attrs["title"])
tool.setGeometry(*ds.attrs["rect"])
name = ds.attrs["itool_name"]
name = None if name == "" else name
tool = cls(
ds[_ITOOL_DATA_NAME].rename(name), state=json.loads(ds.attrs["itool_state"])
)
tool.setWindowTitle(ds.attrs["itool_title"])
tool.setGeometry(*ds.attrs["itool_rect"])
return tool

@classmethod
Expand Down Expand Up @@ -405,7 +415,10 @@ class ImageTool(BaseImageTool):

def __init__(self, data=None, **kwargs) -> None:
super().__init__(data, **kwargs)
self.mnb = ItoolMenuBar(self.slicer_area, self)
self._recent_name_filter: str | None = None
self._recent_directory: str | None = None

self.mnb = ItoolMenuBar(self)

self.slicer_area.sigDataChanged.connect(self._update_title)
self._update_title()
Expand All @@ -419,10 +432,8 @@ def _update_title(self) -> None:
# Name contains only whitespace
name = None

if name is None and path is None:
title = ""
elif name is None:
title = f"{path}"
if name is None:
title = "" if path is None else path.stem
elif path is None or name == path.stem:
title = f"{name}"
else:
Expand Down Expand Up @@ -481,7 +492,8 @@ def _open_file(
fn, kargs = valid_loaders[self._recent_name_filter]

try:
self.slicer_area.set_data(fn(fname, **kargs), file_path=fname)
with wait_dialog(self, "Loading..."):
self.slicer_area.set_data(fn(fname, **kargs), file_path=fname)
except Exception as e:
QtWidgets.QMessageBox.critical(
self,
Expand Down Expand Up @@ -536,7 +548,8 @@ def _to_hdf5(darr: xr.DataArray, file: str, **kwargs) -> None:
if dialog.exec():
files = dialog.selectedFiles()
fn, kargs = valid_savers[dialog.selectedNameFilter()]
fn(self.slicer_area._data, files[0], **kargs)
with wait_dialog(self, "Saving..."):
fn(self.slicer_area._data, files[0], **kargs)


class ItoolMenuBar(DictMenuBar):
Expand Down Expand Up @@ -817,18 +830,21 @@ def _normalize(self) -> None:
def _reset_filters(self) -> None:
self.slicer_area.apply_func(None)

@QtCore.Slot()
def _set_colormap_options(self) -> None:
self.slicer_area.set_colormap(
reverse=self.colorAct[0].isChecked(),
high_contrast=self.colorAct[1].isChecked(),
zero_centered=self.colorAct[2].isChecked(),
)

@QtCore.Slot()
def _copy_cursor_val(self) -> None:
copy_to_clipboard(
str(_convert_to_native(self.slicer_area.array_slicer._values))
)

@QtCore.Slot()
def _copy_cursor_idx(self) -> None:
copy_to_clipboard(
str(_convert_to_native(self.slicer_area.array_slicer._indices))
Expand Down
23 changes: 11 additions & 12 deletions src/erlab/interactive/kspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
ColorMapComboBox, # noqa: F401
ColorMapGammaWidget, # noqa: F401
)
from erlab.interactive.utils import copy_to_clipboard, generate_code, xImageItem
from erlab.interactive.utils import (
copy_to_clipboard,
generate_code,
wait_dialog,
xImageItem,
)
from erlab.plotting.bz import get_bz_edge

if TYPE_CHECKING:
Expand Down Expand Up @@ -397,18 +402,12 @@ def show_converted(self) -> None:
if self.data.kspace._has_hv:
self.data.kspace.inner_potential = self._offset_spins["V0"].value()

wait_dialog = QtWidgets.QDialog(self)
dialog_layout = QtWidgets.QVBoxLayout()
wait_dialog.setLayout(dialog_layout)
dialog_layout.addWidget(QtWidgets.QLabel("Converting..."))

wait_dialog.open()
from erlab.interactive.imagetool import ImageTool, itool
with wait_dialog(self, "Converting..."):
from erlab.interactive.imagetool import ImageTool, itool

data_kconv = self.data.kspace.convert(
bounds=self.bounds, resolution=self.resolution
)
wait_dialog.close()
data_kconv = self.data.kspace.convert(
bounds=self.bounds, resolution=self.resolution
)

tool = cast(ImageTool | None, itool(data_kconv, execute=False))
if tool is not None:
Expand Down
16 changes: 16 additions & 0 deletions src/erlab/interactive/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import contextlib
import functools
import inspect
import itertools
Expand Down Expand Up @@ -43,6 +44,7 @@
"generate_code",
"make_crosshairs",
"parse_data",
"wait_dialog",
"xImageItem",
]

Expand Down Expand Up @@ -71,6 +73,20 @@ def parse_data(data) -> xr.DataArray:
return data # .astype(float, order="C")


@contextlib.contextmanager
def wait_dialog(parent: QtWidgets.QWidget, message: str):
wait_dialog = QtWidgets.QDialog(parent)
dialog_layout = QtWidgets.QVBoxLayout()
wait_dialog.setLayout(dialog_layout)
dialog_layout.addWidget(QtWidgets.QLabel(message))

try:
wait_dialog.open()
yield wait_dialog
finally:
wait_dialog.close()


def array_rect(data):
data_coords = tuple(data[dim].values for dim in data.dims)
data_incs = tuple(coord[1] - coord[0] for coord in data_coords)
Expand Down

0 comments on commit b356fe0

Please sign in to comment.