gsplot 0.0.4__tar.gz → 0.0.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.
Files changed (32) hide show
  1. {gsplot-0.0.4 → gsplot-0.0.6}/PKG-INFO +4 -4
  2. {gsplot-0.0.4 → gsplot-0.0.6}/README.md +3 -3
  3. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/__init__.py +5 -1
  4. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/config/config.py +179 -2
  5. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/logger.py +2 -0
  6. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/line.py +3 -1
  7. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/line_base.py +32 -45
  8. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/scatter.py +6 -2
  9. gsplot-0.0.6/gsplot/version.py +2 -0
  10. {gsplot-0.0.4 → gsplot-0.0.6}/pyproject.toml +1 -1
  11. gsplot-0.0.4/gsplot/version.py +0 -2
  12. {gsplot-0.0.4 → gsplot-0.0.6}/LICENSE +0 -0
  13. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/base/base.py +0 -0
  14. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/base/base_alias_validator.py +0 -0
  15. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/color/colormap.py +0 -0
  16. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/data/load_file.py +0 -0
  17. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/figure/axes.py +0 -0
  18. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/figure/axes_base.py +0 -0
  19. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/figure/figure_tools.py +0 -0
  20. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/figure/show.py +0 -0
  21. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/figure/store.py +0 -0
  22. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/hello_world/hello_world.py +0 -0
  23. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/path/path.py +0 -0
  24. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/line_colormap_base.py +0 -0
  25. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/line_colormap_dashed.py +0 -0
  26. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/line_colormap_solid.py +0 -0
  27. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/plot/scatter_colormap.py +0 -0
  28. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/style/graph.py +0 -0
  29. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/style/label.py +0 -0
  30. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/style/legend.py +0 -0
  31. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/style/legend_colormap.py +0 -0
  32. {gsplot-0.0.4 → gsplot-0.0.6}/gsplot/style/ticks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gsplot
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: General-scientific plot based on matplotlib
5
5
  Author: Giordano Mattoni
6
6
  Author-email: mattoni@scphys.kyoto-u.ac.jp
@@ -32,7 +32,7 @@ Description-Content-Type: text/markdown
32
32
  ----------------
33
33
 
34
34
  <p align="center" style="font-weight: bold; font-size: 1.2em; margin: 20px 0;">
35
- <a href="https://soichiroyamane.github.io/gsplot/" style="text-decoration: none;">Docs</a> |
35
+ <a href="https://soichiroyamane.github.io/gsplot/stable" style="text-decoration: none;">Docs</a> |
36
36
  <a href="#authors" style="text-decoration: none;">Authors</a> |
37
37
  <a href="#license" style="text-decoration: none;">License</a>
38
38
  </p>
@@ -48,13 +48,13 @@ Welcome to **gsplot** (general-scientific plot), a toolkit designed to enhance t
48
48
 
49
49
  ### 📈 Example using gsplot
50
50
 
