Skip to content
Merged

Fixes #193

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
f80b261
Register cellposev4 in benchmark run scripts
dariarom94 Jul 19, 2026
1a2fa09
fix anndata version mismatch with txsim
dariarom94 Jul 19, 2026
82add80
add segger to workflow (test)
dariarom94 Jul 19, 2026
53e1728
duplicates when FOV stiching cleaned up
dariarom94 Jul 19, 2026
1186b7a
chunks issue atera
dariarom94 Jul 20, 2026
18644d7
segger update image
dariarom94 Jul 20, 2026
ecb302d
claude fix for segger
dariarom94 Jul 20, 2026
7d66898
Merge branch 'main' into fixes
dariarom94 Jul 20, 2026
d400ebe
atera version fix
dariarom94 Jul 20, 2026
64d7b4e
wf for the custom rnaseq scripts
dariarom94 Jul 20, 2026
3edfbf1
adjust the loader image name
dariarom94 Jul 20, 2026
cbd2f12
adjust the memory
dariarom94 Jul 20, 2026
184260e
troubleshootig edges
dariarom94 Jul 20, 2026
9fa9a33
Merge branch 'main' into fixes
dariarom94 Jul 20, 2026
36631c4
segger update
dariarom94 Jul 21, 2026
0626127
cell type label correction
dariarom94 Jul 21, 2026
3186435
fix boundaries
dariarom94 Jul 21, 2026
d8a7d93
Merge branch 'main' into fixes
dariarom94 Jul 21, 2026
3505718
OOM fixes
dariarom94 Jul 21, 2026
d6e110a
fix code
dariarom94 Jul 21, 2026
4660f26
RCTD
dariarom94 Jul 21, 2026
5abd651
segger to RAPIDS
dariarom94 Jul 21, 2026
fe2e90a
Merge branch 'main' into fixes
dariarom94 Jul 21, 2026
0b23474
fix rctd
dariarom94 Jul 22, 2026
196ff1f
segger debug (torchvision)
dariarom94 Jul 22, 2026
4be7bd4
Merge branch 'main' into fixes
dariarom94 Jul 22, 2026
b8d3d7b
save the xenium version
dariarom94 Jul 22, 2026
202ac49
add atera to datasets
dariarom94 Jul 22, 2026
14be8d0
Add gene efficiency correction as a separate pipeline stage (#183)
dariarom94 Jul 22, 2026
0cf0243
moscot to pca and segger troubleshooting
dariarom94 Jul 22, 2026
d7afb84
added fastreseg
dariarom94 Jul 23, 2026
f87a1d9
segger bug new fix
dariarom94 Jul 23, 2026
123e112
fastreseg to workflow
dariarom94 Jul 23, 2026
7549589
add fastreseg test
dariarom94 Jul 23, 2026
9fa9604
Merge branch 'main' into fixes
dariarom94 Jul 23, 2026
ff04467
optimized fastreseg build
dariarom94 Jul 23, 2026
7ffc514
Merge branch 'main' into fixes
dariarom94 Jul 23, 2026
a7404d8
add s3 paths
dariarom94 Jul 23, 2026
19e5f83
troubleshoot comseg/segger
dariarom94 Jul 24, 2026
aaca151
segger update
dariarom94 Jul 25, 2026
c9bdb91
data loader bug
dariarom94 Jul 25, 2026
1df9834
Merge branch 'main' into fixes
dariarom94 Jul 25, 2026
4467d32
rctd adjustment (raw counts)
dariarom94 Jul 26, 2026
58912e4
fix segger and comseg
dariarom94 Jul 26, 2026
0a5aa99
optimize cosmx
dariarom94 Jul 26, 2026
298e666
Merge branch 'main' into fixes
dariarom94 Jul 26, 2026
c921937
parameter test for cellpose4
dariarom94 Jul 26, 2026
57c2d79
add atera
dariarom94 Jul 26, 2026
cf67e09
add a test in pciseq and dynamic memory for bruker
dariarom94 Jul 27, 2026
9f71692
add test to vizgen data
dariarom94 Jul 28, 2026
d795f33
Merge branch 'main' into fixes
dariarom94 Jul 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 83 additions & 53 deletions src/datasets/loaders/vizgen_merscope/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from datetime import datetime
from pathlib import Path

import dask.array as da
import geopandas as gpd
import h5py
import numpy as np
import pandas as pd
import spatialdata as sd
import spatialdata_io as sdio
Expand Down Expand Up @@ -44,47 +46,50 @@
)


def _cell_polygon(cell_grp):
"""Boundary for one cell: prefer zIndex_3, else any available z-plane.

MERSCOPE stores a cell's boundary only at the z-planes where it appears, so keying on a
single hardcoded z-index (the old ``["zIndex_3"]``) drops -- or KeyErrors on -- every cell
not present at that plane. Returns None if the cell has no usable boundary.
"""
z_keys = list(cell_grp.keys())
z = "zIndex_3" if "zIndex_3" in z_keys else (z_keys[0] if z_keys else None)
if z is None or "p_0" not in cell_grp[z] or "coordinates" not in cell_grp[z]["p_0"]:
return None
return MultiPolygon([Polygon(cell_grp[z]["p_0"]["coordinates"][()][0])])


