12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 | def get_reference_spots(nbp_file: NotebookPage, nbp_basic: NotebookPage, spot_details: np.ndarray,
tile_origin: np.ndarray, transform: np.ndarray) -> NotebookPage:
"""
This takes each spot found on the reference round/channel and computes the corresponding intensity
in each of the imaging rounds/channels.
See `'ref_spots'` section of `notebook_comments.json` file
for description of the variables in the page.
The following variables:
* `gene_no`
* `score`
* `score_diff`
* `intensity`
will be set to `None` so the page can be added to a *Notebook*. `call_reference_spots` should then be run
to give their actual values. This is so if there is an error in `call_reference_spots`,
`get_reference_spots` won't have to be re-run.
Args:
nbp_file: `file_names` notebook page
nbp_basic: `basic_info` notebook page
spot_details: `int [n_spots x 7]`.
`spot_details[s]` is `[tile, round, channel, isolated, y, x, z]` of spot `s`.
This is saved in the find_spots notebook page i.e. `nb.find_spots.spot_details`.
tile_origin: `float [n_tiles x 3]`.
`tile_origin[t,:]` is the bottom left yxz coordinate of tile `t`.
yx coordinates in `yx_pixels` and z coordinate in `z_pixels`.
This is saved in the `stitch` notebook page i.e. `nb.stitch.tile_origin`.
transform: `float [n_tiles x n_rounds x n_channels x 4 x 3]`.
`transform[t, r, c]` is the affine transform to get from tile `t`, `ref_round`, `ref_channel` to
tile `t`, round `r`, channel `c`.
This is saved in the register notebook page i.e. `nb.register.transform`.
Returns:
`NotebookPage[ref_spots]` - Page containing intensity of each reference spot on each imaging round/channel.
"""
nbp = NotebookPage("ref_spots")
r = nbp_basic.ref_round
c = nbp_basic.ref_channel
# all means all spots found on the reference round / channel
all_local_yxz = np.zeros((0, 3), dtype=np.int16)
all_isolated = np.zeros(0, dtype=bool)
all_local_tile = np.zeros(0, dtype=np.int16)
for t in nbp_basic.use_tiles:
t_local_yxz, t_isolated = spot_yxz(spot_details, t, r, c, return_isolated=True)
if np.shape(t_local_yxz)[0] > 0:
all_local_yxz = np.append(all_local_yxz, t_local_yxz, axis=0)
all_isolated = np.append(all_isolated, t_isolated.astype(bool), axis=0)
all_local_tile = np.append(all_local_tile, np.ones_like(t_isolated, dtype=np.int16) * t)
# find duplicate spots as those detected on a tile which is not tile centre they are closest to
not_duplicate = get_non_duplicate(tile_origin, nbp_basic.use_tiles, nbp_basic.tile_centre, all_local_yxz,
all_local_tile)
# nd means all spots that are not duplicate
nd_local_yxz = all_local_yxz[not_duplicate]
nd_isolated = all_isolated[not_duplicate]
nd_local_tile = all_local_tile[not_duplicate]
invalid_value = -nbp_basic.tile_pixel_value_shift
# Only save used rounds/channels initially
n_use_rounds = len(nbp_basic.use_rounds)
n_use_channels = len(nbp_basic.use_channels)
use_tiles = np.array(nbp_basic.use_tiles.copy())
n_use_tiles = len(use_tiles)
nd_spot_colors_use = np.zeros((nd_local_tile.shape[0], n_use_rounds, n_use_channels), dtype=np.int32)
transform = jnp.asarray(transform)
print('Reading in spot_colors for ref_round spots')
for t in nbp_basic.use_tiles:
in_tile = nd_local_tile == t
if np.sum(in_tile) > 0:
print(f"Tile {np.where(use_tiles==t)[0][0]+1}/{n_use_tiles}")
# this line will return invalid_value for spots outside tile bounds on particular r/c.
nd_spot_colors_use[in_tile] = get_spot_colors(jnp.asarray(nd_local_yxz[in_tile]), t,
transform, nbp_file, nbp_basic)
# good means all spots that were in bounds of tile on every imaging round and channel that was used.
# nd_spot_colors_use = np.moveaxis(nd_spot_colors_use, 0, -1)
# use_rc_index = np.ix_(nbp_basic.use_rounds, nbp_basic.use_channels)
# nd_spot_colors_use = np.moveaxis(nd_spot_colors_use[use_rc_index], -1, 0)
good = ~np.any(nd_spot_colors_use == invalid_value, axis=(1, 2))
good_local_yxz = nd_local_yxz[good]
good_isolated = nd_isolated[good]
good_local_tile = nd_local_tile[good]
# add in un-used rounds with invalid_value
n_good = np.sum(good)
good_spot_colors = np.full((n_good, nbp_basic.n_rounds,
nbp_basic.n_channels), invalid_value, dtype=np.int32)
good_spot_colors[np.ix_(np.arange(n_good), nbp_basic.use_rounds, nbp_basic.use_channels)] = nd_spot_colors_use[good]
# save spot info to notebook
nbp.local_yxz = good_local_yxz
nbp.isolated = good_isolated
nbp.tile = good_local_tile
nbp.colors = good_spot_colors
# Set variables added in call_reference_spots to None so can save to Notebook.
# I.e. if call_reference_spots hit error, but we did not do this,
# we would have to run get_reference_spots again.
nbp.gene_no = None
nbp.score = None
nbp.score_diff = None
nbp.intensity = None
return nbp
|