colormap-complex 0.1.2__tar.gz → 0.2.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 (22) hide show
  1. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/PKG-INFO +3 -3
  2. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/README.md +1 -1
  3. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/pyproject.toml +9 -3
  4. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex/__init__.py +1 -1
  5. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex/_main.py +47 -16
  6. colormap_complex-0.2.0/src/colormap_complex/data/bremm.npy +0 -0
  7. colormap_complex-0.2.0/src/colormap_complex/data/cubediagonal.npy +0 -0
  8. colormap_complex-0.2.0/src/colormap_complex/data/schumann.npy +0 -0
  9. colormap_complex-0.2.0/src/colormap_complex/data/steiger.npy +0 -0
  10. colormap_complex-0.2.0/src/colormap_complex/data/teulingfig2.npy +0 -0
  11. colormap_complex-0.2.0/src/colormap_complex/data/ziegler.npy +0 -0
  12. colormap_complex-0.2.0/src/colormap_complex/matplotlib.py +69 -0
  13. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex.egg-info/PKG-INFO +3 -3
  14. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex.egg-info/SOURCES.txt +7 -0
  15. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/tests/test_main.py +9 -17
  16. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/LICENSE +0 -0
  17. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/setup.cfg +0 -0
  18. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/setup.py +0 -0
  19. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex/py.typed +0 -0
  20. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex.egg-info/dependency_links.txt +0 -0
  21. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex.egg-info/requires.txt +0 -0
  22. {colormap_complex-0.1.2 → colormap_complex-0.2.0}/src/colormap_complex.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: colormap-complex
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Complex / 2d colormap / Domain coloring for matplotlib etc.
5
5
  Author-email: 34j <34j.95a2p@simplelogin.com>
6
6
  License: Apache-2.0
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
20
  Classifier: Topic :: Software Development :: Libraries
21
- Requires-Python: >=3.9
21
+ Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: colour-science>=0.4.4
@@ -84,7 +84,7 @@ import numpy as np
84
84
  lin = np.linspace(-1, 1, 100)
85
85
  x, y = np.meshgrid(lin, lin)
86
86
  z = x + 1j * y
87
- c = colormap(type="oklab", scale=True)(z.real, z.imag)
87
+ c = colormap(type="oklab")(z.real, z.imag, scale=True)
88
88
  plt.imshow(c, extent=(-1, 1, -1, 1), origin='lower')
89
89
  ```
90
90
 
@@ -57,7 +57,7 @@ import numpy as np
57
57
  lin = np.linspace(-1, 1, 100)
58
58
  x, y = np.meshgrid(lin, lin)
59
59
  z = x + 1j * y
60
- c = colormap(type="oklab", scale=True)(z.real, z.imag)
60
+ c = colormap(type="oklab")(z.real, z.imag, scale=True)
61
61
  plt.imshow(c, extent=(-1, 1, -1, 1), origin='lower')
62
62
  ```
63
63
 
@@ -4,14 +4,14 @@ requires = [ "setuptools" ]
4
4
 
5
5
  [project]
6
6
  name = "colormap-complex"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "Complex / 2d colormap / Domain coloring for matplotlib etc."
9
9
  readme = "README.md"
10
10
  license = { text = "Apache-2.0" }
11
11
  authors = [
12
12
  { name = "34j", email = "34j.95a2p@simplelogin.com" },
13
13
  ]
