nettracer3d 1.0.3__tar.gz → 1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nettracer3d might be problematic. Click here for more details.
- {nettracer3d-1.0.3/src/nettracer3d.egg-info → nettracer3d-1.0.4}/PKG-INFO +3 -2
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/README.md +3 -2
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/pyproject.toml +1 -1
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/nettracer.py +84 -38
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/nettracer_gui.py +29 -10
- {nettracer3d-1.0.3 → nettracer3d-1.0.4/src/nettracer3d.egg-info}/PKG-INFO +3 -2
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/LICENSE +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/setup.cfg +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/__init__.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/cellpose_manager.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/community_extractor.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/excelotron.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/modularity.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/morphology.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/neighborhoods.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/network_analysis.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/network_draw.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/node_draw.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/painting.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/proximity.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/run.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/segmenter.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/segmenter_GPU.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/simple_network.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d/smart_dilate.py +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d.egg-info/entry_points.txt +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d.egg-info/requires.txt +0 -0
- {nettracer3d-1.0.3 → nettracer3d-1.0.4}/src/nettracer3d.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
|
|
5
5
|
Author-email: Liam McLaughlin <liamm@wustl.edu>
|
|
6
6
|
Project-URL: Documentation, https://nettracer3d.readthedocs.io/en/latest/
|
|
@@ -110,6 +110,7 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
|
|
|
110
110
|
|
|
111
111
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
112
112
|
|
|
113
|
-
-- Version 1.0.
|
|
113
|
+
-- Version 1.0.4 Updates --
|
|
114
114
|
|
|
115
115
|
* Some small bug fixes and adjustments
|
|
116
|
+
* Heatmap theoretical distances can now be calculated based on an area constrained within a binary mask.
|
|
@@ -65,6 +65,7 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
|
|
|
65
65
|
|
|
66
66
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
67
67
|
|
|
68
|
-
-- Version 1.0.
|
|
68
|
+
-- Version 1.0.4 Updates --
|
|
69
69
|
|
|
70
|
-
* Some small bug fixes and adjustments
|
|
70
|
+
* Some small bug fixes and adjustments
|
|
71
|
+
* Heatmap theoretical distances can now be calculated based on an area constrained within a binary mask.
|
|
@@ -1903,6 +1903,7 @@ def mirror_points_for_edge_correction(points_array, bounds, max_r, dim=3):
|
|
|
1903
1903
|
all_points = np.vstack([all_points, mirrored_points])
|
|
1904
1904
|
|
|
1905
1905
|
return all_points
|
|
1906
|
+
|
|
1906
1907
|
def get_max_r_from_proportion(bounds, proportion):
|
|
1907
1908
|
"""
|
|
1908
1909
|
Calculate max_r based on bounds and proportion, matching your generate_r_values logic.
|
|
@@ -6054,57 +6055,94 @@ class Network_3D:
|
|
|
6054
6055
|
self.node_identities = modify_dict
|
|
6055
6056
|
|
|
6056
6057
|
|
|
6057
|
-
def nearest_neighbors_avg(self, root, targ, xy_scale = 1, z_scale = 1, num = 1, heatmap = False, threed = True, numpy = False, quant = False, centroids = True):
|
|
6058
|
-
|
|
6059
|
-
def distribute_points_uniformly(n, shape, z_scale, xy_scale, num, is_2d=False):
|
|
6058
|
+
def nearest_neighbors_avg(self, root, targ, xy_scale = 1, z_scale = 1, num = 1, heatmap = False, threed = True, numpy = False, quant = False, centroids = True, mask = None):
|
|
6060
6059
|
|
|
6060
|
+
def distribute_points_uniformly(n, shape, z_scale, xy_scale, num, is_2d=False, mask=None):
|
|
6061
6061
|
from scipy.spatial import KDTree
|
|
6062
|
-
|
|
6063
6062
|
if n <= 1:
|
|
6064
6063
|
return 0
|
|
6065
|
-
|
|
6066
|
-
# Calculate total positions and sampling step
|
|
6067
|
-
total_positions = np.prod(shape)
|
|
6068
|
-
if n >= total_positions:
|
|
6069
|
-
# If we want more points than positions, just return scaled unit distance
|
|
6070
|
-
return xy_scale if is_2d else min(z_scale, xy_scale)
|
|
6071
|
-
|
|
6072
|
-
# Create uniformly spaced indices
|
|
6073
|
-
indices = np.linspace(0, total_positions - 1, n, dtype=int)
|
|
6074
6064
|
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6065
|
+
if mask is not None:
|
|
6066
|
+
# Handle mask-based distribution
|
|
6067
|
+
# Find all valid positions where mask is True
|
|
6068
|
+
valid_positions = np.where(mask)
|
|
6069
|
+
total_valid_positions = len(valid_positions[0])
|
|
6070
|
+
|
|
6071
|
+
if total_valid_positions == 0:
|
|
6072
|
+
raise ValueError("No valid positions found in mask")
|
|
6073
|
+
|
|
6074
|
+
if n >= total_valid_positions:
|
|
6075
|
+
# If we want more points than valid positions, return scaled unit distance
|
|
6076
|
+
return xy_scale if is_2d else min(z_scale, xy_scale)
|
|
6077
|
+
|
|
6078
|
+
# Create uniformly spaced indices within valid positions
|
|
6079
|
+
valid_indices = np.linspace(0, total_valid_positions - 1, n, dtype=int)
|
|
6080
|
+
|
|
6081
|
+
# Convert to coordinates and apply scaling
|
|
6082
|
+
coords = []
|
|
6083
|
+
for idx in valid_indices:
|
|
6084
|
+
if len(shape) == 3:
|
|
6085
|
+
coord = (valid_positions[0][idx], valid_positions[1][idx], valid_positions[2][idx])
|
|
6086
|
+
scaled_coord = [coord[0] * z_scale, coord[1] * xy_scale, coord[2] * xy_scale]
|
|
6087
|
+
elif len(shape) == 2:
|
|
6088
|
+
coord = (valid_positions[0][idx], valid_positions[1][idx])
|
|
6089
|
+
scaled_coord = [coord[0] * xy_scale, coord[1] * xy_scale]
|
|
6090
|
+
coords.append(scaled_coord)
|
|
6091
|
+
|
|
6092
|
+
coords = np.array(coords)
|
|
6093
|
+
|
|
6094
|
+
# Find a good query point (closest to center of valid region)
|
|
6079
6095
|
if len(shape) == 3:
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6096
|
+
center_pos = [np.mean(valid_positions[0]) * z_scale,
|
|
6097
|
+
np.mean(valid_positions[1]) * xy_scale,
|
|
6098
|
+
np.mean(valid_positions[2]) * xy_scale]
|
|
6099
|
+
else:
|
|
6100
|
+
center_pos = [np.mean(valid_positions[0]) * xy_scale,
|
|
6101
|
+
np.mean(valid_positions[1]) * xy_scale]
|
|
6102
|
+
|
|
6103
|
+
# Find point closest to center of valid region
|
|
6104
|
+
center_distances = np.sum((coords - center_pos)**2, axis=1)
|
|
6105
|
+
middle_idx = np.argmin(center_distances)
|
|
6106
|
+
query_point = coords[middle_idx]
|
|
6107
|
+
|
|
6108
|
+
else:
|
|
6109
|
+
# Original behavior when no mask is provided
|
|
6110
|
+
total_positions = np.prod(shape)
|
|
6111
|
+
if n >= total_positions:
|
|
6112
|
+
return xy_scale if is_2d else min(z_scale, xy_scale)
|
|
6113
|
+
|
|
6114
|
+
# Create uniformly spaced indices
|
|
6115
|
+
indices = np.linspace(0, total_positions - 1, n, dtype=int)
|
|
6116
|
+
|
|
6117
|
+
# Convert flat indices to coordinates
|
|
6118
|
+
coords = []
|
|
6119
|
+
for idx in indices:
|
|
6120
|
+
coord = np.unravel_index(idx, shape)
|
|
6121
|
+
if len(shape) == 3:
|
|
6122
|
+
scaled_coord = [coord[0] * z_scale, coord[1] * xy_scale, coord[2] * xy_scale]
|
|
6123
|
+
elif len(shape) == 2:
|
|
6124
|
+
scaled_coord = [coord[0] * xy_scale, coord[1] * xy_scale]
|
|
6125
|
+
coords.append(scaled_coord)
|
|
6126
|
+
|
|
6127
|
+
coords = np.array(coords)
|
|
6128
|
+
|
|
6129
|
+
# Pick a point near the middle of the array
|
|
6130
|
+
middle_idx = len(coords) // 2
|
|
6131
|
+
query_point = coords[middle_idx]
|
|
6088
6132
|
|
|
6089
6133
|
# Build KDTree
|
|
6090
6134
|
tree = KDTree(coords)
|
|
6091
6135
|
|
|
6092
|
-
# Pick a point near the middle of the array
|
|
6093
|
-
middle_idx = len(coords) // 2
|
|
6094
|
-
query_point = coords[middle_idx]
|
|
6095
|
-
|
|
6096
6136
|
# Find the num+1 nearest neighbors (including the point itself)
|
|
6097
6137
|
distances, indices = tree.query(query_point, k=num+1)
|
|
6098
6138
|
|
|
6099
6139
|
# Exclude the point itself (distance 0) and get the actual neighbors
|
|
6100
6140
|
neighbor_distances = distances[1:num+1]
|
|
6101
|
-
|
|
6102
6141
|
if num == n:
|
|
6103
6142
|
neighbor_distances[-1] = neighbor_distances[-2]
|
|
6104
6143
|
|
|
6105
6144
|
avg_distance = np.mean(neighbor_distances)
|
|
6106
6145
|
|
|
6107
|
-
|
|
6108
6146
|
return avg_distance
|
|
6109
6147
|
|
|
6110
6148
|
do_borders = not centroids
|
|
@@ -6167,11 +6205,11 @@ class Network_3D:
|
|
|
6167
6205
|
if heatmap:
|
|
6168
6206
|
root_set = []
|
|
6169
6207
|
compare_set = []
|
|
6170
|
-
if root is None:
|
|
6171
|
-
|
|
6172
|
-
root_set = list(self.node_centroids.keys())
|
|
6208
|
+
if root is None and not do_borders:
|
|
6173
6209
|
compare_set = root_set
|
|
6174
|
-
|
|
6210
|
+
if not do_borders:
|
|
6211
|
+
root_set = list(self.node_centroids.keys())
|
|
6212
|
+
elif self.node_identities is not None:
|
|
6175
6213
|
for node, iden in self.node_identities.items():
|
|
6176
6214
|
|
|
6177
6215
|
if iden == root:
|
|
@@ -6199,7 +6237,8 @@ class Network_3D:
|
|
|
6199
6237
|
targ = [targ]
|
|
6200
6238
|
|
|
6201
6239
|
compare_set_neigh = approx_boundaries(self.nodes, targ, self.node_identities, keep_labels = False)
|
|
6202
|
-
|
|
6240
|
+
|
|
6241
|
+
avg, output = proximity.average_nearest_neighbor_distances(self.node_centroids, root_set_neigh, compare_set_neigh, xy_scale=self.xy_scale, z_scale=self.z_scale, num = num, do_borders = do_borders)
|
|
6203
6242
|
|
|
6204
6243
|
if quant:
|
|
6205
6244
|
try:
|
|
@@ -6241,7 +6280,15 @@ class Network_3D:
|
|
|
6241
6280
|
else:
|
|
6242
6281
|
is_2d = False
|
|
6243
6282
|
|
|
6244
|
-
|
|
6283
|
+
if root_set == []:
|
|
6284
|
+
avail_nodes = np.unique(self.nodes)
|
|
6285
|
+
compare_set = list(avail_nodes)
|
|
6286
|
+
if 0 in compare_set:
|
|
6287
|
+
del compare_set[0]
|
|
6288
|
+
root_set = compare_set
|
|
6289
|
+
elif compare_set == []:
|
|
6290
|
+
compare_set = root_set
|
|
6291
|
+
pred = distribute_points_uniformly(len(compare_set), bounds, self.z_scale, self.xy_scale, num = num, is_2d = is_2d, mask = mask)
|
|
6245
6292
|
|
|
6246
6293
|
node_intensity = {}
|
|
6247
6294
|
import math
|
|
@@ -6249,7 +6296,6 @@ class Network_3D:
|
|
|
6249
6296
|
|
|
6250
6297
|
for node in root_set:
|
|
6251
6298
|
node_intensity[node] = math.log(pred/output[node])
|
|
6252
|
-
#print(output[node])
|
|
6253
6299
|
node_centroids[node] = self.node_centroids[node]
|
|
6254
6300
|
|
|
6255
6301
|
if numpy:
|
|
@@ -1280,7 +1280,9 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1280
1280
|
|
|
1281
1281
|
if my_network.node_identities is not None:
|
|
1282
1282
|
identity_menu = QMenu("Show Identity", self)
|
|
1283
|
-
|
|
1283
|
+
idens = list(set(my_network.node_identities.values()))
|
|
1284
|
+
idens.sort()
|
|
1285
|
+
for item in idens:
|
|
1284
1286
|
show_identity = identity_menu.addAction(f"ID: {item}")
|
|
1285
1287
|
show_identity.triggered.connect(lambda checked, item=item: self.handle_show_identities(sort=item))
|
|
1286
1288
|
context_menu.addMenu(identity_menu)
|
|
@@ -5612,7 +5614,8 @@ class ImageViewerWindow(QMainWindow):
|
|
|
5612
5614
|
)
|
|
5613
5615
|
|
|
5614
5616
|
self.last_load = directory
|
|
5615
|
-
|
|
5617
|
+
self.last_saved = os.path.dirname(directory)
|
|
5618
|
+
self.last_save_name = directory
|
|
5616
5619
|
|
|
5617
5620
|
if directory != "":
|
|
5618
5621
|
|
|
@@ -5694,8 +5697,6 @@ class ImageViewerWindow(QMainWindow):
|
|
|
5694
5697
|
f"Failed to load Network 3D Object: {str(e)}"
|
|
5695
5698
|
)
|
|
5696
5699
|
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
5700
|
def load_network(self):
|
|
5700
5701
|
"""Load in the network from a .xlsx (need to add .csv support)"""
|
|
5701
5702
|
|
|
@@ -9038,7 +9039,7 @@ class ComNeighborDialog(QDialog):
|
|
|
9038
9039
|
|
|
9039
9040
|
mode = self.mode.currentIndex()
|
|
9040
9041
|
|
|
9041
|
-
seed =
|
|
9042
|
+
seed = int(self.seed.text()) if self.seed.text().strip() else 42
|
|
9042
9043
|
|
|
9043
9044
|
limit = int(self.limit.text()) if self.limit.text().strip() else None
|
|
9044
9045
|
|
|
@@ -9235,6 +9236,11 @@ class NearNeighDialog(QDialog):
|
|
|
9235
9236
|
self.numpy.setChecked(False)
|
|
9236
9237
|
self.numpy.clicked.connect(self.toggle_map)
|
|
9237
9238
|
heatmap_layout.addRow("Overlay:", self.numpy)
|
|
9239
|
+
|
|
9240
|
+
self.mode = QComboBox()
|
|
9241
|
+
self.mode.addItems(["Anywhere", "Within Masked Bounds of Edges", "Within Masked Bounds of Overlay1", "Within Masked Bounds of Overlay2"])
|
|
9242
|
+
self.mode.setCurrentIndex(0)
|
|
9243
|
+
heatmap_layout.addRow("For heatmap, measure theoretical point distribution how?", self.mode)
|
|
9238
9244
|
|
|
9239
9245
|
main_layout.addWidget(heatmap_group)
|
|
9240
9246
|
|
|
@@ -9326,35 +9332,48 @@ class NearNeighDialog(QDialog):
|
|
|
9326
9332
|
root = None
|
|
9327
9333
|
targ = None
|
|
9328
9334
|
|
|
9335
|
+
mode = self.mode.currentIndex()
|
|
9336
|
+
|
|
9337
|
+
if mode == 0:
|
|
9338
|
+
mask = None
|
|
9339
|
+
else:
|
|
9340
|
+
try:
|
|
9341
|
+
mask = self.parent().channel_data[mode] != 0
|
|
9342
|
+
except:
|
|
9343
|
+
print("Could not binarize mask")
|
|
9344
|
+
mask = None
|
|
9345
|
+
|
|
9329
9346
|
heatmap = self.map.isChecked()
|
|
9330
9347
|
threed = self.threed.isChecked()
|
|
9331
9348
|
numpy = self.numpy.isChecked()
|
|
9332
9349
|
num = int(self.num.text()) if self.num.text().strip() else 1
|
|
9333
9350
|
quant = self.quant.isChecked()
|
|
9334
9351
|
centroids = self.centroids.isChecked()
|
|
9352
|
+
|
|
9335
9353
|
if not centroids:
|
|
9354
|
+
print("Using 1 nearest neighbor due to not using centroids")
|
|
9336
9355
|
num = 1
|
|
9337
9356
|
|
|
9338
9357
|
if root is not None and targ is not None:
|
|
9339
9358
|
title = f"Nearest {num} Neighbor(s) Distance of {targ} from {root}"
|
|
9340
|
-
header = f"Shortest Distance to Closest {num} {targ}(s)"
|
|
9359
|
+
header = f"Avg Shortest Distance to Closest {num} {targ}(s)"
|
|
9341
9360
|
header2 = f"{root} Node ID"
|
|
9342
9361
|
header3 = f'Theoretical Uniform Distance to Closest {num} {targ}(s)'
|
|
9343
9362
|
else:
|
|
9344
9363
|
title = f"Nearest {num} Neighbor(s) Distance Between Nodes"
|
|
9345
|
-
header = f"Shortest Distance to Closest {num} Nodes"
|
|
9364
|
+
header = f"Avg Shortest Distance to Closest {num} Nodes"
|
|
9346
9365
|
header2 = "Root Node ID"
|
|
9347
9366
|
header3 = f'Simulated Theoretical Uniform Distance to Closest {num} Nodes'
|
|
9348
9367
|
|
|
9349
|
-
if
|
|
9368
|
+
if my_network.node_centroids is None:
|
|
9350
9369
|
self.parent().show_centroid_dialog()
|
|
9351
9370
|
if my_network.node_centroids is None:
|
|
9352
9371
|
return
|
|
9353
9372
|
|
|
9354
9373
|
if not numpy:
|
|
9355
|
-
avg, output, quant_overlay, pred = my_network.nearest_neighbors_avg(root, targ, my_network.xy_scale, my_network.z_scale, num = num, heatmap = heatmap, threed = threed, quant = quant, centroids = centroids)
|
|
9374
|
+
avg, output, quant_overlay, pred = my_network.nearest_neighbors_avg(root, targ, my_network.xy_scale, my_network.z_scale, num = num, heatmap = heatmap, threed = threed, quant = quant, centroids = centroids, mask = mask)
|
|
9356
9375
|
else:
|
|
9357
|
-
avg, output, overlay, quant_overlay, pred = my_network.nearest_neighbors_avg(root, targ, my_network.xy_scale, my_network.z_scale, num = num, heatmap = heatmap, threed = threed, numpy = True, quant = quant, centroids = centroids)
|
|
9376
|
+
avg, output, overlay, quant_overlay, pred = my_network.nearest_neighbors_avg(root, targ, my_network.xy_scale, my_network.z_scale, num = num, heatmap = heatmap, threed = threed, numpy = True, quant = quant, centroids = centroids, mask = mask)
|
|
9358
9377
|
self.parent().load_channel(3, overlay, data = True, preserve_zoom = (self.parent().ax.get_xlim(), self.parent().ax.get_ylim()))
|
|
9359
9378
|
|
|
9360
9379
|
if quant_overlay is not None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
|
|
5
5
|
Author-email: Liam McLaughlin <liamm@wustl.edu>
|
|
6
6
|
Project-URL: Documentation, https://nettracer3d.readthedocs.io/en/latest/
|
|
@@ -110,6 +110,7 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
|
|
|
110
110
|
|
|
111
111
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
112
112
|
|
|
113
|
-
-- Version 1.0.
|
|
113
|
+
-- Version 1.0.4 Updates --
|
|
114
114
|
|
|
115
115
|
* Some small bug fixes and adjustments
|
|
116
|
+
* Heatmap theoretical distances can now be calculated based on an area constrained within a binary mask.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|