Skip to content

Commit f9f67b9

Browse files
committed
update tiling
1 parent 70cd1a1 commit f9f67b9

File tree

2 files changed

+124
-103
lines changed

2 files changed

+124
-103
lines changed

src/navigate/controller/sub_controllers/tiling.py

Lines changed: 81 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,19 @@ def __init__(self, view, parent_controller):
133133
self.cam_settings_widgets["FOV_Y"].get_variable().trace_add(
134134
"write", lambda *args: self.update_fov("x")
135135
)
136-
self.stack_acq_widgets["abs_z_start"].get_variable().trace_add(
136+
# primary z/f
137+
self.primary_z_axis = self.stack_acq_widgets["z_device"].get().split(" - ")[1]
138+
self.primary_f_axis = self.stack_acq_widgets["f_device"].get().split(" - ")[1]
139+
self.stack_acq_widgets["z_device"].get_variable().trace_add(
140+
"write", lambda *args: self.update_fov("z_device")
141+
)
142+
self.stack_acq_widgets["f_device"].get_variable().trace_add(
143+
"write", lambda *args: self.update_fov("f_device")
144+
)
145+
self.stack_acq_widgets["start_position"].get_variable().trace_add(
137146
"write", lambda *args: self.update_fov("z")
138147
)
139-
self.stack_acq_widgets["abs_z_end"].get_variable().trace_add(
148+
self.stack_acq_widgets["end_position"].get_variable().trace_add(
140149
"write", lambda *args: self.update_fov("z")
141150
)
142151
self.stack_acq_widgets["start_focus"].get_variable().trace_add(
@@ -158,12 +167,6 @@ def __init__(self, view, parent_controller):
158167
self.variables[f"{axis}_fov"].trace_add(
159168
"write", lambda *args, axis=axis: self.calculate_tiles(axis)
160169
)
161-
self.variables[f"{axis}_start"].trace_add(
162-
"write", lambda *args, axis=axis: self.update_fov(axis)
163-
)
164-
self.variables[f"{axis}_end"].trace_add(
165-
"write", lambda *args, axis=axis: self.update_fov(axis)
166-
)
167170

168171
# Calculating Number of Tiles traces
169172
self.variables[f"{axis}_dist"].trace_add(
@@ -248,45 +251,7 @@ def set_table(self):
248251
pandas dataframe which is then set as the new table data.
249252
The table is then redrawn.
250253
"""
251-
if False in self.is_validated.values():
252-
messagebox.showwarning(
253-
title="Navigate",
254-
message="Can't calculate positions, "
255-
"please make sure all FOV Dists are correct!",
256-
)
257-
return
258-
259-
x_start = float(self.variables["x_start"].get())
260-
x_stop = float(self.variables["x_end"].get())
261-
x_tiles = int(self.variables["x_tiles"].get())
262-
263-
y_start = float(self.variables["y_start"].get())
264-
y_stop = float(self.variables["y_end"].get())
265-
y_tiles = int(self.variables["y_tiles"].get())
266254

267-
# shift z by coordinate origin of local z-stack
268-
z_start = float(self.variables["z_start"].get()) - float(
269-
self.stack_acq_widgets["start_position"].get()
270-
)
271-
z_stop = float(self.variables["z_end"].get()) - float(
272-
self.stack_acq_widgets["end_position"].get()
273-
)
274-
z_tiles = int(self.variables["z_tiles"].get())
275-
276-
# Default to fixed theta
277-
r_start = float(self.stage_position_vars["theta"].get())
278-
r_stop = float(self.stage_position_vars["theta"].get())
279-
r_tiles = 1
280-
281-
f_start = float(self.variables["f_start"].get()) - float(
282-
self.stack_acq_widgets["start_focus"].get()
283-
)
284-
f_stop = float(self.variables["f_end"].get()) - float(
285-
self.stack_acq_widgets["end_focus"].get()
286-
)
287-
f_tiles = int(self.variables["f_tiles"].get())
288-
289-
# for consistency, always go from low to high
290255
def sort_vars(a, b):
291256
"""Sort two variables from low to high
292257
@@ -305,38 +270,55 @@ def sort_vars(a, b):
305270
if a > b:
306271
return b, a
307272
return a, b
273+
274+
if False in self.is_validated.values():
275+
messagebox.showwarning(
276+
title="Navigate",
277+
message="Can't calculate positions, "
278+
"please make sure all FOV Dists are correct!",
279+
)
280+
return
281+
282+
tiling_setting = {}
283+
for axis in self._axes:
284+
start_pos = float(self.variables[f"{axis}_start"].get())
285+
stop_pos = float(self.variables[f"{axis}_end"].get())
286+
tiles = int(self.variables[f"{axis}_tiles"].get())
287+
fov = float(self.variables[f"{axis}_fov"].get())
288+
289+
if axis == self.primary_z_axis:
290+
start_pos -= float(
291+
self.stack_acq_widgets["start_position"].get()
292+
)
293+
stop_pos -= float(
294+
self.stack_acq_widgets["end_position"].get()
295+
)
296+
elif axis == self.primary_f_axis:
297+
start_pos -= float(
298+
self.stack_acq_widgets["start_focus"].get()
299+
)
300+
stop_pos -= float(
301+
self.stack_acq_widgets["end_focus"].get()
302+
)
303+
304+
start_pos, stop_pos = sort_vars(start_pos, stop_pos)
305+
tiling_setting[f"{axis}_start"] = start_pos
306+
# tiling_setting[f"{axis}_stop"] = stop_pos
307+
tiling_setting[f"{axis}_tiles"] = tiles
308+
tiling_setting[f"{axis}_length"] = fov
308309

309-
x_start, x_stop = sort_vars(x_start, x_stop)
310-
y_start, y_stop = sort_vars(y_start, y_stop)
311-
z_start, z_stop = sort_vars(z_start, z_stop)
312-
r_start, r_stop = sort_vars(r_start, r_stop)
313-
f_start, f_stop = sort_vars(f_start, f_stop)
310+
tiling_setting["theta_start"] = float(self.stage_position_vars["theta"].get())
311+
# tiling_setting["theta_stop"] = float(self.stage_position_vars["theta"].get())
312+
tiling_setting["theta_tiles"] = 1
313+
tiling_setting["theta_length"] = 0
314314

315315
overlap = float(self._percent_overlap) / 100
316-
table_values = compute_tiles_from_bounding_box(
317-
x_start=x_start,
318-
x_tiles=x_tiles,
319-
x_length=float(self.variables["x_fov"].get()),
320-
x_overlap=overlap,
321-
y_start=y_start,
322-
y_tiles=y_tiles,
323-
y_length=float(self.variables["y_fov"].get()),
324-
y_overlap=overlap,
325-
z_start=z_start,
326-
z_tiles=z_tiles,
327-
z_length=float(self.variables["z_fov"].get()),
328-
z_overlap=overlap,
329-
theta_start=r_start,
330-
theta_tiles=r_tiles,
331-
theta_length=0,
332-
theta_overlap=overlap,
333-
f_start=f_start,
334-
f_tiles=f_tiles,
335-
f_length=float(self.variables["f_fov"].get()),
336-
f_overlap=overlap,
316+
columns, table_values = compute_tiles_from_bounding_box(
317+
overlap=overlap,
318+
**tiling_setting
337319
)
338320

339-
update_table(self.multipoint_table, table_values)
321+
update_table(self.multipoint_table, table_values, columns)
340322

341323
# If we have additional axes, create self.d{axis} for each
342324
# additional axis, to ensure we keep track of the step size
@@ -498,39 +480,60 @@ def update_fov(self, axis=None):
498480
"""
499481

500482
if axis is None:
501-
axis = self._axes
483+
axes = self._axes
502484
elif isinstance(axis, str):
503-
axis = [axis]
485+
if axis == "z_device":
486+
# get the new primary z axis
487+
primary_z = self.stack_acq_widgets["z_device"].get().split(" - ")[1]
488+
if self.primary_z_axis != primary_z:
489+
self.variables[f"{primary_z}_fov"].set(self.variables[f"{self.primary_z_axis}_fov"].get())
490+
self.variables[f"{self.primary_z_axis}_fov"].set(0)
491+
self.primary_z_axis = primary_z
492+
return
493+
elif axis == "f_device":
494+
# get the new primary f axis
495+
primary_f = self.stack_acq_widgets["f_device"].get().split(" - ")[1]
496+
if self.primary_f_axis != primary_f:
497+
self.variables[f"{primary_f}_fov"].set(self.variables[f"{self.primary_f_axis}_fov"].get())
498+
self.variables[f"{self.primary_f_axis}_fov"].set(0)
499+
self.primary_f_axis = primary_f
500+
return
501+
else:
502+
axes = [axis]
504503

505-
for ax in axis:
504+
for ax in axes:
506505
try:
507506
# Calculate signed fov
508507
if ax == "y":
509508
y = float(self.cam_settings_widgets["FOV_X"].get()) * sign(
510509
float(self.variables["x_end"].get())
511510
- float(self.variables["x_start"].get())
512511
)
512+
axis = "y"
513513
elif ax == "x":
514514
x = float(self.cam_settings_widgets["FOV_Y"].get()) * sign(
515515
float(self.variables["y_end"].get())
516516
- float(self.variables["y_start"].get())
517517
)
518+
axis = "x"
518519
elif ax == "z":
519520
z = float(self.stack_acq_widgets["end_position"].get()) - float(
520521
self.stack_acq_widgets["start_position"].get()
521522
)
523+
axis = self.primary_z_axis
522524
elif ax == "f":
523525
f = float(self.stack_acq_widgets["end_focus"].get()) - float(
524526
self.stack_acq_widgets["start_focus"].get()
525527
)
528+
axis = self.primary_f_axis
526529

527530
# for ax in self._axes:
528531
# self._fov[ax] = locals().get(ax)
529-
self.variables[f"{ax}_fov"].set(
532+
self.variables[f"{axis}_fov"].set(
530533
abs(locals().get(ax))
531534
) # abs(self._fov[ax]))
532535

533-
self.calculate_tiles(ax)
536+
self.calculate_tiles(axis)
534537
except (TypeError, ValueError) as e:
535538
logger.debug(
536539
f"Controller - Tiling Wizard - Caught ValueError: {e}. "

src/navigate/tools/multipos_table_tools.py

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,21 @@ def compute_tiles_from_bounding_box(
6161
x_start,
6262
x_tiles,
6363
x_length,
64-
x_overlap,
6564
y_start,
6665
y_tiles,
6766
y_length,
68-
y_overlap,
6967
z_start,
7068
z_tiles,
7169
z_length,
72-
z_overlap,
7370
theta_start,
7471
theta_tiles,
7572
theta_length,
76-
theta_overlap,
7773
f_start,
7874
f_tiles,
7975
f_length,
80-
f_overlap,
76+
overlap=0.1,
8177
f_track_with_z=False,
78+
**kwargs,
8279
):
8380
"""Create a grid of ROIs to image based on start position, number of tiles, and
8481
signed FOV length in each dimension.
@@ -91,49 +88,58 @@ def compute_tiles_from_bounding_box(
9188
Number of tiles to take along x-dimension.
9289
x_length : float
9390
Signed length of the FOV along x-dimension.
94-
x_overlap : float
95-
Fractional overlap of ROIs along x-dimension.
9691
y_start : float
9792
Starting position along y-dimension.
9893
y_tiles : int
9994
Number of tiles to take along y-dimension.
10095
y_length : float
10196
Signed length of the FOV along y-dimension.
102-
y_overlap : float
103-
Fractional overlap of ROIs along y-dimension.
10497
z_start : float
10598
Starting position along z-dimension.
10699
z_tiles : int
107100
Number of tiles to take along z-dimension.
108101
z_length : float
109102
Signed length of the FOV along z-dimension.
110-
z_overlap : float
111-
Fractional overlap of ROIs along z-dimension.
112103
theta_start : float
113104
Starting position along rotation dimension.
114105
theta_tiles : int
115106
Number of tiles to take along rotation dimension.
116107
theta_length : float
117108
Signed length of the FOV along rotation dimension.
118-
theta_overlap : float
119-
Fractional overlap of ROIs along rotation dimension.
120109
f_start : float
121110
Starting position along focus dimension.
122111
f_tiles : int
123112
Number of tiles to take along focus dimension.
124113
f_length : float
125114
Signed length of the FOV along focus dimension.
126-
f_overlap : float
127-
Fractional overlap of ROIs along focus dimension.
115+
overlap : float
116+
Fractional overlap of ROIs.
128117
f_track_with_z : bool
129118
Make focus track with z/assume focus is z-dependent.
119+
**kwargs : additional keyword arguments
120+
axis_start: Starting position along that axis
121+
axis_tiles: Number of tiles to take along axis
122+
axis_length: Signed length of the FOV along axis
130123
131124
Returns
132125
-------
133-
np.array
126+
result : tuple ([str], np.array)
127+
axes
134128
(n_positions x (x, y, z, theta, f)) array of positions, gridding out the space
135129
"""
136130

131+
# get additional axes
132+
additional_settings = {}
133+
for k in kwargs.keys():
134+
if k.endswith("_start"):
135+
axis = k[:-6]
136+
if f"{axis}_tiles" in kwargs.keys() and f"{axis}_length" in kwargs.keys():
137+
additional_settings[axis] = {
138+
"start": kwargs[f"{axis}_start"],
139+
"tiles": 1 if kwargs[f"{axis}_tiles"] <= 0 else kwargs[f"{axis}_tiles"],
140+
"step": kwargs[f"{axis}_length"] * (1 - overlap)
141+
}
142+
137143
# Error checking to prevent empty list when tiles are zero
138144
x_tiles = 1 if x_tiles <= 0 else x_tiles
139145
y_tiles = 1 if y_tiles <= 0 else y_tiles
@@ -142,11 +148,11 @@ def compute_tiles_from_bounding_box(
142148
f_tiles = 1 if f_tiles <= 0 else f_tiles
143149

144150
# Calculate the step between the edge of each frame
145-
x_step = x_length * (1 - x_overlap)
146-
y_step = y_length * (1 - y_overlap)
147-
z_step = z_length * (1 - z_overlap)
148-
theta_step = theta_length * (1 - theta_overlap)
149-
f_step = f_length * (1 - f_overlap)
151+
x_step = x_length * (1 - overlap)
152+
y_step = y_length * (1 - overlap)
153+
z_step = z_length * (1 - overlap)
154+
theta_step = theta_length * (1 - overlap)
155+
f_step = f_length * (1 - overlap)
150156

151157
# grid out each dimension from (x_start, y_start, z_start) in steps
152158
def dim_vector(start, n_tiles, step):
@@ -166,6 +172,11 @@ def dim_vector(start, n_tiles, step):
166172
# we assume theta FOVs have no thickness
167173
fs = dim_vector(f_start, f_tiles, f_step)
168174

175+
additional_coordinates = []
176+
for axis in additional_settings:
177+
values = additional_settings[axis]
178+
additional_coordinates.append(dim_vector(values["start"], values["tiles"], values["step"]))
179+
169180
if f_track_with_z:
170181
# grid out the 4D space...
171182
x, y, z, t = np.meshgrid(xs, ys, zs, thetas)
@@ -177,9 +188,14 @@ def dim_vector(start, n_tiles, step):
177188
] # This only works if len(fs) = len(zs)
178189
# TODO: Don't clip f. Practically fine for now.
179190
else:
180-
x, y, z, t, f = np.meshgrid(xs, ys, zs, thetas, fs)
191+
result = np.meshgrid(xs, ys, zs, thetas, fs, *additional_coordinates)
192+
193+
axes = ["x", "y", "z", "theta", "f"]
194+
axes.extend(list(additional_settings.keys()))
195+
table_values = np.vstack([v.ravel() for v in result]).T
181196

182-
return np.vstack([x.ravel(), y.ravel(), z.ravel(), t.ravel(), f.ravel()]).T
197+
return (axes, table_values)
198+
# return np.vstack([x.ravel(), y.ravel(), z.ravel(), t.ravel(), f.ravel()]).T
183199

184200

185201
def calc_num_tiles(dist, overlap, roi_length):
@@ -217,7 +233,7 @@ def calc_num_tiles(dist, overlap, roi_length):
217233
return int(num_tiles)
218234

219235

220-
def update_table(table, pos, append=False):
236+
def update_table(table, pos, axes, append=False):
221237
"""Updates and redraws table based on given list.
222238
223239
List is converted to a pandas dataframe before setting data in table.
@@ -229,6 +245,8 @@ def update_table(table, pos, append=False):
229245
pos: list or np.array
230246
List or np.array of positions to be added to table. Each row contains an X, Y,
231247
Z, R, F position
248+
axes: list of str
249+
List of axes
232250
append: bool
233251
Append the new positions to the table
234252
@@ -237,7 +255,7 @@ def update_table(table, pos, append=False):
237255
None :
238256
Table is updated
239257
"""
240-
frame = pd.DataFrame(pos, columns=list("XYZRF"))
258+
frame = pd.DataFrame(pos, columns=[axis.upper() for axis in axes])
241259
if append:
242260
table.model.df = table.model.df.append(frame, ignore_index=True)
243261
else:

0 commit comments

Comments
 (0)