spacr 0.0.70__py3-none-any.whl → 0.0.80__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.
spacr/plot.py CHANGED
@@ -12,17 +12,13 @@ import imageio.v2 as imageio
12
12
  from IPython.display import display
13
13
  from skimage.segmentation import find_boundaries
14
14
  from skimage import measure
15
+ from skimage.measure import find_contours, label, regionprops
15
16
 
16
17
  from ipywidgets import IntSlider, interact
17
18
  from IPython.display import Image as ipyimage
18
19
 
19
20
  from .logger import log_function_call
20
21
 
21
-
22
- #from .io import _save_figure
23
- #from .timelapse import _save_mask_timelapse_as_gif
24
- #from .utils import normalize_to_dtype, _remove_outside_objects, _remove_multiobject_cells, _find_similar_sized_images, _remove_noninfected
25
-
26
22
  def plot_masks(batch, masks, flows, cmap='inferno', figuresize=20, nr=1, file_type='.npz', print_object_number=True):
27
23
  """
28
24
  Plot the masks and flows for a given batch of images.
@@ -193,7 +189,7 @@ def _get_colours_merged(outline_color):
193
189
  outline_colors = [[1, 0, 0], [0, 0, 1], [0, 1, 0]] # rbg
194
190
  return outline_colors
195
191
 
196
- def plot_images_and_arrays(folders, lower_percentile=1, upper_percentile=99, threshold=1000, extensions=['.npy', '.tif', '.tiff', '.png']):
192
+ def plot_images_and_arrays(folders, lower_percentile=1, upper_percentile=99, threshold=1000, extensions=['.npy', '.tif', '.tiff', '.png'], overlay=False, max_nr=None, randomize=True):
197
193
  """
198
194
  Plot images and arrays from the given folders.
199
195
 
