maidr 1.4.1__tar.gz → 1.4.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 (58) hide show
  1. {maidr-1.4.1 → maidr-1.4.2}/PKG-INFO +1 -1
  2. {maidr-1.4.1 → maidr-1.4.2}/maidr/__init__.py +1 -1
  3. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/enum/smooth_keywords.py +3 -0
  4. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/regplot.py +29 -21
  5. maidr-1.4.2/maidr/util/regression_line_utils.py +69 -0
  6. {maidr-1.4.1 → maidr-1.4.2}/pyproject.toml +1 -1
  7. maidr-1.4.1/maidr/util/regression_line_utils.py +0 -19
  8. {maidr-1.4.1 → maidr-1.4.2}/LICENSE +0 -0
  9. {maidr-1.4.1 → maidr-1.4.2}/README.md +0 -0
  10. {maidr-1.4.1 → maidr-1.4.2}/maidr/api.py +0 -0
  11. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/__init__.py +0 -0
  12. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/context_manager.py +0 -0
  13. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/enum/__init__.py +0 -0
  14. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/enum/library.py +0 -0
  15. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/enum/maidr_key.py +0 -0
  16. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/enum/plot_type.py +0 -0
  17. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/figure_manager.py +0 -0
  18. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/maidr.py +0 -0
  19. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/__init__.py +0 -0
  20. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/barplot.py +0 -0
  21. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/boxplot.py +0 -0
  22. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/candlestick.py +0 -0
  23. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/grouped_barplot.py +0 -0
  24. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/heatmap.py +0 -0
  25. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/histogram.py +0 -0
  26. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/lineplot.py +0 -0
  27. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/maidr_plot.py +0 -0
  28. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/maidr_plot_factory.py +0 -0
  29. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/mplfinance_barplot.py +0 -0
  30. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/mplfinance_lineplot.py +0 -0
  31. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/regplot.py +0 -0
  32. {maidr-1.4.1 → maidr-1.4.2}/maidr/core/plot/scatterplot.py +0 -0
  33. {maidr-1.4.1 → maidr-1.4.2}/maidr/exception/__init__.py +0 -0
  34. {maidr-1.4.1 → maidr-1.4.2}/maidr/exception/extraction_error.py +0 -0
  35. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/__init__.py +0 -0
  36. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/barplot.py +0 -0
  37. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/boxplot.py +0 -0
  38. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/candlestick.py +0 -0
  39. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/clear.py +0 -0
  40. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/common.py +0 -0
  41. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/heatmap.py +0 -0
  42. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/highlight.py +0 -0
  43. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/histogram.py +0 -0
  44. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/kdeplot.py +0 -0
  45. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/lineplot.py +0 -0
  46. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/mplfinance.py +0 -0
  47. {maidr-1.4.1 → maidr-1.4.2}/maidr/patch/scatterplot.py +0 -0
  48. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/__init__.py +0 -0
  49. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/dedup_utils.py +0 -0
  50. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/environment.py +0 -0
  51. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/mixin/__init__.py +0 -0
  52. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/mixin/extractor_mixin.py +0 -0
  53. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/mixin/merger_mixin.py +0 -0
  54. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/mplfinance_utils.py +0 -0
  55. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/plot_detection.py +0 -0
  56. {maidr-1.4.1 → maidr-1.4.2}/maidr/util/svg_utils.py +0 -0
  57. {maidr-1.4.1 → maidr-1.4.2}/maidr/widget/__init__.py +0 -0
  58. {maidr-1.4.1 → maidr-1.4.2}/maidr/widget/shiny.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: maidr
3
- Version: 1.4.1
3
+ Version: 1.4.2
4
4
  Summary: Multimodal Access and Interactive Data Representations
5
5
  License: GPL-3.0-or-later
6
6
  Keywords: accessibility,visualization,sonification,braille,tactile,multimodal,data representation,blind,low vision,visual impairments
