mayutils 1.2.0__tar.gz → 1.2.2__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 (68) hide show
  1. {mayutils-1.2.0 → mayutils-1.2.2}/PKG-INFO +3 -1
  2. {mayutils-1.2.0 → mayutils-1.2.2}/pyproject.toml +7 -1
  3. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/__init__.py +1 -0
  4. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/live.py +26 -2
  5. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/benchmarking.py +1 -1
  6. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/logging.py +6 -6
  7. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/interfaces/google.py +20 -13
  8. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/interfaces/microsoft.py +30 -0
  9. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/colours.py +6 -1
  10. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/dataframes.py +10 -7
  11. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/datetime.py +7 -5
  12. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/decorators.py +1 -1
  13. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/functions.py +4 -1
  14. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/scripts/versioning.py +1 -1
  15. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/plotly/charts.py +89 -31
  16. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/plotly/traces.py +1 -3
  17. mayutils-1.2.0/src/mayutils/.DS_Store +0 -0
  18. mayutils-1.2.0/src/mayutils/data/.DS_Store +0 -0
  19. mayutils-1.2.0/src/mayutils/data/queries/.DS_Store +0 -0
  20. mayutils-1.2.0/src/mayutils/scripts/.DS_Store +0 -0
  21. mayutils-1.2.0/src/mayutils/visualisation/.DS_Store +0 -0
  22. {mayutils-1.2.0 → mayutils-1.2.2}/LICENSE +0 -0
  23. {mayutils-1.2.0 → mayutils-1.2.2}/README.md +0 -0
  24. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/core/__init__.py +0 -0
  25. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/core/constants.py +0 -0
  26. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/__init__.py +0 -0
  27. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/analysis/__init__.py +0 -0
  28. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/cache/.gitkeep +0 -0
  29. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/local.py +0 -0
  30. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/queries/.gitkeep +0 -0
  31. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/queries/__init__.py +0 -0
  32. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/queries/examples/.gitkeep +0 -0
  33. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/data/read.py +0 -0
  34. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/__init__.py +0 -0
  35. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/databases.py +0 -0
  36. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/filesystem.py +0 -0
  37. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/memoisation.py +0 -0
  38. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/oauth.py +0 -0
  39. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/environment/webdrivers.py +0 -0
  40. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/export/__init__.py +0 -0
  41. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/export/images.py +0 -0
  42. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/export/pdf.py +0 -0
  43. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/export/slides.py +0 -0
  44. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/interfaces/__init__.py +0 -0
  45. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/interfaces/streamlit.py +0 -0
  46. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/mathematics/__init__.py +0 -0
  47. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/mathematics/numba.py +0 -0
  48. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/mathematics/numpy.py +0 -0
  49. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/__init__.py +0 -0
  50. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/classes.py +0 -0
  51. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/dictionaries.py +0 -0
  52. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/hashing.py +0 -0
  53. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/numbers.py +0 -0
  54. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/strings.py +0 -0
  55. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/objects/types.py +0 -0
  56. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/scripts/__init__.py +0 -0
  57. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/scripts/clear_cache.py +0 -0
  58. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/testing/__init__.py +0 -0
  59. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/__init__.py +0 -0
  60. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/console.py +0 -0
  61. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/__init__.py +0 -0
  62. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/combine.py +0 -0
  63. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/matplotlib/__init__.py +0 -0
  64. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/matplotlib/template.py +0 -0
  65. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/plotly/__init__.py +0 -0
  66. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/plotly/templates.py +0 -0
  67. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/graphs/plotly/utilities.py +0 -0
  68. {mayutils-1.2.0 → mayutils-1.2.2}/src/mayutils/visualisation/notebook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mayutils
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: Utilities for Python from Mayuran Visakan
5
5
  Author: Mayuran Visakan
6
6
  Author-email: Mayuran Visakan <mayuran.k.v@gmail.com>
@@ -48,6 +48,7 @@ Requires-Dist: numba>=0.62.0rc1
48
48
  Requires-Dist: numpy>=2.3.2
