patchworks 0.11.20__tar.gz → 1.0.0__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.
Files changed (77) hide show
  1. {patchworks-0.11.20 → patchworks-1.0.0}/.github/workflows/release.yml +0 -14
  2. {patchworks-0.11.20 → patchworks-1.0.0}/PKG-INFO +3 -3
  3. {patchworks-0.11.20 → patchworks-1.0.0}/pyproject.toml +2 -2
  4. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_chunks.py +1 -1
  5. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_relabel.py +34 -4
  6. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/plugins/ome_zarr.py +98 -0
  7. {patchworks-0.11.20 → patchworks-1.0.0}/tests/test_relations.py +6 -2
  8. {patchworks-0.11.20 → patchworks-1.0.0}/.github/workflows/docs.yml +0 -0
  9. {patchworks-0.11.20 → patchworks-1.0.0}/.github/workflows/lint.yml +0 -0
  10. {patchworks-0.11.20 → patchworks-1.0.0}/.gitignore +0 -0
  11. {patchworks-0.11.20 → patchworks-1.0.0}/.markdownlint-cli2.yaml +0 -0
  12. {patchworks-0.11.20 → patchworks-1.0.0}/LICENSE +0 -0
  13. {patchworks-0.11.20 → patchworks-1.0.0}/README.md +0 -0
  14. {patchworks-0.11.20 → patchworks-1.0.0}/cliff.toml +0 -0
  15. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/chunks.md +0 -0
  16. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/cluster.md +0 -0
  17. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/io.md +0 -0
  18. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/merge_tile_labels.md +0 -0
  19. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/plugins/cellpose.md +0 -0
  20. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/plugins/napari.md +0 -0
  21. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/plugins/ome_zarr.md +0 -0
  22. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/relabel.md +0 -0
  23. {patchworks-0.11.20 → patchworks-1.0.0}/docs/api/tile_process.md +0 -0
  24. {patchworks-0.11.20 → patchworks-1.0.0}/docs/assets/logo.png +0 -0
  25. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/cellpose_2d.md +0 -0
  26. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/cellpose_2d.py +0 -0
  27. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/cellpose_3d.md +0 -0
  28. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/cellpose_3d.py +0 -0
  29. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/custom.md +0 -0
  30. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/custom_method.py +0 -0
  31. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/standalone_merge.md +0 -0
  32. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/stardist.md +0 -0
  33. {patchworks-0.11.20 → patchworks-1.0.0}/docs/examples/stardist_2d.py +0 -0
  34. {patchworks-0.11.20 → patchworks-1.0.0}/docs/getting_started.md +0 -0
  35. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/gpu_distributed.md +0 -0
  36. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/merging.md +0 -0
  37. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/ome_zarr_napari.md +0 -0
  38. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/performance.md +0 -0
  39. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/pitfalls.md +0 -0
  40. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/skip_empty.md +0 -0
  41. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/snakemake.md +0 -0
  42. {patchworks-0.11.20 → patchworks-1.0.0}/docs/guide/tiling.md +0 -0
  43. {patchworks-0.11.20 → patchworks-1.0.0}/docs/index.md +0 -0
  44. {patchworks-0.11.20 → patchworks-1.0.0}/mkdocs.yml +0 -0
  45. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/__init__.py +0 -0
  46. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_cluster.py +0 -0
  47. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_core.py +0 -0
  48. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_distributed.py +0 -0
  49. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_io.py +0 -0
  50. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_merge.py +0 -0
  51. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/_relations.py +0 -0
  52. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/plugins/__init__.py +0 -0
  53. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/plugins/cellpose.py +0 -0
  54. {patchworks-0.11.20 → patchworks-1.0.0}/src/patchworks/plugins/napari.py +0 -0
  55. {patchworks-0.11.20 → patchworks-1.0.0}/tests/test_core.py +0 -0
  56. {patchworks-0.11.20 → patchworks-1.0.0}/tests/test_distributed.py +0 -0
  57. {patchworks-0.11.20 → patchworks-1.0.0}/tests/test_napari.py +0 -0
  58. {patchworks-0.11.20 → patchworks-1.0.0}/tests/test_ome_zarr.py +0 -0
  59. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/README.md +0 -0
  60. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/Snakefile +0 -0
  61. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/config/config.yaml +0 -0
  62. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/config/config_cyto.yaml +0 -0
  63. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/config/config_nuclei.yaml +0 -0
  64. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/config/multi.yaml +0 -0
  65. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/pixi.toml +0 -0
  66. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/profile/slurm/config.yaml +0 -0
  67. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/rules/common.smk +0 -0
  68. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/rules/convert.smk +0 -0
  69. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/rules/merge.smk +0 -0
  70. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/rules/segment.smk +0 -0
  71. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/_pw.py +0 -0
  72. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/convert.py +0 -0
  73. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/fetch_model.py +0 -0
  74. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/merge.py +0 -0
  75. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/prepare_tiles.py +0 -0
  76. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/run_multi.py +0 -0
  77. {patchworks-0.11.20 → patchworks-1.0.0}/workflow/scripts/segment_tile.py +0 -0
@@ -48,17 +48,3 @@ jobs:
48
48
 
49
49
  - name: Publish to PyPI
50
50
  uses: pypa/gh-action-pypi-publish@release/v1
51
-
52
- # Rebuild the org-wide pdoc apidocs site so it picks up the new version.
53
- apidocs:
54
- needs: release
55
- runs-on: ubuntu-latest
56
- steps:
57
- - name: Trigger imcf.github.io apidocs rebuild
58
- uses: peter-evans/repository-dispatch@v3
59
- with:
60
- # Fine-grained PAT with "Contents: write" on imcf/imcf.github.io,
61
- # stored as the APIDOCS_DISPATCH_TOKEN secret in this repo.
62
- token: ${{ secrets.APIDOCS_DISPATCH_TOKEN }}
63
- repository: imcf/imcf.github.io
64
- event-type: dispatch-event
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchworks
3
- Version: 0.11.20
3
+ Version: 1.0.0
4
4
  Summary: Tiled processing of arbitrarily large images with globally consistent labels
5
5
  Project-URL: Homepage, https://github.com/imcf/patchworks
6
6
  Project-URL: Issues, https://github.com/imcf/patchworks/issues
7
- Author: IMCF Basel
7
+ Author-email: Laurent Guerard <laurent.guerard@unibas.ch>
8
8
  License: GPL-3.0-only
9
9
  License-File: LICENSE
10
10
  Keywords: bioimage,chunked,dask,image processing,segmentation,tiling,zarr
11
- Classifier: Development Status :: 4 - Beta
11
+ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Science/Research
13
13
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
14
  Classifier: Programming Language :: Python :: 3
@@ -8,7 +8,7 @@ dynamic = ["version"]
8
8
  description = "Tiled processing of arbitrarily large images with globally consistent labels"
9
9
  readme = "README.md"
10
10
  license = { text = "GPL-3.0-only" }