@@ -1,4 +1,4 @@
1
- __version__ = "1.4.1"
1
+ __version__ = "1.4.2"
2
2
 
3
3
  from .api import close, render, save_html, show, stacked
4
4
  from .core import Maidr
@@ -2,8 +2,11 @@
2
2
  SMOOTH_KEYWORDS = [
3
3
  "smooth",
4
4
  "lowess",
5
+ "loess",
5
6
  "regression",
6
7
  "linear regression",
8
+ "linear fit",
9
+ "fit",
7
10
  "kde",
8
11
  "density",
9
12
  "gaussian",
@@ -5,11 +5,10 @@ from matplotlib.axes import Axes
5
5
  from matplotlib.lines import Line2D
6
6
  from maidr.core.enum import PlotType
7
7
  from maidr.patch.common import common
8
- import numpy as np
9
8
  from maidr.core.context_manager import ContextManager
10
9
  import uuid
11
10
  from maidr.core.enum.smooth_keywords import SMOOTH_KEYWORDS
12
- from maidr.util.regression_line_utils import find_regression_line
11
+ from maidr.util.regression_line_utils import find_smooth_lines_by_label
13
12
 
14
13
 
15
14
  def regplot(wrapped, instance, args, kwargs) -> Axes:
@@ -23,27 +22,34 @@ def regplot(wrapped, instance, args, kwargs) -> Axes:
23
22
  # Prevent any MAIDR layer registration during plotting when scatter=False
24
23
  with ContextManager.set_internal_context():
25
24
  ax = wrapped(*args, **kwargs)
25
+
26
26
  axes = ax if isinstance(ax, Axes) else ax.axes if hasattr(ax, "axes") else None
27
27
  if axes is not None:
28
- regression_line = find_regression_line(axes)
29
- if regression_line is not None:
30
- # ---
31
- # Assign a unique gid to the regression line if not already set.
32
- # This is necessary because the SVG output may contain many <g> and <path> tags,
33
- # and only the regression line should be uniquely selectable for accessibility and highlighting.
34
- # By setting a unique gid, we ensure the backend and frontend can generate a reliable selector
35
- # (e.g., g[id='maidr-...'] path) that matches only the intended regression line.
36
- # ---
37
- if regression_line.get_gid() is None:
28
+ # Find and register all smooth lines
29
+ smooth_lines = find_smooth_lines_by_label(axes)
30
+ for line in smooth_lines:
31
+ # If line doesn't have a gid yet, assign one and register
32
+ if line.get_gid() is None:
38
33
  new_gid = f"maidr-{uuid.uuid4()}"
39
- regression_line.set_gid(new_gid)
40
- common(
41
- PlotType.SMOOTH,
42
- lambda *a, **k: ax,
43
- instance,
44
- args,
45
- dict(kwargs, regression_line=regression_line),
46
- )
34
+ line.set_gid(new_gid)
35
+ common(
36
+ PlotType.SMOOTH,
37
+ lambda *a, **k: ax,
38
+ instance,
39
+ args,
40
+ dict(kwargs, regression_line=line),
41
+ )
42
+ else:
43
+ # Even if it has a gid, register it as a smooth layer
44
+ # This handles the case where patched_plot already assigned a gid
45
+ common(
46
+ PlotType.SMOOTH,
47
+ lambda *a, **k: ax,
48
+ instance,
49
+ args,
50
+ dict(kwargs, regression_line=line),
51
+ )
52
+
47
53
  return ax
48
54
 
49
55
 
@@ -53,7 +59,8 @@ def patched_plot(wrapped, instance, args, kwargs):
53
59
  """
54
60
  # Call the original plot function
55
61
  lines = wrapped(*args, **kwargs)
56
- # lines can be a list of Line2D objects
62
+
63
+ # Check each line for smooth keywords and register if found
57
64
  for line in lines:
58
65
  if isinstance(line, Line2D):
59
66
  label = line.get_label() or ""
@@ -72,6 +79,7 @@ def patched_plot(wrapped, instance, args, kwargs):
72
79
  args,
73
80
  dict(kwargs, regression_line=line),
74
81
  )
82
+
75
83
  return lines
76
84
 
77
85
 
@@ -0,0 +1,69 @@
1
+ from matplotlib.lines import Line2D
2
+ from matplotlib.axes import Axes
3
+ import numpy as np
4
+ from typing import List, Union
5
+ from maidr.core.enum.smooth_keywords import SMOOTH_KEYWORDS
6
+
7
+
8
+ def find_regression_line(axes: Axes) -> Union[Line2D, None]:
9
+ """
10
+ Helper to find the regression line (Line2D) in the given axes.
11
+ """
12
+ return next(
13
+ (
14
+ artist
15
+ for artist in axes.get_children()
16
+ if isinstance(artist, Line2D)
17
+ and artist.get_label() not in (None, "", "_nolegend_")
18
+ and artist.get_xydata() is not None
19
+ and np.asarray(artist.get_xydata()).size > 0
20
+ ),
21
+ None,
22
+ )
23
+
24
+
25
+ def find_smooth_lines_by_label(axes: Axes) -> List[Line2D]:
26
+ """
27
+ Helper to find all smooth/regression lines (Line2D) in the given axes by checking their labels.
28
+
29
+ This function detects smooth lines by examining their labels for smooth-related keywords
30
+ or generic '_child' labels that are commonly created by seaborn's regplot function.
31
+
32
+ Parameters
33
+ ----------
34
+ axes : matplotlib.axes.Axes
35
+ The matplotlib axes object to search for smooth lines.
36
+
37
+ Returns
38
+ -------
39
+ List[Line2D]
40
+ List of Line2D objects that have labels matching smooth keywords or generic '_child' labels.
41
+
42
+ Examples
43
+ --------
44
+ >>> import matplotlib.pyplot as plt
45
+ >>> import seaborn as sns
46
+ >>>
47
+ >>> fig, ax = plt.subplots()
48
+ >>> # Create a regplot with smooth line
49
+ >>> sns.regplot(x=[1, 2, 3], y=[1, 2, 3], ax=ax, lowess=True)
50
+ >>>
51
+ >>> # Find smooth lines
52
+ >>> smooth_lines = find_smooth_lines_by_label(ax)
53
+ >>> print(f"Found {len(smooth_lines)} smooth lines")
54
+ """
55
+ smooth_lines = []
56
+ for line in axes.get_lines():
57
+ if isinstance(line, Line2D):
58
+ label = line.get_label() or ""
59
+ label_str = str(label)
60
+
61
+ # Check if label matches smooth keywords
62
+ if any(key in label_str.lower() for key in SMOOTH_KEYWORDS):
63
+ smooth_lines.append(line)
64
+ # Also check for seaborn regplot lines with generic labels (like '_child0', '_child1')
65
+ elif label_str.startswith("_child"):
66
+ # Lines with _child labels are likely smooth lines from seaborn regplot
67
+ smooth_lines.append(line)
68
+
69
+ return smooth_lines
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "maidr"
7
- version = "1.4.1"
7
+ version = "1.4.2"
8
8
  description = "Multimodal Access and Interactive Data Representations"
9
9
  authors = [
10
10
  "JooYoung Seo <jseo1005@illinois.edu>",
@@ -1,19 +0,0 @@
1
- from matplotlib.lines import Line2D
2
- import numpy as np
3
-
4
-
5
- def find_regression_line(axes):
6
- """
7
- Helper to find the regression line (Line2D) in the given axes.
8
- """
9
- return next(
10
- (
11
- artist
12
- for artist in axes.get_children()
13
- if isinstance(artist, Line2D)
14
- and artist.get_label() not in (None, "", "_nolegend_")
15
- and artist.get_xydata() is not None
16
- and np.asarray(artist.get_xydata()).size > 0
17
- ),
18
- None,
19
- )
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
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
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