nettracer3d 0.9.0__tar.gz → 0.9.1__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-0.9.0/src/nettracer3d.egg-info → nettracer3d-0.9.1}/PKG-INFO +7 -14
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/README.md +6 -13
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/pyproject.toml +1 -1
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/neighborhoods.py +107 -16
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/nettracer.py +60 -31
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/nettracer_gui.py +546 -308
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/segmenter.py +514 -372
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/segmenter_GPU.py +434 -281
- {nettracer3d-0.9.0 → nettracer3d-0.9.1/src/nettracer3d.egg-info}/PKG-INFO +7 -14
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/LICENSE +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/setup.cfg +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/__init__.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/cellpose_manager.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/community_extractor.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/excelotron.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/modularity.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/morphology.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/network_analysis.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/network_draw.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/node_draw.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/painting.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/proximity.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/run.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/simple_network.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d/smart_dilate.py +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d.egg-info/entry_points.txt +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/src/nettracer3d.egg-info/requires.txt +0 -0
- {nettracer3d-0.9.0 → nettracer3d-0.9.1}/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: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
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,16 +110,9 @@ 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 0.9.
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* Improved branch labelling method
|
|
120
|
-
* Updated branch removal in skeletonization method to no longer trim branches that do not reach their node.
|
|
121
|
-
* Added default branchpoint and branch-adjacency calculation options.
|
|
122
|
-
* Improved speed of painting and panning.
|
|
123
|
-
* Enabled the nearest neighbor method to handle non-centroid objects, for the first neighbor at least. And updated it to actually predict theoretical clustering when coloring the heatmap.
|
|
124
|
-
* Improved segmenter.
|
|
125
|
-
* Added centroids UMAP method.
|
|
113
|
+
-- Version 0.9.1 Updates --
|
|
114
|
+
* Adjusted the segment by 3D function to now show the 3D chunks in the preview mode. Previously it showed 2D segmentations in the preview which finished the current plane faster but didn't show accurate training data.
|
|
115
|
+
* Adjusted the neighborhood heatmap predicted range value to now just simulate a uniform distribution rather than trying to use a mathematical algorithm.
|
|
116
|
+
* The image display window now uses image pyramids and cropping for zoom ins so it should run a lot faster on bigger images.
|
|
117
|
+
* The community UMAP can now color them by neighborhood.
|
|
118
|
+
* No longer zooms all the way out by default with right click in zoom mode. Now user needs to Shift + Right Click.
|
|
@@ -65,16 +65,9 @@ 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 0.9.
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* Improved branch labelling method
|
|
75
|
-
* Updated branch removal in skeletonization method to no longer trim branches that do not reach their node.
|
|
76
|
-
* Added default branchpoint and branch-adjacency calculation options.
|
|
77
|
-
* Improved speed of painting and panning.
|
|
78
|
-
* Enabled the nearest neighbor method to handle non-centroid objects, for the first neighbor at least. And updated it to actually predict theoretical clustering when coloring the heatmap.
|
|
79
|
-
* Improved segmenter.
|
|
80
|
-
* Added centroids UMAP method.
|
|
68
|
+
-- Version 0.9.1 Updates --
|
|
69
|
+
* Adjusted the segment by 3D function to now show the 3D chunks in the preview mode. Previously it showed 2D segmentations in the preview which finished the current plane faster but didn't show accurate training data.
|
|
70
|
+
* Adjusted the neighborhood heatmap predicted range value to now just simulate a uniform distribution rather than trying to use a mathematical algorithm.
|
|
71
|
+
* The image display window now uses image pyramids and cropping for zoom ins so it should run a lot faster on bigger images.
|
|
72
|
+
* The community UMAP can now color them by neighborhood.
|
|
73
|
+
* No longer zooms all the way out by default with right click in zoom mode. Now user needs to Shift + Right Click.
|
|
@@ -346,7 +346,8 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
346
346
|
random_state: int = 42,
|
|
347
347
|
id_dictionary: Optional[Dict[int, str]] = None,
|
|
348
348
|
graph_label = "Community ID",
|
|
349
|
-
title = 'UMAP Visualization of Community Compositions'
|
|
349
|
+
title = 'UMAP Visualization of Community Compositions',
|
|
350
|
+
neighborhoods: Optional[Dict[int, int]] = None):
|
|
350
351
|
"""
|
|
351
352
|
Convert cluster composition data to UMAP visualization.
|
|
352
353
|
|
|
@@ -366,6 +367,9 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
366
367
|
id_dictionary : dict, optional
|
|
367
368
|
Dictionary mapping cluster IDs to identity names. If provided, colors will be
|
|
368
369
|
assigned by identity rather than cluster ID, and a legend will be shown.
|
|
370
|
+
neighborhoods : dict, optional
|
|
371
|
+
Dictionary mapping node IDs to neighborhood IDs {node_id: neighborhood_id}.
|
|
372
|
+
If provided, points will be colored by neighborhood using community coloration methods.
|
|
369
373
|
|
|
370
374
|
Returns:
|
|
371
375
|
--------
|
|
@@ -389,25 +393,70 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
389
393
|
# Fit and transform the composition data
|
|
390
394
|
embedding = reducer.fit_transform(compositions)
|
|
391
395
|
|
|
392
|
-
#
|
|
393
|
-
if
|
|
394
|
-
#
|
|
396
|
+
# Determine coloring scheme based on parameters
|
|
397
|
+
if neighborhoods is not None:
|
|
398
|
+
# Use neighborhood coloring - import the community extractor methods
|
|
399
|
+
from . import community_extractor
|
|
400
|
+
|
|
401
|
+
# Filter neighborhoods to only include cluster_ids that exist in our data
|
|
402
|
+
filtered_neighborhoods = {node_id: neighborhood_id
|
|
403
|
+
for node_id, neighborhood_id in neighborhoods.items()
|
|
404
|
+
if node_id in cluster_ids}
|
|
405
|
+
|
|
406
|
+
# Create a dummy labeled array just for the coloring function
|
|
407
|
+
# We only need the coloring logic, not actual clustering
|
|
408
|
+
dummy_array = np.array(cluster_ids)
|
|
409
|
+
|
|
410
|
+
# Get colors using the community coloration method
|
|
411
|
+
_, neighborhood_color_names = community_extractor.assign_community_colors(
|
|
412
|
+
filtered_neighborhoods, dummy_array
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
# Create color mapping for our points
|
|
416
|
+
unique_neighborhoods = sorted(list(set(filtered_neighborhoods.values())))
|
|
417
|
+
colors = community_extractor.generate_distinct_colors(len(unique_neighborhoods))
|
|
418
|
+
neighborhood_to_color = {neighborhood: colors[i] for i, neighborhood in enumerate(unique_neighborhoods)}
|
|
419
|
+
|
|
420
|
+
# Map each cluster to its neighborhood color
|
|
421
|
+
point_colors = []
|
|
422
|
+
neighborhood_labels = []
|
|
423
|
+
for cluster_id in cluster_ids:
|
|
424
|
+
if cluster_id in filtered_neighborhoods:
|
|
425
|
+
neighborhood_id = filtered_neighborhoods[cluster_id]
|
|
426
|
+
point_colors.append(neighborhood_to_color[neighborhood_id])
|
|
427
|
+
neighborhood_labels.append(neighborhood_id)
|
|
428
|
+
else:
|
|
429
|
+
# Default color for nodes not in any neighborhood
|
|
430
|
+
point_colors.append((128, 128, 128)) # Gray
|
|
431
|
+
neighborhood_labels.append("Unknown")
|
|
432
|
+
|
|
433
|
+
# Normalize RGB values for matplotlib (0-1 range)
|
|
434
|
+
point_colors = [(r/255.0, g/255.0, b/255.0) for r, g, b in point_colors]
|
|
435
|
+
use_neighborhood_coloring = True
|
|
436
|
+
|
|
437
|
+
elif id_dictionary is not None:
|
|
438
|
+
# Use identity coloring (existing logic)
|
|
395
439
|
identities = [id_dictionary.get(cluster_id, "Unknown") for cluster_id in cluster_ids]
|
|
396
440
|
unique_identities = sorted(list(set(identities)))
|
|
397
441
|
colors = generate_distinct_colors(len(unique_identities))
|
|
398
442
|
identity_to_color = {identity: colors[i] for i, identity in enumerate(unique_identities)}
|
|
399
443
|
point_colors = [identity_to_color[identity] for identity in identities]
|
|
400
444
|
use_identity_coloring = True
|
|
445
|
+
use_neighborhood_coloring = False
|
|
401
446
|
else:
|
|
402
447
|
# Use default cluster ID coloring
|
|
403
448
|
point_colors = cluster_ids
|
|
404
449
|
use_identity_coloring = False
|
|
450
|
+
use_neighborhood_coloring = False
|
|
405
451
|
|
|
406
452
|
# Create visualization
|
|
407
453
|
plt.figure(figsize=(12, 8))
|
|
408
454
|
|
|
409
455
|
if n_components == 2:
|
|
410
|
-
if
|
|
456
|
+
if use_neighborhood_coloring:
|
|
457
|
+
scatter = plt.scatter(embedding[:, 0], embedding[:, 1],
|
|
458
|
+
c=point_colors, s=100, alpha=0.7)
|
|
459
|
+
elif use_identity_coloring:
|
|
411
460
|
scatter = plt.scatter(embedding[:, 0], embedding[:, 1],
|
|
412
461
|
c=point_colors, s=100, alpha=0.7)
|
|
413
462
|
else:
|
|
@@ -418,7 +467,10 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
418
467
|
# Add cluster ID labels
|
|
419
468
|
for i, cluster_id in enumerate(cluster_ids):
|
|
420
469
|
display_label = f'{cluster_id}'
|
|
421
|
-
if
|
|
470
|
+
if use_neighborhood_coloring and cluster_id in filtered_neighborhoods:
|
|
471
|
+
neighborhood_id = filtered_neighborhoods[cluster_id]
|
|
472
|
+
display_label = f'{cluster_id}\n(N{neighborhood_id})'
|
|
473
|
+
elif id_dictionary is not None:
|
|
422
474
|
identity = id_dictionary.get(cluster_id, "Unknown")
|
|
423
475
|
display_label = f'{cluster_id}\n({identity})'
|
|
424
476
|
|
|
@@ -428,7 +480,20 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
428
480
|
fontsize=9, alpha=0.8, ha='left')
|
|
429
481
|
|
|
430
482
|
# Add appropriate legend/colorbar
|
|
431
|
-
if
|
|
483
|
+
if use_neighborhood_coloring:
|
|
484
|
+
# Create custom legend for neighborhoods
|
|
485
|
+
legend_elements = []
|
|
486
|
+
for neighborhood_id in unique_neighborhoods:
|
|
487
|
+
color = neighborhood_to_color[neighborhood_id]
|
|
488
|
+
norm_color = (color[0]/255.0, color[1]/255.0, color[2]/255.0)
|
|
489
|
+
legend_elements.append(
|
|
490
|
+
plt.Line2D([0], [0], marker='o', color='w',
|
|
491
|
+
markerfacecolor=norm_color,
|
|
492
|
+
markersize=10, label=f'Neighborhood {neighborhood_id}')
|
|
493
|
+
)
|
|
494
|
+
plt.legend(handles=legend_elements, title='Neighborhoods',
|
|
495
|
+
bbox_to_anchor=(1.05, 1), loc='upper left')
|
|
496
|
+
elif use_identity_coloring:
|
|
432
497
|
# Create custom legend for identities
|
|
433
498
|
legend_elements = [plt.Line2D([0], [0], marker='o', color='w',
|
|
434
499
|
markerfacecolor=identity_to_color[identity],
|
|
@@ -441,7 +506,9 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
441
506
|
|
|
442
507
|
plt.xlabel('UMAP Component 1')
|
|
443
508
|
plt.ylabel('UMAP Component 2')
|
|
444
|
-
if
|
|
509
|
+
if use_neighborhood_coloring:
|
|
510
|
+
title += ' (Colored by Neighborhood)'
|
|
511
|
+
elif use_identity_coloring:
|
|
445
512
|
title += ' (Colored by Identity)'
|
|
446
513
|
plt.title(title)
|
|
447
514
|
|
|
@@ -449,7 +516,10 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
449
516
|
fig = plt.figure(figsize=(14, 10))
|
|
450
517
|
ax = fig.add_subplot(111, projection='3d')
|
|
451
518
|
|
|
452
|
-
if
|
|
519
|
+
if use_neighborhood_coloring:
|
|
520
|
+
scatter = ax.scatter(embedding[:, 0], embedding[:, 1], embedding[:, 2],
|
|
521
|
+
c=point_colors, s=100, alpha=0.7)
|
|
522
|
+
elif use_identity_coloring:
|
|
453
523
|
scatter = ax.scatter(embedding[:, 0], embedding[:, 1], embedding[:, 2],
|
|
454
524
|
c=point_colors, s=100, alpha=0.7)
|
|
455
525
|
else:
|
|
@@ -460,7 +530,10 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
460
530
|
# Add cluster ID labels
|
|
461
531
|
for i, cluster_id in enumerate(cluster_ids):
|
|
462
532
|
display_label = f'C{cluster_id}'
|
|
463
|
-
if
|
|
533
|
+
if use_neighborhood_coloring and cluster_id in filtered_neighborhoods:
|
|
534
|
+
neighborhood_id = filtered_neighborhoods[cluster_id]
|
|
535
|
+
display_label = f'C{cluster_id}\n(N{neighborhood_id})'
|
|
536
|
+
elif id_dictionary is not None:
|
|
464
537
|
identity = id_dictionary.get(cluster_id, "Unknown")
|
|
465
538
|
display_label = f'C{cluster_id}\n({identity})'
|
|
466
539
|
|
|
@@ -471,12 +544,27 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
471
544
|
ax.set_ylabel('UMAP Component 2')
|
|
472
545
|
ax.set_zlabel('UMAP Component 3')
|
|
473
546
|
title = '3D UMAP Visualization of Cluster Compositions'
|
|
474
|
-
if
|
|
547
|
+
if use_neighborhood_coloring:
|
|
548
|
+
title += ' (Colored by Neighborhood)'
|
|
549
|
+
elif use_identity_coloring:
|
|
475
550
|
title += ' (Colored by Identity)'
|
|
476
551
|
ax.set_title(title)
|
|
477
552
|
|
|
478
553
|
# Add appropriate legend/colorbar
|
|
479
|
-
if
|
|
554
|
+
if use_neighborhood_coloring:
|
|
555
|
+
# Create custom legend for neighborhoods
|
|
556
|
+
legend_elements = []
|
|
557
|
+
for neighborhood_id in unique_neighborhoods:
|
|
558
|
+
color = neighborhood_to_color[neighborhood_id]
|
|
559
|
+
norm_color = (color[0]/255.0, color[1]/255.0, color[2]/255.0)
|
|
560
|
+
legend_elements.append(
|
|
561
|
+
plt.Line2D([0], [0], marker='o', color='w',
|
|
562
|
+
markerfacecolor=norm_color,
|
|
563
|
+
markersize=10, label=f'Neighborhood {neighborhood_id}')
|
|
564
|
+
)
|
|
565
|
+
ax.legend(handles=legend_elements, title='Neighborhoods',
|
|
566
|
+
bbox_to_anchor=(1.05, 1), loc='upper left')
|
|
567
|
+
elif use_identity_coloring:
|
|
480
568
|
# Create custom legend for identities
|
|
481
569
|
legend_elements = [plt.Line2D([0], [0], marker='o', color='w',
|
|
482
570
|
markerfacecolor=identity_to_color[identity],
|
|
@@ -496,12 +584,15 @@ def visualize_cluster_composition_umap(cluster_data: Dict[int, np.ndarray],
|
|
|
496
584
|
print(f"Classes: {class_labels}")
|
|
497
585
|
for i, cluster_id in enumerate(cluster_ids):
|
|
498
586
|
composition = compositions[i]
|
|
499
|
-
|
|
500
|
-
if
|
|
587
|
+
additional_info = ""
|
|
588
|
+
if use_neighborhood_coloring and cluster_id in filtered_neighborhoods:
|
|
589
|
+
neighborhood_id = filtered_neighborhoods[cluster_id]
|
|
590
|
+
additional_info = f" (Neighborhood: {neighborhood_id})"
|
|
591
|
+
elif id_dictionary is not None:
|
|
501
592
|
identity = id_dictionary.get(cluster_id, "Unknown")
|
|
502
|
-
|
|
593
|
+
additional_info = f" (Identity: {identity})"
|
|
503
594
|
|
|
504
|
-
print(f"Cluster {cluster_id}{
|
|
595
|
+
print(f"Cluster {cluster_id}{additional_info}: {composition}")
|
|
505
596
|
# Show which classes dominate this cluster
|
|
506
597
|
dominant_indices = np.argsort(composition)[::-1][:2] # Top 2
|
|
507
598
|
dominant_classes = [class_labels[idx] for idx in dominant_indices]
|
|
@@ -5492,7 +5492,7 @@ class Network_3D:
|
|
|
5492
5492
|
neighborhoods.visualize_cluster_composition_umap(self.node_centroids, None, id_dictionary = self.node_identities, graph_label = "Node ID", title = 'UMAP Visualization of Node Centroids')
|
|
5493
5493
|
|
|
5494
5494
|
|
|
5495
|
-
def community_id_info_per_com(self, umap = False, label =
|
|
5495
|
+
def community_id_info_per_com(self, umap = False, label = 0, limit = 0, proportional = False, neighbors = None):
|
|
5496
5496
|
|
|
5497
5497
|
community_dict = invert_dict(self.communities)
|
|
5498
5498
|
summation = 0
|
|
@@ -5581,7 +5581,19 @@ class Network_3D:
|
|
|
5581
5581
|
if umap:
|
|
5582
5582
|
from . import neighborhoods
|
|
5583
5583
|
|
|
5584
|
-
|
|
5584
|
+
|
|
5585
|
+
if self.communities is not None and label == 2:
|
|
5586
|
+
neighbor_group = {}
|
|
5587
|
+
for node, com in self.communities.items():
|
|
5588
|
+
neighbor_group[com] = neighbors[node]
|
|
5589
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, neighborhoods = neighbor_group)
|
|
5590
|
+
elif label == 1:
|
|
5591
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = True)
|
|
5592
|
+
else:
|
|
5593
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = False)
|
|
5594
|
+
|
|
5595
|
+
|
|
5596
|
+
#neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = label)
|
|
5585
5597
|
|
|
5586
5598
|
return output, id_set
|
|
5587
5599
|
|
|
@@ -5856,44 +5868,57 @@ class Network_3D:
|
|
|
5856
5868
|
|
|
5857
5869
|
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):
|
|
5858
5870
|
|
|
5871
|
+
def distribute_points_uniformly(n, shape, z_scale, xy_scale, num, is_2d=False):
|
|
5872
|
+
|
|
5873
|
+
from scipy.spatial import KDTree
|
|
5859
5874
|
|
|
5860
|
-
def distribute_points_uniformly(n, shape, z_scale, xy_scale, is_2d=False):
|
|
5861
5875
|
if n <= 1:
|
|
5862
5876
|
return 0
|
|
5863
|
-
|
|
5864
|
-
# Calculate total
|
|
5877
|
+
|
|
5878
|
+
# Calculate total positions and sampling step
|
|
5865
5879
|
total_positions = np.prod(shape)
|
|
5880
|
+
if n >= total_positions:
|
|
5881
|
+
# If we want more points than positions, just return scaled unit distance
|
|
5882
|
+
return xy_scale if is_2d else min(z_scale, xy_scale)
|
|
5866
5883
|
|
|
5867
|
-
#
|
|
5868
|
-
|
|
5884
|
+
# Create uniformly spaced indices
|
|
5885
|
+
indices = np.linspace(0, total_positions - 1, n, dtype=int)
|
|
5869
5886
|
|
|
5870
|
-
#
|
|
5871
|
-
|
|
5872
|
-
|
|
5887
|
+
# Convert flat indices to coordinates
|
|
5888
|
+
coords = []
|
|
5889
|
+
for idx in indices:
|
|
5890
|
+
coord = np.unravel_index(idx, shape)
|
|
5891
|
+
if len(shape) == 3:
|
|
5892
|
+
# Apply scaling: [z, y, x] with respective scales
|
|
5893
|
+
scaled_coord = [coord[0] * z_scale, coord[1] * xy_scale, coord[2] * xy_scale]
|
|
5894
|
+
elif len(shape) == 2:
|
|
5895
|
+
# Apply scaling: [y, x] with xy_scale
|
|
5896
|
+
scaled_coord = [coord[0] * xy_scale, coord[1] * xy_scale]
|
|
5897
|
+
coords.append(scaled_coord)
|
|
5873
5898
|
|
|
5874
|
-
|
|
5875
|
-
coord1 = np.unravel_index(idx1, shape)
|
|
5876
|
-
coord2 = np.unravel_index(idx2, shape)
|
|
5899
|
+
coords = np.array(coords)
|
|
5877
5900
|
|
|
5878
|
-
#
|
|
5879
|
-
|
|
5880
|
-
p1 = np.array([coord1[0] * z_scale, coord1[1] * xy_scale, coord1[2] * xy_scale])
|
|
5881
|
-
p2 = np.array([coord2[0] * z_scale, coord2[1] * xy_scale, coord2[2] * xy_scale])
|
|
5882
|
-
elif len(shape) == 2:
|
|
5883
|
-
p1 = np.array([coord1[0] * xy_scale, coord1[1] * xy_scale])
|
|
5884
|
-
p2 = np.array([coord2[0] * xy_scale, coord2[1] * xy_scale])
|
|
5901
|
+
# Build KDTree
|
|
5902
|
+
tree = KDTree(coords)
|
|
5885
5903
|
|
|
5886
|
-
#
|
|
5887
|
-
|
|
5904
|
+
# Pick a point near the middle of the array
|
|
5905
|
+
middle_idx = len(coords) // 2
|
|
5906
|
+
query_point = coords[middle_idx]
|
|
5888
5907
|
|
|
5889
|
-
#
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5908
|
+
# Find the num+1 nearest neighbors (including the point itself)
|
|
5909
|
+
distances, indices = tree.query(query_point, k=num+1)
|
|
5910
|
+
|
|
5911
|
+
# Exclude the point itself (distance 0) and get the actual neighbors
|
|
5912
|
+
neighbor_distances = distances[1:num+1]
|
|
5913
|
+
|
|
5914
|
+
if num == n:
|
|
5915
|
+
neighbor_distances[-1] = neighbor_distances[-2]
|
|
5916
|
+
|
|
5917
|
+
avg_distance = np.mean(neighbor_distances)
|
|
5894
5918
|
|
|
5895
|
-
return neighbor_distance
|
|
5896
5919
|
|
|
5920
|
+
return avg_distance
|
|
5921
|
+
|
|
5897
5922
|
do_borders = not centroids
|
|
5898
5923
|
|
|
5899
5924
|
if centroids:
|
|
@@ -6017,7 +6042,7 @@ class Network_3D:
|
|
|
6017
6042
|
else:
|
|
6018
6043
|
is_2d = False
|
|
6019
6044
|
|
|
6020
|
-
pred = distribute_points_uniformly(len(compare_set), bounds, self.z_scale, self.xy_scale, is_2d = is_2d)
|
|
6045
|
+
pred = distribute_points_uniformly(len(compare_set), bounds, self.z_scale, self.xy_scale, num = num, is_2d = is_2d)
|
|
6021
6046
|
|
|
6022
6047
|
node_intensity = {}
|
|
6023
6048
|
import math
|
|
@@ -6025,18 +6050,22 @@ class Network_3D:
|
|
|
6025
6050
|
|
|
6026
6051
|
for node in root_set:
|
|
6027
6052
|
node_intensity[node] = math.log(pred/output[node])
|
|
6053
|
+
#print(output[node])
|
|
6028
6054
|
node_centroids[node] = self.node_centroids[node]
|
|
6029
6055
|
|
|
6030
6056
|
if numpy:
|
|
6031
6057
|
|
|
6032
6058
|
overlay = neighborhoods.create_node_heatmap(node_intensity, node_centroids, shape = shape, is_3d=threed, labeled_array = self.nodes, colorbar_label="Clustering Intensity", title = title)
|
|
6033
6059
|
|
|
6034
|
-
return avg, output, overlay, quant_overlay
|
|
6060
|
+
return avg, output, overlay, quant_overlay, pred
|
|
6035
6061
|
|
|
6036
6062
|
else:
|
|
6037
6063
|
neighborhoods.create_node_heatmap(node_intensity, node_centroids, shape = shape, is_3d=threed, labeled_array = None, colorbar_label="Clustering Intensity", title = title)
|
|
6038
6064
|
|
|
6039
|
-
|
|
6065
|
+
else:
|
|
6066
|
+
pred = None
|
|
6067
|
+
|
|
6068
|
+
return avg, output, quant_overlay, pred
|
|
6040
6069
|
|
|
6041
6070
|
|
|
6042
6071
|
|