microlive 1.0.14__py3-none-any.whl → 1.0.15__py3-none-any.whl

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.
microlive/__init__.py CHANGED
@@ -23,7 +23,7 @@ Authors:
23
23
  Nathan L. Nowling, Brian Munsky, Ning Zhao
24
24
  """
25
25
 
26
- __version__ = "1.0.14"
26
+ __version__ = "1.0.15"
27
27
  __author__ = "Luis U. Aguilera, William S. Raymond, Rhiannon M. Sears, Nathan L. Nowling, Brian Munsky, Ning Zhao"
28
28
 
29
29
  # Package name (for backward compatibility)
microlive/gui/app.py CHANGED
@@ -9054,7 +9054,7 @@ class GUI(QMainWindow):
9054
9054
  # Cluster radius
9055
9055
  self.cluster_radius_input = QSpinBox()
9056
9056
  self.cluster_radius_input.setMinimum(100)
9057
- self.cluster_radius_input.setMaximum(2000)
9057
+ self.cluster_radius_input.setMaximum(6000)
9058
9058
  self.cluster_radius_input.setValue(self.cluster_radius_nm)
9059
9059
  self.cluster_radius_input.valueChanged.connect(self.update_cluster_radius)
9060
9060
  params_layout.addRow("Cluster radius (nm):", self.cluster_radius_input)
@@ -11701,9 +11701,13 @@ class GUI(QMainWindow):
11701
11701
  layout = QVBoxLayout(self.coloc_verify_distance_widget)
11702
11702
  layout.setContentsMargins(10, 5, 10, 5)
11703
11703
 
11704
- # Info label
11705
- info_label = QLabel("Review and correct Distance-based colocalization results:")
11704
+ # Info label explaining what is displayed
11705
+ info_label = QLabel(
11706
+ "Review unique particle tracks. Each row shows a time-averaged crop. "
11707
+ "A track is marked colocalized (✓) if ANY frame is within the distance threshold."
11708
+ )
11706
11709
  info_label.setStyleSheet("font-style: italic; color: #999;")
11710
+ info_label.setWordWrap(True)
11707
11711
  layout.addWidget(info_label)
11708
11712
 
11709
11713
  # Top bar with stats and buttons
@@ -12553,6 +12557,9 @@ class GUI(QMainWindow):
12553
12557
  channels=(ch1, ch2)
12554
12558
  )
12555
12559
 
12560
+ # Reset sorted flag so Sort button can be used
12561
+ self._verify_visual_sorted = False
12562
+
12556
12563
  # Update stats label
12557
12564
  self._update_verify_visual_stats()
12558
12565
 
@@ -12570,20 +12577,76 @@ class GUI(QMainWindow):
12570
12577
  )
12571
12578
 
12572
12579
  def sort_verify_visual(self):
12573
- """Sort Verify Visual results by prediction value (lowest to highest)."""
12580
+ """Sort Verify Visual results by prediction value (lowest to highest for review)."""
12574
12581
  if not hasattr(self, 'verify_visual_checkboxes') or len(self.verify_visual_checkboxes) == 0:
12582
+ QMessageBox.information(self, "No Data", "No spots to sort. Please click Populate first.")
12583
+ return
12584
+
12585
+ if not hasattr(self, 'colocalization_results') or not self.colocalization_results:
12586
+ QMessageBox.warning(self, "No Results", "No colocalization results available.")
12575
12587
  return
12576
12588
 
12577
- values = self.colocalization_results.get('prediction_values_vector') if hasattr(self, 'colocalization_results') else None
12589
+ results = self.colocalization_results
12590
+ values = results.get('prediction_values_vector')
12591
+ mean_crop = results.get('mean_crop_filtered')
12592
+ crop_size = results.get('crop_size', 15)
12593
+ flag_vector = results.get('flag_vector')
12594
+ ch1 = results.get('ch1_index', 0)
12595
+ ch2 = results.get('ch2_index', 1)
12596
+
12578
12597
  if values is None or len(values) == 0:
12579
12598
  QMessageBox.information(self, "Cannot Sort", "No prediction values available for sorting.")
12580
12599
  return
12581
12600
 
12582
- # Re-populate with sorted order would require rebuilding crops
12583
- # For now, show a message that sorting is based on visual arrangement
12584
- QMessageBox.information(self, "Sort",
12585
- "Spots are already displayed in their original detection order. "
12586
- "Lower prediction values indicate uncertain colocalization.")
12601
+ if mean_crop is None:
12602
+ QMessageBox.warning(self, "No Data", "Crop data not available for sorting.")
12603
+ return
12604
+
12605
+ # Check if already sorted (compare to original order)
12606
+ if hasattr(self, '_verify_visual_sorted') and self._verify_visual_sorted:
12607
+ QMessageBox.information(self, "Already Sorted", "Spots are already sorted by prediction value.")
12608
+ return
12609
+
12610
+ # Get current checkbox states before sorting
12611
+ current_states = [chk.isChecked() for chk in self.verify_visual_checkboxes]
12612
+
12613
+ # Create sorted indices (ascending by prediction value - uncertain first)
12614
+ num_spots = len(values)
12615
+ sorted_indices = np.argsort(values)
12616
+
12617
+ # Re-order checkbox states to match new sort order
12618
+ sorted_states = [current_states[i] if i < len(current_states) else False for i in sorted_indices]
12619
+
12620
+ # Re-order crops - each spot is crop_size rows in the mean_crop array
12621
+ num_crop_spots = mean_crop.shape[0] // crop_size
12622
+ if num_crop_spots < num_spots:
12623
+ num_spots = num_crop_spots
12624
+ sorted_indices = sorted_indices[:num_spots]
12625
+
12626
+ sorted_crop = np.zeros_like(mean_crop[:num_spots*crop_size])
12627
+ for new_idx, old_idx in enumerate(sorted_indices[:num_spots]):
12628
+ if old_idx < num_crop_spots:
12629
+ sorted_crop[new_idx*crop_size:(new_idx+1)*crop_size] = \
12630
+ mean_crop[old_idx*crop_size:(old_idx+1)*crop_size]
12631
+
12632
+ # Re-create verification crops with sorted data
12633
+ self._create_verification_crops(
12634
+ scroll_area=self.verify_visual_scroll_area,
12635
+ checkboxes_list_attr='verify_visual_checkboxes',
12636
+ mean_crop=sorted_crop,
12637
+ crop_size=crop_size,
12638
+ flag_vector=sorted_states, # Use previously checked states after reorder
12639
+ stats_label=self.verify_visual_stats_label,
12640
+ num_channels=2,
12641
+ channels=(ch1, ch2)
12642
+ )
12643
+
12644
+ # Mark as sorted
12645
+ self._verify_visual_sorted = True
12646
+ self._verify_visual_sort_indices = sorted_indices
12647
+
12648
+ # Update stats
12649
+ self._update_verify_visual_stats()
12587
12650
 
12588
12651
  def cleanup_verify_visual(self):
12589
12652
  """Clear all checkboxes in Verify Visual subtab."""
@@ -12630,7 +12693,11 @@ class GUI(QMainWindow):
12630
12693
  # === Verify Distance Subtab Methods ===
12631
12694
 
12632
12695
  def populate_verify_distance(self):
12633
- """Populate the Verify Distance subtab with Distance colocalization results."""
12696
+ """Populate the Verify Distance subtab with Distance colocalization results.
12697
+
12698
+ Calculates and stores the minimum distance from each reference channel spot
12699
+ to its nearest partner in the target channel for sorting purposes.
12700
+ """
12634
12701
  if not hasattr(self, 'distance_coloc_results') or not self.distance_coloc_results:
12635
12702
  QMessageBox.warning(self, "No Results",
12636
12703
  "Please run Distance colocalization first.")
@@ -12641,8 +12708,10 @@ class GUI(QMainWindow):
12641
12708
  ch0 = results.get('channel_0', 0)
12642
12709
  ch1 = results.get('channel_1', 1)
12643
12710
  df_coloc = results.get('df_colocalized', pd.DataFrame())
12711
+ df_ch1_all = results.get('df_ch1_all', pd.DataFrame())
12644
12712
  threshold_px = results.get('threshold_distance_px', 2.0)
12645
12713
  threshold_nm = results.get('threshold_distance_nm', 130.0)
12714
+ use_3d = results.get('use_3d', False)
12646
12715
 
12647
12716
  # We need to create crops from tracking data
12648
12717
  if not hasattr(self, 'df_tracking') or self.df_tracking.empty:
@@ -12684,28 +12753,129 @@ class GUI(QMainWindow):
12684
12753
 
12685
12754
  num_spots = mean_crop.shape[0] // crop_size
12686
12755
 
12687
- # Create flag vector based on distance colocalization
12688
- # Mark spots as colocalized if their coordinates match
12689
- coloc_coords = set()
12756
+ # Build set of colocalized coordinates for matching
12757
+ # Use a tolerance-based approach instead of exact coordinate matching
12758
+ coloc_coords_array = np.empty((0, 4)) # z, y, x, cell_id
12690
12759
  if not df_coloc.empty:
12691
- for _, row in df_coloc.iterrows():
12692
- coord = (round(row.get('x', 0), 1), round(row.get('y', 0), 1))
12693
- coloc_coords.add(coord)
12694
-
12760
+ if 'z' in df_coloc.columns and use_3d:
12761
+ coloc_coords_array = df_coloc[['z', 'y', 'x', 'cell_id']].values
12762
+ else:
12763
+ # Add dummy z=0 for 2D matching
12764
+ coloc_coords_array = np.column_stack([
12765
+ np.zeros(len(df_coloc)),
12766
+ df_coloc['y'].values,
12767
+ df_coloc['x'].values,
12768
+ df_coloc['cell_id'].values
12769
+ ])
12770
+
12771
+ # Calculate minimum distances for each spot in ch0 to nearest spot in ch1
12772
+ # This will be used for sorting (ascending = closest to threshold = most uncertain)
12773
+ distance_values = []
12695
12774
  flag_vector = []
12696
- for i, (_, row) in enumerate(df_ch0.drop_duplicates(subset=['particle']).iterrows()):
12775
+
12776
+ # Get ch1 coordinates for distance calculation
12777
+ ch1_coords = None
12778
+ if not df_ch1_all.empty and 'x' in df_ch1_all.columns and 'y' in df_ch1_all.columns:
12779
+ if use_3d and 'z' in df_ch1_all.columns:
12780
+ ch1_coords = df_ch1_all[['z', 'y', 'x']].values
12781
+ else:
12782
+ ch1_coords = df_ch1_all[['y', 'x']].values
12783
+
12784
+ # Get anisotropic scaling for 3D
12785
+ voxel_z_nm = results.get('voxel_z_nm', 300.0)
12786
+ voxel_xy_nm = results.get('voxel_xy_nm', 130.0)
12787
+ z_scale = voxel_z_nm / voxel_xy_nm if use_3d and voxel_xy_nm > 0 else 1.0
12788
+
12789
+ # Use the same particle column identification as CropArray
12790
+ # This ensures our iteration matches the crop order
12791
+ df_ch0_copy = df_ch0.copy()
12792
+ if 'unique_particle' in df_ch0_copy.columns:
12793
+ particle_col = 'unique_particle'
12794
+ elif 'cell_id' in df_ch0_copy.columns:
12795
+ if 'spot_type' in df_ch0_copy.columns:
12796
+ df_ch0_copy['unique_particle'] = (
12797
+ df_ch0_copy['cell_id'].astype(str) + '_' +
12798
+ df_ch0_copy['spot_type'].astype(str) + '_' +
12799
+ df_ch0_copy['particle'].astype(str)
12800
+ )
12801
+ else:
12802
+ df_ch0_copy['unique_particle'] = (
12803
+ df_ch0_copy['cell_id'].astype(str) + '_' +
12804
+ df_ch0_copy['particle'].astype(str)
12805
+ )
12806
+ particle_col = 'unique_particle'
12807
+ else:
12808
+ particle_col = 'particle'
12809
+
12810
+ # Helper function to check if a spot coordinate is in the colocalized set
12811
+ def is_coord_colocalized(z, y, x, cell_id, coloc_arr, tolerance=1.0):
12812
+ """Check if a spot is in the colocalized set using coordinate tolerance."""
12813
+ if len(coloc_arr) == 0:
12814
+ return False
12815
+ # Filter by cell_id first for efficiency
12816
+ cell_mask = coloc_arr[:, 3].astype(int) == int(cell_id)
12817
+ cell_coloc = coloc_arr[cell_mask]
12818
+ if len(cell_coloc) == 0:
12819
+ return False
12820
+ # Check distance to each colocalized spot
12821
+ for cz, cy, cx, _ in cell_coloc:
12822
+ dist_xy = np.sqrt((x - cx)**2 + (y - cy)**2)
12823
+ dist_z = abs(z - cz) if use_3d else 0
12824
+ if dist_xy <= tolerance and dist_z <= tolerance:
12825
+ return True
12826
+ return False
12827
+
12828
+ # Iterate unique particles in the same order as CropArray
12829
+ unique_particles = df_ch0_copy[particle_col].unique()
12830
+
12831
+ for i, particle_id in enumerate(unique_particles):
12697
12832
  if i >= num_spots:
12698
12833
  break
12699
- coord = (round(row.get('x', 0), 1), round(row.get('y', 0), 1))
12700
- flag_vector.append(coord in coloc_coords)
12834
+
12835
+ df_particle = df_ch0_copy[df_ch0_copy[particle_col] == particle_id]
12836
+
12837
+ # Check if ANY observation of this particle is colocalized
12838
+ is_coloc = False
12839
+ min_dist_all = threshold_px * 10.0 # Large default
12840
+
12841
+ for _, row in df_particle.iterrows():
12842
+ x_val, y_val = row['x'], row['y']
12843
+ z_val = row.get('z', 0)
12844
+ cell_id = row.get('cell_id', 0)
12845
+
12846
+ # Check if this observation is in the colocalized set
12847
+ if len(coloc_coords_array) > 0:
12848
+ if is_coord_colocalized(z_val, y_val, x_val, cell_id, coloc_coords_array, tolerance=1.0):
12849
+ is_coloc = True
12850
+
12851
+ # Calculate minimum distance to any ch1 spot for this observation
12852
+ if ch1_coords is not None and len(ch1_coords) > 0:
12853
+ if use_3d and ch1_coords.shape[1] == 3:
12854
+ spot_coord = np.array([[z_val * z_scale, y_val, x_val]])
12855
+ ch1_scaled = ch1_coords.copy().astype(float)
12856
+ ch1_scaled[:, 0] = ch1_scaled[:, 0] * z_scale # Scale Z
12857
+ else:
12858
+ spot_coord = np.array([[y_val, x_val]])
12859
+ ch1_scaled = ch1_coords
12860
+
12861
+ from scipy.spatial.distance import cdist
12862
+ distances = cdist(spot_coord, ch1_scaled, metric='euclidean')
12863
+ obs_min_dist = float(np.min(distances))
12864
+ if obs_min_dist < min_dist_all:
12865
+ min_dist_all = obs_min_dist
12866
+
12867
+ flag_vector.append(is_coloc)
12868
+ distance_values.append(min_dist_all)
12701
12869
 
12702
- # Pad flag_vector if needed
12870
+ # Pad vectors if needed (shouldn't happen, but just in case)
12703
12871
  while len(flag_vector) < num_spots:
12704
12872
  flag_vector.append(False)
12873
+ distance_values.append(threshold_px * 10.0)
12705
12874
 
12706
- # Store for later use
12875
+ # Store for later use (sorting, etc.)
12707
12876
  self.verify_distance_mean_crop = mean_crop
12708
12877
  self.verify_distance_crop_size = crop_size
12878
+ self.verify_distance_values = np.array(distance_values) # For sorting by distance
12709
12879
 
12710
12880
  # Create spot crops with checkboxes
12711
12881
  self._create_verification_crops(
@@ -12719,6 +12889,9 @@ class GUI(QMainWindow):
12719
12889
  channels=(ch0, ch1)
12720
12890
  )
12721
12891
 
12892
+ # Reset sorted flag so Sort button can be used
12893
+ self._verify_distance_sorted = False
12894
+
12722
12895
  # Update stats label
12723
12896
  self._update_verify_distance_stats()
12724
12897
 
@@ -12743,9 +12916,88 @@ class GUI(QMainWindow):
12743
12916
  )
12744
12917
 
12745
12918
  def sort_verify_distance(self):
12746
- """Sort Verify Distance results (by cell ID or coordinate)."""
12747
- QMessageBox.information(self, "Sort",
12748
- "Distance colocalization spots are displayed in detection order.")
12919
+ """Sort Verify Distance results by distance value (ascending - closest to threshold first).
12920
+
12921
+ Similar to Visual method's certainty-based sorting, but uses the measured
12922
+ distance to nearest partner. Spots with distances closest to the colocalization
12923
+ threshold are shown first as they represent the most uncertain classifications.
12924
+ """
12925
+ if not hasattr(self, 'verify_distance_checkboxes') or len(self.verify_distance_checkboxes) == 0:
12926
+ QMessageBox.information(self, "No Data", "No spots to sort. Please click Populate first.")
12927
+ return
12928
+
12929
+ if not hasattr(self, 'verify_distance_mean_crop') or self.verify_distance_mean_crop is None:
12930
+ QMessageBox.warning(self, "No Data", "Crop data not available for sorting.")
12931
+ return
12932
+
12933
+ # Check if distance values are available
12934
+ if not hasattr(self, 'verify_distance_values') or self.verify_distance_values is None:
12935
+ QMessageBox.warning(self, "No Distance Data",
12936
+ "Distance values not available. Please re-run Populate.")
12937
+ return
12938
+
12939
+ # Check if already sorted
12940
+ if hasattr(self, '_verify_distance_sorted') and self._verify_distance_sorted:
12941
+ QMessageBox.information(self, "Already Sorted", "Spots are already sorted by distance value.")
12942
+ return
12943
+
12944
+ mean_crop = self.verify_distance_mean_crop
12945
+ crop_size = self.verify_distance_crop_size
12946
+ distance_values = self.verify_distance_values
12947
+
12948
+ # Get current checkbox states before sorting
12949
+ current_states = [chk.isChecked() for chk in self.verify_distance_checkboxes]
12950
+ num_spots = len(current_states)
12951
+
12952
+ # Sort ascending by distance (closest to threshold = most uncertain first)
12953
+ # This matches the Visual method's approach of showing uncertain cases first
12954
+ sorted_indices = np.argsort(distance_values)
12955
+
12956
+ # Re-order states and distances
12957
+ sorted_states = [current_states[i] if i < len(current_states) else False for i in sorted_indices]
12958
+ sorted_distances = distance_values[sorted_indices]
12959
+
12960
+ # Re-order crops
12961
+ num_crop_spots = mean_crop.shape[0] // crop_size
12962
+ if num_crop_spots < num_spots:
12963
+ num_spots = num_crop_spots
12964
+ sorted_indices = sorted_indices[:num_spots]
12965
+
12966
+ sorted_crop = np.zeros_like(mean_crop[:num_spots*crop_size])
12967
+ for new_idx, old_idx in enumerate(sorted_indices[:num_spots]):
12968
+ if old_idx < num_crop_spots:
12969
+ sorted_crop[new_idx*crop_size:(new_idx+1)*crop_size] = \
12970
+ mean_crop[old_idx*crop_size:(old_idx+1)*crop_size]
12971
+
12972
+ # Get channels from distance results
12973
+ results = self.distance_coloc_results if hasattr(self, 'distance_coloc_results') else {}
12974
+ ch0 = results.get('channel_0', 0)
12975
+ ch1 = results.get('channel_1', 1)
12976
+ image = self.corrected_image if self.corrected_image is not None else self.image_stack
12977
+ num_channels = image.shape[-1] if image is not None and image.ndim == 5 else 1
12978
+
12979
+ # Re-create verification crops with sorted data
12980
+ self._create_verification_crops(
12981
+ scroll_area=self.verify_distance_scroll_area,
12982
+ checkboxes_list_attr='verify_distance_checkboxes',
12983
+ mean_crop=sorted_crop,
12984
+ crop_size=crop_size,
12985
+ flag_vector=sorted_states,
12986
+ stats_label=self.verify_distance_stats_label,
12987
+ num_channels=num_channels,
12988
+ channels=(ch0, ch1)
12989
+ )
12990
+
12991
+ # Update stored data after sorting for consistency
12992
+ self.verify_distance_mean_crop = sorted_crop
12993
+ self.verify_distance_values = sorted_distances
12994
+ self._verify_distance_sort_indices = sorted_indices # Store for reference
12995
+
12996
+ # Mark as sorted
12997
+ self._verify_distance_sorted = True
12998
+
12999
+ # Update stats
13000
+ self._update_verify_distance_stats()
12749
13001
 
12750
13002
  def cleanup_verify_distance(self):
12751
13003
  """Clear all checkboxes in Verify Distance subtab."""
@@ -12833,7 +13085,12 @@ class GUI(QMainWindow):
12833
13085
 
12834
13086
  # Checkbox
12835
13087
  chk = QCheckBox(f"Spot {i+1}")
12836
- chk.setChecked(bool(flag_vector[i]) if i < len(flag_vector) else False)
13088
+ # Safely get the flag value (handle numpy arrays, lists, etc.)
13089
+ try:
13090
+ flag_val = bool(flag_vector[i]) if i < len(flag_vector) else False
13091
+ except (TypeError, IndexError):
13092
+ flag_val = False
13093
+ chk.setChecked(flag_val)
12837
13094
  chk.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
12838
13095
 
12839
13096
  # Connect to stats update
@@ -15475,6 +15732,7 @@ class GUI(QMainWindow):
15475
15732
  self.verify_visual_checkboxes = []
15476
15733
  if hasattr(self, 'verify_visual_stats_label'):
15477
15734
  self.verify_visual_stats_label.setText("Run Visual colocalization first, then click Populate")
15735
+ self._verify_visual_sorted = False
15478
15736
 
15479
15737
  # Reset Verify Distance
15480
15738
  if hasattr(self, 'verify_distance_scroll_area'):
@@ -15483,6 +15741,11 @@ class GUI(QMainWindow):
15483
15741
  self.verify_distance_checkboxes = []
15484
15742
  if hasattr(self, 'verify_distance_stats_label'):
15485
15743
  self.verify_distance_stats_label.setText("Run Distance colocalization first, then click Populate")
15744
+ # Reset stored distance data for sorting
15745
+ self.verify_distance_mean_crop = None
15746
+ self.verify_distance_crop_size = None
15747
+ self.verify_distance_values = None
15748
+ self._verify_distance_sorted = False
15486
15749
 
15487
15750
  def reset_cellpose_tab(self):
15488
15751
  """Reset Cellpose tab state, masks, and UI controls to defaults."""
microlive/microscopy.py CHANGED
@@ -3948,7 +3948,8 @@ class BigFISH():
3948
3948
 
3949
3949
  # Select isolated spots (cluster_id < 0) and set cluster_size to 1
3950
3950
  spots_no_clusters = clusters_and_spots_big_fish[clusters_and_spots_big_fish[:,-1] < 0].copy()
3951
- spots_no_clusters[:,-1] = 1 # Replace cluster_id with cluster_size=1
3951
+ if len(spots_no_clusters) > 0:
3952
+ spots_no_clusters[:,-1] = 1 # Replace cluster_id with cluster_size=1
3952
3953
 
3953
3954
  # Select cluster centroids with cluster_size > 1
3954
3955
  clusters_no_spots = clusters[clusters[:,-2] > 1]
@@ -5012,6 +5013,7 @@ class DataProcessing():
5012
5013
  self.fast_gaussian_fit = fast_gaussian_fit
5013
5014
  # This number represent the number of columns that doesnt change with the number of color channels in the image
5014
5015
  self.NUMBER_OF_CONSTANT_COLUMNS_IN_DATAFRAME = 18
5016
+
5015
5017
  def get_dataframe(self):
5016
5018
  '''
5017
5019
  This method extracts data from the class SpotDetection and returns the data as a dataframe.
@@ -5162,7 +5164,7 @@ class DataProcessing():
5162
5164
  array_spots_nuc[:,10:13] = spots_nuc[:,:3] # populating coord
5163
5165
  array_spots_nuc[:,13] = 1 # is_nuc
5164
5166
  array_spots_nuc[:,14] = 0 # is_cluster
5165
- array_spots_nuc[:,15] = 0 # cluster_size
5167
+ array_spots_nuc[:,15] = spots_nuc[:,3] # cluster_size (use actual detected value)
5166
5168
  array_spots_nuc[:,16] = spot_type # spot_type
5167
5169
  array_spots_nuc[:,17] = is_cell_in_border # is_cell_fragmented
5168
5170
 
@@ -5171,7 +5173,7 @@ class DataProcessing():
5171
5173
  array_spots_cytosol_only[:,10:13] = spots_cytosol_only[:,:3] # populating coord
5172
5174
  array_spots_cytosol_only[:,13] = 0 # is_nuc
5173
5175
  array_spots_cytosol_only[:,14] = 0 # is_cluster
5174
- array_spots_cytosol_only[:,15] = 1 # cluster_size
5176
+ array_spots_cytosol_only[:,15] = spots_cytosol_only[:,3] # cluster_size (use actual detected value)
5175
5177
  array_spots_cytosol_only[:,16] = spot_type # spot_type
5176
5178
  array_spots_cytosol_only[:,17] = is_cell_in_border # is_cell_fragmented
5177
5179
  if (detected_cyto_clusters == True): #(detected_cyto == True) and
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microlive
3
- Version: 1.0.14
3
+ Version: 1.0.15
4
4
  Summary: Live-cell microscopy image analysis and single-molecule measurements
5
5
  Project-URL: Homepage, https://github.com/ningzhaoAnschutz/microlive
6
6
  Project-URL: Documentation, https://github.com/ningzhaoAnschutz/microlive/blob/main/docs/user_guide.md
@@ -1,14 +1,13 @@
1
- microlive/__init__.py,sha256=ZAui2VsXaQAYA4fnc1FhYO1v3lfGGEFrmTJyZeBAY9E,1385
1
+ microlive/__init__.py,sha256=7MuUee2Gl8qB6BxHVh-WCCBShmt7ZNkKgYRLAvTVT9A,1385
2
2
  microlive/imports.py,sha256=VAAMavSLIKO0LooadTXfCdZiv8LQbV_wITeIv8IHwxM,7531
3
- microlive/microscopy.py,sha256=97T9tEOVwBhEbAZujlDSeC3jt5xSQSCGJ8kboI6ucho,710732
3
+ microlive/microscopy.py,sha256=OFqf0JXJW4-2cLHvXnwwp_SfMFsUXwp5lDKbkCRR4ok,710841
4
4
  microlive/ml_spot_detection.py,sha256=pVbOSGNJ0WWMuPRML42rFwvjKVZ0B1fJux1179OIbAg,10603
5
5
  microlive/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  microlive/data/icons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  microlive/data/icons/icon_micro.png,sha256=b5tFv4E6vUmLwYmYeM4PJuxLV_XqEzN14ueolekTFW0,370236
8
8
  microlive/data/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- microlive/data/models/spot_detection_cnn.pth,sha256=Np7vpPJIbKQmuKY0Hx-4IkeEDsnks_QEgs7TqaYgZmI,8468580
10
9
  microlive/gui/__init__.py,sha256=tB-CdDC7x5OwYFAQxLOUvfVnUThaXKXVRsB68YP0Y6Q,28
11
- microlive/gui/app.py,sha256=GTl2Iwe5uG603Ja6ykwfSG2kB7YaZJYQukLpC0DOurw,787890
10
+ microlive/gui/app.py,sha256=bloU7fOVHB09SCtpmRMtoPzEwE64zGgI2SVRsQD6Hug,800266
12
11
  microlive/gui/main.py,sha256=b66W_2V-pclGKOozfs75pwrCGbL_jkVU3kFt8RFMZIc,2520
13
12
  microlive/gui/micro_mac.command,sha256=TkxYOO_5A2AiNJMz3_--1geBYfl77THpOLFZnV4J2ac,444
14
13
  microlive/gui/micro_windows.bat,sha256=DJUKPhDbCO4HToLwSMT-QTYRe9Kr1wn5A2Ijy2klIrw,773
@@ -21,8 +20,9 @@ microlive/utils/__init__.py,sha256=metAf2zPS8w23d8dyM7-ld1ovrOKBdx3y3zu5IVrzIg,5
21
20
  microlive/utils/device.py,sha256=tcPMU8UiXL-DuGwhudUgrbjW1lgIK_EUKIOeOn0U6q4,2533
22
21
  microlive/utils/model_downloader.py,sha256=EruviTEh75YBekpznn1RZ1Nj8lnDmeC4TKEnFLOow6Y,9448
23
22
  microlive/utils/resources.py,sha256=Jz7kPI75xMLCBJMyX7Y_3ixKi_UgydfQkF0BlFtLCKs,1753
24
- microlive-1.0.14.dist-info/METADATA,sha256=mxn3h5atEOVG_u04F48N-H2ORlMJLC0c4aJQ9bGbB5c,12434
25
- microlive-1.0.14.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
- microlive-1.0.14.dist-info/entry_points.txt,sha256=Zqp2vixyD8lngcfEmOi8fkCj7vPhesz5xlGBI-EubRw,54
27
- microlive-1.0.14.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
28
- microlive-1.0.14.dist-info/RECORD,,
23
+ microlive/data/models/spot_detection_cnn.pth,sha256=Np7vpPJIbKQmuKY0Hx-4IkeEDsnks_QEgs7TqaYgZmI,8468580
24
+ microlive-1.0.15.dist-info/METADATA,sha256=s3CJducpiRGKEiKt6iodAbjo72wZGO1fOQBBU6Jkmb0,12434
25
+ microlive-1.0.15.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
+ microlive-1.0.15.dist-info/entry_points.txt,sha256=Zqp2vixyD8lngcfEmOi8fkCj7vPhesz5xlGBI-EubRw,54
27
+ microlive-1.0.15.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
28
+ microlive-1.0.15.dist-info/RECORD,,