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,422 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from threading import Lock
6
+ from typing import Any, cast
7
+
8
+ import matplotlib as mpl
9
+ from matplotlib import rcParams
10
+ from rich.traceback import install
11
+
12
+ rcParams["pdf.fonttype"] = 42
13
+ rcParams["ps.fonttype"] = 42
14
+
15
+ # Legend with normal box (as V1)
16
+ rcParams["legend.fancybox"] = False
17
+ rcParams["legend.framealpha"] = None
18
+ rcParams["legend.edgecolor"] = "inherit"
19
+ rcParams["legend.frameon"] = False
20
+
21
+ # Nice round numbers on axis and 'tight' axis limits to data (as V1)
22
+ rcParams["axes.autolimit_mode"] = "round_numbers"
23
+ rcParams["axes.xmargin"] = 0
24
+ rcParams["axes.ymargin"] = 0
25
+
26
+ # Ticks as in mpl V1 (everywhere and inside)
27
+ rcParams["xtick.direction"] = "in"
28
+ rcParams["ytick.direction"] = "in"
29
+ rcParams["xtick.top"] = True
30
+ rcParams["ytick.right"] = True
31
+ rcParams["legend.labelspacing"] = 0.3
32
+
33
+ rcParams["font.family"] = "sans-serif"
34
+ rcParams["font.sans-serif"] = ["DejaVu Sans"]
35
+
36
+ rcParams["xtick.major.pad"] = 6
37
+ rcParams["ytick.major.pad"] = 6
38
+
39
+ __all__: list[str] = ["config_load", "config_dict", "config_entry_option"]
40
+
41
+
42
+ class Config:
43
+ """
44
+ A thread-safe singleton class for managing configuration data.
45
+
46
+ This class provides a centralized mechanism to load, retrieve, and manage
47
+ configuration settings. It ensures thread safety through a locking mechanism.
48
+
49
+ Attributes
50
+ --------------------
51
+ _instance : Config or None
52
+ The singleton instance of the `Config` class.
53
+ _lock : threading.Lock
54
+ A lock to ensure thread safety during singleton initialization.
55
+ _config_dict : dict of str, Any
56
+ The loaded configuration data.
57
+
58
+ Methods
59
+ --------------------
60
+ load(config_path=None)
61
+ Loads configuration data from a specified path or reloads the default configuration.
62
+ get_config_entry_option(key)
63
+ Retrieves a specific entry from the configuration dictionary based on the provided key.
64
+
65
+ Examples
66
+ --------------------
67
+ >>> config = Config()
68
+ >>> config_data = config.load("path/to/config.json")
69
+ >>> print(config_data)
70
+ {'setting1': 'value1', 'setting2': 'value2', 'setting3': {'setting4': 'value4'}}
71
+
72
+ >>> entry_option = config.get_config_entry_option("setting1")
73
+ >>> print(entry_option)
74
+ {'setting3': 'value3'}
75
+ """
76
+
77
+ _instance: Config | None = None
78
+ _lock: Lock = Lock()
79
+
80
+ def __new__(cls) -> "Config":
81
+ """
82
+ Ensures a single instance of the Config class (singleton pattern).
83
+
84
+ Returns
85
+ --------------------
86
+ Config
87
+ The singleton instance of the Config class.
88
+ """
89
+ with cls._lock:
90
+ if cls._instance is None:
91
+ cls._instance = super(Config, cls).__new__(cls)
92
+ cls._instance._initialize_config_dict()
93
+ return cls._instance
94
+
95
+ def _initialize_config_dict(self) -> None:
96
+ """
97
+ Initializes the configuration dictionary by loading default configuration data.
98
+ """
99
+ self._config_dict: dict[str, Any] = ConfigLoad().init_load()
100
+
101
+ @property
102
+ def config_dict(self) -> dict[str, Any]:
103
+ """
104
+ The configuration dictionary containing all loaded settings.
105
+
106
+ Returns
107
+ --------------------
108
+ dict of str, Any
109
+ The current configuration dictionary.
110
+ """
111
+ return self._config_dict
112
+
113
+ @config_dict.setter
114
+ def config_dict(self, config_dict: dict[str, Any]) -> None:
115
+ """
116
+ Sets a new configuration dictionary.
117
+
118
+ Parameters
119
+ --------------------
120
+ config_dict : dict of str, Any
121
+ The new configuration dictionary to set.
122
+ """
123
+ self._config_dict = config_dict
124
+
125
+ def load(self, config_path: str | None = None) -> dict[str, Any]:
126
+ """
127
+ Loads configuration data from a file or reloads the current configuration.
128
+
129
+ Parameters
130
+ --------------------
131
+ config_path : str or None, optional
132
+ The path to the configuration file. If `None`, reloads the existing configuration (default is None).
133
+
134
+ Returns
135
+ --------------------
136
+ dict of str, Any
137
+ The loaded configuration dictionary.
138
+
139
+ Examples
140
+ --------------------
141
+ >>> config = Config()
142
+ >>> config_data = config.load("path/to/config.json")
143
+ >>> print(config_data)
144
+ {'setting1': 'value1', 'setting2': 'value2'}
145
+ """
146
+ loader: ConfigLoad = ConfigLoad(config_path)
147
+ config_dict: dict[str, Any] = (
148
+ loader.init_load() if config_path else loader.get_config()
149
+ )
150
+ self.config_dict = config_dict
151
+ return config_dict
152
+
153
+ def get_config_entry_option(self, key: str) -> dict[str, Any]:
154
+ """
155
+ Retrieves a specific entry from the configuration dictionary.
156
+
157
+ Parameters
158
+ --------------------
159
+ key : str
160
+ The key for the configuration entry to retrieve.
161
+
162
+ Returns
163
+ --------------------
164
+ dict of str, Any
165
+ The configuration entry corresponding to the provided key.
166
+
167
+ Examples
168
+ --------------------
169
+ >>> config = Config()
170
+ >>> entry_option = config.get_config_entry_option("setting3")
171
+ >>> print(entry_option)
172
+ {'setting4': 'value4'}
173
+ """
174
+ entry_option: dict[str, Any] = self.config_dict.get(key, {})
175
+ return entry_option
176
+
177
+
178
+ class ConfigLoad:
179
+ """
180
+ A utility class for loading and applying configuration files.
181
+
182
+ This class handles the discovery of configuration file paths, loading configuration
183
+ data, and applying specific settings such as Matplotlib parameters (`rcParams`) and
184
+ rich traceback settings.
185
+
186
+ Attributes
187
+ --------------------
188
+ DEFAULT_CONFIG_NAME : str
189
+ The default name of the configuration file ("gsplot.json").
190
+ config_path : str or None
191
+ The resolved path to the configuration file, if found.
192
+
193
+ Parameters
194
+ --------------------
195
+ config_path : str or None, optional
196
+ The explicit path to the configuration file. If not provided, default
197
+ locations will be searched (default is None).
198
+
199
+ Methods
200
+ --------------------
201
+ find_config_path(config_path)
202
+ Resolves the configuration file path based on the provided path or default locations.
203
+ init_load()
204
+ Loads the configuration file and applies specific settings if present.
205
+ apply_rc_params(rc_params)
206
+ Applies Matplotlib `rcParams` settings from the configuration file.
207
+ get_config()
208
+ Reads and returns the configuration file as a dictionary.
209
+
210
+ Examples
211
+ --------------------
212
+ >>> loader = ConfigLoad()
213
+ >>> config = loader.init_load()
214
+ >>> print(config)
215
+ {'rcParams': {'figure.dpi': 100}, 'rich': {'traceback': {}}}
216
+ """
217
+
218
+ DEFAULT_CONFIG_NAME: str = "gsplot.json"
219
+
220
+ def __init__(self, config_path: str | None = None) -> None:
221
+ self.config_path: str | None = self.find_config_path(config_path)
222
+
223
+ def find_config_path(self, config_path: str | None) -> str | None:
224
+ """
225
+ Determines the configuration file path.
226
+
227
+ If a path is provided, it checks its existence. If no path is provided,
228
+ searches default locations for the configuration file.
229
+
230
+ Parameters
231
+ --------------------
232
+ config_path : str or None
233
+ The explicit path to the configuration file.
234
+
235
+ Returns
236
+ --------------------
237
+ str or None
238
+ The resolved configuration file path, or None if no file is found.
239
+
240
+ Raises
241
+ --------------------
242
+ FileNotFoundError
243
+ If the provided path does not exist.
244
+
245
+ Examples
246
+ --------------------
247
+ >>> loader = ConfigLoad(config_path="path/to/config.json")
248
+ >>> print(loader.config_path)
249
+ 'path/to/config.json'
250
+ """
251
+ if config_path:
252
+ if not os.path.exists(config_path):
253
+ raise FileNotFoundError(f"Configuration file not found: {config_path}")
254
+ return config_path
255
+
256
+ # Search in default locations
257
+ search_paths = [
258
+ os.getcwd(), # Current directory
259
+ os.path.join(
260
+ os.path.expanduser("~"), ".config", "gsplot"
261
+ ), # User config directory
262
+ os.path.expanduser("~"), # Home directory
263
+ ]
264
+
265
+ for path in search_paths:
266
+ potential_path = os.path.join(path, ConfigLoad.DEFAULT_CONFIG_NAME)
267
+ if os.path.exists(potential_path):
268
+ return potential_path
269
+ return None
270
+
271
+ def init_load(self) -> dict[str, Any]:
272
+ """
273
+ Loads the configuration file and applies specific settings if present.
274
+
275
+ This method reads the configuration file and applies Matplotlib `rcParams`
276
+ and rich traceback settings if they are defined in the configuration.
277
+
278
+ Returns
279
+ --------------------
280
+ dict of str, Any
281
+ The loaded configuration dictionary.
282
+
283
+ Examples
284
+ --------------------
285
+ >>> loader = ConfigLoad()
286
+ >>> config = loader.init_load()
287
+ >>> print(config)
288
+ {'rcParams': {'figure.dpi': 100}, 'rich': {'traceback': {}}}
289
+ """
290
+ config_dict: dict[str, Any] = self.get_config()
291
+ if "rcParams" in config_dict:
292
+ rc_params = config_dict["rcParams"]
293
+ self.apply_rc_params(rc_params)
294
+ if "rich" in config_dict:
295
+ if "traceback" in config_dict["rich"]:
296
+ traceback_params = config_dict["rich"]["traceback"]
297
+ install(**traceback_params)
298
+ return config_dict
299
+
300
+ @staticmethod
301
+ def apply_rc_params(rc_params: dict[str, Any]) -> None:
302
+ """
303
+ Applies Matplotlib `rcParams` settings from the configuration file.
304
+
305
+ Parameters
306
+ --------------------
307
+ rc_params : dict of str, Any
308
+ A dictionary of Matplotlib `rcParams` settings.
309
+
310
+ Examples
311
+ --------------------
312
+ >>> rc_params = {"figure.dpi": 100, "backend": "TkAgg"}
313
+ >>> ConfigLoad.apply_rc_params(rc_params)
314
+ """
315
+ backend = rc_params.pop("backends", None)
316
+ if backend:
317
+ mpl.use(backend)
318
+ rcParams.update(rc_params)
319
+
320
+ def get_config(self) -> dict[str, Any]:
321
+ """
322
+ Reads and returns the configuration file as a dictionary.
323
+
324
+ Returns
325
+ --------------------
326
+ dict of str, Any
327
+ The loaded configuration dictionary. Returns an empty dictionary if
328
+ no configuration file is found.
329
+
330
+ Examples
331
+ --------------------
332
+ >>> loader = ConfigLoad("path/to/config.json")
333
+ >>> config = loader.get_config()
334
+ >>> print(config)
335
+ {'rcParams': {'figure.dpi': 100}, 'rich': {'traceback': {}}}
336
+ """
337
+ if not self.config_path:
338
+ return {}
339
+ with open(self.config_path, "r") as f:
340
+ return cast(dict[str, Any], json.load(f))
341
+
342
+
343
+ def config_load(config_path: str | None = None) -> dict[str, Any]:
344
+ """
345
+ Loads the configuration data from a specified file or reloads the existing configuration.
346
+
347
+ This function initializes the `Config` singleton, loads the configuration file,
348
+ and returns the loaded configuration dictionary.
349
+
350
+ Parameters
351
+ --------------------
352
+ config_path : str or None, optional
353
+ The path to the configuration file. If `None`, the existing configuration is reloaded (default is None).
354
+
355
+ Returns
356
+ --------------------
357
+ dict of str, Any
358
+ The loaded configuration dictionary.
359
+
360
+ Examples
361
+ --------------------
362
+ >>> import gsplot as gs
363
+ >>> config_data = gs.config_load("path/to/config.json")
364
+ >>> print(config_data)
365
+ {'rcParams': {'figure.dpi': 100}, 'rich': {'traceback': {}}}
366
+ """
367
+ _config: Config = Config()
368
+ config_dict: dict[str, Any] = _config.load(config_path)
369
+ return config_dict
370
+
371
+
372
+ def config_dict() -> dict[str, Any]:
373
+ """
374
+ Retrieves the current configuration dictionary.
375
+
376
+ This function accesses the `Config` singleton and returns the configuration
377
+ dictionary currently in memory.
378
+
379
+ Returns
380
+ --------------------
381
+ dict of str, Any
382
+ The current configuration dictionary.
383
+
384
+ Examples
385
+ --------------------
386
+ >>> import gsplot as gs
387
+ >>> config_data = gs.config_dict()
388
+ >>> print(config_data)
389
+ {'rcParams': {'figure.dpi': 100}, 'rich': {'traceback': {}}}
390
+ """
391
+ _config: Config = Config()
392
+ config_dict: dict[str, Any] = _config.config_dict
393
+ return config_dict
394
+
395
+
396
+ def config_entry_option(key: str) -> dict[str, Any]:
397
+ """
398
+ Retrieves a specific entry from the configuration dictionary based on the provided key.
399
+
400
+ This function accesses the `Config` singleton and retrieves the configuration
401
+ entry associated with the given key.
402
+
403
+ Parameters
404
+ --------------------
405
+ key : str
406
+ The key for the configuration entry to retrieve.
407
+
408
+ Returns
409
+ --------------------
410
+ dict of str, Any
411
+ The configuration entry corresponding to the provided key.
412
+
413
+ Examples
414
+ --------------------
415
+ >>> import gsplot as gs
416
+ >>> entry_option = gs.config_entry_option("rcParams")
417
+ >>> print(entry_option)
418
+ {'figure.dpi': 100, 'backend': 'TkAgg'}
419
+ """
420
+ _config: Config = Config()
421
+ entry_option: dict[str, Any] = _config.get_config_entry_option(key)
422
+ return entry_option
@@ -0,0 +1,188 @@
1
+ from os import PathLike
2
+ from typing import Any, Iterable
3
+
4
+ import numpy as np
5
+ from numpy.typing import NDArray
6
+
7
+ from ..base.base import CreateClassParams, ParamsGetter, bind_passed_params
8
+
9
+ __all__: list[str] = ["load_file"]
10
+
11
+
12
+ class LoadFile:
13
+ """
14
+ A utility class to load data from a file or iterable source using NumPy's `genfromtxt`.
15
+
16
+ This class provides an interface for loading structured data from files or iterables
17
+ with options for handling delimiters, skipping headers/footers, and unpacking the data.
18
+
19
+ Parameters
20
+ --------------------
21
+ f : str, os.PathLike, Iterable[str], or Iterable[bytes]
22
+ The file path, file-like object, or iterable source from which to load data.
23
+ delimiter : str or None, optional
24
+ The string used to separate values. If `None`, any whitespace is treated as a delimiter (default is ",").
25
+ skip_header : int, optional
26
+ The number of lines to skip at the beginning of the file (default is 0).
27
+ skip_footer : int, optional
28
+ The number of lines to skip at the end of the file (default is 0).
29
+ unpack : bool, optional
30
+ Whether to unpack columns into separate arrays (default is True).
31
+ **kwargs : Any
32
+ Additional keyword arguments to pass to NumPy's `genfromtxt`.
33
+
34
+ Attributes
35
+ --------------------
36
+ f : str, os.PathLike, Iterable[str], or Iterable[bytes]
37
+ The file path, file-like object, or iterable source from which to load data.
38
+ delimiter : str or None
39
+ The string used to separate values.
40
+ skip_header : int
41
+ The number of lines to skip at the beginning of the file.
42
+ skip_footer : int
43
+ The number of lines to skip at the end of the file.
44
+ unpack : bool
45
+ Whether to unpack columns into separate arrays.
46
+ kwargs : Any
47
+ Additional arguments passed to `genfromtxt`.
48
+
49
+ Methods
50
+ --------------------
51
+ load_data()
52
+ Loads the data using NumPy's `genfromtxt` with the specified parameters.
53
+
54
+ Examples
55
+ --------------------
56
+ >>> loader = LoadFile("data.csv", delimiter=",", skip_header=1, unpack=False)
57
+ >>> data = loader.load_data()
58
+ >>> print(data)
59
+ array([[1.0, 2.0, 3.0],
60
+ [4.0, 5.0, 6.0],
61
+ [7.0, 8.0, 9.0]])
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ f: str | PathLike | Iterable[str] | Iterable[bytes],
67
+ delimiter: str | None = ",",
68
+ skip_header: int = 0,
69
+ skip_footer: int = 0,
70
+ unpack: bool = True,
71
+ **kwargs: Any,
72
+ ) -> None:
73
+
74
+ self.f: str | PathLike | Iterable[str] | Iterable[bytes] = f
75
+ self.delimiter: str | None = delimiter
76
+ self.skip_header: int = skip_header
77
+ self.skip_footer: int = skip_footer
78
+ self.unpack: bool = unpack
79
+ self.kwargs: Any = kwargs
80
+
81
+ def load_data(self) -> NDArray[Any]:
82
+ """
83
+ Loads the data using NumPy's `genfromtxt` with the specified parameters.
84
+
85
+ Returns
86
+ --------------------
87
+ numpy.ndarray
88
+ The loaded data as a NumPy array.
89
+
90
+ Raises
91
+ --------------------
92
+ ValueError
93
+ If the file cannot be loaded or parsed correctly.
94
+
95
+ Examples
96
+ --------------------
97
+ >>> loader = LoadFile("data.csv", delimiter=",", skip_header=1, unpack=False)
98
+ >>> data = loader.load_data()
99
+ >>> print(data)
100
+ array([[1.0, 2.0, 3.0],
101
+ [4.0, 5.0, 6.0],
102
+ [7.0, 8.0, 9.0]])
103
+ """
104
+
105
+ # np.genfromtxt does not have args parameter
106
+ return np.genfromtxt(
107
+ fname=self.f,
108
+ delimiter=self.delimiter,
109
+ skip_header=self.skip_header,
110
+ skip_footer=self.skip_footer,
111
+ unpack=self.unpack,
112
+ **self.kwargs,
113
+ )
114
+
115
+
116
+ @bind_passed_params()
117
+ def load_file(
118
+ f: str | PathLike | Iterable[str] | Iterable[bytes],
119
+ delimiter: str | None = ",",
120
+ skip_header: int = 0,
121
+ skip_footer: int = 0,
122
+ unpack: bool = True,
123
+ **kwargs: Any,
124
+ ) -> NDArray[Any]:
125
+ """
126
+ Loads structured data from a file or iterable source using the specified parameters.
127
+
128
+ This function provides a flexible interface for loading data with NumPy's `genfromtxt`.
129
+ It captures and processes the passed parameters, allowing for customized file loading
130
+ options, such as handling delimiters, skipping headers/footers, and unpacking columns.
131
+
132
+ Parameters
133
+ --------------------
134
+ f : str, os.PathLike, Iterable[str], or Iterable[bytes]
135
+ The file path, file-like object, or iterable source from which to load data.
136
+ delimiter : str or None, optional
137
+ The string used to separate values. If `None`, any whitespace is treated as a delimiter (default is ",").
138
+ skip_header : int, optional
139
+ The number of lines to skip at the beginning of the file (default is 0).
140
+ skip_footer : int, optional
141
+ The number of lines to skip at the end of the file (default is 0).
142
+ unpack : bool, optional
143
+ Whether to unpack columns into separate arrays (default is True).
144
+ **kwargs : Any
145
+ Additional keyword arguments to pass to NumPy's `genfromtxt`.
146
+
147
+ Notes
148
+ --------------------
149
+ This function utilizes the `ParamsGetter` to retrieve bound parameters and
150
+ the `CreateClassParams` class to handle the merging of default, configuration,
151
+ and passed parameters.
152
+
153
+ Returns
154
+ --------------------
155
+ numpy.ndarray
156
+ The loaded data as a NumPy array.
157
+
158
+ Raises
159
+ --------------------
160
+ ValueError
161
+ If the file cannot be loaded or parsed correctly.
162
+
163
+ Examples
164
+ --------------------
165
+ >>> import gsplot as gs
166
+ >>> data = gs.load_file("data.csv", delimiter=",", skip_header=1, unpack=False)
167
+ >>> print(data)
168
+ array([[1.0, 2.0, 3.0],
169
+ [4.0, 5.0, 6.0],
170
+ [7.0, 8.0, 9.0]])
171
+
172
+ >>> data = gs.load_file(["1,2,3", "4,5,6", "7,8,9"], delimiter=",", unpack=True)
173
+ >>> print(data)
174
+ [array([1.0, 4.0, 7.0]), array([2.0, 5.0, 8.0]), array([3.0, 6.0, 9.0])]
175
+ """
176
+
177
+ passed_params: dict[str, Any] = ParamsGetter("passed_params").get_bound_params()
178
+ class_params = CreateClassParams(passed_params).get_class_params()
179
+
180
+ _load_file: LoadFile = LoadFile(
181
+ class_params["f"],
182
+ class_params["delimiter"],
183
+ class_params["skip_header"],
184
+ class_params["skip_footer"],
185
+ class_params["unpack"],
186
+ **class_params["kwargs"],
187
+ )
188
+ return _load_file.load_data()