Skip to content

Commit 9a221b7

Browse files
fix(csection): only keep cross-section curves for visible images
Cross-section panels kept one curve for every image ever shown, so plots with hundreds of hidden images became progressively slower to refresh. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7a7c990 commit 9a221b7

2 files changed

Lines changed: 81 additions & 2 deletions

File tree

‎plotpy/panels/csection/csplot.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,19 @@ def get_cross_section_curves(self) -> list[CrossSectionItem]:
167167
def items_changed(self, plot: BasePlot) -> None:
168168
"""Items have changed in the plot
169169
170+
Cross section curves are kept for visible image items only: the curve
171+
of an image item that is hidden or removed is deleted, and created
172+
again when the item is shown. Keeping the curves of hidden items would
173+
make every change cost more as images accumulate in the plot (e.g. an
174+
application showing one image at a time among many hidden ones).
175+
170176
Args:
171177
plot: Plot containing the image items to be used for cross section
172178
"""
173-
# Del obsolete cross section items
174179
new_sources = plot.get_items(item_type=ICSImageItemType)
180+
# Del cross section items of removed or hidden image items
175181
for source in self.known_items.copy():
176-
if source not in new_sources:
182+
if source not in new_sources or not source.isVisible():
177183
curve = self.known_items.pop(source)
178184
curve.clear_data() # useful to emit SIG_CS_CURVE_CHANGED
179185
# (eventually notify other panels that the
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Licensed under the terms of the BSD 3-Clause
4+
# (see plotpy/LICENSE for details)
5+
6+
"""Cross section panels keep curves for visible images only; unchanged axis
7+
styles do not lay out the plot again."""
8+
9+
from __future__ import annotations
10+
11+
import numpy as np
12+
from guidata.qthelpers import qt_app_context
13+
from qtpy import QtWidgets as QW
14+
15+
from plotpy.builder import make
16+
17+
18+
def _window():
19+
win = make.dialog(type="image", show_xsection=True, show_ysection=True)
20+
win.show()
21+
return win
22+
23+
24+
def test_cross_section_curves_follow_visible_images():
25+
"""Hidden images have no cross section curve, until they are shown again."""
26+
with qt_app_context(exec_loop=False):
27+
win = _window()
28+
plot = win.manager.get_plot()
29+
xcs = win.manager.get_xcs_panel().cs_plot
30+
ycs = win.manager.get_ycs_panel().cs_plot
31+
data = np.random.default_rng(0).random((16, 16))
32+
images = []
33+
for _index in range(20):
34+
if images:
35+
plot.set_item_visible(images[-1], False, notify=False, replot=False)
36+
image = make.image(data.copy())
37+
plot.add_item(image)
38+
images.append(image)
39+
QW.QApplication.processEvents()
40+
assert list(xcs.known_items) == [images[-1]]
41+
assert list(ycs.known_items) == [images[-1]]
42+
plot.set_item_visible(images[-1], False)
43+
assert not xcs.known_items
44+
plot.set_item_visible(images[0], True)
45+
assert list(xcs.known_items) == [images[0]]
46+
assert xcs.known_items[images[0]].isVisible()
47+
plot.del_item(images[0])
48+
assert not xcs.known_items and not ycs.known_items
49+
win.close()
50+
51+
52+
def test_unchanged_axis_style_does_not_relayout():
53+
"""Setting the same titles again neither lays out the plot nor notifies."""
54+
with qt_app_context(exec_loop=False):
55+
win = _window()
56+
plot = win.manager.get_plot()
57+
plot.set_titles(title="T", xlabel="x", ylabel="y", xunit="mm", yunit="mm")
58+
layouts, notifications = [], []
59+
update_layout = plot.updateLayout
60+
plot.updateLayout = lambda: (layouts.append(1), update_layout())
61+
plot.SIG_PLOT_LABELS_CHANGED.connect(notifications.append)
62+
plot.set_titles(title="T", xlabel="x", ylabel="y", xunit="mm", yunit="mm")
63+
assert not layouts and not notifications
64+
plot.set_titles(xlabel="x2")
65+
assert plot.get_axis_title("bottom") == "x2"
66+
assert plot.axisTitle(plot.get_axis_id("bottom")).text() == "x2 (mm)"
67+
assert layouts and notifications
68+
win.close()
69+
70+
71+
if __name__ == "__main__":
72+
test_cross_section_curves_follow_visible_images()
73+
test_unchanged_axis_style_does_not_relayout()

0 commit comments

Comments
 (0)