mergechannels 0.1.2__cp39-cp39-musllinux_1_2_aarch64.whl → 0.3.0__cp39-cp39-musllinux_1_2_aarch64.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.

Potentially problematic release.


This version of mergechannels might be problematic. Click here for more details.

mergechannels/__init__.py CHANGED
@@ -1,13 +1,13 @@
1
1
  # Import Rust functions
2
2
  from .mergechannels import ( # type: ignore
3
- apply_color_map,
4
- apply_colors_and_merge_nc,
3
+ dispatch_single_channel,
4
+ dispatch_multi_channel,
5
5
  )
6
-
7
6
  from ._internal import merge
8
7
 
8
+
9
9
  __all__ = [
10
- 'apply_color_map',
11
- 'apply_colors_and_merge_nc',
10
+ 'dispatch_single_channel',
11
+ 'dispatch_multi_channel',
12
12
  'merge',
13
13
  ]
@@ -1,27 +1,30 @@
1
- from typing import Sequence, Literal
2
1
 
2
+ from typing import Literal, Sequence
3
3
  import numpy as np
4
4
 
5
- from ._luts import COLORMAPS
6
- from ._blending import BLENDING_OPTIONS
5
+ from python.mergechannels._blending import BLENDING_OPTIONS
6
+ from python.mergechannels._luts import COLORMAPS
7
+
7
8
 
8
9
  def merge(
9
- arrs: Sequence[np.ndarray],
10
- colors: Sequence[COLORMAPS] = (),
11
- blending: Literal[BLENDING_OPTIONS] = 'max',
10
+ arrs: np.ndarray | Sequence[np.ndarray],
11
+ colors: Sequence[COLORMAPS] = (),
12
+ blending: Literal[BLENDING_OPTIONS] = 'max',
12
13
  saturation_limits: tuple[float, float] = (0.2, 99.8),
13
14
  ) -> np.ndarray:
14
15
  ...
15
16
 
16
- def apply_color_map(
17
- arr: np.ndarray,
18
- cmap_name: COLORMAPS,
19
- saturation_limits: tuple[float, float] = (0.2, 99.8),
20
- ) -> np.ndarray: ...
17
+ def dispatch_single_channel(
18
+ array_reference: np.ndarray,
19
+ cmap_name: str,
20
+ limits: tuple[float, float],
21
+ ) -> np.ndarray:
22
+ ...
21
23
 
22
- def apply_colors_and_merge_nc(
23
- arrs: Sequence[np.ndarray],
24
- colors: Sequence[COLORMAPS] = (),
25
- blending: Literal[BLENDING_OPTIONS] = 'max',
26
- saturation_limits: Sequence[tuple[float, float]] = (),
27
- ) -> np.ndarray: ...
24
+ def dispatch_multi_channel(
25
+ array_references: Sequence[np.ndarray],
26
+ cmap_names: Sequence[str],
27
+ blending: Literal[BLENDING_OPTIONS],
28
+ limits: Sequence[tuple[float, float]],
29
+ ) -> np.ndarray:
30
+ ...
@@ -3,8 +3,8 @@ from typing import Sequence
3
3
  import numpy as np
4
4
 
5
5
  from mergechannels import (
6
- apply_color_map,
7
- apply_colors_and_merge_nc,
6
+ dispatch_single_channel,
7
+ dispatch_multi_channel,
8
8
  )
9
9
  from ._luts import COLORMAPS
10
10
  from ._blending import BLENDING_OPTIONS
@@ -13,6 +13,7 @@ def merge(
13
13
  arrs: Sequence[np.ndarray],
14
14
  colors: Sequence[COLORMAPS],
15
15
  blending: BLENDING_OPTIONS = 'max',
16
+ saturation_limits: tuple[float, float] = (0.011, 0.999),
16
17
  ) -> np.ndarray:
17
18
  '''
18
19
  apply cmaps to arrays and blend the colors
@@ -30,9 +31,9 @@ def merge(
30
31
  raise ValueError(
31
32
  f'Expected every array to have the same shape, got {arr_shapes}'
32
33
  )
33
- if not len(arr_shapes[0]) == 2:
34
+ if len(arr_shapes[0]) not in (2, 3):
34
35
  raise ValueError(
35
- f'Expected every array to be 2D, got {arr_shapes[0]}'
36
+ f'Expected every array to be 2D or 3D, got {arr_shapes[0]}'
36
37
  )
37
38
  arr_dtypes = [arr.dtype for arr in arrs]
38
39
  if not len(set(arr_dtypes)) == 1:
@@ -40,8 +41,25 @@ def merge(
40
41
  f'Expected every array to have the same dtype, got {arr_dtypes}'
41
42
  )
42
43
  # endregion
43
-
44
44
  if n_arrs == 1:
45
- return apply_color_map(arr=arrs[0], cmap_name=colors[0])
45
+ if arrs[0].dtype == 'uint8':
46
+ limits = (0, 255)
47
+ else:
48
+ low, high = np.percentile(arrs[0], np.array(saturation_limits) * 100)
49
+ limits = (low, high)
50
+ return dispatch_single_channel(
51
+ array_reference=arrs[0],
52
+ cmap_name=colors[0],
53
+ limits=limits,
54
+ )
46
55
  else:
47
- return apply_colors_and_merge_nc(arrs, colors, blending)
56
+ if all(arr.dtype == 'uint8' for arr in arrs):
57
+ limits = (0, 255)
58
+ else:
59
+ limits = tuple(np.percentile(arr, np.array(saturation_limits) * 100) for arr in arrs)
60
+ return dispatch_multi_channel(
61
+ array_references=arrs,
62
+ cmap_names=colors,
63
+ blending=blending,
64
+ limits=limits, # type: ignore
65
+ )
mergechannels/_luts.py CHANGED
@@ -1,81 +1,177 @@
1
1
  from typing import Literal
2
2
 
3
3
  COLORMAPS = Literal[
4
+ 'Circus Ink Purple',
5
+ 'Spectrum Parabolic Ramp',
6
+ 'Pop cherry',
7
+ 'Circus Green',
4
8
  'Rainbow RGB',
9
+ 'Parabolic RGB',
5
10
  '3color-RMB',
11
+ 'Pop magenta inverted',
6
12
  'Red Hot',
13
+ 'Duo Cyan',
7
14
  'Yellow',
15
+ 'Grays g=0.25 inverted',
8
16
  'betterRed',
17
+ 'Grays g=1.75',
9
18
  'blue_orange_icb',
19
+ 'Pop green',
10
20
  'mpl-inferno',
11
21
  'I Blue',
12
22
  'BOP purple',
23
+ 'Duo Yellow',
24
+ 'Phase Ink Mint-Cherry',
13
25
  'betterOrange',
14
26
  'Blue',
15
27
  '6_shades',
28
+ 'Ink Cyan',
16
29
  'OIMB3',
30
+ 'Quartetto MYGB Blue',
31
+ 'Ink Green',
17
32
  'Red/Green',
18
33
  'Turbo',
34
+ 'Circus Ink Black',
35
+ 'Duo Green',
19
36
  'mpl-viridis',
37
+ 'Grays g=0.25',
38
+ 'Quartetto RYGB Blue',
20
39
  'smart',
21
40
  'Thermal',
22
41
  'OIMB2',
42
+ 'Pop blue inverted',
43
+ 'Duo Intense Cherry',
44
+ 'Phase Bold Green-Magenta',
45
+ 'Quartetto MYGB Magenta',
46
+ 'Pop purple inverted',
23
47
  'glow',
24
48
  'OPF orange',
49
+ 'Pop cyan inverted',
25
50
  'physics',
51
+ 'Phase Ink Yellow-Cyan',
52
+ 'Circus Ink Mint',
53
+ 'Ink Wash Purple',
26
54
  'OIMB1',
27
55
  'betterCyan',
28
56
  'mpl-magma',
57
+ 'Duo Intense Green',
29
58
  'edges',
59
+ 'Quartetto MYGB Green',
60
+ 'Ink Wash Cherry',
30
61
  'OPF purple',
62
+ 'Ink Wash Cyan',
63
+ 'Duo Intense Purple',
31
64
  'I Yellow',
32
65
  '16_colors',
66
+ 'Circus Cyan',
67
+ 'Pop lavender inverted',
33
68
  'sepia',
69
+ 'Duo Intense Cyan',
70
+ 'Grays g=1.00 inverted',
34
71
  'ICA2',
72
+ 'Quartetto RYGB Green',
73
+ 'Ink Wash Green',
74
+ 'Pop blue',
75
+ 'Quartetto RYGB Red',
35
76
  'I Forest',
36
77
  'ICA3',
78
+ 'Circus Yellow',
79
+ 'Pop mint',
37
80
  'BOP orange',
81
+ 'Grays g=1.25 inverted',
38
82
  'I Red',
39
83
  '3color-CGY',
40
84
  'I Green',
41
85
  'Fire',
42
86
  'Magenta Hot',
87
+ 'Grays g=0.50',
43
88
  'Orange Hot',
89
+ 'Circus Ink Cherry',
90
+ 'Pop purple',
91
+ 'Ink Yellow',
44
92
  'unionjack',
93
+ 'Ink Wash Yellow',
45
94
  'I Cyan',
46
95
  'Cyan Hot',
96
+ 'Pop mint inverted',
47
97
  'I Magenta',
48
98
  'Grays',
99
+ 'Phase Green-Magenta',
49
100
  'Cyan',
101
+ 'Grays g=0.75',
102
+ 'Phase Bold Ink Mint-Cherry',
103
+ 'Grays g=1.75 inverted',
50
104
  'phase',
51
105
  'gem',
106
+ 'Pop cherry inverted',
107
+ 'Pop red',
108
+ 'Circus Cherry',
52
109
  'OPF fresh',
110
+ 'Circus Ink Cyan',
53
111
  'betterGreen',
112
+ 'Phase Ink Green-Magenta',
54
113
  '3color-BMR',
114
+ 'Ink Wash Black',
115
+ 'Pop red inverted',
116
+ 'Duo Purple',
55
117
  'betterBlue',
118
+ 'Phase Bold Ink Yellow-Cyan',
119
+ 'Quartetto RYGB Yellow',
56
120
  'Magenta',
121
+ 'Duo Mint',
57
122
  'Red',
123
+ 'Grays g=1.25',
58
124
  'I Bordeaux',
125
+ 'Grays g=1.50 inverted',
126
+ 'Green Hot',
59
127
  'glasbey',
60
128
  'glasbey_on_dark',
61
129
  'mpl-plasma',
130
+ 'Ink Cherry',
131
+ 'Ink Mint',
132
+ 'Circus Ink Yellow',
133
+ 'Pop cyan',
134
+ 'Pop green inverted',
135
+ 'Ink Purple',
62
136
  '3color-YGC',
137
+ 'Pop yellow',
138
+ 'Quartetto MYGB Yellow',
139
+ 'Duo Cherry',
63
140
  'Green',
141
+ 'Grays g=0.50 inverted',
142
+ 'Circus Ink Green',
64
143
  'ICA',
144
+ 'Phase Mint-Cherry',
145
+ 'Ink Black',
65
146
  'Yellow Hot',
147
+ 'Phase Bold Yellow-Cyan',
66
148
  'thallium',
149
+ 'Pop yellow inverted',
67
150
  'Spectrum',
68
151
  'royal',
69
152
  'glasbey_inverted',
70
153
  'betterYellow',
154
+ 'Circus Purple',
155
+ 'Grays g=2.00',
71
156
  'HiLo',
72
157
  'cool',
73
158
  'Green Fire Blue',
159
+ 'Ink Wash Mint',
160
+ 'Grays g=0.75 inverted',
74
161
  'BOP blue',
75
162
  'thal',
76
163
  'Ice',
164
+ 'Circus Mint',
165
+ 'Grays g=1.50',
166
+ 'Duo Intense Mint',
77
167
  'brgbcmyw',
168
+ 'Phase Yellow-Cyan',
78
169
  'I Purple',
170
+ 'Duo Intense Yellow',
171
+ 'Phase Bold Ink Green-Magenta',
172
+ 'Pop magenta',
79
173
  '3-3-2 RGB',
174
+ 'Grays g=2.00 inverted',
80
175
  '5_ramps',
176
+ 'Phase Bold Mint-Cherry',
81
177
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mergechannels
3
- Version: 0.1.2
3
+ Version: 0.3.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -12,7 +12,10 @@ Classifier: Programming Language :: Python :: 3.11
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Dist: numpy>1.25.0
15
+ Provides-Extra: nvim
15
16
  License-File: LICENSE
17
+ Summary: Apply and merge colormaps
18
+ Author-email: Zac Swider <zac.swider@gmail.com>
16
19
  License: MIT
17
20
  Requires-Python: >=3.9, <=3.13
18
21
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
@@ -60,8 +63,7 @@ plt.show()
60
63
  print(colorized.shape, colorized.dtype)
61
64
  >> (512, 512, 3) uint8
62
65
  ```
63
- ![colorize a single image](https://raw.githubusercontent.com/zacswider/README_Images/main/camera_red-green.png
64
- )
66
+ ![colorize a single image](https://raw.githubusercontent.com/zacswider/README_Images/main/camera_red-green.png)
65
67
 
66
68
 
67
69
  ### apply a different colormap to each channel
@@ -71,38 +73,66 @@ import matplotlib.pyplot as plt
71
73
  import mergechannels as mc
72
74
 
73
75
  cells, nuclei = data.cells3d().max(axis=0)
74
- cells = to_uint8(cells) # normalize your own arrays, mergechannels doesn't currently handle this
75
- nuclei = to_uint8(nuclei) # normalize your own arrays, mergechannels doesn't currently handle this
76
+ assert cells.dtype == 'uint16' and nuclei.dtype == 'uint16'
77
+ fig, axes = plt.subplots(1, 2, figsize=(3, 6), dpi=300)
78
+ for ax in axes.ravel(): ax.axis('off')
79
+ (a, b) = axes.ravel()
80
+ a.imshow(mc.merge([cells, nuclei],['Orange Hot', 'Cyan Hot']))
81
+ b.imshow(mc.merge([cells, nuclei],['I Blue', 'I Forest'], blending='min'))
82
+ fig.tight_layout()
83
+ plt.show()
84
+ ```
85
+ ![max and min multicolor blending](https://raw.githubusercontent.com/zacswider/README_Images/main/overlay_normal_and_inverted.png)
76
86
 
77
- fig, axes = plt.subplots(2, 2, figsize=(6, 6), dpi=150)
87
+ ### apply a colormap to a whole stack
88
+ ```python
89
+ from skimage import data
90
+ from matplotlib import pyplot as plt
91
+ import mergechannels as mc
92
+
93
+ volume = data.cells3d()
94
+ cells = volume[:, 0]
95
+ nuclei = volume[:, 1]
96
+ merged = mc.merge([cells, nuclei],['Orange Hot', 'Cyan Hot'])
97
+ plt.imshow(merged[24]); plt.show()
98
+ ```
99
+ ![colorize a whole stack of images](https://raw.githubusercontent.com/zacswider/README_Images/main/merged_stacks.png)
100
+
101
+ ### adjust the saturation limits when applying colormaps
102
+ ``` python
103
+ from skimage import data
104
+ import matplotlib.pyplot as plt
105
+ import mergechannels as mc
106
+
107
+ cells, nuclei = data.cells3d().max(axis=0)
108
+ channels = [cells, nuclei]
109
+ colormaps = ['I Blue', 'I Forest']
110
+ fig, axes = plt.subplots(1, 2, figsize=(3, 6), dpi=300)
78
111
  for ax in axes.ravel(): ax.axis('off')
79
- (a, b, c, d) = axes.ravel()
80
- a.imshow(cells, cmap='gray')
81
- b.imshow(nuclei, cmap='gray')
82
- c.imshow(
83
- mc.merge(
84
- [cells, nuclei],
85
- ['Orange Hot', 'Cyan Hot'], # maximum blending is the default
86
- ),
87
- )
88
- d.imshow(
112
+ (a, b) = axes.ravel()
113
+ a.imshow(mc.merge(channels, colormaps, blending='min'))
114
+ b.imshow(
89
115
  mc.merge(
90
- [cells, nuclei],
91
- ['I Blue', 'I Forest'],
92
- blending='min', # use minimum blending with inverted colormaps
116
+ channels,
117
+ colormaps,
118
+ blending='min',
119
+ saturation_limits=(
120
+ 0.01, # bottom 1% of pixels set to black point
121
+ 0.97, # top 3% of pixels set to white point
122
+ ),
93
123
  ),
94
124
  )
95
125
  fig.tight_layout()
96
126
  plt.show()
97
127
  ```
98
- ![max and min multicolor blending](https://raw.githubusercontent.com/zacswider/README_Images/main/cells_multicolor.png)
128
+ ![adjust saturation limits](https://raw.githubusercontent.com/zacswider/README_Images/main/adjust_sat_lims.png)
99
129
 
100
130
 
101
131
  ## Roadmap
102
- mergechannels is currently incredibly simple. It can apply one or more colormaps to one or more 2D 8-bit images and that's it.
132
+ mergechannels is currently incredibly simple. It can apply one or more colormaps to one or more 2D and 3D 8-bit or 16-bit images and that's it.
103
133
  - Add support for any numerical dtype
104
- - Add support for 3D images
105
134
  - Add option to return any colormap as a matplotlib colormap
135
+ - Add option to pass external colormaps to mergechannels
106
136
  - Add support for directly passing matplotlib colormaps instead of colormap names
107
137
  - Parallelize colormap application on large images (if it's helpful)
108
138
  - Add option to overlay binary or instance masks onto colorized images
@@ -0,0 +1,12 @@
1
+ mergechannels-0.3.0.dist-info/METADATA,sha256=5KI3P3u9O0prtayGxavf_PooNdXYHHnyLp_fjrgW1Pw,5725
2
+ mergechannels-0.3.0.dist-info/WHEEL,sha256=q7wQuuLF3Wf37kPvdOw6GyhvyvSy97yv-4o7K0-XKZc,106
3
+ mergechannels-0.3.0.dist-info/licenses/LICENSE,sha256=csvD60rgtSorbYEM3f8867qNyPCzmIXyFNj8h01Bd6c,1071
4
+ mergechannels.libs/libgcc_s-e52197c3.so.1,sha256=vkPW1Auw6CH9Bjk7frmX3hry_1H9c0tRI0Ncyg71WUI,724137
5
+ mergechannels/__init__.py,sha256=TTNiDGOOJ6_-yR-qvX_nXph646Sz6-MEORc8ItksCRE,232
6
+ mergechannels/__init__.pyi,sha256=tiDx6v14J0cedFdk6fzVRRyA21b4Z8eB_rtSTUjI804,749
7
+ mergechannels/_blending.py,sha256=mE5Cr9wvVJRcwfymg_UUZUjdIKx2mldfLU8QJT95bVM,84
8
+ mergechannels/_internal.py,sha256=ZcdBUFEq8k2Ve_ASOZLTuPBaFEEPqadc9LqAGmBqOas,1773
9
+ mergechannels/_luts.py,sha256=RswhkrCGAFtDthmVHt-Kk7lxROwS-kdsQy1EboyUUc8,3009
10
+ mergechannels/mergechannels.cpython-39-aarch64-linux-gnu.so,sha256=RE0NnmgLsYC5mJ6VoGYiPkOtE1QMDyHAthBrrlegg8M,1116993
11
+ mergechannels/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ mergechannels-0.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.8.3)
2
+ Generator: maturin (1.8.6)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp39-cp39-musllinux_1_2_aarch64
@@ -1,12 +0,0 @@
1
- mergechannels-0.1.2.dist-info/METADATA,sha256=fdx3XuAlrCeScx655leoDJJEMtrZQ2-K2tX--JalIAI,4676
2
- mergechannels-0.1.2.dist-info/WHEEL,sha256=fSQ1RLO65S2ujgMQXIb-QvyD1St9n5vbyy6LJmLKNTk,106
3
- mergechannels-0.1.2.dist-info/licenses/LICENSE,sha256=csvD60rgtSorbYEM3f8867qNyPCzmIXyFNj8h01Bd6c,1071
4
- mergechannels.libs/libgcc_s-e52197c3.so.1,sha256=vkPW1Auw6CH9Bjk7frmX3hry_1H9c0tRI0Ncyg71WUI,724137
5
- mergechannels/_luts.py,sha256=DxwCMBnAAJc1ZX-D4cq8HabW-sLuBQpUqOWMWXqt_84,1035
6
- mergechannels/_internal.py,sha256=Abzeacre5CQOcWn9WDIVuxFdEjTLIudEWQn8EsiH3oE,1243
7
- mergechannels/__init__.pyi,sha256=lSMX8eip_zkzoJPJKvxvAhOsewwagoAhS9H5gXJ2Da8,711
8
- mergechannels/__init__.py,sha256=jy8Qd3TOQ0mm-K64snjOqjdDQiSJ3gWjOjGZrliYy6k,222
9
- mergechannels/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- mergechannels/_blending.py,sha256=mE5Cr9wvVJRcwfymg_UUZUjdIKx2mldfLU8QJT95bVM,84
11
- mergechannels/mergechannels.cpython-39-aarch64-linux-gnu.so,sha256=MYGbZhRZ0iCJf8FM9wceddReuHZUT8m-EmoKxQjjppo,920313
12
- mergechannels-0.1.2.dist-info/RECORD,,