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,66 @@
1
+ from typing import Any
2
+
3
+ from matplotlib import pyplot as plt
4
+ from numpy.typing import NDArray
5
+
6
+ __all__: list[str] = ["get_figure_size"]
7
+
8
+
9
+ class FigureLayout:
10
+ """
11
+ A utility class for retrieving the size of the current Matplotlib figure.
12
+
13
+ This class provides a method to get the size of the current figure in inches.
14
+
15
+ Methods
16
+ --------------------
17
+ get_figure_size()
18
+ Retrieves the size of the current figure in inches.
19
+
20
+ Examples
21
+ --------------------
22
+ >>> layout = FigureLayout()
23
+ >>> size = layout.get_figure_size()
24
+ >>> print(size)
25
+ array([10., 6.]) # Example output (width, height in inches)
26
+ """
27
+
28
+ def get_figure_size(self) -> NDArray[Any]:
29
+ """
30
+ Retrieves the size of the current Matplotlib figure in inches.
31
+
32
+ Returns
33
+ --------------------
34
+ numpy.ndarray
35
+ The width and height of the current figure in inches as a NumPy array.
36
+
37
+ Examples
38
+ --------------------
39
+ >>> layout = FigureLayout()
40
+ >>> size = layout.get_figure_size()
41
+ >>> print(size)
42
+ array([10., 6.]) # Example output (width, height in inches)
43
+ """
44
+ figure_size = plt.gcf().get_size_inches()
45
+ return figure_size
46
+
47
+
48
+ def get_figure_size() -> NDArray[Any]:
49
+ """
50
+ A convenient function to retrieve the size of the current Matplotlib figure.
51
+
52
+ This function is a shorthand for calling `FigureLayout().get_figure_size()`.
53
+
54
+ Returns
55
+ --------------------
56
+ numpy.ndarray
57
+ The width and height of the current figure in inches as a NumPy array.
58
+
59
+ Examples
60
+ --------------------
61
+ >>> import gsplot as gs
62
+ >>> size = gs.get_figure_size()
63
+ >>> print(size)
64
+ array([10., 6.]) # Example output (width, height in inches)
65
+ """
66
+ return FigureLayout().get_figure_size()
gsplot/figure/show.py ADDED
@@ -0,0 +1,205 @@
1
+ from typing import Any
2
+
3
+ import matplotlib.pyplot as plt
4
+
5
+ from ..base.base import CreateClassParams, ParamsGetter, bind_passed_params
6
+ from .store import StoreSingleton
7
+
8
+ __all__: list[str] = ["show"]
9
+
10
+
11
+ class Show:
12
+ """
13
+ A utility class for managing figure saving and displaying in Matplotlib.
14
+
15
+ This class provides functionality to save the current figure in multiple formats
16
+ and optionally display it.
17
+
18
+ Parameters
19
+ --------------------
20
+ name : str, optional
21
+ The base name for saved figure files (default is "gsplot").
22
+ ft_list : list of str, optional
23
+ A list of file formats for saving the figure (default is ["png", "pdf"]).
24
+ dpi : float, optional
25
+ The resolution (dots per inch) for saving the figure (default is 600).
26
+ show : bool, optional
27
+ Whether to display the figure (default is True).
28
+ *args : Any
29
+ Additional positional arguments passed to `plt.savefig`.
30
+ **kwargs : Any
31
+ Additional keyword arguments passed to `plt.savefig`.
32
+
33
+ Attributes
34
+ --------------------
35
+ name : str
36
+ The base name for saved figure files.
37
+ ft_list : list of str
38
+ A list of file formats for saving the figure.
39
+ dpi : float
40
+ The resolution for saving the figure.
41
+ show : bool
42
+ Whether to display the figure.
43
+ args : Any
44
+ Additional positional arguments passed to `plt.savefig`.
45
+ kwargs : Any
46
+ Additional keyword arguments passed to `plt.savefig`.
47
+ _store_singleton : StoreSingleton
48
+ A singleton instance for managing the storage state.
49
+
50
+ Methods
51
+ --------------------
52
+ store_fig()
53
+ Saves the current figure in the specified formats.
54
+ get_store()
55
+ Retrieves the storage state from the singleton instance.
56
+ show_fig()
57
+ Displays the current figure if `show` is True.
58
+
59
+ Examples
60
+ --------------------
61
+ >>> show_instance = Show(name="example", ft_list=["png", "jpg"], dpi=300, show=False)
62
+ >>> show_instance.store_fig()
63
+ >>> show_instance.show_fig() # Will not display the figure since `show=False`
64
+ """
65
+
66
+ def __init__(
67
+ self,
68
+ name: str = "gsplot",
69
+ ft_list: list[str] = ["png", "pdf"],
70
+ dpi: float = 600,
71
+ show: bool = True,
72
+ *args: Any,
73
+ **kwargs: Any,
74
+ ):
75
+
76
+ self.name: str = name
77
+ self.ft_list: list[str] = ft_list
78
+ self.dpi: float = dpi
79
+ self.show: bool = show
80
+ self.args: Any = args
81
+ self.kwargs: Any = kwargs
82
+
83
+ self._store_singleton: StoreSingleton = StoreSingleton()
84
+
85
+ def store_fig(self) -> None:
86
+ """
87
+ Saves the current figure in the specified formats.
88
+
89
+ This method uses the provided file formats and resolution to save the figure.
90
+
91
+ Raises
92
+ --------------------
93
+ Exception
94
+ If an error occurs during saving, a warning is printed.
95
+
96
+ Examples
97
+ --------------------
98
+ >>> show_instance = Show(name="example", ft_list=["png", "jpg"], dpi=300)
99
+ >>> show_instance.store_fig()
100
+ """
101
+ if self.get_store():
102
+ # save figure
103
+ fname_list: list[str] = [f"{self.name}.{ft}" for ft in self.ft_list]
104
+
105
+ # !TODO: figure out **kwargs for savefig. None, or *args, **kwargs
106
+ for fname in fname_list:
107
+ try:
108
+ plt.savefig(
109
+ fname,
110
+ bbox_inches="tight",
111
+ dpi=self.dpi,
112
+ *self.args,
113
+ **self.kwargs,
114
+ )
115
+ except Exception as e:
116
+ print(f"Error saving figure: {e}")
117
+ plt.savefig(fname, bbox_inches="tight", dpi=self.dpi)
118
+
119
+ def get_store(self) -> bool | int:
120
+ """
121
+ Retrieves the storage state from the singleton instance.
122
+
123
+ Returns
124
+ --------------------
125
+ bool or int
126
+ The storage state indicating whether saving is enabled.
127
+
128
+ Examples
129
+ --------------------
130
+ >>> show_instance = Show()
131
+ >>> print(show_instance.get_store())
132
+ True
133
+ """
134
+
135
+ store: bool | int = self._store_singleton.store
136
+ return store
137
+
138
+ def show_fig(self) -> None:
139
+ """
140
+ Displays the current figure if `show` is True.
141
+
142
+ Examples
143
+ --------------------
144
+ >>> show_instance = Show(show=True)
145
+ >>> show_instance.show_fig()
146
+ """
147
+ if self.show:
148
+ plt.show()
149
+
150
+
151
+ @bind_passed_params()
152
+ def show(
153
+ fname: str = "gsplot",
154
+ ft_list: list[str] = ["png", "pdf"],
155
+ dpi: float = 600,
156
+ show: bool = True,
157
+ *args: Any,
158
+ **kwargs: Any,
159
+ ) -> None:
160
+ """
161
+ A convenience function to save and optionally display a Matplotlib figure.
162
+
163
+ This function wraps the `Show` class for easier access and management of figure
164
+ saving and displaying.
165
+
166
+ Parameters
167
+ --------------------
168
+ fname : str, optional
169
+ The base name for saved figure files (default is "gsplot").
170
+ ft_list : list of str, optional
171
+ A list of file formats for saving the figure (default is ["png", "pdf"]).
172
+ dpi : float, optional
173
+ The resolution (dots per inch) for saving the figure (default is 600).
174
+ show : bool, optional
175
+ Whether to display the figure (default is True).
176
+ *args : Any
177
+ Additional positional arguments passed to `plt.savefig`.
178
+ **kwargs : Any
179
+ Additional keyword arguments passed to `plt.savefig`.
180
+
181
+ Notes
182
+ --------------------
183
+ This function utilizes the `ParamsGetter` to retrieve bound parameters and
184
+ the `CreateClassParams` class to handle the merging of default, configuration,
185
+ and passed parameters.
186
+
187
+ Examples
188
+ --------------------
189
+ >>> import gsplot as gs
190
+ >>> gs.show(fname="example", ft_list=["png", "jpg"], dpi=300, show=True)
191
+ """
192
+ passed_params: dict[str, Any] = ParamsGetter("passed_params").get_bound_params()
193
+ class_params = CreateClassParams(passed_params).get_class_params()
194
+
195
+ _show: Show = Show(
196
+ class_params["fname"],
197
+ class_params["ft_list"],
198
+ class_params["dpi"],
199
+ class_params["show"],
200
+ *class_params["args"],
201
+ **class_params["kwargs"],
202
+ )
203
+
204
+ _show.store_fig()
205
+ _show.show_fig()
gsplot/figure/store.py ADDED
@@ -0,0 +1,119 @@
1
+ from __future__ import annotations
2
+
3
+ import threading
4
+
5
+ __all__: list[str] = []
6
+
7
+
8
+ class StoreSingleton:
9
+ """
10
+ A thread-safe singleton class for managing a shared storage state.
11
+
12
+ This class ensures that a single instance is used to manage the storage state
13
+ across an application. The storage state can be a boolean or an integer (0 or 1),
14
+ providing flexibility for different use cases.
15
+
16
+ Attributes
17
+ --------------------
18
+ store : bool or int
19
+ The current storage state, which can be either a boolean or an integer (0 or 1).
20
+
21
+ Methods
22
+ --------------------
23
+ store
24
+ Retrieves the current storage state.
25
+ store(value)
26
+ Sets the storage state to a boolean or an integer (0 or 1).
27
+
28
+ Examples
29
+ --------------------
30
+ >>> singleton = StoreSingleton()
31
+ >>> print(singleton.store)
32
+ False # Default value
33
+
34
+ >>> singleton.store = True
35
+ >>> print(singleton.store)
36
+ True
37
+
38
+ >>> singleton.store = 1
39
+ >>> print(singleton.store)
40
+ 1
41
+
42
+ >>> singleton.store = "invalid" # Raises ValueError
43
+ Traceback (most recent call last):
44
+ ...
45
+ ValueError: Store must be a boolean or integer.
46
+ """
47
+
48
+ _instance: StoreSingleton | None = None
49
+ _lock: threading.Lock = threading.Lock() # Lock to ensure thread safety
50
+
51
+ def __new__(cls) -> "StoreSingleton":
52
+ with cls._lock:
53
+ if cls._instance is None:
54
+ cls._instance = super(StoreSingleton, cls).__new__(cls)
55
+ cls._instance._initialize_store()
56
+ return cls._instance
57
+
58
+ def _initialize_store(self) -> None:
59
+ """
60
+ Initializes the storage state to its default value (False).
61
+ """
62
+ # Explicitly initialize the instance variable with a type hint
63
+ self._store: bool | int = False
64
+
65
+ @property
66
+ def store(self) -> bool | int:
67
+ """
68
+ Retrieves the current storage state.
69
+
70
+ Returns
71
+ --------------------
72
+ bool or int
73
+ The current storage state.
74
+
75
+ Examples
76
+ --------------------
77
+ >>> singleton = StoreSingleton()
78
+ >>> print(singleton.store)
79
+ False
80
+ """
81
+ return self._store
82
+
83
+ @store.setter
84
+ def store(self, value: bool | int) -> None:
85
+ """
86
+ Sets the storage state.
87
+
88
+ Parameters
89
+ --------------------
90
+ value : bool or int
91
+ The new storage state. Must be a boolean or an integer (0 or 1).
92
+
93
+ Raises
94
+ --------------------
95
+ ValueError
96
+ If the value is not a boolean or integer, or if an integer is not 0 or 1.
97
+
98
+ Examples
99
+ --------------------
100
+ >>> singleton = StoreSingleton()
101
+ >>> singleton.store = True
102
+ >>> print(singleton.store)
103
+ True
104
+
105
+ >>> singleton.store = 1
106
+ >>> print(singleton.store)
107
+ 1
108
+
109
+ >>> singleton.store = "invalid" # Raises ValueError
110
+ Traceback (most recent call last):
111
+ ...
112
+ ValueError: Store must be a boolean or integer.
113
+ """
114
+ if not isinstance(value, (bool, int)):
115
+ raise ValueError("Store must be a boolean or integer.")
116
+ if isinstance(value, int) and value not in [0, 1]:
117
+ raise ValueError("Store must be 0 or 1 if integer.")
118
+
119
+ self._store = value
@@ -0,0 +1,23 @@
1
+ from rich import print
2
+
3
+ from ..version import __commit__, __version__
4
+
5
+ __all__ = ["hello_world"]
6
+
7
+
8
+ def hello_world() -> None:
9
+ """
10
+ Print the version, commit hash, and an ASCII art of the logo.
11
+ """
12
+ ascii_art = r"""
13
+ ██████╗ ███████╗██████╗ ██╗ ██████╗ ████████╗
14
+ ██╔════╝ ██╔════╝██╔══██╗██║ ██╔═══██╗╚══██╔══╝
15
+ ██║ ███╗███████╗██████╔╝██║ ██║ ██║ ██║
16
+ ██║ ██║╚════██║██╔═══╝ ██║ ██║ ██║ ██║
17
+ ╚██████╔╝███████║██║ ███████╗╚██████╔╝ ██║
18
+ ╚═════╝ ╚══════╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝
19
+ """
20
+
21
+ print(f"Version: {__version__}")
22
+ print(f"Commit : {__commit__}")
23
+ print(ascii_art)
gsplot/logger.py ADDED
@@ -0,0 +1,155 @@
1
+ import os
2
+ from datetime import datetime
3
+ from typing import Any, cast
4
+
5
+ import yaml
6
+ from rich import print
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+ from rich.text import Text
10
+
11
+ from .version import __commit__, __version__
12
+
13
+
14
+ class Logger:
15
+ HOME = os.path.expanduser("~")
16
+ LOG_PATH = os.path.join(HOME, ".config", "gsplot")
17
+ LOG_FILE_NAME = "gsplot_log.yml"
18
+ LOG_FILE_PATH = os.path.join(LOG_PATH, LOG_FILE_NAME)
19
+
20
+ def __init__(self):
21
+ self.console = Console()
22
+ self.log: dict[str, Any] = {}
23
+ self.version_idx: int | None = None
24
+ self.commit_idx: int | None = None
25
+
26
+ self.is_error: bool = False
27
+
28
+ self.create_file()
29
+ self.log = self.read_file()
30
+
31
+ def _create_empty_file(self):
32
+ with open(self.LOG_FILE_PATH, "w") as file:
33
+ file.write("{}")
34
+
35
+ def create_file(self):
36
+ if not os.path.exists(self.LOG_PATH):
37
+ os.makedirs(self.LOG_PATH)
38
+
39
+ # if YAML file does not exist, create it
40
+ if not os.path.exists(self.LOG_FILE_PATH):
41
+ self._create_empty_file()
42
+
43
+ def _init_log(self):
44
+ return {"versions": []}
45
+
46
+ def read_file(self) -> dict[str, Any]:
47
+ with open(self.LOG_FILE_PATH, "r") as file:
48
+ log = yaml.safe_load(file)
49
+
50
+ if not log or not log.get("versions"):
51
+ log = self._init_log()
52
+
53
+ return cast(dict[str, Any], log)
54
+
55
+ def get_date(self):
56
+ return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
57
+
58
+ def _error_message(self, e: Exception) -> None:
59
+ warning_message = f"[bold yellow]gsplot log file is corrupted. [bold green]See gsplot_log.yml file: {self.LOG_FILE_PATH}\n[bold red]Error: {e}"
60
+
61
+ self.console.print(
62
+ Panel(
63
+ Text.from_markup(warning_message),
64
+ title="[bold yellow]Warning",
65
+ style="bold yellow",
66
+ )
67
+ )
68
+
69
+ def _get_versions_from_log(self) -> list[dict[str, str]]:
70
+ try:
71
+ return cast(list[dict[str, str]], self.log.get("versions", []))
72
+ except Exception as e:
73
+ self.is_error = True
74
+ self._error_message(e)
75
+ return []
76
+
77
+ def _get_commits_from_version(self, version: str) -> list[dict[str, str]]:
78
+ try:
79
+ return next(
80
+ (
81
+ v.get("commits", [])
82
+ for v in self.log["versions"]
83
+ if v.get("version") == version
84
+ ),
85
+ [],
86
+ )
87
+ except Exception as e:
88
+ self.is_error = True
89
+ self._error_message(e)
90
+ return []
91
+
92
+ def _has_same_version(self, version: str) -> bool:
93
+ # Retrieve the list of versions from the log
94
+ versions: list[dict[str, str]] | None = self._get_versions_from_log()
95
+
96
+ if not versions:
97
+ return False
98
+
99
+ # Find the index of the version that matches the input
100
+ self.version_idx = next(
101
+ (i for i, v in enumerate(versions) if v.get("version") == version), None
102
+ )
103
+
104
+ # Return True if a match is found, otherwise False
105
+ return self.version_idx is not None
106
+
107
+ def _has_same_commit(self, commit: str) -> bool:
108
+ # Get commits from the version
109
+ commits: list[dict[str, str]] = self._get_commits_from_version(__version__)
110
+
111
+ if not commits:
112
+ return False
113
+
114
+ # Find the commit in the list of commits
115
+ self.commit_idx = next(
116
+ (i for i, c in enumerate(commits) if c.get("commit") == commit), None
117
+ )
118
+
119
+ # Return True if a match is found
120
+ return self.commit_idx is not None
121
+
122
+ def create_log(self):
123
+ if not self._has_same_version(__version__):
124
+ current = {
125
+ "version": __version__,
126
+ "commits": [{"commit": __commit__, "date": self.get_date()}],
127
+ }
128
+
129
+ self.log["versions"].append(current)
130
+ else:
131
+ if not self._has_same_commit(__commit__):
132
+ self.log["versions"][self.version_idx]["commits"].append(
133
+ {"commit": __commit__, "date": self.get_date()}
134
+ )
135
+
136
+ def write_log(self, log: dict[str, Any]) -> None:
137
+ with open(self.LOG_FILE_PATH, "w") as file:
138
+ yaml.dump(log, file, default_flow_style=False, sort_keys=False, indent=2)
139
+
140
+ def make_log(self) -> None:
141
+ if self.is_error:
142
+ return None
143
+
144
+ try:
145
+ self.create_log()
146
+ except Exception as e:
147
+ self.is_error = True
148
+ self._error_message(e)
149
+
150
+ self.write_log(self.log)
151
+
152
+
153
+ def logger():
154
+ _logger = Logger()
155
+ _logger.make_log()