Skip to content

Commit 218274d

Browse files
committed
Color each cutout diaSource by its owning diaObject
In plot_objects_sharing_sources, source markers now take the palette color of the diaObject they belong to instead of a single shared color. The right panel maps sources to their run-2 owner so the same source can read differently across the two runs.
1 parent a2cfebf commit 218274d

1 file changed

Lines changed: 32 additions & 5 deletions

File tree

python/lsst/analysis/ap/nb_utils.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ def _render_cutout_axes(ax, row, cutout_data, sources,
636636
marker_size, marker_symbol,
637637
source_marker_size, current_source_marker_size,
638638
current_source_color,
639+
source_match_ids=None,
639640
title=None, subtitle=""):
640641
"""Render one diaSource cutout onto an existing matplotlib Axes
641642
using preloaded data from `_load_cutout`.
@@ -689,13 +690,28 @@ def _render_cutout_axes(ax, row, cutout_data, sources,
689690
src_xs = src_ys = None
690691
other_src_mask = current_src_mask = None
691692

693+
# Per-diaSource color resolution: map each diaSource to its
694+
# owning diaObject (in this panel's view), then to that
695+
# diaObject's palette color. Falls back to `current_source_color`
696+
# for sources whose owner is not present in `obj_ids`.
697+
if source_match_ids is None:
698+
match_ids_list = sources["diaObjectId"].tolist()
699+
else:
700+
match_ids_list = list(source_match_ids)
701+
src_to_match = dict(zip(sources["diaSourceId"].tolist(),
702+
match_ids_list))
703+
id_to_color = dict(zip(obj_ids.tolist(), obj_colors))
704+
705+
def _color_for(diaSourceId):
706+
return id_to_color.get(
707+
src_to_match.get(int(diaSourceId)), current_source_color)
708+
692709
if other_src_mask is not None and other_src_mask.any():
693-
# Share the current-diaSource color so the source positions are
694-
# easy to read against the cm.bone background; the marker
695-
# symbol (+ vs x) still distinguishes them.
710+
other_indices = np.flatnonzero(other_src_mask)
711+
other_colors = [_color_for(int(id_arr[i])) for i in other_indices]
696712
ax.scatter(src_xs[other_src_mask], src_ys[other_src_mask],
697713
s=source_marker_size, marker="+",
698-
c=current_source_color, linewidths=1.0,
714+
c=other_colors, linewidths=1.0,
699715
label="other diaSource")
700716

701717
if len(obj_ids) > 0:
@@ -718,7 +734,7 @@ def _render_cutout_axes(ax, row, cutout_data, sources,
718734
if current_src_mask is not None and current_src_mask.any():
719735
ax.scatter(src_xs[current_src_mask], src_ys[current_src_mask],
720736
s=current_source_marker_size, marker="x",
721-
c=current_source_color, linewidths=2.0,
737+
c=_color_for(this_id), linewidths=2.0,
722738
label=f"current diaSourceId={this_id}")
723739

724740
if title is None:
@@ -926,6 +942,16 @@ def plot_objects_sharing_sources(diaObjectId, sources1, sources2,
926942
left_overlays = _prepare_object_overlays(ro1, palette)
927943
right_overlays = _prepare_object_overlays(ro2, palette)
928944

945+
# diaSourceId -> run-2 diaObjectId, so the right panel can color
946+
# each diaSource by its run-2 owner. The left panel uses the
947+
# default (sources["diaObjectId"], the run-1 owner) since
948+
# `sources` is a slice of `sources1`.
949+
src_to_obj2 = dict(zip(
950+
sources2["diaSourceId"].to_numpy(),
951+
sources2["diaObjectId"].to_numpy()))
952+
right_match_ids = [src_to_obj2.get(int(sid))
953+
for sid in sources["diaSourceId"]]
954+
929955
n_rows = len(sources)
930956
# One subfigure per row so each row can carry a single shared
931957
# suptitle above both panels; the per-axes title is then just the
@@ -959,6 +985,7 @@ def plot_objects_sharing_sources(diaObjectId, sources1, sources2,
959985
_render_cutout_axes(ax_right, row, cutout_data, sources,
960986
*right_overlays,
961987
title="", subtitle=column_labels[1],
988+
source_match_ids=right_match_ids,
962989
**common_kw)
963990

964991
if output_path is not None:

0 commit comments

Comments
 (0)