Skip to content

View all bits in display_results method in Pixel Decoder #81

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion examples/bioprotean_mouse/04_pixeldecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ def decode_pixels(
datastore.save_mtx()

if __name__ == "__main__":
root_path = Path(r"/mnt/data/bartelle/20241108_Bartelle_MouseMERFISH_LC")
root_path = Path(r"/data/smFISH/12062024_Bartelle24hrcryo_sample2")
decode_pixels(root_path=root_path,run_baysor=False)
34 changes: 34 additions & 0 deletions examples/bioprotean_smFISH/smFISH_decoding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from merfish3danalysis.qi2labDataStore import qi2labDataStore
from merfish3danalysis.PixelDecoder import PixelDecoder
from pathlib import Path
# import numpy as np

root_path = Path(r"/data/smFISH/02202025_Bartelle_control_smFISH_TqIB")

# initialize datastore
datastore_path = root_path / Path(r"qi2labdatastore")
datastore = qi2labDataStore(datastore_path)
merfish_bits = datastore.num_bits

# initialize decodor class
decoder = PixelDecoder(
datastore=datastore,
use_mask=False,
merfish_bits=merfish_bits,
verbose=1,
smFISH = True
)

# decode one tile
decoder.decode_one_tile(
tile_idx=0, # Specify the tile index
display_results=True, # Set to True to visualize results in Napari
lowpass_sigma=(3, 1, 1), # Lowpass filter sigma
magnitude_threshold=0.9, # L2-norm threshold
minimum_pixels=3.0, # Minimum number of pixels for a barcode
use_normalization=False, # Use normalization
ufish_threshold=0.5 # Ufish threshold
)

# # Save barcodes
# decoder._save_barcodes()
52 changes: 52 additions & 0 deletions examples/bioprotean_smFISH/smFISH_spot_detection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from merfish3danalysis.qi2labDataStore import qi2labDataStore
from pathlib import Path
import pandas as pd

root_path = Path(r"/data/smFISH/02202025_Bartelle_control_smFISH_TqIB")

class smFISH_spotdetection:
def __init__(self, datastore, threshold=5):
self.datastore = datastore
self.threshold = threshold

def read_ufish_localizations(self, tile_id, bit_id):
self._ufish_localizations_root_path = self.datastore._ufish_localizations_root_path
current_ufish_localizations_path = (
self._ufish_localizations_root_path
/ Path(tile_id)
/ Path(bit_id + ".parquet")
)
if not current_ufish_localizations_path.exists():
raise FileNotFoundError(f"File {current_ufish_localizations_path} does not exist.")
return pd.read_parquet(current_ufish_localizations_path)

def get_tile_ids(self):
if not self.datastore._ufish_localizations_root_path.exists():
raise FileNotFoundError(f"Directory {self.datastore._ufish_localizations_root_path} does not exist.")
return sorted([p.name for p in self.datastore._ufish_localizations_root_path.iterdir() if p.is_dir()], key=lambda x: int(x.replace("tile", "")))

def get_bit_ids(self, tile_id):
tile_path = self.datastore._ufish_localizations_root_path / Path(tile_id)
if not tile_path.exists():
raise FileNotFoundError(f"Directory {tile_path} does not exist.")
return sorted([p.stem for p in tile_path.glob("*.parquet")], key=lambda x: int(x.replace("bit", "")))


datastore_path = root_path / Path(r"qi2labdatastore")
datastore = qi2labDataStore(datastore_path)
smfish_class = smFISH_spotdetection(datastore)

tile_ids = smfish_class.get_tile_ids()
for tile_id in tile_ids:
bit_ids = smfish_class.get_bit_ids(tile_id)
for bit_id in bit_ids:
ufish_localizations_df = smfish_class.read_ufish_localizations(tile_id, bit_id)

ufish_probabilities = ufish_localizations_df.loc[:, "sum_prob_pixels"]
ufish_localizations_df["thresholded_probabilities"] = ufish_probabilities.where(ufish_probabilities >= smfish_class.threshold, 0)

output_path = datastore_path / "ufish_localizations_thresholded" / tile_id / f"{bit_id}_thresholded.parquet"
output_path.parent.mkdir(parents=True, exist_ok=True)
ufish_localizations_df.to_parquet(output_path)

print("Thresholded probabilities saved")
45 changes: 29 additions & 16 deletions src/merfish3danalysis/PixelDecoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def __init__(
use_mask: Optional[bool] = False,
z_range: Optional[Sequence[int]] = None,
include_blanks: Optional[bool] = True,
smFISH: bool = False
):
self._datastore = datastore
self._verbose = verbose
Expand All @@ -79,6 +80,10 @@ def __init__(

self._n_merfish_bits = merfish_bits

# Is this data smFISH or MERFISH?
# Default is False, meaning data is MERFISH
self._smFISH = smFISH

if self._datastore.microscope_type == "2D":
self._is_3D = False
else:
Expand Down Expand Up @@ -956,8 +961,8 @@ def _extract_barcodes(
for barcode_index in iterable_barcode:
on_bits_indices = np.where(self._codebook_matrix[barcode_index])[0]

if len(on_bits_indices) == 1:
break
# if len(on_bits_indices) == 1:
# break

if self._is_3D:
if self._verbose > 1:
Expand Down Expand Up @@ -999,10 +1004,10 @@ def _extract_barcodes(

df_barcode = pd.DataFrame(props)

df_barcode["on_bit_1"] = on_bits_indices[0] + 1
df_barcode["on_bit_2"] = on_bits_indices[1] + 1
df_barcode["on_bit_3"] = on_bits_indices[2] + 1
df_barcode["on_bit_4"] = on_bits_indices[3] + 1
df_barcode["on_bit_1"] = on_bits_indices[0] + 1 if len(on_bits_indices) > 0 else 0
df_barcode["on_bit_2"] = on_bits_indices[1] + 1 if len(on_bits_indices) > 1 else 0
df_barcode["on_bit_3"] = on_bits_indices[2] + 1 if len(on_bits_indices) > 2 else 0
df_barcode["on_bit_4"] = on_bits_indices[3] + 1 if len(on_bits_indices) > 3 else 0
df_barcode["barcode_id"] = df_barcode.apply(
lambda x: (barcode_index + 1), axis=1
)
Expand Down Expand Up @@ -1116,10 +1121,10 @@ def _extract_barcodes(

df_barcode = pd.DataFrame(props)

df_barcode["on_bit_1"] = on_bits_indices[0] + 1
df_barcode["on_bit_2"] = on_bits_indices[1] + 1
df_barcode["on_bit_3"] = on_bits_indices[2] + 1
df_barcode["on_bit_4"] = on_bits_indices[3] + 1
df_barcode["on_bit_1"] = on_bits_indices[0] + 1 if len(on_bits_indices) > 0 else 0
df_barcode["on_bit_2"] = on_bits_indices[1] + 1 if len(on_bits_indices) > 1 else 0
df_barcode["on_bit_3"] = on_bits_indices[2] + 1 if len(on_bits_indices) > 2 else 0
df_barcode["on_bit_4"] = on_bits_indices[3] + 1 if len(on_bits_indices) > 3 else 0
df_barcode["barcode_id"] = df_barcode.apply(
lambda x: (barcode_index + 1), axis=1
)
Expand Down Expand Up @@ -1841,12 +1846,20 @@ def on_close_callback():
app = QApplication.instance()

app.lastWindowClosed.connect(on_close_callback)

viewer.add_image(
self._scaled_pixel_images,
scale=[self._axial_step, self._pixel_size, self._pixel_size],
name="pixels",
)

if self._smFISH:
for bit in range(self._datastore.num_bits):
viewer.add_image(
self._scaled_pixel_images[bit],
scale=[self._axial_step, self._pixel_size, self._pixel_size],
name="pixels_" + str(bit),
)
else:
viewer.add_image(
self._scaled_pixel_images,
scale=[self._axial_step, self._pixel_size, self._pixel_size],
name="pixels",
)

viewer.add_image(
self._decoded_image,
Expand Down
11 changes: 11 additions & 0 deletions src/merfish3danalysis/run_baysor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@



#in pixeldecoder.py
_reformat_barcodes_for_baysor

# in qi2labdatastore.py

_reformat_barcodes_for_baysor

_run_baysor