mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-10-29 08:21:27 +01:00
fix(waveform): use thin line when downsampling no-line curves
This commit is contained in:
1 parent
e4b02bcdf3
commit
7b54f6246e
4 files changed
+82
-15
No files matched your search
@@ -1056,6 +1056,7 @@ class Curve(RPCBase):
|
||||
Args:
|
||||
pen_style(Literal["solid", "dash", "dot", "dashdot", "none"]): Style of the pen.
|
||||
Use "none" to display markers without connecting lines.
|
||||
During automatic downsampling, "none" uses a 1 px solid line without markers.
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
|
||||
@@ -137,17 +137,23 @@ class Curve(BECConnector, pg.PlotDataItem):
|
||||
"none": QtCore.Qt.NoPen,
|
||||
}
|
||||
pen_style = pen_style_map.get(self.config.pen_style, QtCore.Qt.SolidLine)
|
||||
line_fallback = self.config.pen_style == "none" and self.opts["autoDownsample"]
|
||||
pen_width = self.config.pen_width
|
||||
if line_fallback:
|
||||
pen_style = QtCore.Qt.SolidLine
|
||||
pen_width = 1
|
||||
|
||||
pen = pg.mkPen(color=self.config.color, width=self.config.pen_width, style=pen_style)
|
||||
pen = pg.mkPen(color=self.config.color, width=pen_width, style=pen_style)
|
||||
self.setPen(pen)
|
||||
|
||||
if self.config.symbol:
|
||||
symbol = None if line_fallback else self.config.symbol
|
||||
if symbol:
|
||||
symbol_color = self.config.symbol_color or self.config.color
|
||||
brush = pg.mkBrush(color=symbol_color)
|
||||
|
||||
self.setSymbolBrush(brush)
|
||||
self.setSymbolSize(self.config.symbol_size)
|
||||
self.setSymbol(self.config.symbol)
|
||||
self.setSymbol(symbol)
|
||||
|
||||
@property
|
||||
def dap_params(self):
|
||||
@@ -279,8 +285,7 @@ class Curve(BECConnector, pg.PlotDataItem):
|
||||
symbol(str): Symbol of the curve.
|
||||
"""
|
||||
self.config.symbol = symbol
|
||||
self.setSymbol(symbol)
|
||||
self.updateItems()
|
||||
self.apply_config()
|
||||
|
||||
def set_symbol_color(self, symbol_color: str):
|
||||
"""
|
||||
@@ -319,6 +324,7 @@ class Curve(BECConnector, pg.PlotDataItem):
|
||||
Args:
|
||||
pen_style(Literal["solid", "dash", "dot", "dashdot", "none"]): Style of the pen.
|
||||
Use "none" to display markers without connecting lines.
|
||||
During automatic downsampling, "none" uses a 1 px solid line without markers.
|
||||
"""
|
||||
self.config.pen_style = pen_style
|
||||
self.apply_config()
|
||||
|
||||
@@ -1938,7 +1938,8 @@ class Waveform(PlotBase):
|
||||
Curve items, by deactivating the symbol and activating downsampling auto, method='mean',
|
||||
if the data length exceeds N points. If the data length is less than N points, the
|
||||
symbol will be activated and downsampling will be deactivated. Maximum points will be
|
||||
5x the limit. Curves without a connecting line retain their markers at any length.
|
||||
5x the limit. The "none" style uses a 1 px solid line without markers while
|
||||
downsampling, retaining its configured appearance for smaller datasets.
|
||||
|
||||
Args:
|
||||
curve(Curve): The curve to adjust.
|
||||
@@ -1949,21 +1950,25 @@ class Waveform(PlotBase):
|
||||
if limit <= 1:
|
||||
logger.warning("Limit must be greater than 1.")
|
||||
return
|
||||
if curve.config.pen_style == "none" and curve.config.symbol is None:
|
||||
curve.set_symbol("o")
|
||||
if curve.config.pen_style == "none":
|
||||
downsampling = data_length > limit
|
||||
curve.setDownsampling(ds=None if downsampling else 1, auto=downsampling, method=method)
|
||||
if not downsampling and curve.config.symbol is None:
|
||||
curve.set_symbol("o")
|
||||
curve.apply_config()
|
||||
curve.setClipToView(True)
|
||||
return
|
||||
if data_length > limit:
|
||||
if curve.config.pen_style != "none" and curve.config.symbol is not None:
|
||||
if curve.config.symbol is not None:
|
||||
curve.set_symbol(None)
|
||||
if curve.config.pen_width > 3:
|
||||
curve.set_pen_width(3)
|
||||
curve.setDownsampling(ds=None, auto=True, method=method)
|
||||
curve.setClipToView(True)
|
||||
elif data_length <= limit:
|
||||
if curve.config.pen_style != "none":
|
||||
curve.set_symbol("o")
|
||||
curve.set_symbol("o")
|
||||
curve.set_pen_width(4)
|
||||
curve.setDownsampling(ds=1, auto=None, method=method)
|
||||
curve.setDownsampling(ds=1, auto=False, method=method)
|
||||
curve.setClipToView(True)
|
||||
|
||||
def setup_dap_for_scan(self):
|
||||
|
||||
@@ -1262,10 +1262,10 @@ def test_curve_no_line_style_preserves_markers(qtbot, mocked_client):
|
||||
np.testing.assert_array_equal(curve.scatter.getData(), [[2, 3, 4], [5, 6, 7]])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data_length", [500, 1500])
|
||||
@pytest.mark.parametrize("data_length", [1000, 1001])
|
||||
@pytest.mark.parametrize("symbol", [None, "d"])
|
||||
def test_curve_no_line_style_keeps_async_markers(qtbot, mocked_client, data_length, symbol):
|
||||
"""Async data retain markers, including when automatic styling previously hid them."""
|
||||
def test_curve_no_line_style_async_downsampling(qtbot, mocked_client, data_length, symbol):
|
||||
"""No-line curves fall back to a thin line without markers above the async limit."""
|
||||
wf = create_widget(qtbot, Waveform, client=mocked_client)
|
||||
curve = wf.plot(
|
||||
x=[1, 2, 3],
|
||||
@@ -1280,6 +1280,13 @@ def test_curve_no_line_style_keeps_async_markers(qtbot, mocked_client, data_leng
|
||||
wf._auto_adjust_async_curve_settings(curve, data_length)
|
||||
curve.setData(np.arange(data_length), np.arange(data_length))
|
||||
|
||||
assert curve.config.pen_style == "none"
|
||||
assert curve.config.pen_width == 3
|
||||
if data_length > 1000:
|
||||
assert curve.curve.opts["pen"].style() == Qt.SolidLine
|
||||
assert curve.curve.opts["pen"].widthF() == 1
|
||||
assert not curve.scatter.isVisible()
|
||||
return
|
||||
assert curve.curve.opts["pen"].style() == Qt.NoPen
|
||||
assert curve.scatter.isVisible()
|
||||
assert curve.config.symbol == (symbol or "o")
|
||||
@@ -1288,6 +1295,54 @@ def test_curve_no_line_style_keeps_async_markers(qtbot, mocked_client, data_leng
|
||||
assert curve.scatter.opts["brush"].color().name() == "#654321"
|
||||
|
||||
|
||||
def test_curve_no_line_downsampling_style_updates_and_restore(qtbot, mocked_client):
|
||||
"""Appearance updates keep the fallback, and smaller data restore the saved markers."""
|
||||
wf = create_widget(qtbot, Waveform, client=mocked_client)
|
||||
curve = wf.plot(x=np.arange(1500), y=np.arange(1500))
|
||||
wf._auto_adjust_async_curve_settings(curve, 1500)
|
||||
curve.set_pen_style("none")
|
||||
assert curve.curve.opts["pen"].style() == Qt.SolidLine
|
||||
assert curve.curve.opts["pen"].widthF() == 1
|
||||
assert not curve.scatter.isVisible()
|
||||
|
||||
curve.set_color("#123456")
|
||||
curve.set_pen_width(7)
|
||||
curve.set_symbol("d")
|
||||
curve.set_symbol_color("#654321")
|
||||
curve.set_symbol_size(12)
|
||||
assert curve.curve.opts["pen"].style() == Qt.SolidLine
|
||||
assert curve.curve.opts["pen"].widthF() == 1
|
||||
assert curve.curve.opts["pen"].color().name() == "#123456"
|
||||
assert not curve.scatter.isVisible()
|
||||
assert curve.config.pen_style == "none"
|
||||
assert curve.config.pen_width == 7
|
||||
assert curve.config.symbol == "d"
|
||||
|
||||
wf._auto_adjust_async_curve_settings(curve, 1000)
|
||||
curve.setData(np.arange(1000), np.arange(1000))
|
||||
assert not curve.opts["autoDownsample"]
|
||||
assert curve.curve.opts["pen"].style() == Qt.NoPen
|
||||
assert curve.config.pen_width == 7
|
||||
assert curve.scatter.isVisible()
|
||||
assert curve.scatter.opts["symbol"] == "d"
|
||||
assert curve.scatter.opts["size"] == 12
|
||||
assert curve.scatter.opts["brush"].color().name() == "#654321"
|
||||
|
||||
|
||||
def test_curve_no_line_after_named_style_downsampling_ends(qtbot, mocked_client):
|
||||
"""Selecting no line after a named style leaves downsampling does not keep the fallback."""
|
||||
wf = create_widget(qtbot, Waveform, client=mocked_client)
|
||||
curve = wf.plot(x=np.arange(1500), y=np.arange(1500))
|
||||
wf._auto_adjust_async_curve_settings(curve, 1500)
|
||||
wf._auto_adjust_async_curve_settings(curve, 1000)
|
||||
curve.setData(np.arange(1000), np.arange(1000))
|
||||
curve.set_pen_style("none")
|
||||
|
||||
assert not curve.opts["autoDownsample"]
|
||||
assert curve.curve.opts["pen"].style() == Qt.NoPen
|
||||
assert curve.scatter.isVisible()
|
||||
|
||||
|
||||
def test_curve_no_line_style_restores_existing_styles(qtbot, mocked_client):
|
||||
"""The no-line style is reversible, and legacy null styles still draw solid lines."""
|
||||
wf = create_widget(qtbot, Waveform, client=mocked_client)
|
||||
|
||||
Reference in new issue
Block a user