gsplot 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
1
+ import inspect
2
+ from typing import Any
3
+
4
+ from ..config.config import Config
5
+
6
+ __all__: list[str] = []
7
+
8
+
9
+ class AliasValidator:
10
+ """
11
+ Validates alias mappings for function parameters and configuration options.
12
+
13
+ This class ensures that aliased parameters do not conflict with their original keys
14
+ in both function arguments and configuration entries. If an alias and its original
15
+ key are used simultaneously, an error is raised.
16
+
17
+ Parameters
18
+ --------------------
19
+ alias_map : dict of str, Any
20
+ A mapping of alias keys to their original parameter keys.
21
+ passed_params : dict of str, Any
22
+ The parameters explicitly passed to the function, including `kwargs`.
23
+
24
+ Attributes
25
+ --------------------
26
+ wrapped_func_name : str
27
+ The name of the wrapped function where the validation is performed.
28
+ alias_map : dict of str, Any
29
+ The mapping of alias keys to original parameter keys.
30
+ passed_params : dict of str, Any
31
+ The explicitly passed parameters, updated during validation.
32
+ config_entry_option : dict of str, Any
33
+ Configuration options for the wrapped function.
34
+
35
+ Methods
36
+ --------------------
37
+ get_wrapped_func_name()
38
+ Retrieves the name of the wrapped function.
39
+ get_config_entry_option()
40
+ Retrieves the configuration options for the wrapped function.
41
+ check_duplicate_kwargs()
42
+ Checks and resolves conflicts between alias keys and their original keys
43
+ in both `passed_params` and `config_entry_option`.
44
+ validate()
45
+ Performs the full validation by checking for duplicate aliases and resolving conflicts.
46
+
47
+ Examples
48
+ --------------------
49
+ >>> @bind_passed_params()
50
+ >>> def example_func(p1, p2, p3):
51
+ >>> passed_params: dict[str, Any] = ParamsGetter(
52
+ >>> "passed_params"
53
+ >>> ).get_bound_params()
54
+ >>> AliasValidator(alias_map, passed_params).validate()
55
+ >>> class_params: dict[str, Any] = CreateClassParams(passed_params).get_class_params()
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ alias_map: dict[str, Any],
61
+ passed_params: dict[str, Any],
62
+ ) -> None:
63
+ self.wrapped_func_name: str = self.get_wrapped_func_name()
64
+
65
+ self.alias_map: dict[str, Any] = alias_map
66
+ self.passed_params: dict[str, Any] = passed_params
67
+ self.config_entry_option: dict[str, Any] = self.get_config_entry_option()
68
+
69
+ def get_wrapped_func_name(self) -> str:
70
+ """
71
+ Retrieves the name of the wrapped function.
72
+
73
+ Returns
74
+ --------------------
75
+ str
76
+ The name of the wrapped function.
77
+
78
+ Raises
79
+ --------------------
80
+ Exception
81
+ If the current frame or its ancestors cannot be accessed.
82
+ """
83
+ current_frame = inspect.currentframe()
84
+
85
+ # Ensure that the frames to the wrapped function can be accessed.
86
+ if (
87
+ not current_frame
88
+ or not current_frame.f_back
89
+ or not current_frame.f_back.f_back
90
+ ):
91
+ raise Exception("Cannot get current frame")
92
+
93
+ wrapped_func_frame = current_frame.f_back.f_back
94
+
95
+ wrapped_func_name = wrapped_func_frame.f_code.co_name
96
+ return wrapped_func_name
97
+
98
+ def get_config_entry_option(self) -> dict[str, Any]:
99
+ """
100
+ Retrieves the configuration options for the wrapped function.
101
+
102
+ Returns
103
+ --------------------
104
+ dict of str, Any
105
+ The configuration options for the wrapped function.
106
+ """
107
+ config_entry_option: dict[str, Any] = Config().get_config_entry_option(
108
+ self.wrapped_func_name
109
+ )
110
+ return config_entry_option
111
+
112
+ def check_duplicate_kwargs(self):
113
+ """
114
+ Checks and resolves conflicts between alias keys and their original keys
115
+ in both `passed_params` and `config_entry_option`.
116
+
117
+ Raises
118
+ --------------------
119
+ ValueError
120
+ If an alias and its original key are used simultaneously in the
121
+ function call or configuration file.
122
+ """
123
+
124
+ def checker_passed_params():
125
+ for alias, key in self.alias_map.items():
126
+ if alias in self.passed_params["kwargs"]:
127
+ if key in self.passed_params:
128
+ raise ValueError(
129
+ f"The parameters '{alias}' and '{key}' cannot both be used simultaneously in the '{self.wrapped_func_name}' function."
130
+ )
131
+ self.passed_params[key] = self.passed_params["kwargs"][alias]
132
+ del self.passed_params["kwargs"][alias]
133
+
134
+ def checker_config_entry_option(config_entry_option: dict[str, Any]):
135
+ for alias, key in self.alias_map.items():
136
+ if alias in config_entry_option:
137
+ if key in config_entry_option:
138
+ raise ValueError(
139
+ f"The parameters '{alias}' and '{key}' cannot both be used simultaneously in the '{self.wrapped_func_name}' in the configuration file."
140
+ )
141
+ Config().config_dict[self.wrapped_func_name][key] = (
142
+ config_entry_option[alias]
143
+ )
144
+ del Config().config_dict[self.wrapped_func_name][alias]
145
+
146
+ # Check for duplicate kwargs in passed_params and config_entry_option
147
+ checker_passed_params()
148
+ checker_config_entry_option(self.config_entry_option)
149
+
150
+ def validate(self):
151
+ """
152
+ Performs the full validation by checking for duplicate aliases
153
+ and resolving conflicts in `passed_params` and `config_entry_option`.
154
+ """
155
+ self.check_duplicate_kwargs()
@@ -0,0 +1,218 @@
1
+ from typing import Any
2
+
3
+ import matplotlib as mpl
4
+ import numpy as np
5
+ from numpy.typing import ArrayLike, NDArray
6
+
7
+ from ..base.base import CreateClassParams, ParamsGetter, bind_passed_params
8
+
9
+ __all__: list[str] = ["get_cmap"]
10
+
11
+
12
+ class Colormap:
13
+ """
14
+ A utility class for managing and generating colormap data for visualization.
15
+
16
+ This class allows for the creation of normalized and reversed colormap arrays
17
+ using Matplotlib colormaps.
18
+
19
+ Attributes
20
+ --------------------
21
+ DEFAULT_N : int
22
+ The default number of evenly spaced values to generate when no colormap data
23
+ or number of points (N) is provided.
24
+ cmap : str
25
+ The name of the Matplotlib colormap to use.
26
+ cmap_data : numpy.ndarray
27
+ The array of colormap data, either generated or provided.
28
+ normalize : bool
29
+ Whether to normalize the colormap data.
30
+ reverse : bool
31
+ Whether to reverse the colormap data.
32
+
33
+ Parameters
34
+ --------------------
35
+ cmap : str, optional
36
+ The name of the Matplotlib colormap to use (default is "viridis").
37
+ N : int, optional
38
+ The number of evenly spaced values to generate for the colormap data.
39
+ If specified, `cmap_data` must be `None`.
40
+ cmap_data : array-like, optional
41
+ Custom colormap data to use. If specified, `N` must be `None`.
42
+ normalize : bool, optional
43
+ Whether to normalize the colormap data (default is True).
44
+ reverse : bool, optional
45
+ Whether to reverse the colormap data (default is False).
46
+
47
+ Methods
48
+ --------------------
49
+ get_split_cmap()
50
+ Generates the final colormap array, applying normalization and reversal if specified.
51
+ _initialize_cmap_data(N, cmap_data)
52
+ Initializes the colormap data based on the number of points or a custom array.
53
+ _normalize(ndarray)
54
+ Normalizes an array to the range [0, 1].
55
+
56
+ Examples
57
+ --------------------
58
+ >>> colormap = Colormap(cmap="plasma", N=5, normalize=True, reverse=True)
59
+ >>> print(colormap.get_split_cmap())
60
+ [[0.940015 0.975158 0.131326 1. ]
61
+ [0.647257 0.107541 0.508936 1. ]
62
+ [0.20803 0.05997 0.481219 1. ]
63
+ [0.069447 0.037392 0.283268 1. ]
64
+ [0.050383 0.029803 0.527975 1. ]]
65
+ """
66
+
67
+ DEFAULT_N: int = 10
68
+
69
+ def __init__(
70
+ self,
71
+ cmap: str = "viridis",
72
+ N: int | None = None,
73
+ cmap_data: ArrayLike | None = None,
74
+ normalize: bool = True,
75
+ reverse: bool = False,
76
+ ) -> None:
77
+
78
+ self.cmap: str = cmap
79
+ self.cmap_data: NDArray[Any] = self._initialize_cmap_data(N, cmap_data)
80
+ self.normalize: bool = normalize
81
+ self.reverse: bool = reverse
82
+
83
+ def _initialize_cmap_data(
84
+ self, N: int | None, cmap_data: ArrayLike | None
85
+ ) -> NDArray[Any]:
86
+ """
87
+ Initializes the colormap data based on the provided number of points or custom array.
88
+
89
+ Parameters
90
+ ----------
91
+ N : int, optional
92
+ The number of evenly spaced values to generate. If specified, `cmap_data` must be `None`.
93
+ cmap_data : array-like, optional
94
+ Custom colormap data to use. If specified, `N` must be `None`.
95
+
96
+ Returns
97
+ -------
98
+ numpy.ndarray
99
+ The initialized colormap data.
100
+
101
+ Raises
102
+ --------------------
103
+ ValueError
104
+ If both `N` and `cmap_data` are provided.
105
+ """
106
+ if N is not None and cmap_data is not None:
107
+ raise ValueError("Only one of N and ndarray can be specified.")
108
+ if N is not None:
109
+ return np.linspace(0, 1, N)
110
+ if cmap_data is not None:
111
+ return np.array(cmap_data)
112
+ return np.linspace(0, 1, self.DEFAULT_N)
113
+
114
+ def get_split_cmap(self) -> NDArray[Any]:
115
+ """
116
+ Generates the final colormap array, applying normalization and reversal if specified.
117
+
118
+ Returns
119
+ --------------------
120
+ numpy.ndarray
121
+ The final colormap array with RGBA values.
122
+ """
123
+ if self.normalize:
124
+ cmap_data = self._normalize(self.cmap_data)
125
+ else:
126
+ cmap_data = self.cmap_data
127
+ if self.reverse:
128
+ cmap_data = cmap_data[::-1]
129
+ return np.array(mpl.colormaps.get_cmap(self.cmap)(cmap_data))
130
+
131
+ @staticmethod
132
+ def _normalize(ndarray: NDArray[Any]) -> NDArray[Any]:
133
+ """
134
+ Normalizes an array to the range [0, 1].
135
+
136
+ Parameters
137
+ --------------------
138
+ ndarray : numpy.ndarray
139
+ The array to normalize.
140
+
141
+ Returns
142
+ --------------------
143
+ numpy.ndarray
144
+ The normalized array.
145
+ """
146
+ return np.array(
147
+ (ndarray - np.min(ndarray)) / (np.max(ndarray) - np.min(ndarray))
148
+ )
149
+
150
+
151
+ @bind_passed_params()
152
+ def get_cmap(
153
+ cmap: str = "viridis",
154
+ N: int | None = 10,
155
+ cmap_data: ArrayLike | None = None,
156
+ normalize: bool = True,
157
+ reverse: bool = False,
158
+ ) -> NDArray[Any]:
159
+ """
160
+ Generates a colormap array using the specified parameters.
161
+
162
+ This function provides a convenient interface to create and customize
163
+ colormaps using Matplotlib's colormap utilities. Parameters can be passed
164
+ directly or via a `Colormap` class.
165
+
166
+ Parameters
167
+ --------------------
168
+ cmap : str, optional
169
+ The name of the Matplotlib colormap to use (default is "viridis").
170
+ N : int or None, optional
171
+ The number of evenly spaced values to generate for the colormap data.
172
+ If `None`, `cmap_data` must be provided (default is 10).
173
+ cmap_data : array-like or None, optional
174
+ Custom colormap data to use. If specified, `N` must be `None` (default is None).
175
+ normalize : bool, optional
176
+ Whether to normalize the colormap data to the range [0, 1] (default is True).
177
+ reverse : bool, optional
178
+ Whether to reverse the colormap data (default is False).
179
+
180
+ Notes
181
+ --------------------
182
+ This function utilizes the `ParamsGetter` to retrieve bound parameters and
183
+ the `CreateClassParams` class to handle the merging of default, configuration,
184
+ and passed parameters.
185
+
186
+ Returns
187
+ --------------------
188
+ numpy.ndarray
189
+ The generated colormap array as an RGBA numpy array.
190
+
191
+ Raises
192
+ --------------------
193
+ ValueError
194
+ If both `N` and `cmap_data` are provided simultaneously.
195
+
196
+ Examples
197
+ --------------------
198
+ >>> import gsplot as gs
199
+ >>> colormap_array = gs.get_cmap(cmap="plasma", N=5, normalize=True, reverse=True)
200
+ >>> print(colormap_array)
201
+ [[0.940015 0.975158 0.131326 1. ]
202
+ [0.647257 0.107541 0.508936 1. ]
203
+ [0.20803 0.05997 0.481219 1. ]
204
+ [0.069447 0.037392 0.283268 1. ]
205
+ [0.050383 0.029803 0.527975 1. ]]
206
+ """
207
+ passed_params: dict[str, Any] = ParamsGetter("passed_params").get_bound_params()
208
+ class_params = CreateClassParams(passed_params).get_class_params()
209
+
210
+ _colormap: Colormap = Colormap(
211
+ class_params["cmap"],
212
+ class_params["N"],
213
+ class_params["cmap_data"],
214
+ class_params["normalize"],
215
+ class_params["reverse"],
216
+ )
217
+
218
+ return _colormap.get_split_cmap()