DiaModality 0.2.6__tar.gz → 0.2.8__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.
@@ -1,29 +1,9 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: DiaModality
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Summary: Tool to plot modality vector diagrams
5
5
  Author-email: konung-yaropolk <yaropolk1995@gmail.com>
6
- License: MIT License
7
-
8
- Copyright (c) 2024 konung-yaropolk
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
6
+ License-Expression: MIT
27
7
  Project-URL: Homepage, https://github.com/konung-yaropolk/DiaModality
28
8
  Project-URL: Repository, https://github.com/konung-yaropolk/DiaModality.git
29
9
  Project-URL: Issues, https://github.com/konung-yaropolk/DiaModality/issues
@@ -31,7 +11,6 @@ Keywords: Visualization,Science,Plotting,Matplotlib
31
11
  Classifier: Programming Language :: Python
32
12
  Classifier: Programming Language :: Python :: 3
33
13
  Classifier: Programming Language :: Python :: 3.12
34
- Classifier: License :: OSI Approved :: MIT License
35
14
  Classifier: Operating System :: OS Independent
36
15
  Classifier: Development Status :: 4 - Beta
37
16
  Classifier: Intended Audience :: Science/Research
@@ -43,11 +22,13 @@ License-File: LICENSE
43
22
  Requires-Dist: numpy
44
23
  Requires-Dist: matplotlib
45
24
  Requires-Dist: scsv>=0.1.4
25
+ Dynamic: license-file
46
26
 
47
27
  # DiaModality - The Modality Diagram
48
28
 
49
29
  Simple tool to plot vector modality diagram
50
30
 
31
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/konung-yaropolk/DiaModality/tests.yml?label=Tests&color=green)
51
32
  [![pypi_version](https://img.shields.io/pypi/v/diamodality?label=PyPI&color=green)](https://pypi.org/project/diamodality)
52
33
  [![GitHub Release](https://img.shields.io/github/v/release/konung-yaropolk/DiaModality?label=GitHub&color=green&link=https%3A%2F%2Fgithub.com%2Fkonung-yaropolk%2FDiaModality)](https://github.com/konung-yaropolk/DiaModality)
53
34
  [![PyPI - License](https://img.shields.io/pypi/l/diamodality)](https://pypi.org/project/diamodality)
@@ -2,6 +2,7 @@
2
2
 
3
3
  Simple tool to plot vector modality diagram
4
4
 
5
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/konung-yaropolk/DiaModality/tests.yml?label=Tests&color=green)
5
6
  [![pypi_version](https://img.shields.io/pypi/v/diamodality?label=PyPI&color=green)](https://pypi.org/project/diamodality)
6
7
  [![GitHub Release](https://img.shields.io/github/v/release/konung-yaropolk/DiaModality?label=GitHub&color=green&link=https%3A%2F%2Fgithub.com%2Fkonung-yaropolk%2FDiaModality)](https://github.com/konung-yaropolk/DiaModality)
7
8
  [![PyPI - License](https://img.shields.io/pypi/l/diamodality)](https://pypi.org/project/diamodality)
@@ -5,7 +5,8 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "DiaModality"
7
7
  dynamic = ["version", "dependencies"]
8
- license = {file = "LICENSE"}
8
+ license = "MIT"
9
+ # license = {file = "LICENSE"}
9
10
  authors = [
10
11
  { name="konung-yaropolk", email="yaropolk1995@gmail.com" },
11
12
  ]
@@ -17,7 +18,7 @@ classifiers = [
17
18
  "Programming Language :: Python",
18
19
  "Programming Language :: Python :: 3",
19
20
  "Programming Language :: Python :: 3.12",
20
- "License :: OSI Approved :: MIT License",
21
+ # "License :: OSI Approved :: MIT License",
21
22
  "Operating System :: OS Independent",
22
23
  "Development Status :: 4 - Beta",
23
24
  "Intended Audience :: Science/Research",
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env python
2
+ import os
3
+ import pathlib
4
+ import numpy as np
2
5
  import matplotlib.pyplot as plt
3
6
  # import matplotlib.colors as mcolors
4
7
  import matplotlib.gridspec as gridspec
5
- import numpy as np
6
8
 
7
9
  # Only use for plot layout adjustment
8
10
  DEBUG = False
9
11
 
10
12
 
11
- class __Figure():
13
+ class _Figure():
12
14
  '''
13
15
  Super class of all future plots
14
16
  '''
@@ -44,22 +46,24 @@ class __Figure():
44
46
  plt.suptitle(self.title)
45
47
 
46
48
 
47
- class __Output():
49
+ class _Output():
48
50
  '''
49
51
  Output options mixin
50
52
  '''
51
53
 
52
54
  def show(self):
53
- plt.show()
55
+ self.fig.show()
54
56
 
55
- def save(self,
56
- filename,
57
- type='png',
58
- transparent=False):
59
- plt.savefig('{}.{}'.format(filename, type), transparent=transparent)
57
+ def save(self, filename: str, file_type: str = 'png', transparent: bool = False) -> None:
58
+ p = pathlib.Path(filename)
59
+ if p.suffix.lower() == f'.{file_type.lower()}':
60
+ out_path = p
61
+ else:
62
+ out_path = p.with_suffix(f'.{file_type}')
63
+ self.fig.savefig(out_path, transparent=transparent)
60
64
 
61
65
 
62
- class ModalityPlot(__Figure, __Output):
66
+ class ModalityPlot(_Figure, _Output):
63
67
  '''
64
68
  Input fotmat:
65
69
 
@@ -157,10 +161,11 @@ class ModalityPlot(__Figure, __Output):
157
161
  Each row containing at least one value that will be represented as a point.
158
162
  '''
159
163
 
160
- output_data = np.array(input_data, dtype=object)
164
+ data = np.array(input_data, dtype=object)
161
165
  # Replace empty cells with zeros
162
- output_data[output_data is None] = 0
163
- output_data = output_data.astype(np.float32)
166
+ output_data = np.nan_to_num(
167
+ np.array(data, dtype=np.float64),
168
+ nan=0.0)
164
169
 
165
170
  # Replace zeros with False and other numbers with True
166
171
  output_bin = np.array(input_bin, dtype=np.bool_)
@@ -187,32 +192,27 @@ class ModalityPlot(__Figure, __Output):
187
192
  # log_input = np.log1p(input)
188
193
  # func = lambda x: (x - np.min(log_input)) / (np.max(log_input) - np.min(log_input))
189
194
 
190
- return [func(x) for x in input]
191
-
192
- def __vector_addition(self, data, binarization) -> list:
195
+ case _:
196
+ raise ValueError(
197
+ f"Unknown normalization_func {self.normalization_func!r}. "
198
+ "Expected 'linear' or 'sigmoid'."
199
+ )
193
200
 
194
- resultants = np.array((), dtype=np.float32)
201
+ return [func(x) for x in input]
195
202
 
203
+ def __vector_addition(self, data, binarization) -> np.ndarray:
204
+ resultants = []
196
205
  for points, bins in zip(data, binarization):
197
-
198
- # ignore empty lines
199
- if not all(x == 0 for x in points):
200
-
201
- # Calculate resultant vector
202
- resultants = np.append(
203
- resultants,
204
- np.sum(
205
- [points[i] * np.exp(1j * self.angles[i])
206
- if bins[i] or self.whole_sum
207
- else 0
208
- for i in range(len(points))
209
- ]
210
- )
206
+ if np.any(points != 0):
207
+ r = sum(
208
+ points[i] * np.exp(1j * self.angles[i])
209
+ if bins[i] or self.whole_sum else 0
210
+ for i in range(3)
211
211
  )
212
+ resultants.append(r)
212
213
  else:
213
- resultants = np.append(resultants, (0))
214
-
215
- return resultants
214
+ resultants.append(0)
215
+ return np.array(resultants, dtype=complex)
216
216
 
217
217
  def __find_match_modality(self, sample, list) -> int:
218
218
  for i, item in enumerate(list):
@@ -339,9 +339,9 @@ class ModalityPlot(__Figure, __Output):
339
339
  if self.debug_flag:
340
340
  self.__debug_grid(self.fig, 20, 20)
341
341
 
342
- plt.subplots_adjust(wspace=0.0, hspace=0.0)
343
- plt.tight_layout()
344
- plt.suptitle(self.title)
342
+ self.fig.subplots_adjust(wspace=0.0, hspace=0.0)
343
+ self.fig.tight_layout()
344
+ self.fig.suptitle(self.title)
345
345
 
346
346
 
347
347
  if __name__ == '__main__':
@@ -0,0 +1 @@
1
+ __version__ = "0.2.8"
@@ -1,29 +1,9 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: DiaModality
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Summary: Tool to plot modality vector diagrams
5
5
  Author-email: konung-yaropolk <yaropolk1995@gmail.com>
6
- License: MIT License
7
-
8
- Copyright (c) 2024 konung-yaropolk
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
6
+ License-Expression: MIT
27
7
  Project-URL: Homepage, https://github.com/konung-yaropolk/DiaModality
28
8
  Project-URL: Repository, https://github.com/konung-yaropolk/DiaModality.git
29
9
  Project-URL: Issues, https://github.com/konung-yaropolk/DiaModality/issues
@@ -31,7 +11,6 @@ Keywords: Visualization,Science,Plotting,Matplotlib
31
11
  Classifier: Programming Language :: Python
32
12
  Classifier: Programming Language :: Python :: 3
33
13
  Classifier: Programming Language :: Python :: 3.12
34
- Classifier: License :: OSI Approved :: MIT License
35
14
  Classifier: Operating System :: OS Independent
36
15
  Classifier: Development Status :: 4 - Beta
37
16
  Classifier: Intended Audience :: Science/Research
@@ -43,11 +22,13 @@ License-File: LICENSE
43
22
  Requires-Dist: numpy
44
23
  Requires-Dist: matplotlib
45
24
  Requires-Dist: scsv>=0.1.4
25
+ Dynamic: license-file
46
26
 
47
27
  # DiaModality - The Modality Diagram
48
28
 
49
29
  Simple tool to plot vector modality diagram
50
30
 
31
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/konung-yaropolk/DiaModality/tests.yml?label=Tests&color=green)
51
32
  [![pypi_version](https://img.shields.io/pypi/v/diamodality?label=PyPI&color=green)](https://pypi.org/project/diamodality)
52
33
  [![GitHub Release](https://img.shields.io/github/v/release/konung-yaropolk/DiaModality?label=GitHub&color=green&link=https%3A%2F%2Fgithub.com%2Fkonung-yaropolk%2FDiaModality)](https://github.com/konung-yaropolk/DiaModality)
53
34
  [![PyPI - License](https://img.shields.io/pypi/l/diamodality)](https://pypi.org/project/diamodality)
@@ -11,4 +11,5 @@ src/DiaModality.egg-info/PKG-INFO
11
11
  src/DiaModality.egg-info/SOURCES.txt
12
12
  src/DiaModality.egg-info/dependency_links.txt
13
13
  src/DiaModality.egg-info/requires.txt
14
- src/DiaModality.egg-info/top_level.txt
14
+ src/DiaModality.egg-info/top_level.txt
15
+ tests/test_diamodality.py
@@ -0,0 +1,286 @@
1
+ """
2
+ Test suite for DiaModality.ModalityPlot
3
+ Run with: pytest test_diamodality.py -v
4
+ """
5
+
6
+ import pytest
7
+ import numpy as np
8
+ import matplotlib
9
+ matplotlib.use('Agg') # Non-interactive backend — essential for CI / headless runs
10
+
11
+ import sys
12
+ import os
13
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
14
+
15
+ import DiaModality.ModalityPlot as mp
16
+
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Fixtures
20
+ # ---------------------------------------------------------------------------
21
+
22
+ @pytest.fixture
23
+ def simple_data():
24
+ """Minimal valid 3-column dataset."""
25
+ return [
26
+ [1.0, 0.0, 0.0],
27
+ [0.0, 2.0, 0.0],
28
+ [0.0, 0.0, 3.0],
29
+ [1.5, 1.5, 0.0],
30
+ [1.0, 1.0, 1.0],
31
+ ]
32
+
33
+ @pytest.fixture
34
+ def simple_bin():
35
+ """Corresponding binarization."""
36
+ return [
37
+ [1, 0, 0],
38
+ [0, 1, 0],
39
+ [0, 0, 1],
40
+ [1, 1, 0],
41
+ [1, 1, 1],
42
+ ]
43
+
44
+ @pytest.fixture
45
+ def plot(simple_data, simple_bin):
46
+ """A freshly constructed ModalityPlot (closes its figure on teardown)."""
47
+ import matplotlib.pyplot as plt
48
+ p = mp.ModalityPlot(simple_data, simple_bin)
49
+ yield p
50
+ plt.close('all')
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # 1. Construction & basic smoke tests
55
+ # ---------------------------------------------------------------------------
56
+
57
+ class TestConstruction:
58
+
59
+ def test_basic_construction(self, simple_data, simple_bin):
60
+ """Should not raise with valid minimal input."""
61
+ import matplotlib.pyplot as plt
62
+ p = mp.ModalityPlot(simple_data, simple_bin)
63
+ plt.close('all')
64
+
65
+ def test_numpy_input_accepted(self, simple_bin):
66
+ """numpy arrays should be accepted as input."""
67
+ import matplotlib.pyplot as plt
68
+ data = np.array([[1.0, 0.5, 0.0], [0.0, 1.0, 2.0]])
69
+ binarization = np.array([[1, 0, 0], [0, 1, 1]])
70
+ p = mp.ModalityPlot(data, binarization)
71
+ plt.close('all')
72
+
73
+ def test_custom_angles(self, simple_data, simple_bin):
74
+ import matplotlib.pyplot as plt
75
+ p = mp.ModalityPlot(simple_data, simple_bin, angles=[0, 120, 240])
76
+ plt.close('all')
77
+
78
+ def test_custom_modality_names(self, simple_data, simple_bin):
79
+ import matplotlib.pyplot as plt
80
+ p = mp.ModalityPlot(simple_data, simple_bin,
81
+ modalities=('Alpha', 'Beta', 'Gamma'))
82
+ plt.close('all')
83
+
84
+ def test_normalization_linear(self, simple_data, simple_bin):
85
+ import matplotlib.pyplot as plt
86
+ p = mp.ModalityPlot(simple_data, simple_bin,
87
+ normalization_func='linear')
88
+ plt.close('all')
89
+
90
+ def test_normalization_sigmoid(self, simple_data, simple_bin):
91
+ import matplotlib.pyplot as plt
92
+ p = mp.ModalityPlot(simple_data, simple_bin,
93
+ normalization_func='sigmoid')
94
+ plt.close('all')
95
+
96
+
97
+ # ---------------------------------------------------------------------------
98
+ # 2. Input validation / assertions
99
+ # ---------------------------------------------------------------------------
100
+
101
+ class TestInputValidation:
102
+
103
+ def test_mismatched_lengths_raises(self):
104
+ import matplotlib.pyplot as plt
105
+ data = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
106
+ binarization = [[1, 0, 0]] # one row short
107
+ with pytest.raises((AssertionError, ValueError)):
108
+ mp.ModalityPlot(data, binarization)
109
+ plt.close('all')
110
+
111
+ def test_wrong_column_count_raises(self):
112
+ """Only 2 columns instead of 3 should fail."""
113
+ import matplotlib.pyplot as plt
114
+ data = [[1.0, 2.0], [3.0, 4.0]]
115
+ binarization = [[1, 0], [0, 1]]
116
+ with pytest.raises((AssertionError, ValueError, IndexError)):
117
+ mp.ModalityPlot(data, binarization)
118
+ plt.close('all')
119
+
120
+ def test_empty_data_raises(self):
121
+ import matplotlib.pyplot as plt
122
+ with pytest.raises((AssertionError, ValueError)):
123
+ mp.ModalityPlot([], [])
124
+ plt.close('all')
125
+
126
+ def test_none_values_handled(self):
127
+ """None / empty cells (from CSV parsing) should be treated as 0."""
128
+ import matplotlib.pyplot as plt
129
+ data = [[1.0, None, 0.0], [0.0, 2.0, None]]
130
+ binarization = [[1, 0, 0], [0, 1, 0]]
131
+ p = mp.ModalityPlot(data, binarization) # should not raise
132
+ plt.close('all')
133
+
134
+
135
+ # ---------------------------------------------------------------------------
136
+ # 3. Internal helpers — private-name-mangled access
137
+ # ---------------------------------------------------------------------------
138
+
139
+ class TestInternals:
140
+
141
+ def test_format_input_converts_none_to_zero(self):
142
+ """__format_input must replace None with 0 in the data array."""
143
+ # Access through name-mangling
144
+ p_class = mp.ModalityPlot
145
+ # Build a minimal instance to call the method:
146
+ import matplotlib.pyplot as plt
147
+ data = [[1.0, None, 0.5]]
148
+ bindata = [[1, 0, 0]]
149
+ obj = mp.ModalityPlot(data, bindata)
150
+ # After formatting, no NaN/None should remain
151
+ assert not np.isnan(obj.data).any(), "NaNs found after __format_input"
152
+ assert obj.data[0][1] == 0.0, "None was not replaced with 0.0"
153
+ plt.close('all')
154
+
155
+ def test_vector_addition_single_row(self):
156
+ """A single-axis unit vector should land on the unit circle."""
157
+ import matplotlib.pyplot as plt
158
+ data = [[1.0, 0.0, 0.0]]
159
+ bindata = [[1, 0, 0]]
160
+ obj = mp.ModalityPlot(data, bindata, angles=[90, 210, 330],
161
+ whole_sum=False)
162
+ # resultant magnitude should be 1.0 for a pure first-axis point
163
+ resultants = obj._ModalityPlot__vector_addition(obj.data, obj.binarization)
164
+ assert len(resultants) == 1
165
+ # magnitude ≈ 1 (allowing float tolerance)
166
+ assert abs(abs(resultants[0]) - 1.0) < 1e-5, \
167
+ f"Expected |resultant| ≈ 1.0, got {abs(resultants[0])}"
168
+ plt.close('all')
169
+
170
+ def test_normalization_sigmoid_range(self):
171
+ """Sigmoid output must stay within (0, 1)."""
172
+ import matplotlib.pyplot as plt
173
+ obj = mp.ModalityPlot([[1,0,0],[0,1,0]], [[1,0,0],[0,1,0]],
174
+ normalization_func='sigmoid')
175
+ values = np.linspace(-10, 10, 100)
176
+ normed = obj._ModalityPlot__normalization(values)
177
+ assert all(0 < v < 1 for v in normed), "Sigmoid output out of (0, 1) range"
178
+ plt.close('all')
179
+
180
+ def test_normalization_linear_range(self):
181
+ """Linear normalization must output [0, 1]."""
182
+ import matplotlib.pyplot as plt
183
+ obj = mp.ModalityPlot([[1,0,0],[0,1,0]], [[1,0,0],[0,1,0]],
184
+ normalization_func='linear')
185
+ values = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
186
+ normed = obj._ModalityPlot__normalization(values)
187
+ assert abs(min(normed)) < 1e-9, "Linear min should be 0"
188
+ assert abs(max(normed) - 1.0) < 1e-9, "Linear max should be 1"
189
+ plt.close('all')
190
+
191
+ def test_find_match_modality_hit(self):
192
+ """Should return the correct index when a matching pattern exists."""
193
+ import matplotlib.pyplot as plt
194
+ obj = mp.ModalityPlot([[1,0,0],[0,1,0]], [[1,0,0],[0,1,0]])
195
+ patterns = [(True, False, False), (False, True, False)]
196
+ idx = obj._ModalityPlot__find_match_modality((False, True, False), patterns)
197
+ assert idx == 1
198
+ plt.close('all')
199
+
200
+ def test_find_match_modality_miss_returns_zero(self):
201
+ """Should return 0 when no pattern matches."""
202
+ import matplotlib.pyplot as plt
203
+ obj = mp.ModalityPlot([[1,0,0],[0,1,0]], [[1,0,0],[0,1,0]])
204
+ patterns = [(True, False, False)]
205
+ idx = obj._ModalityPlot__find_match_modality((False, True, False), patterns)
206
+ assert idx == 0
207
+ plt.close('all')
208
+
209
+
210
+ # ---------------------------------------------------------------------------
211
+ # 4. Save / output
212
+ # ---------------------------------------------------------------------------
213
+
214
+ class TestOutput:
215
+
216
+ def test_save_creates_file(self, plot, tmp_path):
217
+ outfile = str(tmp_path / 'test_output')
218
+ plot.save(outfile, file_type='png')
219
+ assert (tmp_path / 'test_output.png').exists(), "save() did not create a file"
220
+
221
+ def test_save_svg(self, plot, tmp_path):
222
+ outfile = str(tmp_path / 'test_output')
223
+ plot.save(outfile, file_type='svg')
224
+ assert (tmp_path / 'test_output.svg').exists()
225
+
226
+ def test_save_transparent(self, plot, tmp_path):
227
+ """transparent=True should not raise."""
228
+ outfile = str(tmp_path / 'test_transparent')
229
+ plot.save(outfile, file_type='png', transparent=True)
230
+
231
+
232
+ # ---------------------------------------------------------------------------
233
+ # 5. Edge / boundary cases
234
+ # ---------------------------------------------------------------------------
235
+
236
+ class TestEdgeCases:
237
+
238
+ def test_all_zero_data(self):
239
+ """All-zero data should not crash (vectors are skipped)."""
240
+ import matplotlib.pyplot as plt
241
+ data = [[0.0, 0.0, 0.0]] * 5
242
+ binarization = [[0, 0, 0]] * 5
243
+ # The assertion `self.data.any()` will fire — that's expected behaviour.
244
+ with pytest.raises(AssertionError):
245
+ mp.ModalityPlot(data, binarization)
246
+ plt.close('all')
247
+
248
+ def test_single_row(self):
249
+ import matplotlib.pyplot as plt
250
+ data = [[1.0, 2.0, 3.0]]
251
+ binarization = [[1, 1, 1]]
252
+ p = mp.ModalityPlot(data, binarization)
253
+ plt.close('all')
254
+
255
+ def test_large_dataset(self):
256
+ """Should handle 1000 rows without error or significant slowdown."""
257
+ import matplotlib.pyplot as plt
258
+ rng = np.random.default_rng(42)
259
+ data = rng.uniform(0, 5, (1000, 3)).tolist()
260
+ binarization = (rng.uniform(0, 1, (1000, 3)) > 0.5).astype(int).tolist()
261
+ p = mp.ModalityPlot(data, binarization)
262
+ plt.close('all')
263
+
264
+ def test_whole_sum_false(self):
265
+ import matplotlib.pyplot as plt
266
+ data = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
267
+ binarization = [[1, 0, 0], [0, 1, 0]]
268
+ p = mp.ModalityPlot(data, binarization, whole_sum=False)
269
+ plt.close('all')
270
+
271
+ def test_same_scale_true(self):
272
+ import matplotlib.pyplot as plt
273
+ data = [[1.0, 2.0, 0.5], [0.5, 0.5, 0.5]]
274
+ binarization = [[1, 1, 0], [1, 0, 1]]
275
+ p = mp.ModalityPlot(data, binarization, same_scale=True)
276
+ plt.close('all')
277
+
278
+ def test_full_center_false(self):
279
+ import matplotlib.pyplot as plt
280
+ data = [[1.0, 1.0, 1.0], [1.0, 0.0, 0.0]]
281
+ binarization = [[1, 1, 1], [1, 0, 0]]
282
+ p = mp.ModalityPlot(data, binarization, full_center=False)
283
+ plt.close('all')
284
+
285
+ if __name__ == '__main__':
286
+ pytest.main([__file__, '-v'])
@@ -1 +0,0 @@
1
- __version__ = "0.2.6"
File without changes
File without changes
File without changes