51
- [See more details](https://soichiroyamane.github.io/gsplot/guides/demo/4_paper_plot.html)
51
+ [See more details](https://soichiroyamane.github.io/gsplot/guides/stable/demo/4_paper_plot.html)
52
52
 
53
53
  ![example](docs/_static/tutorial/SC_cal.png)
54
54
 
55
55
  ### 🌃 Example with Python REPL 🐍 and neovim 🌟
56
56
 
57
- [See more details](https://soichiroyamane.github.io/gsplot/guides/demo/13_REPL.html)
57
+ [See more details](https://soichiroyamane.github.io/gsplot/stable/guides/demo/13_REPL.html)
58
58
 
59
59
  ![repl_tutorial](./docs/_static/tutorial/repl_tutorial_sp.gif)
60
60
 
@@ -12,7 +12,7 @@
12
12
  ----------------
13
13
 
14
14
  <p align="center" style="font-weight: bold; font-size: 1.2em; margin: 20px 0;">
15
- <a href="https://soichiroyamane.github.io/gsplot/" style="text-decoration: none;">Docs</a> |
15
+ <a href="https://soichiroyamane.github.io/gsplot/stable" style="text-decoration: none;">Docs</a> |
16
16
  <a href="#authors" style="text-decoration: none;">Authors</a> |
17
17
  <a href="#license" style="text-decoration: none;">License</a>
18
18
  </p>
@@ -28,13 +28,13 @@ Welcome to **gsplot** (general-scientific plot), a toolkit designed to enhance t
28
28
 
29
29
  ### 📈 Example using gsplot
30
30
 
31
- [See more details](https://soichiroyamane.github.io/gsplot/guides/demo/4_paper_plot.html)
31
+ [See more details](https://soichiroyamane.github.io/gsplot/guides/stable/demo/4_paper_plot.html)
32
32
 
33
33
  ![example](docs/_static/tutorial/SC_cal.png)
34
34
 
35
35
  ### 🌃 Example with Python REPL 🐍 and neovim 🌟
36
36
 
37
- [See more details](https://soichiroyamane.github.io/gsplot/guides/demo/13_REPL.html)
37
+ [See more details](https://soichiroyamane.github.io/gsplot/stable/guides/demo/13_REPL.html)
38
38
 
39
39
  ![repl_tutorial](./docs/_static/tutorial/repl_tutorial_sp.gif)
40
40
 
@@ -1,6 +1,6 @@
1
1
  from .color.colormap import get_cmap
2
2
  from .config.config import (Config, config_dict, config_entry_option,
3
- config_load)
3
+ config_load, save_metadata)
4
4
  from .data.load_file import load_file
5
5
  from .figure.axes import axes
6
6
  from .figure.figure_tools import get_figure_size
@@ -33,6 +33,10 @@ Config()
33
33
  # ╰──────────────────────────────────────────────────────────╯
34
34
  logger()
35
35
 
36
+ # ╭──────────────────────────────────────────────────────────╮
37
+ # │ Save Metadata │
38
+ # ╰──────────────────────────────────────────────────────────╯
39
+ save_metadata()
36
40
 
37
41
  __version__ = __version__
38
42
  __commit__ = __commit__
@@ -2,13 +2,18 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
+ from datetime import datetime
5
6
  from threading import Lock
6
7
  from typing import Any, cast
7
8
 
8
9
  import matplotlib as mpl
10
+ import yaml
9
11
  from matplotlib import rcParams
10
12
  from rich.traceback import install
11
13
 
14
+ from ..path.path import PathToMain
15
+ from ..version import __commit__, __version__
16
+
12
17
  rcParams["pdf.fonttype"] = 42
13
18
  rcParams["ps.fonttype"] = 42
14
19
 
@@ -148,9 +153,14 @@ class Config:
148
153
  loader.init_load() if config_path else loader.get_config()
149
154
  )
150
155
  self.config_dict = config_dict
156
+
157
+ # Save metadata
158
+ metadata_store = MetadataStore()
159
+ metadata_store.create_metadata()
160
+
151
161
  return config_dict
152
162
 
153
- def get_config_entry_option(self, key: str) -> dict[str, Any]:
163
+ def get_config_entry_option(self, key: str) -> Any | dict[str, Any]:
154
164
  """
155
165
  Retrieves a specific entry from the configuration dictionary.
156
166
 
@@ -161,7 +171,7 @@ class Config:
161
171
 
162
172
  Returns
163
173
  --------------------
164
- dict of str, Any
174
+ Any and dict of str, Any
165
175
  The configuration entry corresponding to the provided key.
166
176
 
167
177
  Examples
@@ -420,3 +430,170 @@ def config_entry_option(key: str) -> dict[str, Any]:
420
430
  _config: Config = Config()
421
431
  entry_option: dict[str, Any] = _config.get_config_entry_option(key)
422
432
  return entry_option
433
+
434
+
435
+ class MetadataHistory:
436
+ def __init__(
437
+ self,
438
+ new_metadata: Any,
439
+ new_config: Any,
440
+ metadata_dir: str,
441
+ ) -> None:
442
+ self.new_metadata = new_metadata.copy()
443
+ self.new_config = new_config.copy()
444
+ self.metadata_dir = metadata_dir
445
+
446
+ self.needs_update = False
447
+
448
+ self.history: Any = {}
449
+ self.new_entry: Any = {}
450
+ self.history_dir = os.path.join(self.metadata_dir, "history")
451
+
452
+ def _get_old_metadata(self) -> None | Any:
453
+ if not os.path.exists(os.path.join(self.metadata_dir, "metadata.yml")):
454
+ return None
455
+
456
+ with open(os.path.join(self.metadata_dir, "metadata.yml"), "r") as file:
457
+ return yaml.safe_load(file)
458
+
459
+ def _get_old_config(self) -> None | Any:
460
+ if not os.path.exists(os.path.join(self.metadata_dir, "config.json")):
461
+ return None
462
+
463
+ with open(os.path.join(self.metadata_dir, "config.json"), "r") as file:
464
+ return json.load(file)
465
+
466
+ def _is_identical(self) -> None:
467
+ old_metadata = self._get_old_metadata()
468
+ old_config = self._get_old_config()
469
+
470
+ if not old_metadata or not old_config:
471
+ self.needs_update = True
472
+ return None
473
+
474
+ exclude_keys = ["date"]
475
+
476
+ def remove_keys(data: dict, keys: list) -> dict:
477
+ return {k: v for k, v in data.items() if k not in keys}
478
+
479
+ filtered_old_metadata = remove_keys(old_metadata, exclude_keys)
480
+ filtered_new_metadata = remove_keys(self.new_metadata, exclude_keys)
481
+
482
+ if filtered_old_metadata != filtered_new_metadata:
483
+ self.needs_update = True
484
+ return None
485
+
486
+ if old_config != self.new_config:
487
+ self.needs_update = True
488
+ return None
489
+
490
+ def _create_history_dir(self) -> None:
491
+ metadata_history_dir = os.path.join(self.history_dir)
492
+
493
+ if not os.path.exists(metadata_history_dir):
494
+ os.makedirs(metadata_history_dir)
495
+
496
+ def _read_history(self) -> Any:
497
+ self._create_history_dir()
498
+ history_file = os.path.join(self.history_dir, "history.txt")
499
+
500
+ if not os.path.exists(history_file):
501
+ return []
502
+
503
+ try:
504
+ with open(history_file, "r") as file:
505
+ return [json.loads(line) for line in file if line.strip()]
506
+ except Exception as e:
507
+ print(f"Error reading history file: {e}")
508
+ return []
509
+
510
+ def _create_new_history(self) -> None:
511
+ if not self.needs_update:
512
+ return None
513
+
514
+ self.history = self._read_history()
515
+
516
+ self.new_entry = self.new_metadata
517
+ self.new_entry["config"] = self.new_config
518
+
519
+ def _write_history(self) -> None:
520
+ history_file = os.path.join(self.history_dir, "history.txt")
521
+
522
+ with open(history_file, "a") as file:
523
+ json.dump(self.new_entry, file)
524
+ file.write("\n")
525
+
526
+ def create_history(self) -> None:
527
+ self._is_identical()
528
+ self._create_new_history()
529
+ if self.new_entry:
530
+ self._write_history()
531
+
532
+
533
+ class MetadataStore:
534
+ def __init__(
535
+ self,
536
+ ) -> None:
537
+ path_to_main = PathToMain()
538
+ self.main_dir = path_to_main.get_executed_file_dir()
539
+ self.meta_data_dir_name = ".gsplot"
540
+ self.meta_data_dir = os.path.join(
541
+ self.main_dir,
542
+ self.meta_data_dir_name,
543
+ )
544
+
545
+ self.date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
546
+ self.version = __version__
547
+ self.commit = __commit__
548
+
549
+ self.new_metadata = {
550
+ "date": self.date,
551
+ "version": self.version,
552
+ "commit": self.commit,
553
+ }
554
+
555
+ # get config dictionary
556
+ config = Config()
557
+ self.new_config_dict = config.config_dict
558
+ self.is_stored = config.get_config_entry_option("metadata")
559
+
560
+ def _create_metadata_dir(self) -> None:
561
+ if not os.path.exists(self.meta_data_dir):
562
+ os.makedirs(self.meta_data_dir)
563
+
564
+ def _create_new_metadata(self) -> None:
565
+
566
+ with open(os.path.join(self.meta_data_dir, "metadata.yml"), "w") as file:
567
+ yaml.dump(
568
+ self.new_metadata,
569
+ file,
570
+ default_flow_style=False,
571
+ sort_keys=False,
572
+ indent=2,
573
+ )
574
+
575
+ def _create_new_config(self) -> None:
576
+ with open(os.path.join(self.meta_data_dir, "config.json"), "w") as file:
577
+ # write config dictionary to file as json
578
+ json.dump(self.new_config_dict, file, indent=2)
579
+
580
+ def create_metadata(self) -> None:
581
+ if not self.is_stored:
582
+ return None
583
+
584
+ self._create_metadata_dir()
585
+
586
+ metadata_history = MetadataHistory(
587
+ new_metadata=self.new_metadata,
588
+ new_config=self.new_config_dict,
589
+ metadata_dir=self.meta_data_dir,
590
+ )
591
+ metadata_history.create_history()
592
+
593
+ self._create_new_metadata()
594
+ self._create_new_config()
595
+
596
+
597
+ def save_metadata() -> None:
598
+ _metadata = MetadataStore()
599
+ _metadata.create_metadata()
@@ -8,6 +8,8 @@ from rich.console import Console
8
8
  from rich.panel import Panel
9
9
  from rich.text import Text
10
10
 
11
+ from .config.config import Config
12
+ from .path.path import PathToMain
11
13
  from .version import __commit__, __version__
12
14
 
13
15
 
@@ -121,7 +121,9 @@ class Line:
121
121
  """
122
122
  Sets the colors for the line, marker edge, and marker face.
123
123
  """
124
- cycle_color: NDArray[Any] | str = AutoColor(self.axis_index).get_color()
124
+ # TODO: Remove next line
125
+ self.ax = self.axis
126
+ cycle_color: NDArray[Any] | str = AutoColor(self.ax).get_color()
125
127
  if isinstance(cycle_color, np.ndarray):
126
128
  cycle_color = colors.to_hex(
127
129
  tuple(cycle_color)
@@ -4,6 +4,7 @@ import threading
4
4
  from typing import Any, Callable, TypeVar, cast
5
5
 
6
6
  import numpy as np
7
+ from matplotlib.axes import Axes
7
8
  from numpy.typing import NDArray
8
9
 
9
10
  from ..color.colormap import Colormap
@@ -70,50 +71,36 @@ class NumLines:
70
71
 
71
72
  def _initialize_num_lines(self) -> None:
72
73
  """
73
- Initializes the line count to its default value ([0]).
74
+ Initializes the line count to its default dictionary ({}).
74
75
  """
75
76
  # Explicitly initialize the instance variable with a type hint
76
- self._num_lines: list[int] = [0]
77
-
78
- def update_num_lines(self, axis_index: int) -> None:
79
- """
80
- Ensures the line count list is large enough to include the given axis index.
81
-
82
- Parameters
83
- --------------------
84
- axis_index : int
85
- The index of the axis to update.
86
- """
87
- length = len(self._num_lines)
88
- if axis_index + 1 > length:
89
- self._num_lines.extend([0] * (axis_index - length + 1))
77
+ self._num_lines_dict: dict[Axes, int] = {}
90
78
 
91
79
  @property
92
- def num_lines(self) -> list[int]:
80
+ def num_lines_dict(self) -> dict[Axes, int]:
93
81
  """
94
- Retrieves the list of line counts for all axes.
82
+ Retrieves the dictionary containing the number of lines plotted on each axis.
95
83
 
96
84
  Returns
97
85
  --------------------
98
- list[int]
99
- The list of line counts, where each index corresponds to an axis.
86
+ dict[matplotlib.axes.Axes, int]
87
+ A dictionary where each key is an axis and the value is the number of lines plotted.
100
88
 
101
89
  Examples
102
90
  --------------------
103
91
  >>> num_lines = NumLines()
104
- >>> print(num_lines.num_lines)
105
- [0]
92
+ >>> print(num_lines.num_lines_dict)
106
93
  """
107
- return self._num_lines
94
+ return self._num_lines_dict
108
95
 
109
- def num_lines_axis(self, axis_index: int) -> int:
96
+ def num_lines(self, ax: Axes) -> int:
110
97
  """
111
98
  Retrieves the number of lines plotted on a specific axis.
112
99
 
113
100
  Parameters
114
101
  --------------------
115
- axis_index : int
116
- The index of the axis.
102
+ ax : matplotlib.axes.Axes
103
+ The axis to query.
117
104
 
118
105
  Returns
119
106
  --------------------
@@ -123,30 +110,29 @@ class NumLines:
123
110
  Examples
124
111
  --------------------
125
112
  >>> num_lines = NumLines()
126
- >>> print(num_lines.num_lines_axis(0))
127
- 0
113
+ >>> print(num_lines.num_lines_axis(axs[0]))
128
114
  """
129
- self.update_num_lines(axis_index)
130
- return self._num_lines[axis_index]
115
+ if ax not in self._num_lines_dict:
116
+ self._num_lines_dict[ax] = 0
117
+ return self._num_lines_dict[ax]
131
118
 
132
- def increment(self, axis_index: int) -> None:
119
+ def increment(self, ax: Axes) -> None:
133
120
  """
134
121
  Increments the line count for a specific axis.
135
122
 
136
123
  Parameters
137
124
  --------------------
138
- axis_index : int
139
- The index of the axis.
125
+ ax : matplotlib.axes.Axes
126
+ The axis to increment.
140
127
 
141
128
  Examples
142
129
  --------------------
143
130
  >>> num_lines = NumLines()
144
- >>> num_lines.increment(0)
145
- >>> print(num_lines.num_lines_axis(0))
146
- 1
131
+ >>> num_lines.increment(axs[1])
147
132
  """
148
- self.update_num_lines(axis_index)
149
- self._num_lines[axis_index] += 1
133
+ if ax not in self._num_lines_dict:
134
+ self._num_lines_dict[ax] = 0
135
+ self._num_lines_dict[ax] += 1
150
136
 
151
137
  @classmethod
152
138
  def count(cls, func: F) -> F:
@@ -169,14 +155,12 @@ class NumLines:
169
155
  ... def plot_line(axis_index):
170
156
  ... print(f"Plotting on axis {axis_index}")
171
157
  >>> plot_line(0)
172
- Plotting on axis 0
173
- >>> num_lines = NumLines()
174
- >>> print(num_lines.num_lines_axis(0))
175
- 1
176
158
  """
177
159
 
178
160
  def wrapper(self, *args: Any, **kwargs: Any) -> Any:
179
- cls().increment(self.axis_index)
161
+ # TODO: Remove next line
162
+ ax = self.axis
163
+ cls().increment(ax)
180
164
  result = func(self, *args, **kwargs)
181
165
  return result
182
166
 
@@ -240,15 +224,18 @@ class AutoColor:
240
224
  array([0.267004, 0.004874, 0.329415, 1.0]) # Example RGBA color from the colormap
241
225
  """
242
226
 
243
- def __init__(self, axis_index: int) -> None:
227
+ def __init__(self, ax) -> None:
228
+ self.ax: Axes = ax
244
229
  self.COLORMAP_LENGTH: int = 5
245
230
  self.CMAP = "viridis"
246
231
  self.colormap: NDArray[Any] = Colormap(
247
232
  cmap=self.CMAP, N=self.COLORMAP_LENGTH
248
233
  ).get_split_cmap()
249
234
 
250
- self.num_lines_axis: int = NumLines().num_lines_axis(axis_index)
251
- self.cycle_color_index: int = self.num_lines_axis % self.COLORMAP_LENGTH
235
+ _num_lines = NumLines()
236
+ self.num_lines: int = _num_lines.num_lines(self.ax)
237
+
238
+ self.cycle_color_index: int = self.num_lines % self.COLORMAP_LENGTH
252
239
 
253
240
  def get_color(self) -> NDArray[Any]:
254
241
  """
@@ -87,6 +87,8 @@ class Scatter:
87
87
  self.x: NDArray[Any] = np.array(self._x)
88
88
  self.y: NDArray[Any] = np.array(self._y)
89
89
 
90
+ self.color = self.get_color()
91
+
90
92
  def get_color(self) -> ColorType:
91
93
  """
92
94
  Determines the color for the scatter points.
@@ -109,7 +111,9 @@ class Scatter:
109
111
  >>> scatter = Scatter(axis_target=0, x=[1, 2], y=[3, 4])
110
112
  >>> scatter.get_color()
111
113
  """
112
- cycle_color: NDArray | str = AutoColor(self.axis_index).get_color()
114
+ # TODO: fix the next line
115
+ self.ax = self.axis
116
+ cycle_color: NDArray | str = AutoColor(self.ax).get_color()
113
117
  if isinstance(cycle_color, np.ndarray):
114
118
  cycle_color = colors.to_hex(
115
119
  tuple(cycle_color)
@@ -146,7 +150,7 @@ class Scatter:
146
150
  self.x,
147
151
  self.y,
148
152
  s=self.size,
149
- c=self.get_color(),
153
+ c=self.color,
150
154
  alpha=self.alpha,
151
155
  **self.kwargs,
152
156
  )
@@ -0,0 +1,2 @@
1
+ __version__ = '0.0.6'
2
+ __commit__ = 'c31bab11b951aabb64161cd75e0c34e7cd9c9164'
@@ -1,7 +1,7 @@
1
1
  [tool.poetry]
2
2
  name = "gsplot"
3
3
 
4
- version = "0.0.4"
4
+ version = "0.0.6"
5
5
 
6
6
  description = "General-scientific plot based on matplotlib"
7
7
  authors = [
@@ -1,2 +0,0 @@
1
- __version__ = '0.0.4'
2
- __commit__ = 'b4abb098ff682226095e5a00ef7c66de4e55b589'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes