33# Licensed under the terms of the BSD 3-Clause
44# (see plotpy/LICENSE for details)
55
6- """Cross section panels keep curves for visible images only; unchanged axis
7- styles do not lay out the plot again."""
6+ """Cross section panels keep curves for visible images only, and compute the
7+ curves of images added or shown again; unchanged axis styles do not lay out the
8+ plot again."""
89
910from __future__ import annotations
1011
1112import numpy as np
13+ import pytest
1214from guidata .qthelpers import qt_app_context
1315from qtpy import QtWidgets as QW
1416
1517from plotpy .builder import make
1618
1719
1820def _window ():
21+ # In unattended mode, leaving a `qt_app_context` schedules the closing of all
22+ # top-level widgets: process it now, so that it does not close this window
23+ QW .QApplication .processEvents ()
1924 win = make .dialog (type = "image" , show_xsection = True , show_ysection = True )
2025 win .show ()
2126 return win
2227
2328
29+ def _cs_plots (win ):
30+ """Return the X and Y cross section plots of the window"""
31+ return win .manager .get_xcs_panel ().cs_plot , win .manager .get_ycs_panel ().cs_plot
32+
33+
34+ def _add_marker (win , x : float , y : float ):
35+ """Add a marker to the plot and register it for the cross sections"""
36+ plot = win .manager .get_plot ()
37+ marker = make .marker (position = (x , y ))
38+ plot .add_item (marker )
39+ for cs_plot in _cs_plots (win ):
40+ cs_plot .register_shape (plot , marker )
41+ return marker
42+
43+
44+ def _assert_sections (win , image , x : float , y : float ) -> None :
45+ """Assert that the cross section curves of the image are the sections at
46+ (x, y)"""
47+ xcs , ycs = _cs_plots (win )
48+ xcurve , ycurve = xcs .known_items [image ], ycs .known_items [image ]
49+ assert xcurve .dataSize () > 0 and ycurve .dataSize () > 0
50+ # The Y cross section curve is vertical: section values are its X data
51+ assert np .array_equal (xcurve .get_data ()[1 ], image .get_xsection (y )[1 ])
52+ assert np .array_equal (ycurve .get_data ()[0 ], image .get_ysection (x )[1 ])
53+
54+
2455def test_cross_section_curves_follow_visible_images ():
2556 """Hidden images have no cross section curve, until they are shown again."""
2657 with qt_app_context (exec_loop = False ):
@@ -49,6 +80,77 @@ def test_cross_section_curves_follow_visible_images():
4980 win .close ()
5081
5182
83+ def test_cross_section_computed_when_image_shown_again ():
84+ """The cross sections of an image shown again are those at the marker
85+ position, even if the marker was moved while the image was hidden."""
86+ with qt_app_context (exec_loop = False ):
87+ win = _window ()
88+ plot = win .manager .get_plot ()
89+ image1 = make .image (np .arange (16 * 16 , dtype = float ).reshape (16 , 16 ))
90+ image2 = make .image (np .full ((16 , 16 ), 42.0 ))
91+ plot .add_item (image1 )
92+ plot .add_item (image2 )
93+ marker = _add_marker (win , 5 , 5 )
94+ _assert_sections (win , image1 , 5 , 5 )
95+ plot .set_item_visible (image1 , False )
96+ marker .set_pos (10 , 12 )
97+ plot .set_item_visible (image1 , True )
98+ _assert_sections (win , image1 , 10 , 12 )
99+ _assert_sections (win , image2 , 10 , 12 )
100+ win .close ()
101+
102+
103+ def test_cross_section_computed_for_added_image ():
104+ """The cross sections of an image added to the plot are computed at once."""
105+ with qt_app_context (exec_loop = False ):
106+ win = _window ()
107+ plot = win .manager .get_plot ()
108+ plot .add_item (make .image (np .full ((16 , 16 ), 42.0 )))
109+ _add_marker (win , 5 , 7 )
110+ image = make .image (np .arange (16 * 16 , dtype = float ).reshape (16 , 16 ))
111+ plot .add_item (image )
112+ _assert_sections (win , image , 5 , 7 )
113+ win .close ()
114+
115+
116+ def test_cross_section_of_shown_image_follows_autorefresh_mode ():
117+ """With the auto-refresh mode disabled, the cross section curves of an image
118+ shown again are computed on the next refresh only."""
119+ with qt_app_context (exec_loop = False ):
120+ win = _window ()
121+ plot = win .manager .get_plot ()
122+ xcs , _ycs = _cs_plots (win )
123+ image = make .image (np .arange (16 * 16 , dtype = float ).reshape (16 , 16 ))
124+ plot .add_item (image )
125+ _add_marker (win , 5 , 5 )
126+ xcs .toggle_autorefresh (False )
127+ plot .set_item_visible (image , False )
128+ plot .set_item_visible (image , True )
129+ assert xcs .known_items [image ].dataSize () == 0
130+ xcs .update_plot ()
131+ assert xcs .known_items [image ].dataSize () == 16
132+ win .close ()
133+
134+
135+ def test_cross_section_shade_counts_visible_images_only ():
136+ """The shade of the cross section curves ignores hidden images."""
137+ with qt_app_context (exec_loop = False ):
138+ win = _window ()
139+ plot = win .manager .get_plot ()
140+ xcs , _ycs = _cs_plots (win )
141+ images = []
142+ for _index in range (4 ):
143+ if images :
144+ plot .set_item_visible (images [- 1 ], False )
145+ image = make .image (np .ones ((16 , 16 )))
146+ plot .add_item (image )
147+ images .append (image )
148+ assert xcs .param .shade == pytest .approx (xcs .SHADE )
149+ brush_color = xcs .known_items [images [- 1 ]].brush ().color ()
150+ assert brush_color .alphaF () == pytest .approx (xcs .SHADE , abs = 1e-2 )
151+ win .close ()
152+
153+
52154def test_unchanged_axis_style_does_not_relayout ():
53155 """Setting the same titles again neither lays out the plot nor notifies."""
54156 with qt_app_context (exec_loop = False ):
@@ -70,4 +172,8 @@ def test_unchanged_axis_style_does_not_relayout():
70172
71173if __name__ == "__main__" :
72174 test_cross_section_curves_follow_visible_images ()
175+ test_cross_section_computed_when_image_shown_again ()
176+ test_cross_section_computed_for_added_image ()
177+ test_cross_section_of_shown_image_follows_autorefresh_mode ()
178+ test_cross_section_shade_counts_visible_images_only ()
73179 test_unchanged_axis_style_does_not_relayout ()
0 commit comments