DiaModality 0.2.6__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.
- diamodality-0.2.6/LICENSE +21 -0
- diamodality-0.2.6/MANIFEST.in +2 -0
- diamodality-0.2.6/PKG-INFO +169 -0
- diamodality-0.2.6/README.md +123 -0
- diamodality-0.2.6/pyproject.toml +35 -0
- diamodality-0.2.6/requirements.txt +3 -0
- diamodality-0.2.6/setup.cfg +4 -0
- diamodality-0.2.6/src/DiaModality/ModalityPlot.py +348 -0
- diamodality-0.2.6/src/DiaModality/__init__.py +2 -0
- diamodality-0.2.6/src/DiaModality/__main__.py +4 -0
- diamodality-0.2.6/src/DiaModality/_version.py +1 -0
- diamodality-0.2.6/src/DiaModality.egg-info/PKG-INFO +169 -0
- diamodality-0.2.6/src/DiaModality.egg-info/SOURCES.txt +14 -0
- diamodality-0.2.6/src/DiaModality.egg-info/dependency_links.txt +1 -0
- diamodality-0.2.6/src/DiaModality.egg-info/requires.txt +3 -0
- diamodality-0.2.6/src/DiaModality.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 konung-yaropolk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: DiaModality
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Tool to plot modality vector diagrams
|
|
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.
|
|
27
|
+
Project-URL: Homepage, https://github.com/konung-yaropolk/DiaModality
|
|
28
|
+
Project-URL: Repository, https://github.com/konung-yaropolk/DiaModality.git
|
|
29
|
+
Project-URL: Issues, https://github.com/konung-yaropolk/DiaModality/issues
|
|
30
|
+
Keywords: Visualization,Science,Plotting,Matplotlib
|
|
31
|
+
Classifier: Programming Language :: Python
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Development Status :: 4 - Beta
|
|
37
|
+
Classifier: Intended Audience :: Science/Research
|
|
38
|
+
Classifier: Natural Language :: English
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
40
|
+
Requires-Python: >=3.10
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: matplotlib
|
|
45
|
+
Requires-Dist: scsv>=0.1.4
|
|
46
|
+
|
|
47
|
+
# DiaModality - The Modality Diagram
|
|
48
|
+
|
|
49
|
+
Simple tool to plot vector modality diagram
|
|
50
|
+
|
|
51
|
+
[](https://pypi.org/project/diamodality)
|
|
52
|
+
[](https://github.com/konung-yaropolk/DiaModality)
|
|
53
|
+
[](https://pypi.org/project/diamodality)
|
|
54
|
+
[](https://pypi.org/project/diamodality)
|
|
55
|
+
[](https://pypi.org/project/diamodality)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### To install package run the command:
|
|
60
|
+
```bash
|
|
61
|
+
pip install diamodality
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Example use case:
|
|
66
|
+
See the /demo directory on Git repo or
|
|
67
|
+
create and run the following two files:
|
|
68
|
+
*(file names don't matter)*
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
``generate_sample_data.py``:
|
|
72
|
+
```python
|
|
73
|
+
import csv
|
|
74
|
+
import random
|
|
75
|
+
import os
|
|
76
|
+
|
|
77
|
+
num_rows = 1500
|
|
78
|
+
output_file = 'modality_data.csv'
|
|
79
|
+
|
|
80
|
+
# locate working directory
|
|
81
|
+
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
82
|
+
file_path = os.path.join(script_dir, output_file)
|
|
83
|
+
|
|
84
|
+
# Open a new CSV file to write the data
|
|
85
|
+
with open(file_path, mode='w', newline='') as file:
|
|
86
|
+
writer = csv.writer(file)
|
|
87
|
+
|
|
88
|
+
# Generate the data
|
|
89
|
+
signal_treshold = 1.5
|
|
90
|
+
for _ in range(num_rows):
|
|
91
|
+
|
|
92
|
+
# generate data columns:
|
|
93
|
+
col1 = random.uniform(0, 2.7)
|
|
94
|
+
col2 = random.uniform(0, 3.3)
|
|
95
|
+
col3 = random.uniform(0, 7.3)
|
|
96
|
+
|
|
97
|
+
# generate binarization columns:
|
|
98
|
+
col4 = 1 if col1 > signal_treshold else ''
|
|
99
|
+
col5 = 1 if col2 > signal_treshold else ''
|
|
100
|
+
col6 = 1 if col3 > signal_treshold else ''
|
|
101
|
+
|
|
102
|
+
writer.writerow([col1, col2, col3, col4, col5, col6])
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
``plot_sample_data.py``:
|
|
109
|
+
```python
|
|
110
|
+
import DiaModality.ModalityPlot as plt
|
|
111
|
+
import scsv as csv
|
|
112
|
+
import os
|
|
113
|
+
|
|
114
|
+
# input files:
|
|
115
|
+
files = ['modality_data.csv']
|
|
116
|
+
|
|
117
|
+
# Get full path
|
|
118
|
+
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
119
|
+
|
|
120
|
+
for file in files:
|
|
121
|
+
|
|
122
|
+
# Get full path of input files
|
|
123
|
+
file_path = os.path.join(script_dir, file)
|
|
124
|
+
|
|
125
|
+
# Parse data from csv file
|
|
126
|
+
new_csv = csv.OpenFile(file_path)
|
|
127
|
+
data, binarization = new_csv.GetRows(3, 3)
|
|
128
|
+
|
|
129
|
+
# Make figure:
|
|
130
|
+
plot = plt.ModalityPlot(
|
|
131
|
+
data,
|
|
132
|
+
binarization,
|
|
133
|
+
modalities=['Set 1', 'Set 2', 'Set 3'],
|
|
134
|
+
angles=[210, 90, 330],
|
|
135
|
+
labels=False,
|
|
136
|
+
scalecircle=0.5, # Scale circle radius
|
|
137
|
+
scalecircle_linestyle=':',
|
|
138
|
+
scalecircle_linewidth=0.75,
|
|
139
|
+
marker='', # vector endpoints marker
|
|
140
|
+
linestyle='-',
|
|
141
|
+
linewidth=0.5,
|
|
142
|
+
alpha=0.5,
|
|
143
|
+
same_scale=False, # Draw all the subplots in the same scale
|
|
144
|
+
full_center=True, # Draw all vectors in the central subplot,
|
|
145
|
+
# else draw trimodal vectors only
|
|
146
|
+
whole_sum=True, # Calculate all three modality vectors despite binarization
|
|
147
|
+
figsize=(10, 10),
|
|
148
|
+
dpi=100,
|
|
149
|
+
title='Modality Diagram Example',
|
|
150
|
+
colors=(
|
|
151
|
+
'tab:green', # Set 1 color
|
|
152
|
+
'navy', # Set 2 color
|
|
153
|
+
'tab:red', # Set 3 color
|
|
154
|
+
'#1E88E5', # Sets 1 & 2 intersection color
|
|
155
|
+
'#FF9933', # Sets 1 & 3 intersection color
|
|
156
|
+
'#9900FF', # Sets 2 & 3 intersection color
|
|
157
|
+
'black', # All sets intersection color
|
|
158
|
+
),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
plot.save(file_path, type='png', transparent=False)
|
|
162
|
+
plot.show()
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Source page:
|
|
166
|
+
https://github.com/konung-yaropolk/DiaModality
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+

|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# DiaModality - The Modality Diagram
|
|
2
|
+
|
|
3
|
+
Simple tool to plot vector modality diagram
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/diamodality)
|
|
6
|
+
[](https://github.com/konung-yaropolk/DiaModality)
|
|
7
|
+
[](https://pypi.org/project/diamodality)
|
|
8
|
+
[](https://pypi.org/project/diamodality)
|
|
9
|
+
[](https://pypi.org/project/diamodality)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### To install package run the command:
|
|
14
|
+
```bash
|
|
15
|
+
pip install diamodality
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Example use case:
|
|
20
|
+
See the /demo directory on Git repo or
|
|
21
|
+
create and run the following two files:
|
|
22
|
+
*(file names don't matter)*
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
``generate_sample_data.py``:
|
|
26
|
+
```python
|
|
27
|
+
import csv
|
|
28
|
+
import random
|
|
29
|
+
import os
|
|
30
|
+
|
|
31
|
+
num_rows = 1500
|
|
32
|
+
output_file = 'modality_data.csv'
|
|
33
|
+
|
|
34
|
+
# locate working directory
|
|
35
|
+
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
36
|
+
file_path = os.path.join(script_dir, output_file)
|
|
37
|
+
|
|
38
|
+
# Open a new CSV file to write the data
|
|
39
|
+
with open(file_path, mode='w', newline='') as file:
|
|
40
|
+
writer = csv.writer(file)
|
|
41
|
+
|
|
42
|
+
# Generate the data
|
|
43
|
+
signal_treshold = 1.5
|
|
44
|
+
for _ in range(num_rows):
|
|
45
|
+
|
|
46
|
+
# generate data columns:
|
|
47
|
+
col1 = random.uniform(0, 2.7)
|
|
48
|
+
col2 = random.uniform(0, 3.3)
|
|
49
|
+
col3 = random.uniform(0, 7.3)
|
|
50
|
+
|
|
51
|
+
# generate binarization columns:
|
|
52
|
+
col4 = 1 if col1 > signal_treshold else ''
|
|
53
|
+
col5 = 1 if col2 > signal_treshold else ''
|
|
54
|
+
col6 = 1 if col3 > signal_treshold else ''
|
|
55
|
+
|
|
56
|
+
writer.writerow([col1, col2, col3, col4, col5, col6])
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
``plot_sample_data.py``:
|
|
63
|
+
```python
|
|
64
|
+
import DiaModality.ModalityPlot as plt
|
|
65
|
+
import scsv as csv
|
|
66
|
+
import os
|
|
67
|
+
|
|
68
|
+
# input files:
|
|
69
|
+
files = ['modality_data.csv']
|
|
70
|
+
|
|
71
|
+
# Get full path
|
|
72
|
+
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
73
|
+
|
|
74
|
+
for file in files:
|
|
75
|
+
|
|
76
|
+
# Get full path of input files
|
|
77
|
+
file_path = os.path.join(script_dir, file)
|
|
78
|
+
|
|
79
|
+
# Parse data from csv file
|
|
80
|
+
new_csv = csv.OpenFile(file_path)
|
|
81
|
+
data, binarization = new_csv.GetRows(3, 3)
|
|
82
|
+
|
|
83
|
+
# Make figure:
|
|
84
|
+
plot = plt.ModalityPlot(
|
|
85
|
+
data,
|
|
86
|
+
binarization,
|
|
87
|
+
modalities=['Set 1', 'Set 2', 'Set 3'],
|
|
88
|
+
angles=[210, 90, 330],
|
|
89
|
+
labels=False,
|
|
90
|
+
scalecircle=0.5, # Scale circle radius
|
|
91
|
+
scalecircle_linestyle=':',
|
|
92
|
+
scalecircle_linewidth=0.75,
|
|
93
|
+
marker='', # vector endpoints marker
|
|
94
|
+
linestyle='-',
|
|
95
|
+
linewidth=0.5,
|
|
96
|
+
alpha=0.5,
|
|
97
|
+
same_scale=False, # Draw all the subplots in the same scale
|
|
98
|
+
full_center=True, # Draw all vectors in the central subplot,
|
|
99
|
+
# else draw trimodal vectors only
|
|
100
|
+
whole_sum=True, # Calculate all three modality vectors despite binarization
|
|
101
|
+
figsize=(10, 10),
|
|
102
|
+
dpi=100,
|
|
103
|
+
title='Modality Diagram Example',
|
|
104
|
+
colors=(
|
|
105
|
+
'tab:green', # Set 1 color
|
|
106
|
+
'navy', # Set 2 color
|
|
107
|
+
'tab:red', # Set 3 color
|
|
108
|
+
'#1E88E5', # Sets 1 & 2 intersection color
|
|
109
|
+
'#FF9933', # Sets 1 & 3 intersection color
|
|
110
|
+
'#9900FF', # Sets 2 & 3 intersection color
|
|
111
|
+
'black', # All sets intersection color
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
plot.save(file_path, type='png', transparent=False)
|
|
116
|
+
plot.show()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Source page:
|
|
120
|
+
https://github.com/konung-yaropolk/DiaModality
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+

|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=62.6"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "DiaModality"
|
|
7
|
+
dynamic = ["version", "dependencies"]
|
|
8
|
+
license = {file = "LICENSE"}
|
|
9
|
+
authors = [
|
|
10
|
+
{ name="konung-yaropolk", email="yaropolk1995@gmail.com" },
|
|
11
|
+
]
|
|
12
|
+
description = "Tool to plot modality vector diagrams"
|
|
13
|
+
keywords = ["Visualization", "Science", "Plotting", "Matplotlib"]
|
|
14
|
+
readme = {file = "README.md", content-type = "text/markdown"}
|
|
15
|
+
requires-python = ">=3.10"
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Development Status :: 4 - Beta",
|
|
23
|
+
"Intended Audience :: Science/Research",
|
|
24
|
+
"Natural Language :: English",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/konung-yaropolk/DiaModality"
|
|
30
|
+
Repository = "https://github.com/konung-yaropolk/DiaModality.git"
|
|
31
|
+
Issues = "https://github.com/konung-yaropolk/DiaModality/issues"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.dynamic]
|
|
34
|
+
version = {attr = "DiaModality.__version__"}
|
|
35
|
+
dependencies = {file = ["requirements.txt"]}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
# import matplotlib.colors as mcolors
|
|
4
|
+
import matplotlib.gridspec as gridspec
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
# Only use for plot layout adjustment
|
|
8
|
+
DEBUG = False
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class __Figure():
|
|
12
|
+
'''
|
|
13
|
+
Super class of all future plots
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
marker='',
|
|
19
|
+
linestyle='-',
|
|
20
|
+
linewidth=0.5,
|
|
21
|
+
alpha=0.8,
|
|
22
|
+
figsize=(10, 10),
|
|
23
|
+
dpi=100,
|
|
24
|
+
title='',
|
|
25
|
+
) -> None:
|
|
26
|
+
|
|
27
|
+
self.marker = marker
|
|
28
|
+
self.linestyle = linestyle
|
|
29
|
+
self.linewidth = linewidth
|
|
30
|
+
self.alpha = alpha
|
|
31
|
+
self.figsize = figsize
|
|
32
|
+
self.dpi = dpi
|
|
33
|
+
self.title = title
|
|
34
|
+
self.debug_flag = DEBUG
|
|
35
|
+
|
|
36
|
+
# Prepare figure:
|
|
37
|
+
self.fig = plt.figure(figsize=self.figsize, dpi=self.dpi)
|
|
38
|
+
self._make_layout()
|
|
39
|
+
|
|
40
|
+
def _make_layout(self) -> None:
|
|
41
|
+
# Create figure
|
|
42
|
+
plt.subplots_adjust(wspace=0.0, hspace=0.0)
|
|
43
|
+
plt.tight_layout()
|
|
44
|
+
plt.suptitle(self.title)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class __Output():
|
|
48
|
+
'''
|
|
49
|
+
Output options mixin
|
|
50
|
+
'''
|
|
51
|
+
|
|
52
|
+
def show(self):
|
|
53
|
+
plt.show()
|
|
54
|
+
|
|
55
|
+
def save(self,
|
|
56
|
+
filename,
|
|
57
|
+
type='png',
|
|
58
|
+
transparent=False):
|
|
59
|
+
plt.savefig('{}.{}'.format(filename, type), transparent=transparent)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ModalityPlot(__Figure, __Output):
|
|
63
|
+
'''
|
|
64
|
+
Input fotmat:
|
|
65
|
+
|
|
66
|
+
data: list of points, each point should be represented as a
|
|
67
|
+
list or touple containing three floats, one per modality.
|
|
68
|
+
|
|
69
|
+
'''
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
data: list,
|
|
74
|
+
binarization: list,
|
|
75
|
+
modalities=('Set A', 'Set B', 'Set C'),
|
|
76
|
+
angles=[90, 210, 330],
|
|
77
|
+
labels=True,
|
|
78
|
+
scalecircle=1, # Scale circle radius
|
|
79
|
+
scalecircle_linestyle=':',
|
|
80
|
+
scalecircle_linewidth=1,
|
|
81
|
+
marker='', # vector endpoints marker
|
|
82
|
+
linestyle='-',
|
|
83
|
+
linewidth=0.5,
|
|
84
|
+
alpha=0.8,
|
|
85
|
+
same_scale=False, # Draw all the subplots in the same scale
|
|
86
|
+
# Draw all vectors in the central subplot, else draw trimodal vectors only
|
|
87
|
+
full_center=True,
|
|
88
|
+
whole_sum=True, # Calculate all three modality vectors despite binarization
|
|
89
|
+
figsize=(10, 10),
|
|
90
|
+
dpi=300,
|
|
91
|
+
title='',
|
|
92
|
+
colors=(
|
|
93
|
+
'tab:green', # Set 1 color
|
|
94
|
+
'navy', # Set 2 color
|
|
95
|
+
'tab:red', # Set 3 color
|
|
96
|
+
'#1E88E5', # Sets 1 & 2 intersection color
|
|
97
|
+
'#FF9933', # Sets 1 & 3 intersection color
|
|
98
|
+
'#9900FF', # Sets 2 & 3 intersection color
|
|
99
|
+
'black', # All sets intersection color
|
|
100
|
+
),
|
|
101
|
+
normalization_func='sigmoid',
|
|
102
|
+
) -> None:
|
|
103
|
+
|
|
104
|
+
self.data, self.binarization = self.__format_input(data, binarization)
|
|
105
|
+
self.modalities = modalities
|
|
106
|
+
self.angles = np.deg2rad(angles)
|
|
107
|
+
self.labels = labels
|
|
108
|
+
self.scalecircle = scalecircle
|
|
109
|
+
self.scalecircle_linestyle = scalecircle_linestyle
|
|
110
|
+
self.scalecircle_linewidth = scalecircle_linewidth
|
|
111
|
+
self.same_scale = same_scale
|
|
112
|
+
self.full_center = full_center
|
|
113
|
+
self.whole_sum = whole_sum
|
|
114
|
+
self.colors = colors
|
|
115
|
+
self.normalization_func = normalization_func
|
|
116
|
+
self.modality_patterns = (
|
|
117
|
+
(True, False, False),
|
|
118
|
+
(False, True, False),
|
|
119
|
+
(False, False, True),
|
|
120
|
+
(True, True, False),
|
|
121
|
+
(True, False, True),
|
|
122
|
+
(False, True, True),
|
|
123
|
+
(True, True, True),
|
|
124
|
+
)
|
|
125
|
+
self.modalities_array = (
|
|
126
|
+
(self.modalities[0], None, None),
|
|
127
|
+
(None, self.modalities[1], None),
|
|
128
|
+
(None, None, self.modalities[2]),
|
|
129
|
+
(self.modalities[0], self.modalities[1], None),
|
|
130
|
+
(self.modalities[0], None, self.modalities[2]),
|
|
131
|
+
(None, self.modalities[1], self.modalities[2]),
|
|
132
|
+
(None, None, None),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
super().__init__(
|
|
136
|
+
marker,
|
|
137
|
+
linestyle,
|
|
138
|
+
linewidth,
|
|
139
|
+
alpha,
|
|
140
|
+
figsize,
|
|
141
|
+
dpi,
|
|
142
|
+
title,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# check input:
|
|
146
|
+
assert self.data.any(), 'data array must not be empty'
|
|
147
|
+
assert self.binarization.any(), 'binarization array must not be empty'
|
|
148
|
+
assert len(self.data) == len(
|
|
149
|
+
self.binarization), 'data and binarization arrays must have exact length'
|
|
150
|
+
assert len(self.data[0]) == len(self.binarization[0]
|
|
151
|
+
) == 3, 'data and binarization arrays must have three columns each'
|
|
152
|
+
|
|
153
|
+
def __format_input(self, input_data, input_bin) -> list:
|
|
154
|
+
'''
|
|
155
|
+
Data formatting:
|
|
156
|
+
Each column represents one modality. Empty cells are counted as 0.
|
|
157
|
+
Each row containing at least one value that will be represented as a point.
|
|
158
|
+
'''
|
|
159
|
+
|
|
160
|
+
output_data = np.array(input_data, dtype=object)
|
|
161
|
+
# Replace empty cells with zeros
|
|
162
|
+
output_data[output_data is None] = 0
|
|
163
|
+
output_data = output_data.astype(np.float32)
|
|
164
|
+
|
|
165
|
+
# Replace zeros with False and other numbers with True
|
|
166
|
+
output_bin = np.array(input_bin, dtype=np.bool_)
|
|
167
|
+
|
|
168
|
+
return output_data, output_bin
|
|
169
|
+
|
|
170
|
+
def __normalization(self, input) -> list:
|
|
171
|
+
'''
|
|
172
|
+
Define function to normalize coordinates
|
|
173
|
+
to values in range of 0 to 1 for HSV color model.
|
|
174
|
+
input: np.array
|
|
175
|
+
'''
|
|
176
|
+
|
|
177
|
+
match self.normalization_func:
|
|
178
|
+
|
|
179
|
+
case 'linear':
|
|
180
|
+
def func(x): return (x - np.min(input)) / \
|
|
181
|
+
(np.max(input) - np.min(input))
|
|
182
|
+
|
|
183
|
+
case 'sigmoid':
|
|
184
|
+
def func(x): return 1 / (1 + np.exp(-x))
|
|
185
|
+
|
|
186
|
+
# case 'log':
|
|
187
|
+
# log_input = np.log1p(input)
|
|
188
|
+
# func = lambda x: (x - np.min(log_input)) / (np.max(log_input) - np.min(log_input))
|
|
189
|
+
|
|
190
|
+
return [func(x) for x in input]
|
|
191
|
+
|
|
192
|
+
def __vector_addition(self, data, binarization) -> list:
|
|
193
|
+
|
|
194
|
+
resultants = np.array((), dtype=np.float32)
|
|
195
|
+
|
|
196
|
+
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
|
+
)
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
resultants = np.append(resultants, (0))
|
|
214
|
+
|
|
215
|
+
return resultants
|
|
216
|
+
|
|
217
|
+
def __find_match_modality(self, sample, list) -> int:
|
|
218
|
+
for i, item in enumerate(list):
|
|
219
|
+
if np.array_equal(item, sample):
|
|
220
|
+
return i
|
|
221
|
+
return 0
|
|
222
|
+
|
|
223
|
+
def __draw_scalecircle(self, ax) -> None:
|
|
224
|
+
|
|
225
|
+
# Plot the single-unit circle
|
|
226
|
+
r = self.scalecircle
|
|
227
|
+
theta = np.linspace(0, 2*np.pi, 100)
|
|
228
|
+
ax.plot(theta, [r]*len(theta), color='black',
|
|
229
|
+
linestyle=self.scalecircle_linestyle, linewidth=self.scalecircle_linewidth, zorder=10)
|
|
230
|
+
|
|
231
|
+
def __initiate_subplot(self, ax) -> None:
|
|
232
|
+
|
|
233
|
+
# Set custom design
|
|
234
|
+
ax.set_yticklabels([])
|
|
235
|
+
ax.set_xticks(self.angles if self.labels else [])
|
|
236
|
+
ax.grid(False)
|
|
237
|
+
ax.spines['polar'].set_visible(
|
|
238
|
+
False) if not self.debug_flag else ax.spines['polar'].set_visible(True)
|
|
239
|
+
ax.patch.set_facecolor('none')
|
|
240
|
+
|
|
241
|
+
# Draw coordinate grid on the top of figure
|
|
242
|
+
# to make easier subplots alignment on devtime
|
|
243
|
+
|
|
244
|
+
def __debug_grid(self, fig, y, x) -> None:
|
|
245
|
+
|
|
246
|
+
for i in range(1, y*x+1):
|
|
247
|
+
|
|
248
|
+
ax = fig.add_subplot(y, x, i)
|
|
249
|
+
|
|
250
|
+
# Set the facecolor of the axes
|
|
251
|
+
ax.patch.set_facecolor('none')
|
|
252
|
+
ax.set_xticks([])
|
|
253
|
+
ax.set_yticks([])
|
|
254
|
+
|
|
255
|
+
for spine in ax.spines.values():
|
|
256
|
+
spine.set_edgecolor('black')
|
|
257
|
+
|
|
258
|
+
def __draw_subplot(self, ax, resultants, modality_pattern, modalities) -> None:
|
|
259
|
+
|
|
260
|
+
# for future sets calculation
|
|
261
|
+
sets_counter = [0] * 8
|
|
262
|
+
|
|
263
|
+
# Color measurement in HSV format (temporarry abandoned future)
|
|
264
|
+
# hue_array = self.__normalization(np.angle(resultants))
|
|
265
|
+
# sat_array = np.ones_like(hue_array)
|
|
266
|
+
# val_array = self.__normalization(np.abs(resultants))
|
|
267
|
+
# color = mcolors.hsv_to_rgb((hue, sat, val))
|
|
268
|
+
|
|
269
|
+
for resultant, data_row, bin_row in zip(resultants, self.data, self.binarization):
|
|
270
|
+
|
|
271
|
+
if (resultant
|
|
272
|
+
and np.array_equal(bin_row, modality_pattern)
|
|
273
|
+
or (self.full_center
|
|
274
|
+
and modality_pattern == (True, True, True)
|
|
275
|
+
and (tuple(bin_row) not in self.modality_patterns[:3]
|
|
276
|
+
or self.whole_sum
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
):
|
|
280
|
+
|
|
281
|
+
# defining the modality of responce to apply color and z-order
|
|
282
|
+
modality_pattern_number = self.__find_match_modality(
|
|
283
|
+
bin_row, self.modality_patterns)
|
|
284
|
+
sets_counter[modality_pattern_number] += 1
|
|
285
|
+
color = self.colors[modality_pattern_number]
|
|
286
|
+
zorder = modality_pattern_number
|
|
287
|
+
|
|
288
|
+
ax.plot(
|
|
289
|
+
[0, np.angle(resultant)],
|
|
290
|
+
[0, np.abs(resultant)],
|
|
291
|
+
zorder=zorder,
|
|
292
|
+
marker=self.marker,
|
|
293
|
+
linestyle=self.linestyle,
|
|
294
|
+
linewidth=self.linewidth,
|
|
295
|
+
color=color,
|
|
296
|
+
alpha=self.alpha
|
|
297
|
+
)
|
|
298
|
+
if self.labels:
|
|
299
|
+
ax.set_xticklabels(modalities)
|
|
300
|
+
|
|
301
|
+
if self.scalecircle:
|
|
302
|
+
self.__draw_scalecircle(ax)
|
|
303
|
+
|
|
304
|
+
if not self.whole_sum and sum(modality_pattern) == 1:
|
|
305
|
+
ax.set_visible(False)
|
|
306
|
+
|
|
307
|
+
def _make_layout(self) -> None:
|
|
308
|
+
'''
|
|
309
|
+
Make figure layout,
|
|
310
|
+
starting point of plotting
|
|
311
|
+
'''
|
|
312
|
+
|
|
313
|
+
# Defining layout
|
|
314
|
+
gs = gridspec.GridSpec(20, 20, figure=self.fig)
|
|
315
|
+
ax1 = self.fig.add_subplot(gs[7:17, 1:11], polar=True)
|
|
316
|
+
ax2 = self.fig.add_subplot(gs[1:11, 5:15], polar=True)
|
|
317
|
+
ax3 = self.fig.add_subplot(gs[7:17, 9:19], polar=True)
|
|
318
|
+
ax12 = self.fig.add_subplot(gs[4:14, 3:13], polar=True)
|
|
319
|
+
ax13 = self.fig.add_subplot(gs[7:17, 5:15], polar=True)
|
|
320
|
+
ax23 = self.fig.add_subplot(gs[4:14, 7:17], polar=True)
|
|
321
|
+
ax0 = self.fig.add_subplot(gs[5:15, 5:15], polar=True)
|
|
322
|
+
subplots = (ax1, ax2, ax3, ax12, ax13, ax23, ax0)
|
|
323
|
+
|
|
324
|
+
# calculate resultants
|
|
325
|
+
resultants = self.__vector_addition(self.data, self.binarization)
|
|
326
|
+
|
|
327
|
+
# plot each subplot
|
|
328
|
+
for ax, modality_pattern, modalities in zip(subplots, self.modality_patterns, self.modalities_array):
|
|
329
|
+
self.__initiate_subplot(ax)
|
|
330
|
+
self.__draw_subplot(ax, resultants, modality_pattern, modalities)
|
|
331
|
+
|
|
332
|
+
if self.same_scale:
|
|
333
|
+
rlim = ax0.get_xlim()
|
|
334
|
+
for ax in subplots:
|
|
335
|
+
ax.set_rlim(rlim)
|
|
336
|
+
|
|
337
|
+
# Draw coordinate grid on the top of figure
|
|
338
|
+
# to make easier subplots alignment on devtime
|
|
339
|
+
if self.debug_flag:
|
|
340
|
+
self.__debug_grid(self.fig, 20, 20)
|
|
341
|
+
|
|
342
|
+
plt.subplots_adjust(wspace=0.0, hspace=0.0)
|
|
343
|
+
plt.tight_layout()
|
|
344
|
+
plt.suptitle(self.title)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
if __name__ == '__main__':
|
|
348
|
+
print('This package works as an imported module only.\nUse "import diamodality" statement')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.6"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: DiaModality
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Tool to plot modality vector diagrams
|
|
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.
|
|
27
|
+
Project-URL: Homepage, https://github.com/konung-yaropolk/DiaModality
|
|
28
|
+
Project-URL: Repository, https://github.com/konung-yaropolk/DiaModality.git
|
|
29
|
+
Project-URL: Issues, https://github.com/konung-yaropolk/DiaModality/issues
|
|
30
|
+
Keywords: Visualization,Science,Plotting,Matplotlib
|
|
31
|
+
Classifier: Programming Language :: Python
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Development Status :: 4 - Beta
|
|
37
|
+
Classifier: Intended Audience :: Science/Research
|
|
38
|
+
Classifier: Natural Language :: English
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
40
|
+
Requires-Python: >=3.10
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: matplotlib
|
|
45
|
+
Requires-Dist: scsv>=0.1.4
|
|
46
|
+
|
|
47
|
+
# DiaModality - The Modality Diagram
|
|
48
|
+
|
|
49
|
+
Simple tool to plot vector modality diagram
|
|
50
|
+
|
|
51
|
+
[](https://pypi.org/project/diamodality)
|
|
52
|
+
[](https://github.com/konung-yaropolk/DiaModality)
|
|
53
|
+
[](https://pypi.org/project/diamodality)
|
|
54
|
+
[](https://pypi.org/project/diamodality)
|
|
55
|
+
[](https://pypi.org/project/diamodality)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### To install package run the command:
|
|
60
|
+
```bash
|
|
61
|
+
pip install diamodality
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Example use case:
|
|
66
|
+
See the /demo directory on Git repo or
|
|
67
|
+
create and run the following two files:
|
|
68
|
+
*(file names don't matter)*
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
``generate_sample_data.py``:
|
|
72
|
+
```python
|
|
73
|
+
import csv
|
|
74
|
+
import random
|
|
75
|
+
import os
|
|
76
|
+
|
|
77
|
+
num_rows = 1500
|
|
78
|
+
output_file = 'modality_data.csv'
|
|
79
|
+
|
|
80
|
+
# locate working directory
|
|
81
|
+
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
82
|
+
file_path = os.path.join(script_dir, output_file)
|
|
83
|
+
|
|
84
|
+
# Open a new CSV file to write the data
|
|
85
|
+
with open(file_path, mode='w', newline='') as file:
|
|
86
|
+
writer = csv.writer(file)
|
|
87
|
+
|
|
88
|
+
# Generate the data
|
|
89
|
+
signal_treshold = 1.5
|
|
90
|
+
for _ in range(num_rows):
|
|
91
|
+
|
|
92
|
+
# generate data columns:
|
|
93
|
+
col1 = random.uniform(0, 2.7)
|
|
94
|
+
col2 = random.uniform(0, 3.3)
|
|
95
|
+
col3 = random.uniform(0, 7.3)
|
|
96
|
+
|
|
97
|
+
# generate binarization columns:
|
|
98
|
+
col4 = 1 if col1 > signal_treshold else ''
|
|
99
|
+
col5 = 1 if col2 > signal_treshold else ''
|
|
100
|
+
col6 = 1 if col3 > signal_treshold else ''
|
|
101
|
+
|
|
102
|
+
writer.writerow([col1, col2, col3, col4, col5, col6])
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
``plot_sample_data.py``:
|
|
109
|
+
```python
|
|
110
|
+
import DiaModality.ModalityPlot as plt
|
|
111
|
+
import scsv as csv
|
|
112
|
+
import os
|
|
113
|
+
|
|
114
|
+
# input files:
|
|
115
|
+
files = ['modality_data.csv']
|
|
116
|
+
|
|
117
|
+
# Get full path
|
|
118
|
+
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
119
|
+
|
|
120
|
+
for file in files:
|
|
121
|
+
|
|
122
|
+
# Get full path of input files
|
|
123
|
+
file_path = os.path.join(script_dir, file)
|
|
124
|
+
|
|
125
|
+
# Parse data from csv file
|
|
126
|
+
new_csv = csv.OpenFile(file_path)
|
|
127
|
+
data, binarization = new_csv.GetRows(3, 3)
|
|
128
|
+
|
|
129
|
+
# Make figure:
|
|
130
|
+
plot = plt.ModalityPlot(
|
|
131
|
+
data,
|
|
132
|
+
binarization,
|
|
133
|
+
modalities=['Set 1', 'Set 2', 'Set 3'],
|
|
134
|
+
angles=[210, 90, 330],
|
|
135
|
+
labels=False,
|
|
136
|
+
scalecircle=0.5, # Scale circle radius
|
|
137
|
+
scalecircle_linestyle=':',
|
|
138
|
+
scalecircle_linewidth=0.75,
|
|
139
|
+
marker='', # vector endpoints marker
|
|
140
|
+
linestyle='-',
|
|
141
|
+
linewidth=0.5,
|
|
142
|
+
alpha=0.5,
|
|
143
|
+
same_scale=False, # Draw all the subplots in the same scale
|
|
144
|
+
full_center=True, # Draw all vectors in the central subplot,
|
|
145
|
+
# else draw trimodal vectors only
|
|
146
|
+
whole_sum=True, # Calculate all three modality vectors despite binarization
|
|
147
|
+
figsize=(10, 10),
|
|
148
|
+
dpi=100,
|
|
149
|
+
title='Modality Diagram Example',
|
|
150
|
+
colors=(
|
|
151
|
+
'tab:green', # Set 1 color
|
|
152
|
+
'navy', # Set 2 color
|
|
153
|
+
'tab:red', # Set 3 color
|
|
154
|
+
'#1E88E5', # Sets 1 & 2 intersection color
|
|
155
|
+
'#FF9933', # Sets 1 & 3 intersection color
|
|
156
|
+
'#9900FF', # Sets 2 & 3 intersection color
|
|
157
|
+
'black', # All sets intersection color
|
|
158
|
+
),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
plot.save(file_path, type='png', transparent=False)
|
|
162
|
+
plot.show()
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Source page:
|
|
166
|
+
https://github.com/konung-yaropolk/DiaModality
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+

|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
requirements.txt
|
|
6
|
+
src/DiaModality/ModalityPlot.py
|
|
7
|
+
src/DiaModality/__init__.py
|
|
8
|
+
src/DiaModality/__main__.py
|
|
9
|
+
src/DiaModality/_version.py
|
|
10
|
+
src/DiaModality.egg-info/PKG-INFO
|
|
11
|
+
src/DiaModality.egg-info/SOURCES.txt
|
|
12
|
+
src/DiaModality.egg-info/dependency_links.txt
|
|
13
|
+
src/DiaModality.egg-info/requires.txt
|
|
14
|
+
src/DiaModality.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DiaModality
|