@@ -203,6 +199,7 @@ def plot_images_and_arrays(folders, lower_percentile=1, upper_percentile=99, thr
203
199
  upper_percentile (int, optional): The upper percentile for image normalization. Defaults to 99.
204
200
  threshold (int, optional): The threshold for determining whether to display an image as a mask or normalize it. Defaults to 1000.
205
201
  extensions (list, optional): A list of file extensions to consider. Defaults to ['.npy', '.tif', '.tiff', '.png'].
202
+ overlay (bool, optional): If True, overlay the outlines of the objects on the image. Defaults to False.
206
203
  """
207
204
 
208
205
  def normalize_image(image, lower=1, upper=99):
@@ -226,7 +223,7 @@ def plot_images_and_arrays(folders, lower_percentile=1, upper_percentile=99, thr
226
223
  filtered_dict = {k: v for k, v in file_dict.items() if len(v) == len(folders)}
227
224
  return filtered_dict
228
225
 
229
- def plot_from_file_dict(file_dict, threshold=1000, lower_percentile=1, upper_percentile=99):
226
+ def plot_from_file_dict(file_dict, threshold=1000, lower_percentile=1, upper_percentile=99, overlay=False, save=False):
230
227
  """
231
228
  Plot images and arrays from the given file dictionary.
232
229
 
@@ -235,18 +232,14 @@ def plot_images_and_arrays(folders, lower_percentile=1, upper_percentile=99, thr
235
232
  threshold (int, optional): The threshold for determining whether to display an image as a mask or normalize it. Defaults to 1000.
236
233
  lower_percentile (int, optional): The lower percentile for image normalization. Defaults to 1.
237
234
  upper_percentile (int, optional): The upper percentile for image normalization. Defaults to 99.
235
+ overlay (bool, optional): If True, overlay the outlines of the objects on the image. Defaults to False.
238
236
  """
239
237
 
240
238
  for filename, folder_paths in file_dict.items():
241
- num_files = len(folder_paths)
242
- fig, axes = plt.subplots(1, num_files, figsize=(15, 5))
243
- #fig.suptitle(filename)
244
-
245
- # Ensure axes is always a list
246
- if num_files == 1:
247
- axes = [axes]
239
+ image_data = None
240
+ mask_data = None
248
241
 
249
- for i, (folder, path) in enumerate(folder_paths.items()):
242
+ for folder, path in folder_paths.items():
250
243
  if path.endswith('.npy'):
251
244
  data = np.load(path)
252
245
  elif path.endswith('.tif') or path.endswith('.tiff'):
@@ -254,25 +247,57 @@ def plot_images_and_arrays(folders, lower_percentile=1, upper_percentile=99, thr
254
247
  else:
255
248
  continue
256
249
 
257
- ax = axes[i]
258
250
  unique_values = np.unique(data)
251
+
259
252
  if len(unique_values) > threshold:
260
- # Normalize image to percentiles
261
- data = normalize_image(data, lower_percentile, upper_percentile)
262
- ax.imshow(data, cmap='gray')
253
+ image_data = normalize_image(data, lower_percentile, upper_percentile)
263
254
  else:
264
- # Display as mask with random colormap
265
- cmap = random_cmap(num_objects=len(unique_values))
266
- ax.imshow(data, cmap=cmap)
267
-
268
- ax.set_title(f"{os.path.basename(folder)}: {os.path.basename(path)}")
269
- ax.axis('off')
270
- plt.tight_layout
271
- plt.subplots_adjust(wspace=0.01, hspace=0.01)
272
- plt.show()
273
-
255
+ mask_data = data
256
+
257
+ if image_data is not None and mask_data is not None:
258
+ fig, axes = plt.subplots(1, 2, figsize=(15, 7))
259
+
260
+ # Display the mask with random colormap
261
+ cmap = random_cmap(num_objects=len(np.unique(mask_data)))
262
+ axes[0].imshow(mask_data, cmap=cmap)
263
+ axes[0].set_title(f"{filename} - Mask")
264
+ axes[0].axis('off')
265
+
266
+ # Display the normalized image
267
+ axes[1].imshow(image_data, cmap='gray')
268
+ if overlay:
269
+ labeled_mask = label(mask_data)
270
+ for region in regionprops(labeled_mask):
271
+ if region.image.shape[0] >= 2 and region.image.shape[1] >= 2:
272
+ contours = find_contours(region.image, 0.75)
273
+ for contour in contours:
274
+ # Adjust contour coordinates relative to the full image
275
+ contour[:, 0] += region.bbox[0]
276
+ contour[:, 1] += region.bbox[1]
277
+ axes[1].plot(contour[:, 1], contour[:, 0], linewidth=2, color='magenta')
278
+
279
+ axes[1].set_title(f"{filename} - Normalized Image")
280
+ axes[1].axis('off')
281
+
282
+ plt.tight_layout()
283
+ plt.show()
284
+
285
+ if save:
286
+ save_path = os.path.join(folder,f"{filename}.png")
287
+ plt.savefig(save_path)
288
+
289
+ if overlay:
290
+ print(f'Overlay will only work on the first two folders in the list')
291
+
274
292
  file_dict = find_files(folders, extensions)
275
- plot_from_file_dict(file_dict, threshold, lower_percentile, upper_percentile)
293
+ items = list(file_dict.items())
294
+ if randomize:
295
+ random.shuffle(items)
296
+ if isinstance(max_nr, (int, float)):
297
+ items = items[:int(max_nr)]
298
+ file_dict = dict(items)
299
+
300
+ plot_from_file_dict(file_dict, threshold, lower_percentile, upper_percentile, overlay, save=False)
276
301
  return
277
302
 
278
303
  def _filter_objects_in_plot(stack, cell_mask_dim, nucleus_mask_dim, pathogen_mask_dim, mask_dims, filter_min_max, include_multinucleated, include_multiinfected):
@@ -739,7 +764,53 @@ def _save_scimg_plot(src, nr_imgs=16, channel_indices=[0,1,2], um_per_pixel=0.1,
739
764
 
740
765
  return
741
766
 
742
- def _plot_cropped_arrays(stack, figuresize=20,cmap='inferno'):
767
+ def _plot_cropped_arrays(stack, filename, figuresize=20, cmap='inferno', threshold=500):
768
+ """
769
+ Plot cropped arrays.
770
+
771
+ Args:
772
+ stack (ndarray): The array to be plotted.
773
+ figuresize (int, optional): The size of the figure. Defaults to 20.
774
+ cmap (str, optional): The colormap to be used. Defaults to 'inferno'.
775
+ threshold (int, optional): The threshold for the number of unique intensity values. Defaults to 1000.
776
+
777
+ Returns:
778
+ None
779
+ """
780
+ #start = time.time()
781
+ dim = stack.shape
782
+
783
+ def plot_single_array(array, ax, title, chosen_cmap):
784
+ unique_values = np.unique(array)
785
+ num_unique_values = len(unique_values)
786
+
787
+ if num_unique_values <= threshold:
788
+ chosen_cmap = _generate_mask_random_cmap(array)
789
+ title = f'{title}, {num_unique_values} (obj.)'
790
+
791
+ ax.imshow(array, cmap=chosen_cmap)
792
+ ax.set_title(title, size=18)
793
+ ax.axis('off')
794
+
795
+ if len(dim) == 2:
796
+ fig, ax = plt.subplots(1, 1, figsize=(figuresize, figuresize))
797
+ plot_single_array(stack, ax, 'Channel one', plt.get_cmap(cmap))
798
+ fig.tight_layout()
799
+ plt.show()
800
+ elif len(dim) > 2:
801
+ num_channels = dim[2]
802
+ fig, axs = plt.subplots(1, num_channels, figsize=(figuresize, figuresize))
803
+ for channel in range(num_channels):
804
+ plot_single_array(stack[:, :, channel], axs[channel], f'C. {channel}', plt.get_cmap(cmap))
805
+ fig.tight_layout()
806
+ plt.show()
807
+
808
+ #stop = time.time()
809
+ #duration = stop - start
810
+ #print('plot_cropped_arrays', duration)
811
+ print(f'{filename}')
812
+
813
+ def _plot_cropped_arrays_v1(stack, figuresize=20, cmap='inferno'):
743
814
  """
744
815
  Plot cropped arrays.
745
816
 
@@ -1192,56 +1263,6 @@ def _plot_plates(df, variable, grouping, min_max, cmap, min_count=0):
1192
1263
  plt.show()
1193
1264
  return fig
1194
1265
 
1195
- #def plate_heatmap(src, variable='recruitment', grouping='mean', min_max='allq', cmap='viridis', channel_of_interest=3, min_count=25, verbose=False):
1196
- # db_loc = [src+'/measurements/measurements.db']
1197
- # tables = ['cell', 'nucleus', 'pathogen','cytoplasm']
1198
- # include_multinucleated, include_multiinfected, include_noninfected = True, 2.0, True
1199
- # df, _ = spacr.io._read_and_merge_data(db_loc,
1200
- # tables,
1201
- # verbose=verbose,
1202
- # include_multinucleated=include_multinucleated,
1203
- # include_multiinfected=include_multiinfected,
1204
- # include_noninfected=include_noninfected)
1205
- #
1206
- # df['recruitment'] = df[f'pathogen_channel_{channel_of_interest}_outside_75_percentile']/df[f'cytoplasm_channel_{channel_of_interest}_mean_intensity']
1207
- #
1208
- # spacr.plot._plot_plates(df, variable, grouping, min_max, cmap, min_count)
1209
- # #display(df)
1210
- # #for col in df.columns:
1211
- # # print(col)
1212
- # return
1213
-
1214
- #from finetune cellpose
1215
- #def plot_arrays(src, figuresize=50, cmap='inferno', nr=1, normalize=True, q1=1, q2=99):
1216
- # paths = []
1217
- # for file in os.listdir(src):
1218
- # if file.endswith('.tif') or file.endswith('.tiff'):
1219
- # path = os.path.join(src, file)
1220
- # paths.append(path)
1221
- # paths = random.sample(paths, nr)
1222
- # for path in paths:
1223
- # print(f'Image path:{path}')
1224
- # img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
1225
- # if normalize:
1226
- # img = normalize_to_dtype(array=img, q1=q1, q2=q2)
1227
- # dim = img.shape
1228
- # if len(img.shape) > 2:
1229
- # array_nr = img.shape[2]
1230
- # fig, axs = plt.subplots(1, array_nr, figsize=(figuresize, figuresize))
1231
- # for channel in range(array_nr):
1232
- # i = np.take(img, [channel], axis=2)
1233
- # axs[channel].imshow(i, cmap=plt.get_cmap(cmap))
1234
- # axs[channel].set_title('Channel '+str(channel), size=24)
1235
- # axs[channel].axis('off')
1236
- # else:
1237
- # fig, ax = plt.subplots(1, 1, figsize=(figuresize, figuresize))
1238
- # ax.imshow(img, cmap=plt.get_cmap(cmap))
1239
- # ax.set_title('Channel 0', size=24)
1240
- # ax.axis('off')
1241
- # fig.tight_layout()
1242
- # plt.show()
1243
- # return
1244
-
1245
1266
  def print_mask_and_flows(stack, mask, flows, overlay=False):
1246
1267
  fig, axs = plt.subplots(1, 3, figsize=(30, 10)) # Adjust subplot layout
1247
1268
 
@@ -1434,3 +1455,18 @@ def plot_comparison_results(comparison_results):
1434
1455
  plt.tight_layout()
1435
1456
  plt.show()
1436
1457
  return fig
1458
+
1459
+ def plot_object_outlines(src, objects=['nucleus','cell','pathogen'], channels=[0,1,2], max_nr=10):
1460
+
1461
+ for object_, channel in zip(objects, channels):
1462
+ folders = [os.path.join(src, 'norm_channel_stack', f'{object_}_mask_stack'),
1463
+ os.path.join(src,f'{channel+1}')]
1464
+ print(folders)
1465
+ plot_images_and_arrays(folders,
1466
+ lower_percentile=2,
1467
+ upper_percentile=99.5,
1468
+ threshold=1000,
1469
+ extensions=['.npy', '.tif', '.tiff', '.png'],
1470
+ overlay=True,
1471
+ max_nr=10,
1472
+ randomize=True)