Skip to content

Commit ecb3ebb

Browse files
authored
Merge pull request #48 from Chilipp/master
Add a reload button
2 parents d265841 + de88110 commit ecb3ebb

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ Changed
1212
Added
1313
-----
1414
- A widget to control the plot type for mapplot and plot2d (see
15-
`#46 <https://github.com/psyplot/psy-view/pull/46>`__)
15+
`#46 <https://github.com/psyplot/psy-view/pull/46>`__)
16+
- A button to reload all plots. This is useful, for instance, if the data on
17+
your disk changed and you just want to update the plot
18+
`#48 <https://github.com/psyplot/psy-view/pull/48>`__)

psy_view/ds_widget.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ def __init__(self, ds: Optional[Dataset] = None, *args, **kwargs) -> None:
179179
# third row, navigation
180180
self.navigation_box = QtWidgets.QHBoxLayout()
181181

182+
self.btn_reload = utils.add_pushbutton(
183+
get_psy_icon("refresh.png"), self.reload,
184+
"Close all open datasets and recreate the plots",
185+
self.navigation_box, icon=True
186+
)
187+
182188
# -- animate backwards button
183189
self.btn_animate_backward = utils.add_pushbutton(
184190
"◀◀", lambda: self.animate_backward(),
@@ -311,6 +317,26 @@ def __init__(self, ds: Optional[Dataset] = None, *args, **kwargs) -> None:
311317

312318
self.cids: Dict[str, int] = {}
313319

320+
def reload(self) -> None:
321+
"""Close the plot and recreate it."""
322+
import psyplot.project as psy
323+
324+
sp = self._sp
325+
fname = sp.dsnames_map[self.ds.psy.num] # type: ignore
326+
project = sp.save_project()
327+
sp.close(True, True, True)
328+
self.ds_tree.clear()
329+
self._ds_nums.clear()
330+
self.refresh()
331+
self._sp = sp = psy.Project.load_project(project)
332+
self._ds_nums = sp.datasets
333+
num = next(num for num, f in sp.dsnames_map.items() if f == fname)
334+
self.ds = self.open_datasets[num]
335+
for ds in self._ds_nums.values():
336+
self._add_ds_item(ds)
337+
sp.show()
338+
self.refresh()
339+
314340
def setup_ds_tree(self) -> None:
315341
"""Setup the number of columns and the header of the dataset tree."""
316342
self.ds_tree = tree = QtWidgets.QTreeWidget()
@@ -443,6 +469,9 @@ def set_dataset(self, ds: Optional[Dataset] = None) -> None:
443469
def add_ds_item(self) -> None:
444470
"""Add a new :class:`DatasetTreeItem` for the current :attr:`ds`."""
445471
ds: Dataset = self.ds # type: ignore
472+
self._add_ds_item(ds)
473+
474+
def _add_ds_item(self, ds: Dataset) -> None:
446475
tree = self.ds_tree
447476
ds_item = DatasetTreeItem(ds, self.ds_attr_columns, 0)
448477
fname = psyd.get_filename_ds(ds, False)[0]
@@ -463,6 +492,7 @@ def add_ds_item(self) -> None:
463492
# make sure we do not loose track of open datasets
464493
self._ds_nums[ds.psy.num] = ds
465494

495+
466496
@property
467497
def open_datasets(self) -> Dict[int, Dataset]:
468498
"""Get a mapping from path to dataset number of the open datasets."""
@@ -1640,6 +1670,33 @@ def close_sp(self) -> None:
16401670
if ds.psy.num not in self._sp.datasets:
16411671
self.set_dataset(ds)
16421672

1673+
def reload(self) -> None:
1674+
"""Close the plot and recreate it."""
1675+
import psyplot.project as psy
1676+
1677+
if not all(self._sp.dsnames_map.values()):
1678+
# we have datasets that only exist in memory, so better ask
1679+
answer = QtWidgets.QMessageBox.question(
1680+
self, "Shall I close this?",
1681+
"Reloading the data closes all open plots. Any data in the memory "
1682+
"is lost and open files are reloaded from disk! "
1683+
"Shall I really continue?")
1684+
if answer != QtWidgets.QMessageBox.Yes:
1685+
return
1686+
1687+
sp = self._sp
1688+
fname = sp.dsnames_map[self.ds.psy.num] # type: ignore
1689+
project = sp.save_project()
1690+
sp.close(True, True, True)
1691+
self.ds_tree.clear()
1692+
self._ds_nums.clear()
1693+
self.refresh()
1694+
self._sp = sp = psy.Project.load_project(project)
1695+
num = next(num for num, f in sp.dsnames_map.items() if f == fname)
1696+
self.ds = self.open_datasets[num]
1697+
sp.show()
1698+
self.refresh()
1699+
16431700
def oncpchange(self, sp: Optional[Project]) -> None:
16441701
"""Update this widget from the current psyplot main (or sub) project."""
16451702
self.reset_combo_array()
@@ -1651,6 +1708,8 @@ def oncpchange(self, sp: Optional[Project]) -> None:
16511708
self.btn_del.setEnabled(False)
16521709
elif self.ds is None and self._sp:
16531710
self.set_dataset(next(iter(self._sp.datasets.values())))
1711+
elif self.ds is not None and self._sp:
1712+
self.enable_navigation()
16541713

16551714
def show_fig(self, sp: Optional[Project]) -> None:
16561715
"""Show the figure of the the current subproject."""

tests/conftest.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
import psyplot_gui.compat.qtcompat
44

55

6-
test_dir = osp.dirname(__file__)
6+
_test_dir = osp.dirname(__file__)
77

88

9+
@pytest.fixture
10+
def test_dir() -> str:
11+
return _test_dir
912

1013

1114
@pytest.fixture(params=["regular-test.nc", "regional-icon-test.nc",
1215
"rotated-pole-test.nc", "icon-test.nc"])
13-
def test_file(request):
16+
def test_file(test_dir, request):
1417
return osp.join(test_dir, request.param)
1518

1619

tests/test_ds_widget.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Test the main functionality of the psy-view package, namely the widget"""
22
import os.path as osp
3+
import shutil
34
from PyQt5.QtCore import Qt
45
from PyQt5 import QtWidgets
56
import pytest
@@ -429,3 +430,27 @@ def test_export_animation(qtbot, ds_widget, plotmethod, tmpdir, monkeypatch):
429430
assert not ds_widget._animating
430431

431432
assert osp.exists(osp.join(tmpdir, "test.gif"))
433+
434+
435+
def test_reload(qtbot, test_dir, tmp_path) -> None:
436+
"""Test the reload button."""
437+
import psyplot.project as psy
438+
from psy_view.ds_widget import DatasetWidget
439+
440+
f1, f2 = "regular-test.nc", "regional-icon-test.nc"
441+
shutil.copy(osp.join(test_dir, f1), str(tmp_path / f1))
442+
443+
ds_widget = DatasetWidget(psy.open_dataset(str(tmp_path / f1)))
444+
qtbot.addWidget(ds_widget)
445+
qtbot.mouseClick(ds_widget.variable_buttons['t2m'], Qt.LeftButton)
446+
447+
assert ds_widget.ds_tree.topLevelItemCount() == 1
448+
assert ds_widget.ds["t2m"].ndim == 4
449+
450+
# now copy the icon file to the same destination and reload everything
451+
shutil.copy(osp.join(test_dir, f2), str(tmp_path / f1))
452+
ds_widget.reload()
453+
454+
assert ds_widget.ds_tree.topLevelItemCount() == 1
455+
assert ds_widget.ds["t2m"].ndim == 3
456+
assert len(psy.gcp(True)) == 1

0 commit comments

Comments
 (0)