14
- requires-python = ">=3.9"
14
+ requires-python = ">=3.10"
15
15
  classifiers = [
16
16
  "Development Status :: 2 - Pre-Alpha",
17
17
  "Intended Audience :: Developers",
@@ -38,7 +38,7 @@ urls.repository = "https://github.com/34j/colormap-complex"
38
38
  dev = [
39
39
  "pytest>=8,<9",
40
40
  "pytest-cov>=6,<7",
41
- "matplotlib>=3.9.4",
41
+ "matplotlib>=3.10.1",
42
42
  "scipy>=1.13.1",
43
43
  "python-slugify>=8.0.4",
44
44
  ]
@@ -49,6 +49,12 @@ docs = [
49
49
  "sphinx-autobuild>=2024,<2025; python_version>='3.11'",
50
50
  ]
51
51
 
52
+ [tool.setuptools.packages.find]
53
+ where = ["src"]
54
+
55
+ [tool.setuptools.package-data]
56
+ colormap_complex = ["**/*.npy"]
57
+
52
58
  [tool.ruff]
53
59
  line-length = 100
54
60
  lint.select = [
@@ -1,4 +1,4 @@
1
- __version__ = "0.1.2"
1
+ __version__ = "0.2.0"
2
2
 
3
3
  from ._main import ALL_COLORMAPS, ColormapType, colormap, interpnd
4
4
 
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import Any, Callable, Literal, TypeVar
2
+ from typing import Any, Literal, Protocol, TypeVar
3
3
 
4
4
  import colour
5
5
  import numpy as np
@@ -70,6 +70,42 @@ def interpnd(base: NDArray[TBase], *indices: NDArray[np.number]) -> NDArray[TBas
70
70
  return base[indices_0] * (1 - indices_p) + base[indices_1] * indices_p
71
71
 
72
72
 
73
+ class Colormap(Protocol):
74
+ """Colormap protocol."""
75
+
76
+ __name__: str
77
+
78
+ def __call__(
79
+ self,
80
+ x: NDArray[np.number],
81
+ y: NDArray[np.number],
82
+ /,
83
+ *,
84
+ scale: bool = False,
85
+ ) -> NDArray[np.number]:
86
+ """
87
+ Colormap function.
88
+
89
+ Parameters
90
+ ----------
91
+ x : NDArray[np.number]
92
+ Array of shape (...,)
93
+ y : NDArray[np.number]
94
+ Array of shape (...,)
95
+ scale : bool
96
+ Whether to scale the input to the range [0, 1].
97
+
98
+ Returns
99
+ -------
100
+ NDArray[np.number]
101
+ Colormap of shape (..., 3).
102
+ The colormap is in the range [0, 1].
103
+ If colormap is cyclic, x axis corresponds to the cyclic
104
+ dimension.
105
+
106
+ """
107
+
108
+
73
109
  def colormap(
74
110
  *,
75
111
  type: Literal[
@@ -87,36 +123,26 @@ def colormap(
87
123
  "ziegler",
88
124
  ] = "bremm",
89
125
  cut_outbound: bool = True,
90
- scale: bool = True,
91
126
  clip: bool = True,
92
- ) -> Callable[[NDArray[np.number], NDArray[np.number]], NDArray[np.number]]:
127
+ ) -> Colormap:
93
128
  """
94
129
  2D colormap function.
95
130
 
96
131
  Parameters
97
132
  ----------
98
- x : NDArray[np.number]
99
- Array of shape (...,)
100
- y : NDArray[np.number]
101
- Array of shape (...,)
102
133
  type : Literal['oklab', 'oklch', 'prolab', 'prolch', 'hsv', 'ycbcr',
103
134
  'bremm', 'cubediagonal', 'schumann', 'steiger', 'teulingfig2', 'ziegler']
104
135
  Type of colormap.
105
136
  cut_outbound : bool
106
137
  If using CIE XYZ, cut colors that are out of bounds
107
138
  for the sRGB color space.
108
- scale : bool
109
- Whether to scale the input to the range [0, 1].
110
139
  clip : bool
111
140
  Whether to clip the output to the range [0, 1].
112
141
 
113
142
  Returns
114
143
  -------
115
- NDArray[np.number]
116
- Colormap of shape (..., 3).
117
- The colormap is in the range [0, 1].
118
- If colormap is cyclic, x axis corresponds to the cyclic
119
- dimension.
144
+ Colrmap
145
+ Colormap function.
120
146
 
121
147
  """
122
148
  if type not in ALL_COLORMAPS:
@@ -124,10 +150,13 @@ def colormap(
124
150
  if type in _CACHED_COLORMAPS:
125
151
  file = Path(__file__).parent / "data" / f"{type}.npy"
126
152
  if not file.exists():
127
- raise ValueError(f"Unknown colormap: {type}")
153
+ raise FileNotFoundError("Colormap file not found.")
128
154
  colormap = np.load(file) / 255
155
+ # 512 x 512 x 3
129
156
 
130
- def inner(x: NDArray[np.number], y: NDArray[np.number]) -> NDArray[np.number]:
157
+ def inner(
158
+ x: NDArray[np.number], y: NDArray[np.number], /, *, scale: bool = False
159
+ ) -> NDArray[np.number]:
131
160
  if scale:
132
161
  xmin = np.min(x)
133
162
  xmax = np.max(x)
@@ -194,4 +223,6 @@ def colormap(
194
223
  srgb = np.clip(srgb, 0, 1)
195
224
  return srgb
196
225
 
226
+ inner.__name__ = type
227
+ inner.__doc__ = f"Colormap function of type {type}."
197
228
  return inner
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ import numpy as np
6
+ from matplotlib.colors import BivarColormapFromImage, ListedColormap
7
+
8
+ from ._main import Colormap
9
+
10
+
11
+ def get_mpl_colormap(colormap: Colormap, /, N: int = 128, M: int = 128) -> BivarColormapFromImage:
12
+ """
13
+ Get a matplotlib colormap from a function.
14
+
15
+ Parameters
16
+ ----------
17
+ colormap : Colormap
18
+ The colormap function to use.
19
+ N : int
20
+ The number of colors in the x axis.
21
+ M : int
22
+ The number of colors in the y axis.
23
+
24
+ Returns
25
+ -------
26
+ BivarColormapFromImage
27
+ Matplotlib colormap.
28
+
29
+ """
30
+ return BivarColormapFromImage(
31
+ colormap(np.linspace(0, 1, N)[:, None], np.linspace(0, 1, M)[None, :]),
32
+ name=colormap.__name__,
33
+ )
34
+
35
+
36
+ def get_mpl_1d_colormap(
37
+ colormap: Colormap,
38
+ v: float,
39
+ /,
40
+ axis: Literal[0, 1] = 0,
41
+ N: int = 128,
42
+ ) -> ListedColormap:
43
+ """
44
+ Get a matplotlib colormap from a function.
45
+
46
+ Parameters
47
+ ----------
48
+ colormap : Callable[[NDArray[np.number]], NDArray[np.number]]
49
+ The colormap function to use.
50
+ v : float
51
+ The value to use for the colormap.
52
+ axis : Literal[0, 1]
53
+ The axis to take the colormap from.
54
+ N : int
55
+ The number of colors in the colormap.
56
+
57
+ Returns
58
+ -------
59
+ BivarColormapFromImage
60
+ Matplotlib colormap.
61
+
62
+ """
63
+ if axis == 0:
64
+ x = np.linspace(0, 1, N)
65
+ y = np.full_like(x, v)
66
+ else:
67
+ y = np.linspace(0, 1, N)
68
+ x = np.full_like(y, v)
69
+ return ListedColormap(colormap(x, y), name=colormap.__name__)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: colormap-complex
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Complex / 2d colormap / Domain coloring for matplotlib etc.
5
5
  Author-email: 34j <34j.95a2p@simplelogin.com>
6
6
  License: Apache-2.0
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
20
  Classifier: Topic :: Software Development :: Libraries
21
- Requires-Python: >=3.9
21
+ Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: colour-science>=0.4.4
@@ -84,7 +84,7 @@ import numpy as np
84
84
  lin = np.linspace(-1, 1, 100)
85
85
  x, y = np.meshgrid(lin, lin)
86
86
  z = x + 1j * y
87
- c = colormap(type="oklab", scale=True)(z.real, z.imag)
87
+ c = colormap(type="oklab")(z.real, z.imag, scale=True)
88
88
  plt.imshow(c, extent=(-1, 1, -1, 1), origin='lower')
89
89
  ```
90
90
 
@@ -4,10 +4,17 @@ pyproject.toml
4
4
  setup.py
5
5
  src/colormap_complex/__init__.py
6
6
  src/colormap_complex/_main.py
7
+ src/colormap_complex/matplotlib.py
7
8
  src/colormap_complex/py.typed
8
9
  src/colormap_complex.egg-info/PKG-INFO
9
10
  src/colormap_complex.egg-info/SOURCES.txt
10
11
  src/colormap_complex.egg-info/dependency_links.txt
11
12
  src/colormap_complex.egg-info/requires.txt
12
13
  src/colormap_complex.egg-info/top_level.txt
14
+ src/colormap_complex/data/bremm.npy
15
+ src/colormap_complex/data/cubediagonal.npy
16
+ src/colormap_complex/data/schumann.npy
17
+ src/colormap_complex/data/steiger.npy
18
+ src/colormap_complex/data/teulingfig2.npy
19
+ src/colormap_complex/data/ziegler.npy
13
20
  tests/test_main.py
@@ -1,12 +1,13 @@
1
+ from collections.abc import Callable
1
2
  from os import environ
2
3
  from pathlib import Path
3
- from typing import Any, Callable
4
+ from typing import Any
4
5
 
5
6
  import matplotlib.pyplot as plt
6
7
  import numpy as np
7
8
  import pytest
8
9
  from matplotlib.cm import ScalarMappable
9
- from matplotlib.colors import ListedColormap, Normalize
10
+ from matplotlib.colors import Normalize
10
11
  from scipy.special import (
11
12
  airy,
12
13
  digamma,
@@ -23,6 +24,7 @@ from scipy.special import (
23
24
  from slugify import slugify
24
25
 
25
26
  from colormap_complex import ALL_COLORMAPS, ColormapType, colormap
27
+ from colormap_complex.matplotlib import get_mpl_1d_colormap
26
28
 
27
29
  CI = environ.get("CI", "false").lower() == "true"
28
30
  CACHE_PATH = Path(__file__).parent / ".cache"
@@ -117,17 +119,12 @@ def test_complex_function(
117
119
  angle = np.angle(z)
118
120
  if magnitude_growth:
119
121
  r = np.fmod(np.log(r), 1)
120
- c = colormap(type="oklch")(
121
- angle / (2 * np.pi),
122
- r,
123
- )
122
+ cmap = colormap(type="oklch")
123
+ c = cmap(angle / (2 * np.pi), r, scale=True)
124
124
  ax[2].set_title("f(z) (oklch)")
125
125
  cba = fig.colorbar(
126
126
  ScalarMappable(
127
- norm=Normalize(angle.min(), angle.max()),
128
- cmap=ListedColormap(
129
- colormap(type="oklch", scale=False)(np.linspace(0, 1, 256), np.array(0.5))
130
- ),
127
+ norm=Normalize(angle.min(), angle.max()), cmap=get_mpl_1d_colormap(cmap, 0.5)
131
128
  ),
132
129
  ax=ax[2],
133
130
  )
@@ -136,12 +133,7 @@ def test_complex_function(
136
133
  cbr = fig.colorbar(
137
134
  ScalarMappable(
138
135
  norm=Normalize(0, 1) if magnitude_growth else Normalize(np.min(r), np.max(r)),
139
- cmap=ListedColormap(
140
- colormap(type="oklch", scale=False)(
141
- np.array(0.5),
142
- np.linspace(0, 1, 256),
143
- )
144
- ),
136
+ cmap=get_mpl_1d_colormap(cmap, 0.5, axis=1),
145
137
  ),
146
138
  ax=ax[2],
147
139
  )
@@ -149,7 +141,7 @@ def test_complex_function(
149
141
  cbr.set_ticks([0, 0.5, 1])
150
142
  cbr.set_ticklabels([r"$1$", r"$e^{\frac{1}{2}}$", r"$e$"])
151
143
  else:
152
- c = colormap(type="oklab")(z.real, z.imag)
144
+ c = colormap(type="oklab")(z.real, z.imag, scale=True)
153
145
  ax[2].set_title("f(z) (oklab)")
154
146
  ax[2].imshow(c, extent=(-1, 1, -1, 1), origin="lower")
155
147
  for ax_ in ax: