@@ -224,12 +224,27 @@ def _style_axes_atmosphere(axes: plt.Axes) -> None:
224224
225225
226226def _plot_detection_curves (axes : plt .Axes , runs : RunCollection ) -> None :
227- """One paper-style detection-mode contrast curve per sweep cell."""
227+ """One paper-style detection-mode contrast curve per sweep cell.
228+
229+ Cells whose legend label duplicates an already-drawn one are skipped
230+ (with a logged notice): sweeps over parameters the label does not encode
231+ (e.g. scene.planet.contrast) otherwise stack visually identical lines
232+ and repeated legend entries. Only the first such cell is drawn, so
233+ per-cell Monte Carlo scatter (e.g. the HOSTS exozodi draw) is not
234+ averaged, just represented by one cell.
235+ """
228236
237+ seen : set [str ] = set ()
238+ n_duplicates = 0
229239 for record in _paper_curve_records (runs ):
230240 curve = record .result .state .results .contrast_curve
231241 if curve is None or curve .size == 0 :
232242 continue
243+ key = _curve_legend_label (record , mode = "det" )
244+ if key in seen :
245+ n_duplicates += 1
246+ continue
247+ seen .add (key )
233248 separations_mas = np .asarray (curve ["separation_mas" ], dtype = np .float64 )
234249 contrasts = np .asarray (curve ["contrast" ], dtype = np .float64 )
235250 order = np .argsort (separations_mas )
@@ -272,6 +287,12 @@ def _plot_detection_curves(axes: plt.Axes, runs: RunCollection) -> None:
272287 linewidth = 0 ,
273288 zorder = 1 ,
274289 )
290+ if n_duplicates :
291+ logging .info (
292+ "detection_space: skipped %d sweep cell(s) whose legend label "
293+ "duplicates an already-plotted cell." ,
294+ n_duplicates ,
295+ )
275296
276297
277298# ----------------------------------------------------------------------
@@ -508,12 +529,17 @@ def _bin_widths_um(wavelengths_um: NDArrayFloat) -> NDArrayFloat:
508529def _plot_characterization_curves (axes : plt .Axes , runs : RunCollection ) -> None :
509530 """Overlay char-mode 5σ contrast curves as dashed lines matched in colour."""
510531
532+ seen : set [str ] = set ()
511533 for record in _paper_curve_records (runs ):
512534 payload = _characterization_curve (record )
513535 if payload is None :
514536 continue
515537 separations_mas = np .asarray (payload ["separations_mas" ], dtype = np .float64 )
516538 contrasts = np .asarray (payload ["contrast_5sigma" ], dtype = np .float64 )
539+ key = _curve_legend_label (record , mode = "char" )
540+ if key in seen :
541+ continue
542+ seen .add (key )
517543 mask = (
518544 np .isfinite (separations_mas )
519545 & np .isfinite (contrasts )
@@ -876,17 +902,31 @@ def _attach_legends(
876902
877903 handles : list [Line2D ] = []
878904 labels : list [str ] = []
905+ seen_det : set [str ] = set ()
879906 for record in _paper_curve_records (runs ):
880- if record .result .state .results .contrast_curve is None :
907+ curve = record .result .state .results .contrast_curve
908+ if curve is None :
909+ continue
910+ # Mirror the label dedupe in _plot_detection_curves: one legend
911+ # entry per drawn line.
912+ key = _curve_legend_label (record , mode = "det" )
913+ if key in seen_det :
881914 continue
915+ seen_det .add (key )
882916 handles .append (
883917 Line2D ([], [], color = _DETECTION_COLOR , ** _line_style_for_record (record ))
884918 )
885919 labels .append (_curve_legend_label (record , mode = "det" ))
886920
921+ seen_char : set [str ] = set ()
887922 for record in _paper_curve_records (runs ):
888- if _characterization_curve (record ) is None :
923+ payload = _characterization_curve (record )
924+ if payload is None :
925+ continue
926+ key = _curve_legend_label (record , mode = "char" )
927+ if key in seen_char :
889928 continue
929+ seen_char .add (key )
890930 handles .append (
891931 Line2D (
892932 [],
0 commit comments