49
49
  Requires-Dist: numpy-financial>=1.0.0
50
50
  Requires-Dist: pandas>=2.3.2
51
+ Requires-Dist: pandas-stubs>=2.3.2.250827
51
52
  Requires-Dist: pathlib>=1.0.1
52
53
  Requires-Dist: pendulum[test]>=3.1.0
53
54
  Requires-Dist: pillow>=11.3.0
@@ -71,6 +72,7 @@ Requires-Dist: snowflake-sqlalchemy>=1.7.6
71
72
  Requires-Dist: sqlalchemy>=2.0.43
72
73
  Requires-Dist: streamlit>=1.49.0
73
74
  Requires-Dist: typer>=0.16.1
75
+ Requires-Dist: types-six>=1.17.0.20250515
74
76
  Requires-Dist: unicodeit>=0.7.5
75
77
  Requires-Dist: ruff>=0.9.6 ; extra == 'dev'
76
78
  Requires-Dist: mypy>=1.15.0 ; extra == 'dev'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mayutils"
3
- version = "1.2.0"
3
+ version = "1.2.2"
4
4
  description = "Utilities for Python from Mayuran Visakan"
5
5
  authors = [
6
6
  { name = "Mayuran Visakan", email = "mayuran.k.v@gmail.com" }
@@ -32,6 +32,7 @@ dependencies = [
32
32
  "numpy>=2.3.2",
33
33
  "numpy-financial>=1.0.0",
34
34
  "pandas>=2.3.2",
35
+ "pandas-stubs>=2.3.2.250827",
35
36
  "pathlib>=1.0.1",
36
37
  "pendulum[test]>=3.1.0",
37
38
  "pillow>=11.3.0",
@@ -55,6 +56,7 @@ dependencies = [
55
56
  "sqlalchemy>=2.0.43",
56
57
  "streamlit>=1.49.0",
57
58
  "typer>=0.16.1",
59
+ "types-six>=1.17.0.20250515",
58
60
  "unicodeit>=0.7.5",
59
61
  ]
60
62
 
@@ -73,6 +75,10 @@ generate_encryption_key = "mayutils.environment.oauth:generate_fernet_key"
73
75
  [tool.uv]
74
76
  prerelease = "if-necessary-or-explicit"
75
77
 
78
+ [tool.pyright]
79
+ venvPath = "."
80
+ venv = ".venv"
81
+
76
82
  [build-system]
77
83
  requires = ["uv_build>=0.8.14,<0.9.0"]
78
84
  build-backend = "uv_build"
@@ -16,6 +16,7 @@ def setup(
16
16
  try:
17
17
  from mayutils.objects.dataframes import setup_dataframes
18
18
  from mayutils.visualisation.notebook import setup_notebooks
19
+ import mayutils.visualisation.graphs.plotly.templates # noqa: F401
19
20
 
20
21
  setup_notebooks()
21
22
  setup_dataframes()
@@ -18,7 +18,7 @@ class LiveData(object):
18
18
  - Data is stored in a pandas DataFrame
19
19
  """
20
20
 
21
- def __init__(
21
+ def _initialise(
22
22
  self,
23
23
  query_string: str,
24
24
  engine: EngineWrapper,
@@ -61,6 +61,30 @@ class LiveData(object):
61
61
 
62
62
  return None
63
63
 
64
+ def __init__(
65
+ self,
66
+ query_string: str,
67
+ engine: EngineWrapper,
68
+ index_column: str,
69
+ start_timestamp: datetime,
70
+ rolling: bool = True,
71
+ aggregations: dict[str, Callable[[DataFrame], DataFrame]] = {},
72
+ update_frequency: Optional[timedelta] = None,
73
+ time_format: str = "%Y-%m-%d",
74
+ **format_kwargs,
75
+ ) -> None:
76
+ return self._initialise(
77
+ query_string=query_string,
78
+ engine=engine,
79
+ index_column=index_column,
80
+ start_timestamp=start_timestamp,
81
+ rolling=rolling,
82
+ aggregations=aggregations,
83
+ update_frequency=update_frequency,
84
+ time_format=time_format,
85
+ **format_kwargs,
86
+ )
87
+
64
88
  def update(
65
89
  self,
66
90
  engine: Optional[EngineWrapper] = None,
@@ -118,7 +142,7 @@ class LiveData(object):
118
142
  self,
119
143
  start_timestamp: Optional[datetime] = None,
120
144
  ) -> Self:
121
- self.__init__(
145
+ self._initialise(
122
146
  query_string=self.query_string,
123
147
  engine=self.engine,
124
148
  index_column=self.index_column,
@@ -33,7 +33,7 @@ def timing(
33
33
 
34
34
  length = end - start
35
35
 
36
- logger.log(
36
+ logger.report(
37
37
  f"{func.__name__} took {length:.4f} seconds",
38
38
  show=show,
39
39
  )
@@ -117,7 +117,7 @@ class Logger(logging.Logger):
117
117
 
118
118
  return cls.clone(logger=logger)
119
119
 
120
- def log(
120
+ def report(
121
121
  self,
122
122
  *msgs: str,
123
123
  sep: str = " ",
@@ -176,7 +176,7 @@ def _log(
176
176
  *args,
177
177
  **kwargs,
178
178
  ) -> Any:
179
- logger.log(
179
+ logger.report(
180
180
  f"Calling function: {func.__name__}",
181
181
  level=level,
182
182
  show=show,
@@ -189,7 +189,7 @@ def _log(
189
189
  **kwargs,
190
190
  )
191
191
  end = time.perf_counter()
192
- logger.log(
192
+ logger.report(
193
193
  f"Function {func.__name__} returned ({end - start:.2f}s): {result}",
194
194
  level=level,
195
195
  show=show,
@@ -198,7 +198,7 @@ def _log(
198
198
  return result
199
199
  except Exception as exception:
200
200
  end = time.perf_counter()
201
- logger.log(
201
+ logger.report(
202
202
  f"Function {func.__name__} raised an exception ({end - start:.2f}s): {exception}",
203
203
  level=logging.ERROR,
204
204
  exc_info=True,
@@ -243,13 +243,13 @@ def log(
243
243
  raise ValueError("No target provided")
244
244
  if isinstance(target, type):
245
245
  return _log_class(
246
- cls=target,
246
+ target,
247
247
  *args,
248
248
  **kwargs,
249
249
  )
250
250
  else:
251
251
  return _log(
252
- func=target,
252
+ target,
253
253
  *args,
254
254
  **kwargs,
255
255
  )
@@ -677,6 +677,11 @@ class Slides(object):
677
677
  if y_shift is None:
678
678
  y_shift = self.height * 0.05
679
679
 
680
+ theme_color = ""
681
+ parsed_colour = Colour(0, 0, 0)
682
+ theme_background_color = ""
683
+ parsed_background_colour = Colour(0, 0, 0)
684
+
680
685
  if colour is not None and not isinstance(colour, Colour):
681
686
  if colour.startswith("theme-"):
682
687
  theme_color = colour[len("theme-") :]
@@ -695,7 +700,7 @@ class Slides(object):
695
700
  f"Slide number {slide_number} is out of range. Presentation has {len(self.slides)} slides."
696
701
  )
697
702
 
698
- requests = [
703
+ requests: list[dict[str, Any]] = [
699
704
  {
700
705
  "createShape": {
701
706
  "objectId": element_id,
@@ -747,20 +752,22 @@ class Slides(object):
747
752
  "foregroundColor": (
748
753
  {}
749
754
  if colour is None
750
- else {
751
- "opaqueColor": {
752
- "rgbColor": {
753
- "red": parsed_colour.r / 255,
754
- "green": parsed_colour.g / 255,
755
- "blue": parsed_colour.b / 255,
755
+ else (
756
+ {
757
+ "opaqueColor": {
758
+ "rgbColor": {
759
+ "red": parsed_colour.r / 255,
760
+ "green": parsed_colour.g / 255,
761
+ "blue": parsed_colour.b / 255,
762
+ }
756
763
  }
757
764
  }
758
- }
759
- if not (
760
- isinstance(colour, str)
761
- and colour.startswith("theme-")
765
+ if not (
766
+ isinstance(colour, str)
767
+ and colour.startswith("theme-")
768
+ )
769
+ else {"themeColor": theme_color}
762
770
  )
763
- else {"themeColor": theme_color}
764
771
  )
765
772
  }
766
773
  if colour
@@ -1510,7 +1517,7 @@ class Sheets(object):
1510
1517
  ]:
1511
1518
  raise ValueError(f"Sheet title {new_title} is already used")
1512
1519
 
1513
- sheet_properties = {}
1520
+ sheet_properties: dict[str, str | int] = {}
1514
1521
  if to_position is not None:
1515
1522
  sheet_properties["index"] = target_index
1516
1523
 
@@ -49,6 +49,12 @@ class Presentation:
49
49
  len(self.internal.slide_layouts) - 1
50
50
  ]
51
51
 
52
+ # TODO: Implement display/__repr__/_repr_mimebundle_
53
+ # def __repr__(
54
+ # self,
55
+ # text: str,
56
+ # ) -> Self:
57
+
52
58
  @property
53
59
  def layouts(
54
60
  self,
@@ -89,6 +95,12 @@ class Presentation:
89
95
  ) -> None:
90
96
  self.internal.slide_width = value
91
97
 
98
+ # TODO: Implement
99
+ # @property
100
+ # def title(
101
+ # self,
102
+ # ) -> str:
103
+
92
104
  @property
93
105
  def slides(
94
106
  self,
@@ -306,6 +318,24 @@ class Presentation:
306
318
 
307
319
  return self
308
320
 
321
+ # TODO: Implement
322
+ # def insert_markdown(
323
+ # self,
324
+ # text: str,
325
+ # ) -> Self:
326
+
327
+ # TODO: Implement
328
+ # def insert_image(
329
+ # self,
330
+ # image_path: Path | str,
331
+ # ) -> Self:
332
+
333
+ # TODO: Implement
334
+ # def insert_table(
335
+ # self,
336
+ # table: DataFrame | Styler,
337
+ # ) -> Self:
338
+
309
339
  def save(
310
340
  self,
311
341
  file_path: Path | str,
@@ -138,7 +138,12 @@ class Colour:
138
138
  rgb = getrgb(colour)
139
139
  opacity = rgb[3] if len(rgb) == 4 else opacity
140
140
 
141
- return cls(*rgb[:3], a=opacity)
141
+ return cls(
142
+ r=rgb[0],
143
+ g=rgb[1],
144
+ b=rgb[2],
145
+ a=opacity,
146
+ )
142
147
 
143
148
  def set_opacity(
144
149
  self,
@@ -243,7 +243,6 @@ class DataframeUtilsAccessor(object):
243
243
  def save(
244
244
  self,
245
245
  path: Path | str,
246
- *args,
247
246
  **kwargs,
248
247
  ) -> Path:
249
248
  path = Path(path)
@@ -251,22 +250,25 @@ class DataframeUtilsAccessor(object):
251
250
  if path.suffix in [".png", ".jpeg", ".jpg", ".pdf", ".svg", ".eps"]:
252
251
  return self.styler.save(
253
252
  path=path,
254
- *args,
255
253
  **kwargs,
256
254
  )
255
+
257
256
  elif path.suffix == ".parquet":
258
257
  self.df.to_parquet(
259
258
  path=path,
260
259
  index=True,
261
260
  )
261
+
262
262
  elif path.suffix == ".feather":
263
263
  raise NotImplementedError("Feather not implemented")
264
264
  self.df.to_feather(path)
265
+
265
266
  elif path.suffix == ".csv":
266
267
  self.df.to_csv(
267
268
  path_or_buf=path,
268
269
  index=True,
269
270
  )
271
+
270
272
  elif path.suffix == ".xlsx":
271
273
  with ExcelWriter(path=path) as excel_writer:
272
274
  self.df.to_excel(
@@ -379,21 +381,22 @@ class DataframeUtilsAccessor(object):
379
381
  return to_datetime(series, format=date_format).dt.date
380
382
  elif datetime_type == "time":
381
383
  return to_datetime(series, format=time_format).dt.time
382
- else:
383
- raise ValueError(f"Unknown datetime_type: {datetime_type}")
384
+
385
+ raise ValueError(f"Unknown datetime_type: {datetime_type}")
384
386
 
385
387
  for col, dtype in mapper.items():
386
388
  try:
387
389
  self.df[col] = (
388
390
  convert_datetime(
389
- series=self.df[col],
391
+ series=self.df.loc[:, col],
390
392
  datetime_type=dtype, # type: ignore
391
393
  )
392
394
  if dtype in ["datetime", "date", "time"]
393
- else to_numeric(self.df[col])
395
+ else to_numeric(self.df.loc[:, col])
394
396
  if dtype == "numeric"
395
- else self.df[col].astype(dtype) # type: ignore
397
+ else self.df.loc[:, col].astype(dtype) # type: ignore
396
398
  )
399
+
397
400
  except (
398
401
  KeyError,
399
402
  ValueError,
@@ -268,7 +268,7 @@ class DateTime(BaseDateTime):
268
268
  )
269
269
 
270
270
  @classmethod
271
- def naive(
271
+ def as_naive(
272
272
  cls,
273
273
  year: int,
274
274
  month: int,
@@ -390,13 +390,15 @@ class Interval(BaseInterval):
390
390
  def start(
391
391
  self,
392
392
  ) -> DateTime:
393
- return self._start if not (self._invert and self._absolute) else self._end
393
+ return DateTime.from_base(super().start)
394
+ # return self._start if not (self._invert and self._absolute) else self._end
394
395
 
395
396
  @property
396
397
  def end(
397
398
  self,
398
399
  ) -> DateTime:
399
- return self._end if not (self._invert and self._absolute) else self._start
400
+ return DateTime.from_base(super().end)
401
+ # return self._end if not (self._invert and self._absolute) else self._start
400
402
 
401
403
  @classmethod
402
404
  def from_base(
@@ -440,8 +442,8 @@ class Intervals(object):
440
442
  def sort(
441
443
  self,
442
444
  ) -> Self:
443
- self.intervals = sorted(
444
- self.intervals, key=lambda interval: (interval.start, interval.end)
445
+ self.intervals = tuple(
446
+ sorted(self.intervals, key=lambda interval: (interval.start, interval.end))
445
447
  )
446
448
 
447
449
  return self
@@ -28,7 +28,7 @@ def flexwrap(
28
28
  def true_deco(
29
29
  func: T,
30
30
  ) -> T:
31
- decorated_func = update_wrapper(
31
+ decorated_func: T = update_wrapper( # type: ignore[assignment]
32
32
  wrapped=func,
33
33
  wrapper=deco(
34
34
  func,
@@ -1,3 +1,6 @@
1
+ from typing import Any
2
+
3
+
1
4
  def null(
2
5
  *args,
3
6
  **kwargs,
@@ -9,7 +12,7 @@ def set_inline(
9
12
  object,
10
13
  property,
11
14
  value,
12
- ) -> None:
15
+ ) -> Any:
13
16
  object.__setitem__(property, value)
14
17
 
15
18
  return object
@@ -145,7 +145,7 @@ def bump() -> None:
145
145
  new_version=new_version,
146
146
  )
147
147
 
148
- logger.log(f"Bumped version to {new_version}")
148
+ logger.report(f"Bumped version to {new_version}")
149
149
 
150
150
 
151
151
  if __name__ == "__main__":
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from math import isqrt, ceil
3
3
  from pathlib import Path
4
- from typing import Literal, Optional, Self, final
4
+ from typing import Any, Literal, Optional, Self, final
5
5
  from dataclasses import dataclass, field
6
6
  from mayutils.export.images import IMAGES_FOLDER
7
7
  import numpy as np
@@ -14,7 +14,7 @@ from plotly._subplots import _build_subplot_title_annotations
14
14
 
15
15
  from mayutils.objects.colours import TRANSPARENT, Colour
16
16
 
17
- from mayutils.objects.functions import null, set_inline
17
+ from mayutils.objects.functions import set_inline
18
18
 
19
19
  from mayutils.visualisation.graphs.plotly.templates import (
20
20
  non_primary_axis_dict,
@@ -217,7 +217,6 @@ class SubPlotConfig:
217
217
  cls,
218
218
  plots: tuple[Optional[PlotConfig], ...],
219
219
  cols: Optional[int],
220
- *args,
221
220
  **kwargs,
222
221
  ) -> "SubPlotConfig":
223
222
  if cols is None:
@@ -232,7 +231,6 @@ class SubPlotConfig:
232
231
  tuple(extended_plots[idx : idx + cols])
233
232
  for idx in range(0, len(extended_plots), cols)
234
233
  ),
235
- *args,
236
234
  **kwargs,
237
235
  )
238
236
 
@@ -588,7 +586,7 @@ class Plot(go.Figure):
588
586
  *args,
589
587
  **kwargs,
590
588
  ) -> Self:
591
- self.data = []
589
+ self.data: list[Trace] = []
592
590
 
593
591
  return self
594
592
 
@@ -707,7 +705,11 @@ class Plot(go.Figure):
707
705
  **kwargs,
708
706
  )
709
707
 
710
- return IMAGES_FOLDER / f"{filename}.{image_format}"
708
+ return (
709
+ IMAGES_FOLDER / f"{filename}.{image_formats[0]}"
710
+ if len(image_formats) > 0
711
+ else IMAGES_FOLDER
712
+ )
711
713
 
712
714
  def modifications(
713
715
  self,
@@ -729,7 +731,7 @@ class Plot(go.Figure):
729
731
  opacity = 0.1 if trace.meta == "ecdf" else 0.4 # type: ignore
730
732
  trace.fillcolor = colour.to_str(opacity=opacity) # type: ignore
731
733
 
732
- bound_groups = {}
734
+ bound_groups: dict[str, tuple[tuple[Optional[str], int], list[Trace]]] = {}
733
735
  for idx, trace in enumerate(self.data):
734
736
  if (
735
737
  hasattr(trace, "legendgroup")
@@ -737,7 +739,7 @@ class Plot(go.Figure):
737
739
  and trace.legendgroup.startswith("bounds") # type: ignore
738
740
  ):
739
741
  if trace.legendgroup not in bound_groups: # type: ignore
740
- bound_groups[trace.legendgroup] = [None, []] # type: ignore
742
+ bound_groups[trace.legendgroup] = ((None, 0), []) # type: ignore
741
743
 
742
744
  if trace.fill == "toself": # type: ignore
743
745
  bound_groups[trace.legendgroup][1].append(trace) # type: ignore
@@ -750,7 +752,7 @@ class Plot(go.Figure):
750
752
  colour=shuffled_colourscale[idx % len(shuffled_colourscale)]
751
753
  )
752
754
 
753
- opacity = Colour.parse(colour=bound_traces[0].fillcolor).a
755
+ opacity = Colour.parse(colour=bound_traces[0].fillcolor).a # type: ignore
754
756
  for bound_trace in bound_traces:
755
757
  bound_trace.fillcolor = colour.to_str(opacity=opacity) # type: ignore
756
758
 
@@ -791,8 +793,15 @@ class Plot(go.Figure):
791
793
  xaxis=self.data[idx].xaxis, # type: ignore
792
794
  yaxis=self.data[idx].yaxis, # type: ignore
793
795
  legendgroup=self.data[idx].legendgroup # type: ignore
794
- or null(set_inline(self.data[idx], "legendgroup", idx))
795
- or idx,
796
+ or getattr(
797
+ set_inline(
798
+ self.data[idx],
799
+ "legendgroup",
800
+ idx,
801
+ ),
802
+ "legendgroup",
803
+ idx,
804
+ ),
796
805
  showlegend=False,
797
806
  label_name=False,
798
807
  )
@@ -837,8 +846,15 @@ class Plot(go.Figure):
837
846
  else f"trace {idx} Rug"
838
847
  ),
839
848
  legendgroup=self.data[idx].legendgroup # type: ignore
840
- or null(set_inline(self.data[idx], "legendgroup", idx))
841
- or idx,
849
+ or getattr(
850
+ set_inline(
851
+ self.data[idx],
852
+ "legendgroup",
853
+ idx,
854
+ ),
855
+ "legendgroup",
856
+ idx,
857
+ ),
842
858
  showlegend=False,
843
859
  marker=dict(
844
860
  color=self.data[idx].marker.line.color, # type: ignore
@@ -862,8 +878,15 @@ class Plot(go.Figure):
862
878
  else f"trace {idx} Rug"
863
879
  ),
864
880
  legendgroup=self.data[idx].legendgroup # type: ignore
865
- or null(set_inline(self.data[idx], "legendgroup", idx))
866
- or idx,
881
+ or getattr(
882
+ set_inline(
883
+ self.data[idx],
884
+ "legendgroup",
885
+ idx,
886
+ ),
887
+ "legendgroup",
888
+ idx,
889
+ ),
867
890
  showlegend=False,
868
891
  line=dict(
869
892
  color=TRANSPARENT.to_str(),
@@ -898,8 +921,15 @@ class Plot(go.Figure):
898
921
  else f"trace {idx} Rug"
899
922
  ),
900
923
  legendgroup=self.data[idx].legendgroup # type: ignore
901
- or null(set_inline(self.data[idx], "legendgroup", idx))
902
- or idx,
924
+ or getattr(
925
+ set_inline(
926
+ self.data[idx],
927
+ "legendgroup",
928
+ idx,
929
+ ),
930
+ "legendgroup",
931
+ idx,
932
+ ),
903
933
  showlegend=False,
904
934
  line=dict(
905
935
  color=self.data[idx].marker.line.color, # type: ignore
@@ -933,8 +963,15 @@ class Plot(go.Figure):
933
963
  else f"trace {idx} Rug"
934
964
  ),
935
965
  legendgroup=self.data[idx].legendgroup # type: ignore
936
- or null(set_inline(self.data[idx], "legendgroup", idx))
937
- or idx,
966
+ or getattr(
967
+ set_inline(
968
+ self.data[idx],
969
+ "legendgroup",
970
+ idx,
971
+ ),
972
+ "legendgroup",
973
+ idx,
974
+ ),
938
975
  showlegend=False,
939
976
  line=dict(
940
977
  color=self.data[idx].marker.line.color, # type: ignore
@@ -968,8 +1005,15 @@ class Plot(go.Figure):
968
1005
  else f"trace {idx} Rug"
969
1006
  ),
970
1007
  legendgroup=self.data[idx].legendgroup # type: ignore
971
- or null(set_inline(self.data[idx], "legendgroup", idx))
972
- or idx,
1008
+ or getattr(
1009
+ set_inline(
1010
+ self.data[idx],
1011
+ "legendgroup",
1012
+ idx,
1013
+ ),
1014
+ "legendgroup",
1015
+ idx,
1016
+ ),
973
1017
  showlegend=False,
974
1018
  line=dict(
975
1019
  color=self.data[idx].marker.line.color, # type: ignore
@@ -1096,8 +1140,15 @@ class Plot(go.Figure):
1096
1140
  xaxis=self.data[idx].xaxis, # type: ignore
1097
1141
  yaxis=self.data[idx].yaxis, # type: ignore
1098
1142
  legendgroup=self.data[idx].legendgroup # type: ignore
1099
- or null(set_inline(self.data[idx], "legendgroup", idx))
1100
- or idx,
1143
+ or getattr(
1144
+ set_inline(
1145
+ self.data[idx],
1146
+ "legendgroup",
1147
+ idx,
1148
+ ),
1149
+ "legendgroup",
1150
+ idx,
1151
+ ),
1101
1152
  showlegend=False,
1102
1153
  label_name=False,
1103
1154
  )
@@ -1107,7 +1158,7 @@ class Plot(go.Figure):
1107
1158
  "layout": dict(),
1108
1159
  },
1109
1160
  }
1110
- buttons = {
1161
+ buttons: dict[str, list[dict[str, Any]]] = {
1111
1162
  "scatter": [
1112
1163
  dict(
1113
1164
  label="Toggle Density",
@@ -1482,6 +1533,8 @@ class SubPlot(Plot):
1482
1533
  if is_scene:
1483
1534
  scene_count += 1
1484
1535
  scene_str = str(scene_count) if scene_count != 1 else ""
1536
+ else:
1537
+ scene_str = ""
1485
1538
 
1486
1539
  xaxis_num = (
1487
1540
  col_idx + row_idx * len(subplot_config.plots[0]) + 1 - scene_count
@@ -1588,12 +1641,17 @@ class SubPlot(Plot):
1588
1641
 
1589
1642
  self.modifications()
1590
1643
 
1591
- def add_rug(
1592
- self,
1593
- *args,
1594
- **kwargs,
1595
- ) -> None:
1596
- pass
1644
+ # def add_rug(
1645
+ # self,
1646
+ # rug_type: Literal[
1647
+ # "scatter", "violin", "box", "strip", "historgram", "ecdf"
1648
+ # ] = "scatter",
1649
+ # rug_height: Optional[float] = None,
1650
+ # *args,
1651
+ # **kwargs,
1652
+ # ) -> Self:
1653
+ # raise NotImplementedError("Rug not implemented for SubPlot")
1654
+ # return self
1597
1655
 
1598
1656
 
1599
1657
  def pop_axis_config_title(
@@ -1641,7 +1699,7 @@ def get_domains(
1641
1699
  def sort_traces_by_axes(
1642
1700
  traces: list[Trace],
1643
1701
  ) -> dict:
1644
- traces_axes = {}
1702
+ traces_axes: dict[tuple[str, str], list[Trace]] = {}
1645
1703
  for trace in traces:
1646
1704
  if (trace.xaxis, trace.yaxis) in traces_axes: # type: ignore
1647
1705
  traces_axes[(trace.xaxis, trace.yaxis)].append(trace) # type: ignore
@@ -259,7 +259,7 @@ class Icicle(go.Icicle):
259
259
  if path in node_values:
260
260
  return node_values[path]
261
261
 
262
- total = 0
262
+ total = 0.0
263
263
  for key, value in d.items():
264
264
  new_path = f"{path}/{key}" if path else key
265
265
  if isinstance(value, dict):
@@ -470,7 +470,6 @@ class Bar3d(go.Mesh3d):
470
470
  value_weights: bool = False,
471
471
  x_mapping: Optional[ArrayLike] = None,
472
472
  y_mapping: Optional[ArrayLike] = None,
473
- *args,
474
473
  **kwargs,
475
474
  ) -> Self:
476
475
  if not df.columns.is_unique:
@@ -490,7 +489,6 @@ class Bar3d(go.Mesh3d):
490
489
  y=y,
491
490
  z=z,
492
491
  w=z if value_weights else kwargs.pop("w", None),
493
- *args,
494
492
  **kwargs,
495
493
  )
496
494
 
Binary file
Binary file
File without changes
File without changes