Skip to content

Commit e3f24f5

Browse files
Add analysis script for synapse subtypes
1 parent 1a9d8f8 commit e3f24f5

File tree

2 files changed

+118
-3
lines changed

2 files changed

+118
-3
lines changed

scripts/figures/plot_fig6.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
png_dpi = 300
77

88

9-
def fig_06a(save_path, plot=False):
9+
def fig_06b(save_path, plot=False):
1010
"""Box plot showing the counts for SGN and IHC per gerbil cochlea in comparison to literature values.
1111
"""
1212
main_tick_size = 12
@@ -75,13 +75,29 @@ def fig_06a(save_path, plot=False):
7575
plt.close()
7676

7777

78+
def fig_06d(save_path, plot=False):
79+
"""Plot the synapse distribution measured with different markers.
80+
81+
The underlying measurements were done with 'scripts/measurements/synapse_colocalization.py'
82+
83+
Here are the other relevant numbers for the analysis.
84+
Number of IHCs: 486
85+
Number of matched synapses: 3119
86+
Number and percentage of matched synapses for markers:
87+
CTBP2: 3119 / 3371 (92.52447345001484% matched)
88+
RibA : 3119 / 6701 (46.54529174750037% matched)
89+
"""
90+
# TODO Plot this
91+
92+
7893
def main():
79-
parser = argparse.ArgumentParser(description="Generate plots for Fig 2 of the cochlea paper.")
94+
parser = argparse.ArgumentParser(description="Generate plots for Fig 6 of the cochlea paper.")
8095
parser.add_argument("figure_dir", type=str, help="Output directory for plots.", default="./panels")
8196
args = parser.parse_args()
8297
plot = False
8398

84-
fig_06a(save_path=os.path.join(args.figure_dir, "fig_06a"), plot=plot)
99+
fig_06b(save_path=os.path.join(args.figure_dir, "fig_06b"), plot=plot)
100+
fig_06d(save_path=os.path.join(args.figure_dir, "fig_06d"), plot=plot)
85101

86102

87103
if __name__ == "__main__":
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import json
2+
import os
3+
4+
import numpy as np
5+
import pandas as pd
6+
7+
from flamingo_tools.s3_utils import BUCKET_NAME, create_s3_target
8+
from flamingo_tools.validation import match_detections
9+
10+
COCHLEA = "M_LR_000215_R"
11+
12+
13+
def _load_table(s3, source, valid_ihcs):
14+
source_info = source["spots"]
15+
rel_path = source_info["tableData"]["tsv"]["relativePath"]
16+
table_content = s3.open(os.path.join(BUCKET_NAME, COCHLEA, rel_path, "default.tsv"), mode="rb")
17+
synapse_table = pd.read_csv(table_content, sep="\t")
18+
synapse_table_filtered = synapse_table[synapse_table.matched_ihc.isin(valid_ihcs)]
19+
return synapse_table_filtered
20+
21+
22+
def _save_ihc_table(table, output_name):
23+
ihc_ids, syn_per_ihc = np.unique(table.matched_ihc.values, return_counts=True)
24+
ihc_ids = ihc_ids.astype("int")
25+
ihc_to_count = {ihc_id: count for ihc_id, count in zip(ihc_ids, syn_per_ihc)}
26+
ihc_count_table = pd.DataFrame({
27+
"label_id": list(ihc_to_count.keys()), "synapse_count": list(ihc_to_count.values())
28+
})
29+
output_path = os.path.join("ihc_counts", f"ihc_count_{COCHLEA}_{output_name}.tsv")
30+
ihc_count_table.to_csv(output_path, sep="\t", index=False)
31+
32+
33+
def _run_colocalization(riba_table, ctbp2_table, max_dist=2.0):
34+
coords_riba = riba_table[["z", "y", "x"]].values
35+
coords_ctbp2 = ctbp2_table[["z", "y", "x"]].values
36+
37+
matches_riba, matches_ctbp2, unmatched_riba, unmatched_ctbp2 = match_detections(
38+
coords_riba, coords_ctbp2, max_dist=max_dist,
39+
)
40+
assert len(matches_riba) == len(matches_ctbp2)
41+
42+
# For quick visualization
43+
if False:
44+
matched_coords = coords_riba[matches_riba]
45+
46+
import napari
47+
v = napari.Viewer()
48+
v.add_points(coords_riba, name="RibA", face_color="orange")
49+
v.add_points(coords_ctbp2, name="CTBP2")
50+
v.add_points(matched_coords, name="Coloc", face_color="green")
51+
napari.run()
52+
53+
return matches_riba, unmatched_riba, unmatched_ctbp2
54+
55+
56+
def check_and_filter_synapses():
57+
name_ctbp2 = "CTBP2_synapse_v3_ihc_v4b"
58+
name_riba = "RibA_synapse_v3_ihc_v4b"
59+
60+
s3 = create_s3_target()
61+
content = s3.open(f"{BUCKET_NAME}/{COCHLEA}/dataset.json", mode="r", encoding="utf-8")
62+
info = json.loads(content.read())
63+
sources = info["sources"]
64+
65+
# TODO load from S3 instead
66+
ihc_labels = pd.read_csv("./ihc_counts/ihc-annotation.tsv", sep="\t")
67+
valid_ihcs = ihc_labels.label_id[ihc_labels.ihc == "is_ihc"].values
68+
69+
riba_table = _load_table(s3, sources[name_riba], valid_ihcs)
70+
ctbp2_table = _load_table(s3, sources[name_ctbp2], valid_ihcs)
71+
72+
# Save the single synapse marker tables.
73+
_save_ihc_table(riba_table, "RibA")
74+
_save_ihc_table(ctbp2_table, "CTBP2")
75+
76+
# Run co-localization, analyze it and save the table.
77+
matches_riba, unmatched_riba, unmatched_ctbp2 = _run_colocalization(riba_table, ctbp2_table)
78+
79+
n_matched = len(matches_riba)
80+
print("Number of IHCs:", len(valid_ihcs))
81+
print("Number of matched synapses:", n_matched)
82+
print()
83+
84+
n_ctbp2 = n_matched + len(unmatched_ctbp2)
85+
n_riba = n_matched + len(unmatched_riba)
86+
print("Number and percentage of matched synapses for markers:")
87+
print("CTBP2:", n_matched, "/", n_ctbp2, f"({float(n_matched) / n_ctbp2 * 100}% matched)")
88+
print("RibA :", n_matched, "/", n_riba, f"({float(n_matched) / n_riba * 100}% matched)")
89+
90+
coloc_table = riba_table.iloc[matches_riba]
91+
_save_ihc_table(coloc_table, "coloc")
92+
93+
94+
def main():
95+
check_and_filter_synapses()
96+
97+
98+
if __name__ == "__main__":
99+
main()

0 commit comments

Comments
 (0)