Skip to content

Commit

Permalink
plots.xy_1d: fixup annotations
Browse files Browse the repository at this point in the history
As we want stable series colours when hiding/showing series from the context menu,
the series_idx is not monotonic. To maintain matching colours of the annotations,
this had to be added to _XYSeries.
Moreover, 'location' annotations are now shown once on each pane, unless associated_channels
are specified. In that case, the annotation is only added to the pane(s) where these
channel(s) are shown. To make this information available, the pane_idx had to be added to
_XYSeries.
  • Loading branch information
pmldrmota authored and dnadlinger committed Oct 9, 2023
1 parent ce404ad commit f428ea4
Showing 1 changed file with 70 additions and 45 deletions.
115 changes: 70 additions & 45 deletions ndscan/plots/xy_1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ def combined_uncertainty(points: list[SourcePoint], num_samples_per_point=1):


class _XYSeries(QtCore.QObject):
def __init__(self, view_box, data_name, data_item, error_bar_name, error_bar_item):
def __init__(self, view_box, data_name, data_item, error_bar_name, error_bar_item,
series_idx, pane_idx):
super().__init__(view_box)

self.view_box = view_box
Expand All @@ -62,6 +63,8 @@ def __init__(self, view_box, data_name, data_item, error_bar_name, error_bar_ite
self.error_bar_item = error_bar_item
self.error_bar_name = error_bar_name
self.num_current_points = 0
self.series_idx = series_idx
self.pane_idx = pane_idx

#: Whether to average points with the same x coordinate.
self.averaging_enabled = False
Expand Down Expand Up @@ -243,7 +246,8 @@ def _initialise_series(self, channels):

self.series.append(
_XYSeries(view_box, name, data_item, error_bar_name,
error_bar_item, series_idx))
error_bar_item, series_idx,
len(self.panes) - 1))

channel = channels[name]
label = channel["description"]
Expand Down Expand Up @@ -304,11 +308,26 @@ def _clear_annotations(self):
def _update_annotations(self):
self._clear_annotations()

def channel_ref_to_series_idx(ref):
for i, s in enumerate(self.series):
if "channel_" + s.data_name == ref:
return i
return 0
def channel_refs_to_series(refs):
associated_series = []
seen_panes = set[int]()
for series in self.series:
if series.pane_idx in seen_panes:
# Limit to one entry per pane.
continue
use_series = False
if refs is None:
# Append an entry in each viewbox.
use_series = True
else:
for ref in refs:
if "channel_" + series.data_name == ref:
use_series = True
break
if use_series:
associated_series.append(series)
seen_panes.add(series.pane_idx)
return associated_series

def make_curve_item(series_idx):
color = FIT_COLORS[series_idx % len(FIT_COLORS)]
Expand All @@ -319,51 +338,57 @@ def make_curve_item(series_idx):
for a in annotations:
if a.kind == "location":
if set(a.coordinates.keys()) == {"axis_0"}:
associated_series_idx = max(
channel_ref_to_series_idx(chan)
for chan in a.parameters.get("associated_channels", [None]))

color = FIT_COLORS[associated_series_idx % len(FIT_COLORS)]
vb = self.series[associated_series_idx].view_box
line = VLineItem(a.coordinates["axis_0"],
a.data.get("axis_0_error", None), vb, color,
self.x_data_to_display_scale, self.x_unit_suffix)
self.annotation_items.append(line)
continue

if a.kind == "curve":
associated_series_idx = None
for series_idx, series in enumerate(self.series):
channel_refs = a.parameters.get("associated_channels", None)
associated_series = channel_refs_to_series(channel_refs)
for series in associated_series:
color = FIT_COLORS[series.series_idx % len(FIT_COLORS)]
line = VLineItem(
a.coordinates["axis_0"],
a.data.get("axis_0_error", None),
series.view_box,
color,
self.x_data_to_display_scale,
self.x_unit_suffix,
)
self.annotation_items.append(line)

elif a.kind == "curve":
associated_series = None
for series in self.series:
match_coords = {"axis_0", "channel_" + series.data_name}
if set(a.coordinates.keys()) == match_coords:
associated_series_idx = series_idx
associated_series = series
break
if associated_series_idx is not None:
curve = make_curve_item(associated_series_idx)
series = self.series[associated_series_idx]
vb = series.view_box
item = CurveItem(a.coordinates["axis_0"],
a.coordinates["channel_" + series.data_name], vb,
curve)
if associated_series is not None:
item = CurveItem(
a.coordinates["axis_0"],
a.coordinates["channel_" + associated_series.data_name],
associated_series.view_box,
make_curve_item(associated_series.series_idx),
)
self.annotation_items.append(item)
continue

if a.kind == "computed_curve":
elif a.kind == "computed_curve":
function_name = a.parameters.get("function_name", None)
if ComputedCurveItem.is_function_supported(function_name):
associated_series_idx = max(
channel_ref_to_series_idx(chan)
for chan in a.parameters.get("associated_channels", [None]))

x_limits = [self.x_param_spec.get(n, None) for n in ("min", "max")]
curve = make_curve_item(associated_series_idx)
vb = self.series[associated_series_idx].view_box
item = ComputedCurveItem(function_name, a.data, vb, curve, x_limits)
self.annotation_items.append(item)
continue

logger.info("Ignoring annotation of kind '%s' with coordinates %s", a.kind,
list(a.coordinates.keys()))
channel_refs = a.parameters.get("associated_channels", [])
associated_series = channel_refs_to_series(channel_refs)
for series in associated_series:
x_limits = [
self.x_param_spec.get(n, None) for n in ("min", "max")
]
item = ComputedCurveItem(
function_name,
a.data,
series.view_box,
make_curve_item(series.series_idx),
x_limits,
)
self.annotation_items.append(item)

else:
logger.info("Ignoring annotation of kind '%s' with coordinates %s",
a.kind, list(a.coordinates.keys()))

def build_context_menu(self, pane_idx, builder):
x_schema = self.model.axes[0]
Expand Down

0 comments on commit f428ea4

Please sign in to comment.