11
- authors = [{ name = "IMCF Basel" }]
11
+ authors = [{ name = "Laurent Guerard", email = "laurent.guerard@unibas.ch" }]
12
12
  keywords = [
13
13
  "image processing",
14
14
  "tiling",
@@ -19,7 +19,7 @@ keywords = [
19
19
  "bioimage",
20
20
  ]
21
21
  classifiers = [
22
- "Development Status :: 4 - Beta",
22
+ "Development Status :: 5 - Production/Stable",
23
23
  "Intended Audience :: Science/Research",
24
24
  "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
25
25
  "Programming Language :: Python :: 3",
@@ -179,7 +179,7 @@ def auto_tile_shape(
179
179
  --------
180
180
  >>> tile = auto_tile_shape((128, 2048, 2048), "uint16")
181
181
  >>> tile
182
- (8, 2048, 2048)
182
+ (128, 512, 512)
183
183
  """
184
184
  n_workers = n_workers or os.cpu_count() or 1
185
185
  itemsize = np.dtype(dtype).itemsize
@@ -33,7 +33,7 @@ def relabel_sequential_array(labels: np.ndarray) -> np.ndarray:
33
33
  Examples
34
34
  --------
35
35
  >>> relabel_sequential_array(np.array([0, 500000, 500000, 7]))
36
- array([0, 2, 2, 1])
36
+ array([0, 2, 2, 1], dtype=uint16)
37
37
  """
38
38
  uniq = np.unique(labels)
39
39
  max_label = int(uniq[-1])
@@ -53,11 +53,41 @@ def relabel_sequential_array(labels: np.ndarray) -> np.ndarray:
53
53
 
54
54
 
55
55
  def relabel_sequential_zarr(store_path: str, component: str = "labels") -> int:
56
- """Relabel a written label zarr to contiguous ids, in place. Returns N.
56
+ """Relabel a written label zarr to contiguous ids, in place.
57
57
 
58
58
  Two-pass streaming algorithm — safe for arrays far larger than RAM.
59
- Pass 1 collects unique ids (bounded memory: a set). Pass 2 applies the
60
- lookup-table remap chunk by chunk.
59
+ Pass 1 collects unique ids (bounded memory: a Python ``set``, not the
60
+ voxels themselves). Pass 2 applies the lookup-table remap chunk by
61
+ chunk, writing back into the same store.
62
+
63
+ Parameters
64
+ ----------
65
+ store_path : str
66
+ Path to the zarr store containing the label array.
67
+ component : str, optional
68
+ Array name inside the store to relabel in place (default
69
+ ``"labels"``).
70
+
71
+ Returns
72
+ -------
73
+ int
74
+ Number of distinct objects (``N``); the array now holds ``1..N``
75
+ (background ``0`` unchanged).
76
+
77
+ Examples
78
+ --------
79
+ >>> import zarr
80
+ >>> root = zarr.open_group("staged.zarr", mode="w") # doctest: +SKIP
81
+ >>> root.create_array(
82
+ ... "labels", shape=(4, 4), chunks=(4, 4), dtype="int32"
83
+ ... )[:] = [
84
+ ... [0, 500000, 500000, 0],
85
+ ... [0, 0, 0, 7],
86
+ ... [0, 0, 0, 0],
87
+ ... [0, 0, 0, 0],
88
+ ... ] # doctest: +SKIP
89
+ >>> relabel_sequential_zarr("staged.zarr") # doctest: +SKIP
90
+ 2
61
91
  """
62
92
  root = zarr.open_group(store_path, mode="r+")
63
93
  z = root[component]
@@ -953,10 +953,41 @@ def add_pyramid(
953
953
  ``multiscales`` metadata. Existing calibration is preserved; pass
954
954
  *pixel_size* to set it.
955
955
 
956
+ Parameters
957
+ ----------
958
+ group_path : str or Path
959
+ Zarr group containing the full-resolution array at *base*.
960
+ base : str, optional
961
+ Component name of the existing full-resolution level (default
962
+ ``"0"``). Auto-detected from existing ``multiscales`` metadata if
963
+ present, overriding this.
964
+ axes : str, optional
965
+ One letter per axis, e.g. ``"zyx"``. ``None`` → inferred from
966
+ existing metadata, or from the array's dimensionality.
967
+ pixel_size : dict, tuple or None, optional
968
+ Physical voxel size in micrometers. ``None`` → read from the store's
969
+ existing calibration, if any.
970
+ n_levels : int, optional
971
+ Maximum number of levels including the existing full-resolution one
972
+ (default 5).
973
+ downscale : int, optional
974
+ Per-level X/Y downsampling factor (default 2).
975
+ chunks : tuple of int, optional
976
+ Chunk shape for the written levels. ``None`` → a bounded default.
977
+ shard : bool or tuple of int, optional
978
+ Sharding request (see :func:`to_ome_zarr`'s *shard*).
979
+ progress : bool, optional
980
+ Show a per-level dask progress bar (default ``True``).
981
+
956
982
  Returns
957
983
  -------
958
984
  str
959
985
  The path to the updated group.
986
+
987
+ Examples
988
+ --------
989
+ >>> add_pyramid("scan.zarr", n_levels=4) # doctest: +SKIP
990
+ 'scan.zarr'
960
991
  """
961
992
  if downscale < 2:
962
993
  raise ValueError("downscale must be >= 2")
@@ -1023,10 +1054,38 @@ def register_labels(
1023
1054
  ``labels/.zattrs``, and inherits the parent image's pixel calibration
1024
1055
  (unless *pixel_size* is given).
1025
1056
 
1057
+ Parameters
1058
+ ----------
1059
+ image_store : str or Path
1060
+ OME-ZARR store path containing the image this label belongs to.
1061
+ name : str, optional
1062
+ Label image name under ``labels/`` (default ``"labels"``).
1063
+ axes : str, optional
1064
+ One letter per axis. ``None`` → inferred from the label array.
1065
+ pixel_size : dict, tuple or None, optional
1066
+ Physical voxel size in micrometers. ``None`` → inherited from the
1067
+ parent image's own calibration.
1068
+ n_levels : int, optional
1069
+ Maximum number of pyramid levels including full resolution
1070
+ (default 5).
1071
+ downscale : int, optional
1072
+ Per-level X/Y downsampling factor (default 2).
1073
+ chunks : tuple of int, optional
1074
+ Chunk shape for the written levels. ``None`` → a bounded default.
1075
+ shard : bool or tuple of int, optional
1076
+ Sharding request (see :func:`to_ome_zarr`'s *shard*).
1077
+ progress : bool, optional
1078
+ Show a per-level dask progress bar (default ``True``).
1079
+
1026
1080
  Returns
1027
1081
  -------
1028
1082
  str
1029
1083
  Path to the label group (``image_store/labels/<name>``).
1084
+
1085
+ Examples
1086
+ --------
1087
+ >>> register_labels("scan.zarr", "cells") # doctest: +SKIP
1088
+ 'scan.zarr/labels/cells'
1030
1089
  """
1031
1090
  store = str(image_store)
1032
1091
  group = f"{store}/labels/{name}"
@@ -1078,10 +1137,49 @@ def write_labels(
1078
1137
  single OME-ZARR store. Calibration is inherited from the parent image
1079
1138
  unless *pixel_size* is given.
1080
1139
 
1140
+ Parameters
1141
+ ----------
1142
+ image_store : str or Path
1143
+ OME-ZARR store this label image belongs to.
1144
+ labels : da.Array or np.ndarray
1145
+ Integer label array (0 = background), same spatial shape as the
1146
+ image.
1147
+ name : str, optional
1148
+ Label image name under ``labels/`` (default ``"labels"``).
1149
+ axes : str, optional
1150
+ One letter per axis. ``None`` → inferred from *labels*'
1151
+ dimensionality.
1152
+ pixel_size : dict, tuple or None, optional
1153
+ Physical voxel size in micrometers. ``None`` → inherited from the
1154
+ parent image's own calibration.
1155
+ n_levels : int, optional
1156
+ Maximum number of pyramid levels including full resolution
1157
+ (default 5).
1158
+ downscale : int, optional
1159
+ Per-level X/Y downsampling factor (default 2).
1160
+ chunks : tuple of int, optional
1161
+ Chunk shape for the written levels. ``None`` → a bounded default.
1162
+ shard : bool or tuple of int, optional
1163
+ Sharding request (see :func:`to_ome_zarr`'s *shard*).
1164
+ progress : bool, optional
1165
+ Show a per-level dask progress bar (default ``True``).
1166
+ overwrite : bool, optional
1167
+ Replace an existing label image of the same *name* (default
1168
+ ``False``).
1169
+
1081
1170
  Returns
1082
1171
  -------
1083
1172
  str
1084
1173
  Path to the written label group (``image_store/labels/<name>``).
1174
+
1175
+ Examples
1176
+ --------
1177
+ >>> from patchworks import merge_tile_labels
1178
+ >>> merged = merge_tile_labels(
1179
+ ... "stage.zarr", input_component="staged", write_to="merged.zarr"
1180
+ ... ) # doctest: +SKIP
1181
+ >>> write_labels("scan.zarr", merged, name="cells") # doctest: +SKIP
1182
+ 'scan.zarr/labels/cells'
1085
1183
  """
1086
1184
  arr = labels if isinstance(labels, da.Array) else da.asarray(labels)
1087
1185
  if axes is None:
@@ -17,7 +17,9 @@ def test_label_relations_majority_overlap():
17
17
  b[0:2, 6:8] = 21 # 4 voxels overlap with label 2 -> tie, but let's skew it
18
18
  b[0:2, 6:7] = 20 # tip the tie: label 20 now has 6 voxels vs 21's 2
19
19
 
20
- table = label_relations(da.from_array(a, chunks=(2, 5)), da.from_array(b, chunks=(2, 5)))
20
+ table = label_relations(
21
+ da.from_array(a, chunks=(2, 5)), da.from_array(b, chunks=(2, 5))
22
+ )
21
23
 
22
24
  assert table[1]["match"] == 10
23
25
  assert table[1]["overlap_voxels"] == 4
@@ -32,7 +34,9 @@ def test_label_relations_no_overlap_omitted():
32
34
  a[0, 0] = 1
33
35
  b = np.zeros((2, 2), dtype=np.int32) # all background, no overlap anywhere
34
36
 
35
- table = label_relations(da.from_array(a, chunks=(2, 2)), da.from_array(b, chunks=(2, 2)))
37
+ table = label_relations(
38
+ da.from_array(a, chunks=(2, 2)), da.from_array(b, chunks=(2, 2))
39
+ )
36
40
  assert table == {}
37
41
 
38
42
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes