plotlp 0.1.1__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.
- plotlp-0.1.1/PKG-INFO +47 -0
- plotlp-0.1.1/README.md +30 -0
- plotlp-0.1.1/pyproject.toml +17 -0
- plotlp-0.1.1/src/plotlp/__init__.py +23 -0
- plotlp-0.1.1/src/plotlp/modules/__init__.py +0 -0
- plotlp-0.1.1/src/plotlp/modules/cmap_LP/__init__.py +0 -0
- plotlp-0.1.1/src/plotlp/modules/cmap_LP/cmap.py +132 -0
- plotlp-0.1.1/src/plotlp/modules/cmap_LP/test_cmap.py +79 -0
- plotlp-0.1.1/src/plotlp/modules/color_LP/__init__.py +0 -0
- plotlp-0.1.1/src/plotlp/modules/color_LP/color.py +316 -0
- plotlp-0.1.1/src/plotlp/modules/color_LP/test_color.py +136 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/__init__.py +0 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/style.py +79 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/styles/__init__.py +0 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/styles/darkLP.py +7 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/styles/default.py +373 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/styles/lightLP.py +7 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/styles/styleLP.py +44 -0
- plotlp-0.1.1/src/plotlp/modules/style_LP/test_style.py +90 -0
- plotlp-0.1.1/src/plotlp/modules.json +20 -0
- plotlp-0.1.1/src/plotlp/py.typed +0 -0
- plotlp-0.1.1/src/plotlp/scripts/__init__.py +0 -0
- plotlp-0.1.1/src/plotlp/scripts.json +1 -0
plotlp-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: plotlp
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A library wrapper around matplotlib for custom plots.
|
|
5
|
+
Requires-Dist: corelp
|
|
6
|
+
Requires-Dist: cycler
|
|
7
|
+
Requires-Dist: ipykernel
|
|
8
|
+
Requires-Dist: matplotlib
|
|
9
|
+
Requires-Dist: pytest
|
|
10
|
+
Requires-Dist: sphinx
|
|
11
|
+
Requires-Dist: sphinx-design
|
|
12
|
+
Requires-Dist: sphinx-rtd-theme
|
|
13
|
+
Requires-Dist: spyder-kernels
|
|
14
|
+
Requires-Dist: toml
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# plotLP
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
Author : Lancelot PINCET
|
|
22
|
+
GitHub : https://github.com/LancelotPincet/plotLP
|
|
23
|
+
HTTPS : https://github.com/LancelotPincet/plotLP.git
|
|
24
|
+
SSH : git@github.com:LancelotPincet/plotLP.git
|
|
25
|
+
PyPI : https://pypi.org/project/plotLP
|
|
26
|
+
Docs : https://plotLP.readthedocs.io
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**A library wrapper around matplotlib for custom plots.**
|
|
30
|
+
|
|
31
|
+
plotLP is available on [PyPI](https://pypi.org/project/plotLP) for pip installs.
|
|
32
|
+
For more information, do not hesitate to consult the [Documentation](https://plotLP.readthedocs.io).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## MIT License
|
|
37
|
+
|
|
38
|
+
<details>
|
|
39
|
+
<summary>details</summary>
|
|
40
|
+
|
|
41
|
+
Intellectual property behind this Library is protected via an [MIT license](LICENSE). This means everyone can *freely* use it in a personnal, academic or commercial manner, if they **keep the copyright name** at the top of the codes.
|
|
42
|
+
|
|
43
|
+
The library can be redistributed, *with or without modifications*, in open or closed projects. However the **MIT license must be conserved**. For example in a commercial closed project, this means the **copyright and license must be visible somewhere**, like in the documentation or credits.
|
|
44
|
+
|
|
45
|
+
The license also explains that the **code performances are not warrantied**, and you are responsible for how you are using it. For more information on your rights and obligations please refer to [descriptive websites](https://en.wikipedia.org/wiki/MIT_License), or contact author for approvales.
|
|
46
|
+
|
|
47
|
+
</details>
|
plotlp-0.1.1/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# plotLP
|
|
2
|
+
|
|
3
|
+
```text
|
|
4
|
+
Author : Lancelot PINCET
|
|
5
|
+
GitHub : https://github.com/LancelotPincet/plotLP
|
|
6
|
+
HTTPS : https://github.com/LancelotPincet/plotLP.git
|
|
7
|
+
SSH : git@github.com:LancelotPincet/plotLP.git
|
|
8
|
+
PyPI : https://pypi.org/project/plotLP
|
|
9
|
+
Docs : https://plotLP.readthedocs.io
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**A library wrapper around matplotlib for custom plots.**
|
|
13
|
+
|
|
14
|
+
plotLP is available on [PyPI](https://pypi.org/project/plotLP) for pip installs.
|
|
15
|
+
For more information, do not hesitate to consult the [Documentation](https://plotLP.readthedocs.io).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## MIT License
|
|
20
|
+
|
|
21
|
+
<details>
|
|
22
|
+
<summary>details</summary>
|
|
23
|
+
|
|
24
|
+
Intellectual property behind this Library is protected via an [MIT license](LICENSE). This means everyone can *freely* use it in a personnal, academic or commercial manner, if they **keep the copyright name** at the top of the codes.
|
|
25
|
+
|
|
26
|
+
The library can be redistributed, *with or without modifications*, in open or closed projects. However the **MIT license must be conserved**. For example in a commercial closed project, this means the **copyright and license must be visible somewhere**, like in the documentation or credits.
|
|
27
|
+
|
|
28
|
+
The license also explains that the **code performances are not warrantied**, and you are responsible for how you are using it. For more information on your rights and obligations please refer to [descriptive websites](https://en.wikipedia.org/wiki/MIT_License), or contact author for approvales.
|
|
29
|
+
|
|
30
|
+
</details>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "plotlp"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
description = "A library wrapper around matplotlib for custom plots."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [ "corelp", "cycler", "ipykernel", "matplotlib", "pytest", "sphinx", "sphinx-design", "sphinx-rtd-theme", "spyder-kernels", "toml",]
|
|
8
|
+
|
|
9
|
+
[build-system]
|
|
10
|
+
requires = [ "uv_build>=0.8.8,<0.9.0",]
|
|
11
|
+
build-backend = "uv_build"
|
|
12
|
+
|
|
13
|
+
[tool.uv]
|
|
14
|
+
required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'win32' and (platform_machine == 'AMD64' or platform_machine == 'x86_64')",]
|
|
15
|
+
|
|
16
|
+
[tool.uv.sources.corelp]
|
|
17
|
+
workspace = true
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Date : 2025-08-28
|
|
4
|
+
# Author : Lancelot PINCET
|
|
5
|
+
# GitHub : https://github.com/LancelotPincet
|
|
6
|
+
# Library : plotLP
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
A library wrapper around matplotlib for custom plots.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# %% Lazy imports
|
|
15
|
+
from corelp import getmodule
|
|
16
|
+
__getattr__, __all__ = getmodule(__file__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# %% Test function run
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
from corelp import test
|
|
23
|
+
test(__file__)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Date : 2025-11-17
|
|
4
|
+
# Author : Lancelot PINCET
|
|
5
|
+
# GitHub : https://github.com/LancelotPincet
|
|
6
|
+
# Library : plotLP
|
|
7
|
+
# Module : cmap
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
This module adds custom cmaps to matplotlib.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# %% Libraries
|
|
16
|
+
from corelp import selfkwargs, prop
|
|
17
|
+
from arrLP import normalize
|
|
18
|
+
from plotlp import color
|
|
19
|
+
from matplotlib.colors import LinearSegmentedColormap, to_rgba_array
|
|
20
|
+
import numpy as np
|
|
21
|
+
from scipy.special import erf,erfinv
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# %% Function
|
|
26
|
+
def cmap(**kwargs) :
|
|
27
|
+
'''
|
|
28
|
+
This module adds custom cmaps to matplotlib.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
a : int or float
|
|
33
|
+
TODO.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
b : int or float
|
|
38
|
+
TODO.
|
|
39
|
+
|
|
40
|
+
Raises
|
|
41
|
+
------
|
|
42
|
+
TypeError
|
|
43
|
+
TODO.
|
|
44
|
+
|
|
45
|
+
Examples
|
|
46
|
+
--------
|
|
47
|
+
>>> from plotlp import cmap
|
|
48
|
+
...
|
|
49
|
+
>>> cmap() # TODO
|
|
50
|
+
'''
|
|
51
|
+
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Cmap(LinearSegmentedColormap) :
|
|
57
|
+
name = 'cmapLP'
|
|
58
|
+
|
|
59
|
+
def __init__(self, **kwargs) :
|
|
60
|
+
selfkwargs(self,kwargs)
|
|
61
|
+
r, g, b, a = to_rgba_array(self.colors).T
|
|
62
|
+
nodes = self.nodes
|
|
63
|
+
cdict = {
|
|
64
|
+
"red": np.column_stack([nodes, r, r]),
|
|
65
|
+
"green": np.column_stack([nodes, g, g]),
|
|
66
|
+
"blue": np.column_stack([nodes, b, b]),
|
|
67
|
+
"alpha": np.column_stack([nodes, a, a]),
|
|
68
|
+
}
|
|
69
|
+
super().__init__(self.name,cdict)
|
|
70
|
+
|
|
71
|
+
_black = 'black'
|
|
72
|
+
@prop(variable=True)
|
|
73
|
+
def black(self) -> str :
|
|
74
|
+
if self._black is None :
|
|
75
|
+
return color(rgb=self(self.get_node(0.)))
|
|
76
|
+
return color(auto=self._black)
|
|
77
|
+
|
|
78
|
+
_white = 'white'
|
|
79
|
+
@prop(variable=True)
|
|
80
|
+
def white(self) -> str :
|
|
81
|
+
if self._white is None :
|
|
82
|
+
return color(rgb=self(self.get_node(1.)))
|
|
83
|
+
return color(auto=self._white)
|
|
84
|
+
|
|
85
|
+
_color = None
|
|
86
|
+
@prop(variable=True)
|
|
87
|
+
def color(self) :
|
|
88
|
+
if self._color is None :
|
|
89
|
+
return color(rgb=self(self.get_node(0.5)))
|
|
90
|
+
return color(auto=self._color)
|
|
91
|
+
|
|
92
|
+
_dark = None #dark color
|
|
93
|
+
@prop(variable=True)
|
|
94
|
+
def dark(self) -> str :
|
|
95
|
+
if self._dark is None :
|
|
96
|
+
return color(self(self.get_node(0.25)))
|
|
97
|
+
return color(self._dark)
|
|
98
|
+
|
|
99
|
+
_light = None #light color
|
|
100
|
+
@prop(variable=True)
|
|
101
|
+
def light(self) -> str :
|
|
102
|
+
if self._light is None :
|
|
103
|
+
return color(self(self.get_node(0.75)))
|
|
104
|
+
return color(self._light)
|
|
105
|
+
|
|
106
|
+
_colors = None #list of colors
|
|
107
|
+
@prop()
|
|
108
|
+
def colors(self) -> str :
|
|
109
|
+
return [self.black,self.dark,self.color,self.light,self.white]
|
|
110
|
+
@colors.setter
|
|
111
|
+
def colors(self, value) -> float :
|
|
112
|
+
self._colors = [color(auto=color) for color in value]
|
|
113
|
+
@property
|
|
114
|
+
def ncolors(self) :
|
|
115
|
+
return len(self.colors)
|
|
116
|
+
|
|
117
|
+
_nodes = None #nodes corresponding to colors
|
|
118
|
+
@prop()
|
|
119
|
+
def nodes(self) -> str :
|
|
120
|
+
nodes = np.linspace(0.,1.,self.ncolors)
|
|
121
|
+
return self.get_node(nodes)
|
|
122
|
+
nodebase = 0 #Base defining distribution of colors around center based on erf function, when approching 0 the function tends towards linear distribution
|
|
123
|
+
def get_node(self,node) :
|
|
124
|
+
if self.nodebase == 0 : return node
|
|
125
|
+
node = (erfinv(normalize(node,-erf(self.nodebase),erf(self.nodebase),offset=0,norm=1))/self.nodebase+1)/2
|
|
126
|
+
return (np.round(node * 1000)).astype(int)/1000
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# %% Test function run
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
from corelp import test
|
|
132
|
+
test(__file__)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Date : 2025-11-17
|
|
4
|
+
# Author : Lancelot PINCET
|
|
5
|
+
# GitHub : https://github.com/LancelotPincet
|
|
6
|
+
# Library : plotLP
|
|
7
|
+
# Module : cmap
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
This file allows to test cmap
|
|
11
|
+
|
|
12
|
+
cmap : This module adds custom cmaps to matplotlib.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# %% Libraries
|
|
18
|
+
from corelp import print, debug
|
|
19
|
+
import pytest
|
|
20
|
+
from plotlp import cmap
|
|
21
|
+
debug_folder = debug(__file__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# %% Function test
|
|
26
|
+
def test_function() :
|
|
27
|
+
'''
|
|
28
|
+
Test cmap function
|
|
29
|
+
'''
|
|
30
|
+
print('Hello world!')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# %% Instance fixture
|
|
35
|
+
@pytest.fixture()
|
|
36
|
+
def instance() :
|
|
37
|
+
'''
|
|
38
|
+
Create a new instance at each test function
|
|
39
|
+
'''
|
|
40
|
+
return cmap()
|
|
41
|
+
|
|
42
|
+
def test_instance(instance) :
|
|
43
|
+
'''
|
|
44
|
+
Test on fixture
|
|
45
|
+
'''
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# %% Returns test
|
|
50
|
+
@pytest.mark.parametrize("args, kwargs, expected, message", [
|
|
51
|
+
#([], {}, None, ""),
|
|
52
|
+
([], {}, None, ""),
|
|
53
|
+
])
|
|
54
|
+
def test_returns(args, kwargs, expected, message) :
|
|
55
|
+
'''
|
|
56
|
+
Test cmap return values
|
|
57
|
+
'''
|
|
58
|
+
assert cmap(*args, **kwargs) == expected, message
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# %% Error test
|
|
63
|
+
@pytest.mark.parametrize("args, kwargs, error, error_message", [
|
|
64
|
+
#([], {}, None, ""),
|
|
65
|
+
([], {}, None, ""),
|
|
66
|
+
])
|
|
67
|
+
def test_errors(args, kwargs, error, error_message) :
|
|
68
|
+
'''
|
|
69
|
+
Test cmap error values
|
|
70
|
+
'''
|
|
71
|
+
with pytest.raises(error, match=error_message) :
|
|
72
|
+
cmap(*args, **kwargs)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# %% Test function run
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
from corelp import test
|
|
79
|
+
test(__file__)
|
|
File without changes
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Date : 2025-11-16
|
|
4
|
+
# Author : Lancelot PINCET
|
|
5
|
+
# GitHub : https://github.com/LancelotPincet
|
|
6
|
+
# Library : plotLP
|
|
7
|
+
# Module : color
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Gets a custom Color object.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# %% Libraries
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
import matplotlib.colors as mcolors
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
colors = {
|
|
22
|
+
|
|
23
|
+
#Greys
|
|
24
|
+
'xxdarkgreyLP' : "#1A1A1AFF",
|
|
25
|
+
'xdarkgreyLP' : "#404040FF",
|
|
26
|
+
'darkgreyLP' : "#606060FF",
|
|
27
|
+
'greyLP' : "#808080FF",
|
|
28
|
+
'lightgreyLP' : "#9F9F9FFF",
|
|
29
|
+
'xlightgreyLP' : "#BFBFBFFF",
|
|
30
|
+
'xxlightgreyLP' : "#E6E6E6FF",
|
|
31
|
+
|
|
32
|
+
#Blue
|
|
33
|
+
'darkblueLP' : "#1F4B5BFF",
|
|
34
|
+
'blueLP' : "#2F7089FF",
|
|
35
|
+
'lightblueLP' : "#598DA1FF",
|
|
36
|
+
'xlightblueLP' : "#82A9B8FF",
|
|
37
|
+
'xxlightblueLP' : "#ACC6D0FF",
|
|
38
|
+
|
|
39
|
+
#Green
|
|
40
|
+
'xxdarkgreenLP' : "#294C3AFF",
|
|
41
|
+
'xdarkgreenLP' : "#3E725BFF",
|
|
42
|
+
'darkgreenLP' : "#529878FF",
|
|
43
|
+
'greenLP' : "#68BE95FF",
|
|
44
|
+
'lightgreenLP' : "#9AD4B8FF",
|
|
45
|
+
|
|
46
|
+
#Red
|
|
47
|
+
'darkredLP' : "#8F1E20FF",
|
|
48
|
+
'redLP' : "#D52D2FFF",
|
|
49
|
+
'lightredLP' : "#DE5758FF",
|
|
50
|
+
'xlightredLP' : "#E68181FF",
|
|
51
|
+
'xxlightredLP' : "#EFABADFF",
|
|
52
|
+
|
|
53
|
+
#Yellow
|
|
54
|
+
'xxdarkyellowLP' : "#4D4212FF",
|
|
55
|
+
'xdarkyellowLP' : "#746317FF",
|
|
56
|
+
'darkyellowLP' : "#9A8420FF",
|
|
57
|
+
'yellowLP' : "#C1A529FF",
|
|
58
|
+
'lightyellowLP' : "#D6C36FFF",
|
|
59
|
+
|
|
60
|
+
#Cold
|
|
61
|
+
'xdarkcoldLP' : "#264C46FF",
|
|
62
|
+
'darkcoldLP' : "#39716CFF",
|
|
63
|
+
'coldLP' : "#4C978FFF",
|
|
64
|
+
'lightcoldLP' : "#78B1AAFF",
|
|
65
|
+
'xlightcoldLP' : "#D3E5E4FF",
|
|
66
|
+
|
|
67
|
+
#Warm
|
|
68
|
+
'xdarkwarmLP' : "#653517FF",
|
|
69
|
+
'darkwarmLP' : "#994F20FF",
|
|
70
|
+
'warmLP' : "#CB692CFF",
|
|
71
|
+
'lightwarmLP' : "#D88F60FF",
|
|
72
|
+
'xlightwarmLP' : "#E6B495FF",
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
mcolors.CSS4_COLORS.update(colors)
|
|
76
|
+
mcolors._colors_full_map.update(colors)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# %% Function
|
|
81
|
+
def color(*, name:str=None, hex:str=None, wl:float=None, gray:int=None, rgb:tuple=None, RGB:tuple=None, auto=None, alpha:float=None) :
|
|
82
|
+
'''
|
|
83
|
+
Gets a custom Color object.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
name : str
|
|
88
|
+
Name of color.
|
|
89
|
+
hex : str
|
|
90
|
+
hexadecimal string.
|
|
91
|
+
wl : str
|
|
92
|
+
wavelength [nm] float.
|
|
93
|
+
gray : str
|
|
94
|
+
gray luminosity [0-255].
|
|
95
|
+
rgb : tuple
|
|
96
|
+
rgb(a) tuple [0.-1.].
|
|
97
|
+
RGB : tuple
|
|
98
|
+
RGB(A) tuple [0-255].
|
|
99
|
+
auto : str or tuple or int or float
|
|
100
|
+
Defines what is asked automatically.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
instance : Color
|
|
106
|
+
Color object instance.
|
|
107
|
+
|
|
108
|
+
Examples
|
|
109
|
+
--------
|
|
110
|
+
>>> from plotlp import color
|
|
111
|
+
...
|
|
112
|
+
>>> color(name="blue") # from plt
|
|
113
|
+
>>> color(name="blueLP") # from custom
|
|
114
|
+
>>> color(hex="#2F7089") # from hexadecimals
|
|
115
|
+
>>> color(wl=480) # from wavelenght
|
|
116
|
+
>>> color(gray=180) # from grayscale
|
|
117
|
+
>>> color(rgb=(0, 0, 255)) # from RGB
|
|
118
|
+
...
|
|
119
|
+
>>> blued, greened = color(name="blueLP")
|
|
120
|
+
>>> desaturated = blued.desaturate(0.5) # 1=completely gray
|
|
121
|
+
>>> dark = blued.luminosity(-0.5) # <0 darker down to -1
|
|
122
|
+
>>> light = blued.luminosity(+0.5) # >0 lighter up to +1
|
|
123
|
+
>>> transparent = blued * 0.5 # color * alpha
|
|
124
|
+
>>> opaque = +blued
|
|
125
|
+
>>> invisible = -blued
|
|
126
|
+
>>> mixed = blued.mix(greened, 0.5) # 50/50 mixing blue/green
|
|
127
|
+
>>> complementary = ~blued # complementary color
|
|
128
|
+
'''
|
|
129
|
+
|
|
130
|
+
# Name
|
|
131
|
+
if name is not None :
|
|
132
|
+
r, g, b = mcolors.to_rgb(name)
|
|
133
|
+
return color(rgb=(r*255, g*255, b*255), alpha=alpha)
|
|
134
|
+
|
|
135
|
+
# Hexadecimals
|
|
136
|
+
if hex is not None :
|
|
137
|
+
if hex.startswith('#') :
|
|
138
|
+
hex = hex[1:]
|
|
139
|
+
_alpha = int(hex[6:8], 16)/255 if len(hex)==8 else None
|
|
140
|
+
alpha = _alpha if alpha is None else alpha
|
|
141
|
+
return color(rgb=(int(hex[0:2],16), int(hex[2:4],16), int(hex[4:6], 16)), alpha=alpha)
|
|
142
|
+
|
|
143
|
+
# Wavelength
|
|
144
|
+
if wl is not None :
|
|
145
|
+
gamma = 0.8
|
|
146
|
+
wl = min(max(float(wl),380.),750.) #Wavelength is put to borders
|
|
147
|
+
if wl >= 380 and wl <= 440:
|
|
148
|
+
attenuation = 0.3 + 0.7 * (wl - 380) / (440 - 380)
|
|
149
|
+
r, g, b = ((-(wl - 440) / (440 - 380)) * attenuation) ** gamma, 0.0, (1.0 * attenuation) ** gamma
|
|
150
|
+
elif wl >= 440 and wl <= 490:
|
|
151
|
+
r, g, b = 0.0, ((wl - 440) / (490 - 440)) ** gamma, 1.0
|
|
152
|
+
elif wl >= 490 and wl <= 510:
|
|
153
|
+
r, g, b = 0.0, 1.0, (-(wl - 510) / (510 - 490)) ** gamma
|
|
154
|
+
elif wl >= 510 and wl <= 580:
|
|
155
|
+
r, g, b = ((wl - 510) / (580 - 510)) ** gamma, 1.0, 0.0
|
|
156
|
+
elif wl >= 580 and wl <= 645:
|
|
157
|
+
r, g, b = 1.0, (-(wl - 645) / (645 - 580)) ** gamma, 0.0
|
|
158
|
+
elif wl >= 645 and wl <= 750:
|
|
159
|
+
attenuation = 0.3 + 0.7 * (750 - wl) / (750 - 645)
|
|
160
|
+
r, g, b = (1.0 * attenuation) ** gamma, 0.0, 0.0
|
|
161
|
+
else:
|
|
162
|
+
r, g, b = 0.0, 0.0, 0.0
|
|
163
|
+
return color(rgb=(r*255, g*255, b*255), alpha=alpha)
|
|
164
|
+
|
|
165
|
+
# gray
|
|
166
|
+
if gray is not None :
|
|
167
|
+
return color(rgb=(gray, gray, gray), alpha=alpha)
|
|
168
|
+
|
|
169
|
+
# rgb
|
|
170
|
+
if rgb is not None :
|
|
171
|
+
_alpha = rgb[3] if len(rgb)==4 else 1.
|
|
172
|
+
alpha = _alpha if alpha is None else alpha
|
|
173
|
+
return Color(rgb[0]*255, rgb[1]*255, rgb[2]*255, alpha=alpha)
|
|
174
|
+
|
|
175
|
+
# RGB
|
|
176
|
+
if RGB is not None :
|
|
177
|
+
_alpha = RGB[3]/255 if len(RGB)==4 else 1.
|
|
178
|
+
alpha = _alpha if alpha is None else alpha
|
|
179
|
+
return Color(RGB[0], RGB[1], RGB[2], alpha=alpha)
|
|
180
|
+
|
|
181
|
+
# Auto
|
|
182
|
+
if auto is not None :
|
|
183
|
+
if isinstance(auto, str) :
|
|
184
|
+
if auto.startswith('#') : return color(hex=auto, alpha=alpha)
|
|
185
|
+
else : return color(name=auto, alpha=alpha)
|
|
186
|
+
elif isinstance(auto, tuple) or isinstance(auto, list) :
|
|
187
|
+
if max(*auto) <= 1 : return color(rgb=auto, alpha=alpha)
|
|
188
|
+
else : return color(RGB=auto, alpha=alpha)
|
|
189
|
+
else : # int/float
|
|
190
|
+
if auto <= 255 : return color(gray=auto, alpha=alpha)
|
|
191
|
+
else : return color(wl=auto, alpha=alpha)
|
|
192
|
+
|
|
193
|
+
raise SyntaxError('No valid input was asked for color')
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# %% Class
|
|
198
|
+
@dataclass(slots=True, frozen=True)
|
|
199
|
+
class Color(str) :
|
|
200
|
+
'''
|
|
201
|
+
Gets a custom Color object.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
R : float
|
|
206
|
+
Red value [0-255].
|
|
207
|
+
G : float
|
|
208
|
+
Green value [0-255].
|
|
209
|
+
B : float
|
|
210
|
+
Blue value [0-255].
|
|
211
|
+
alpha : float
|
|
212
|
+
Alpha value [0-1] (0: transparent, 1: opaque).
|
|
213
|
+
|
|
214
|
+
Attributes
|
|
215
|
+
----------
|
|
216
|
+
_attr : int or float
|
|
217
|
+
TODO.
|
|
218
|
+
|
|
219
|
+
Examples
|
|
220
|
+
--------
|
|
221
|
+
>>> from plotlp import color
|
|
222
|
+
...
|
|
223
|
+
>>> instance = color(TODO)
|
|
224
|
+
'''
|
|
225
|
+
|
|
226
|
+
# Attributes
|
|
227
|
+
R : int
|
|
228
|
+
G : int
|
|
229
|
+
B : int
|
|
230
|
+
alpha : float = 1.
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# new
|
|
235
|
+
def __new__(cls, R, G, B, alpha=1) :
|
|
236
|
+
hex = '#{:02x}{:02x}{:02x}{:02x}'.format(int(R), int(G), int(B), int(alpha*255)).upper()
|
|
237
|
+
instance = str.__new__(cls, hex)
|
|
238
|
+
object.__setattr__(instance, 'R', int(R))
|
|
239
|
+
object.__setattr__(instance, 'G', int(G))
|
|
240
|
+
object.__setattr__(instance, 'B', int(B))
|
|
241
|
+
object.__setattr__(instance, 'alpha', float(alpha))
|
|
242
|
+
return instance
|
|
243
|
+
|
|
244
|
+
# RGBA
|
|
245
|
+
@property
|
|
246
|
+
def RGB(self) :
|
|
247
|
+
return (self.R, self.G, self.B)
|
|
248
|
+
@property
|
|
249
|
+
def RGBA(self) :
|
|
250
|
+
return (self.R, self.G, self.B, int(self.alpha * 255))
|
|
251
|
+
|
|
252
|
+
# rgba
|
|
253
|
+
@property
|
|
254
|
+
def r(self) :
|
|
255
|
+
return self.R / 255
|
|
256
|
+
@property
|
|
257
|
+
def g(self) :
|
|
258
|
+
return self.G / 255
|
|
259
|
+
@property
|
|
260
|
+
def b(self) :
|
|
261
|
+
return self.B / 255
|
|
262
|
+
@property
|
|
263
|
+
def a(self) :
|
|
264
|
+
return self.A / 255
|
|
265
|
+
@property
|
|
266
|
+
def rgb(self) :
|
|
267
|
+
return (self.r, self.g, self.b)
|
|
268
|
+
@property
|
|
269
|
+
def rgba(self) :
|
|
270
|
+
return (self.r, self.g, self.b, self.a)
|
|
271
|
+
|
|
272
|
+
# greys
|
|
273
|
+
@property
|
|
274
|
+
def K(self) :
|
|
275
|
+
return int(0.299 * self.R + 0.587 * self.G + 0.114 * self.B)
|
|
276
|
+
@property
|
|
277
|
+
def k(self) :
|
|
278
|
+
return self.K / 255
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
#Complementary color
|
|
283
|
+
def __invert__(self) : # ~color
|
|
284
|
+
return Color(255-self.R, 255-self.G, 255-self.B, alpha=self.alpha)
|
|
285
|
+
|
|
286
|
+
#Play on transparency
|
|
287
|
+
def __mul__(self, alpha) : # color * alpha
|
|
288
|
+
return Color(*self.RGB, alpha=alpha)
|
|
289
|
+
def __pos__(self) : # +color
|
|
290
|
+
return Color(self.RGB, alpha=1)
|
|
291
|
+
def __neg__(self) : # -color
|
|
292
|
+
return Color(self.RGB, alpha=0)
|
|
293
|
+
|
|
294
|
+
# color mixing
|
|
295
|
+
def mix(self, other_color, other_fact=0.5) :
|
|
296
|
+
self_fact = 1 - other_fact
|
|
297
|
+
R = self.R * self_fact + other_color.R * other_fact
|
|
298
|
+
G = self.G * self_fact + other_color.G * other_fact
|
|
299
|
+
B = self.B * self_fact + other_color.B * other_fact
|
|
300
|
+
return Color(R, G, B, alpha=self.alpha)
|
|
301
|
+
#Desaturation
|
|
302
|
+
def desaturate(self, fact) : # desat [0-1]
|
|
303
|
+
gray = Color(self.K, self.K, self.K)
|
|
304
|
+
return self.mix(gray, fact)
|
|
305
|
+
#luminosity
|
|
306
|
+
def luminosity(self, fact) : # desat [-1, +1]
|
|
307
|
+
k = int(fact>=0) * 255
|
|
308
|
+
lum = Color(k, k, k)
|
|
309
|
+
return self.mix(lum, abs(fact))
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# %% Test function run
|
|
314
|
+
if __name__ == "__main__":
|
|
315
|
+
from corelp import test
|
|
316
|
+
test(__file__)
|