def read_boundary_hdf5(folder):
print(datetime.now() - t0, "Convert boundary hdf5 to parquet", flush=True)
all_boundaries = {}
boundaries = None
hdf5_files = os.listdir(folder + "/cell_boundaries/")
hdf5_files = [
f for f in os.listdir(folder + "/cell_boundaries/") if f.endswith(".hdf5")
]
n_files = len(hdf5_files)
incr = n_files // 15
for _, i in enumerate(hdf5_files):
if (_ % incr) == 0:
print(datetime.now() - t0, f"\tProcessed {_}/{n_files}", flush=True)
with h5py.File(folder + "/cell_boundaries/" + i, "r") as f:
for key in f["featuredata"].keys():
if boundaries is not None:
boundaries.loc[key] = MultiPolygon(
[
Polygon(
f["featuredata"][key]["zIndex_3"]["p_0"]["coordinates"][
()
][0]
)
]
) # doesn't matter which zIndex we use, MultiPolygon to work with read function in spatialdata-io
else:
# boundaries = gpd.GeoDataFrame(index=[key], geometry=MultiPolygon([Polygon(f['featuredata'][key]['zIndex_3']['p_0']['coordinates'][()][0])]))
boundaries = gpd.GeoDataFrame(
geometry=gpd.GeoSeries(
MultiPolygon(
[
Polygon(
f["featuredata"][key]["zIndex_3"]["p_0"][
"coordinates"
][()][0]
)
]
),
index=[key],
)
)
all_boundaries[i] = boundaries
boundaries = None
all_concat = pd.concat(list(all_boundaries.values()))
incr = max(1, n_files // 15) # guard against ZeroDivision when <15 files
geoms, index, n_skipped = [], [], 0
for n, fname in enumerate(hdf5_files):
if n % incr == 0:
print(datetime.now() - t0, f"\tProcessed {n}/{n_files}", flush=True)
with h5py.File(folder + "/cell_boundaries/" + fname, "r") as f:
featuredata = f["featuredata"]
for key in featuredata.keys():
poly = _cell_polygon(featuredata[key])
if poly is None:
n_skipped += 1
continue
geoms.append(poly)
index.append(key)
# n_skipped is logged (never silently dropped) so a re-run reveals whether low boundary
# coverage is a reader problem or a genuine property of the raw hdf5.
print(
datetime.now() - t0,
f"Read {len(geoms)} cell boundaries from {n_files} files "
f"({n_skipped} cells had no usable z-plane boundary)",
flush=True,
)
# Build the GeoDataFrame in one pass; the old row-by-row `.loc` growth was O(n^2) over ~10^5 cells.
all_concat = gpd.GeoDataFrame(geometry=gpd.GeoSeries(geoms, index=index))
all_concat = all_concat[
~all_concat.index.duplicated(keep="first")
] # hdf5 can contain duplicates with same cell_id and position, removing those
Expand Down Expand Up @@ -241,23 +246,48 @@ def read_boundary_hdf5(folder):
"return_regions_as_labels": True,
}

for i in range(n_iter):
print(
datetime.now() - t0,
f"Rasterizing iteration {i + 1}/{n_iter} (cells {i * N}..{min((i + 1) * N, n_cells)})",
flush=True,
if n_iter == 1:
# Common case (every current dataset has <65535 cells): a single rasterize call.
# Keep the lazy DataArray exactly as before.
print(datetime.now() - t0, "Rasterizing all cells in a single pass", flush=True)
labels_image = sd.rasterize(
sdata["cell_boundaries"], ["x", "y"], **rasterize_args
)
labels_image_ = sd.rasterize(
sdata["cell_boundaries"].iloc[i * N : min((i + 1) * N, n_cells)],
["x", "y"],
**rasterize_args,
else:
# >65535 cells: rasterize in chunks and merge. Two subtleties make the naive in-place
# merge wrong (it was silently broken before; this path had never run on real data since
# no dataset exceeds 65535 cells):
# 1. sd.rasterize returns a *lazy* (dask-backed) DataArray whose `.values` is a computed
# copy, so the old `labels_image.values[mask] = ...` write never persisted. We
# materialise each chunk and merge in a plain numpy array instead.
# 2. return_regions_as_labels labels each chunk 1..len(chunk) *positionally*, so chunks
# would collide on the same label. We offset each chunk by its global start index
# (and use uint32, since labels exceed uint16 past 65535 cells).
combined = None
template = None
for i in range(n_iter):
start = i * N
end = min((i + 1) * N, n_cells)
print(
datetime.now() - t0,
f"Rasterizing iteration {i + 1}/{n_iter} (cells {start}..{end})",
flush=True,
)
chunk = sd.rasterize(
sdata["cell_boundaries"].iloc[start:end], ["x", "y"], **rasterize_args
)
chunk_np = np.asarray(chunk.data)
if combined is None:
combined = chunk_np.astype("uint32")
template = chunk
else:
mask = chunk_np > 0
combined[mask] = chunk_np[mask].astype("uint32") + start
# Rebuild a dask-backed labels element (spatialdata rejects a numpy-backed one) while
# preserving the template's transform and attrs (incl. label_index_to_category).
labels_image = template.copy(
data=da.from_array(combined, chunks=template.data.chunksize)
)
if i == 0:
labels_image = labels_image_
else:
labels_image.values[labels_image_.values > 0] = labels_image_.values[
labels_image_.values > 0
]

print(datetime.now() - t0, "Rasterization finished", flush=True)
try:
Expand Down
2 changes: 1 addition & 1 deletion src/methods_transcript_assignment/pciseq/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def eta_update_no_assert(self):
# Fail fast with an actionable message instead. This happens when the upstream `cell_labels`
# copied by custom_segmentation is empty (observed for the vizgen lung-cancer merscope dataset,
# whose polygon->label rasterization produced an all-zero image).
if not (label_image > 0).any():
if label_image.max() == 0:
raise ValueError(
f"Segmentation '{par['input_segmentation']}' contains no cells: the label image "
f"(shape={label_image.shape}, dtype={label_image.dtype}) is entirely zero. pciSeq "
Expand Down
Loading