From ba37598dd0272b46c59f46ccb70c93efd94b0587 Mon Sep 17 00:00:00 2001 From: Elihei2 Date: Mon, 1 Jun 2026 13:37:09 +0200 Subject: [PATCH] fix(tiling): fall back to a smaller margin instead of dropping tiles When the inner-tile negative buffer uses too large a margin, small tiles shrink to empty. Previously those tiles were removed from the spatial query, silently dropping every geometry they contained (a frequent cause of large numbers of unassigned transcripts on dense/small-tile datasets). Instead, progressively halve the margin (down to 0) until every tile survives the buffer, emitting a warning with the reduced value. No behavior change when the requested margin already leaves all tiles non-empty. What to review: - src/segger/data/tiling.py: the buffer/fallback loop in the query method. - The loop is bounded (margin strictly halves; terminates at 0 = unbuffered tiles, which can never be empty), so it cannot spin. - Trade-off: a reduced margin means slightly less inner/outer separation for the affected tiles, which is strictly better than dropping their geometries. --- src/segger/data/tiling.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/segger/data/tiling.py b/src/segger/data/tiling.py index 6a5ef72..1e2f920 100644 --- a/src/segger/data/tiling.py +++ b/src/segger/data/tiling.py @@ -100,16 +100,30 @@ def _query_tiles( join_style='mitre', mitre_limit=margin / 2, ) - missing = buffered.is_empty.sum() - # handling tiles too small for buffer - if missing != 0: - import warnings + # Fallback: an over-aggressive margin shrinks small tiles to nothing, + # which would drop their geometries from the query entirely (leaving + # many transcripts unassigned). Rather than lose them, progressively + # halve the margin until every tile survives the negative buffer. + import warnings + eff_margin = margin + while eff_margin > 0 and bool(buffered.is_empty.any()): + n_lost = int(buffered.is_empty.sum()) + eff_margin = eff_margin / 2 if eff_margin > 1e-6 else 0.0 warnings.warn( - f"Margin ({margin}) is too large, causing {missing} " - f"tile(s) to disappear. These tiles will be removed from the query." + f"Margin ({margin}) is too large, causing {n_lost} tile(s) to " + f"disappear; retrying with a reduced margin ({eff_margin}) so " + f"their geometries are not dropped from the query." + ) + buffered = ( + tiles.buffer( + -eff_margin, + cap_style='square', + join_style='mitre', + mitre_limit=max(eff_margin / 2, 1e-9), + ) + if eff_margin > 0 + else tiles ) - # Filter out the empty tiles - buffered = buffered[~buffered.is_empty] tiles = buffered # Spatial query