maidr 1.2.1__py3-none-any.whl → 1.3.0__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.
- maidr/__init__.py +1 -1
- maidr/core/maidr.py +12 -6
- maidr/core/plot/lineplot.py +44 -30
- maidr/patch/lineplot.py +28 -18
- maidr/util/environment.py +26 -7
- {maidr-1.2.1.dist-info → maidr-1.3.0.dist-info}/METADATA +1 -4
- {maidr-1.2.1.dist-info → maidr-1.3.0.dist-info}/RECORD +9 -9
- {maidr-1.2.1.dist-info → maidr-1.3.0.dist-info}/LICENSE +0 -0
- {maidr-1.2.1.dist-info → maidr-1.3.0.dist-info}/WHEEL +0 -0
maidr/__init__.py
CHANGED
maidr/core/maidr.py
CHANGED
|
@@ -8,7 +8,7 @@ import os
|
|
|
8
8
|
import tempfile
|
|
9
9
|
import uuid
|
|
10
10
|
import webbrowser
|
|
11
|
-
from typing import Any, Literal
|
|
11
|
+
from typing import Any, Literal, cast
|
|
12
12
|
|
|
13
13
|
import matplotlib.pyplot as plt
|
|
14
14
|
from htmltools import HTML, HTMLDocument, Tag, tags
|
|
@@ -102,14 +102,20 @@ class Maidr:
|
|
|
102
102
|
The renderer to use for the HTML preview.
|
|
103
103
|
"""
|
|
104
104
|
html = self._create_html_tag(use_iframe=True) # Always use iframe for display
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
|
|
106
|
+
# Use the passed renderer parameter, fallback to auto-detection
|
|
107
|
+
if renderer == "auto":
|
|
108
|
+
_renderer = cast(Literal["ipython", "browser"], Environment.get_renderer())
|
|
109
|
+
else:
|
|
110
|
+
_renderer = renderer
|
|
111
|
+
|
|
112
|
+
# Only try browser opening if explicitly requested as browser and not in notebook
|
|
113
|
+
if _renderer == "browser" and not Environment.is_notebook():
|
|
109
114
|
return self._open_plot_in_browser()
|
|
115
|
+
|
|
110
116
|
if clear_fig:
|
|
111
117
|
plt.close()
|
|
112
|
-
return html.show(
|
|
118
|
+
return html.show(_renderer)
|
|
113
119
|
|
|
114
120
|
def clear(self):
|
|
115
121
|
self._plots = []
|
maidr/core/plot/lineplot.py
CHANGED
|
@@ -8,6 +8,7 @@ from maidr.core.enum.plot_type import PlotType
|
|
|
8
8
|
from maidr.core.plot.maidr_plot import MaidrPlot
|
|
9
9
|
from maidr.exception.extraction_error import ExtractionError
|
|
10
10
|
from maidr.util.mixin.extractor_mixin import LineExtractorMixin
|
|
11
|
+
import uuid
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class MultiLinePlot(MaidrPlot, LineExtractorMixin):
|
|
@@ -42,62 +43,75 @@ class MultiLinePlot(MaidrPlot, LineExtractorMixin):
|
|
|
42
43
|
super().__init__(ax, PlotType.LINE)
|
|
43
44
|
|
|
44
45
|
def _get_selector(self) -> Union[str, List[str]]:
|
|
45
|
-
|
|
46
|
+
# Return selectors for all lines that have data
|
|
47
|
+
all_lines = self.ax.get_lines()
|
|
48
|
+
if not all_lines:
|
|
49
|
+
return ["g[maidr='true'] > path"]
|
|
50
|
+
|
|
51
|
+
selectors = []
|
|
52
|
+
for line in all_lines:
|
|
53
|
+
# Only create selectors for lines that have data (same logic as _extract_line_data)
|
|
54
|
+
xydata = line.get_xydata()
|
|
55
|
+
if xydata is None or not xydata.size: # type: ignore
|
|
56
|
+
continue
|
|
57
|
+
gid = line.get_gid()
|
|
58
|
+
if gid:
|
|
59
|
+
selectors.append(f"g[id='{gid}'] path")
|
|
60
|
+
else:
|
|
61
|
+
selectors.append("g[maidr='true'] > path")
|
|
62
|
+
|
|
63
|
+
if not selectors:
|
|
64
|
+
return ["g[maidr='true'] > path"]
|
|
65
|
+
|
|
66
|
+
return selectors
|
|
46
67
|
|
|
47
|
-
def _extract_plot_data(self) ->
|
|
48
|
-
|
|
49
|
-
data = self._extract_line_data(plot)
|
|
68
|
+
def _extract_plot_data(self) -> Union[List[List[dict]], None]:
|
|
69
|
+
data = self._extract_line_data()
|
|
50
70
|
|
|
51
71
|
if data is None:
|
|
52
|
-
raise ExtractionError(self.type,
|
|
72
|
+
raise ExtractionError(self.type, None)
|
|
53
73
|
|
|
54
74
|
return data
|
|
55
75
|
|
|
56
|
-
def _extract_line_data(
|
|
57
|
-
self, plot: Union[List[Line2D], None]
|
|
58
|
-
) -> Union[List[dict], None]:
|
|
76
|
+
def _extract_line_data(self) -> Union[List[List[dict]], None]:
|
|
59
77
|
"""
|
|
60
|
-
Extract data from
|
|
61
|
-
|
|
62
|
-
Parameters
|
|
63
|
-
----------
|
|
64
|
-
plot : list[Line2D] | None
|
|
65
|
-
List of Line2D objects to extract data from.
|
|
78
|
+
Extract data from all line objects and return as separate arrays.
|
|
66
79
|
|
|
67
80
|
Returns
|
|
68
81
|
-------
|
|
69
|
-
list[dict] | None
|
|
70
|
-
List of dictionaries
|
|
71
|
-
or None if the plot data is invalid.
|
|
82
|
+
list[list[dict]] | None
|
|
83
|
+
List of lists, where each inner list contains dictionaries with x,y coordinates
|
|
84
|
+
and line identifiers for one line, or None if the plot data is invalid.
|
|
72
85
|
"""
|
|
73
|
-
|
|
86
|
+
all_lines = self.ax.get_lines()
|
|
87
|
+
if not all_lines:
|
|
74
88
|
return None
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
all_lines_data = []
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if
|
|
92
|
+
for line in all_lines:
|
|
93
|
+
xydata = line.get_xydata()
|
|
94
|
+
if xydata is None or not xydata.size: # type: ignore
|
|
81
95
|
continue
|
|
82
96
|
|
|
83
|
-
# Tag the element for highlighting
|
|
84
97
|
self._elements.append(line)
|
|
85
98
|
|
|
86
|
-
#
|
|
99
|
+
# Assign unique GID to each line if not already set
|
|
100
|
+
if line.get_gid() is None:
|
|
101
|
+
unique_gid = f"maidr-{uuid.uuid4()}"
|
|
102
|
+
line.set_gid(unique_gid)
|
|
87
103
|
|
|
88
104
|
label: str = line.get_label() # type: ignore
|
|
89
105
|
line_data = [
|
|
90
106
|
{
|
|
91
107
|
MaidrKey.X: float(x),
|
|
92
108
|
MaidrKey.Y: float(y),
|
|
93
|
-
# Replace labels starting with '_child'
|
|
94
|
-
# with an empty string to exclude
|
|
95
|
-
# internal or non-relevant labels from being used as identifiers.
|
|
96
109
|
MaidrKey.FILL: (label if not label.startswith("_child") else ""),
|
|
97
110
|
}
|
|
98
111
|
for x, y in line.get_xydata() # type: ignore
|
|
99
112
|
]
|
|
100
|
-
if len(line_data) > 0:
|
|
101
|
-
all_line_data.append(line_data)
|
|
102
113
|
|
|
103
|
-
|
|
114
|
+
if line_data:
|
|
115
|
+
all_lines_data.append(line_data)
|
|
116
|
+
|
|
117
|
+
return all_lines_data if all_lines_data else None
|
maidr/patch/lineplot.py
CHANGED
|
@@ -7,29 +7,39 @@ from matplotlib.lines import Line2D
|
|
|
7
7
|
from maidr.core.enum import PlotType
|
|
8
8
|
from maidr.patch.common import common
|
|
9
9
|
from maidr.core.enum.smooth_keywords import SMOOTH_KEYWORDS
|
|
10
|
+
from maidr.core.context_manager import ContextManager
|
|
11
|
+
from maidr.core.figure_manager import FigureManager
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def line(wrapped, instance, args, kwargs) -> Axes | list[Line2D]:
|
|
13
15
|
"""
|
|
14
|
-
Wrapper
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
----------
|
|
18
|
-
wrapped : callable
|
|
19
|
-
The wrapped function (plot or lineplot)
|
|
20
|
-
instance : object
|
|
21
|
-
The object to which the wrapped function belongs
|
|
22
|
-
args : tuple
|
|
23
|
-
Positional arguments passed to the wrapped function
|
|
24
|
-
kwargs : dict
|
|
25
|
-
Keyword arguments passed to the wrapped function
|
|
26
|
-
|
|
27
|
-
Returns
|
|
28
|
-
-------
|
|
29
|
-
Axes | list[Line2D]
|
|
30
|
-
The result of the wrapped function after processing
|
|
16
|
+
Wrapper for line plotting functions that creates a single MAIDR plot per axes to handle
|
|
17
|
+
multiline plots (matplotlib) and single-call plots (seaborn) correctly by preventing
|
|
18
|
+
multiple MAIDR layers and using internal context to avoid cyclic processing.
|
|
31
19
|
"""
|
|
32
|
-
|
|
20
|
+
# Don't proceed if the call is made internally by the patched function.
|
|
21
|
+
if ContextManager.is_internal_context():
|
|
22
|
+
return wrapped(*args, **kwargs)
|
|
23
|
+
|
|
24
|
+
# Set the internal context to avoid cyclic processing.
|
|
25
|
+
with ContextManager.set_internal_context():
|
|
26
|
+
# Patch the plotting function.
|
|
27
|
+
plot = wrapped(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
# Get the axes from the plot result (works for both matplotlib and seaborn)
|
|
30
|
+
ax = FigureManager.get_axes(plot)
|
|
31
|
+
if ax is None:
|
|
32
|
+
# If we can't get axes from plot, try from instance
|
|
33
|
+
ax = instance if isinstance(instance, Axes) else getattr(instance, "axes", None)
|
|
34
|
+
|
|
35
|
+
# Check if a MAIDR plot already exists for this axes
|
|
36
|
+
if ax is not None and not hasattr(ax, "_maidr_plot_created"):
|
|
37
|
+
# Create MAIDR plot only once for this axes using common()
|
|
38
|
+
common(PlotType.LINE, lambda *a, **k: plot, instance, args, kwargs)
|
|
39
|
+
# Mark that a MAIDR plot has been created for this axes
|
|
40
|
+
setattr(ax, "_maidr_plot_created", True)
|
|
41
|
+
|
|
42
|
+
return plot
|
|
33
43
|
|
|
34
44
|
|
|
35
45
|
# Patch matplotlib function.
|
maidr/util/environment.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
import sys
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class Environment:
|
|
@@ -24,10 +25,19 @@ class Environment:
|
|
|
24
25
|
try:
|
|
25
26
|
from IPython import get_ipython # type: ignore
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
ipy = get_ipython()
|
|
29
|
+
if ipy is not None:
|
|
30
|
+
# Check for Pyodide/JupyterLite specific indicators
|
|
31
|
+
ipy_str = str(ipy).lower()
|
|
32
|
+
if "pyodide" in ipy_str or "jupyterlite" in ipy_str:
|
|
33
|
+
return True
|
|
34
|
+
# Check for other notebook indicators
|
|
35
|
+
if "ipykernel" in str(ipy) or "google.colab" in str(ipy):
|
|
36
|
+
return True
|
|
37
|
+
# Check for Pyodide platform
|
|
38
|
+
if sys.platform == "emscripten":
|
|
39
|
+
return True
|
|
40
|
+
return False
|
|
31
41
|
except ImportError:
|
|
32
42
|
return False
|
|
33
43
|
|
|
@@ -61,10 +71,19 @@ class Environment:
|
|
|
61
71
|
ipy = ( # pyright: ignore[reportUnknownVariableType]
|
|
62
72
|
IPython.get_ipython() # pyright: ignore[reportUnknownMemberType, reportPrivateImportUsage]
|
|
63
73
|
)
|
|
64
|
-
|
|
74
|
+
if ipy is not None:
|
|
75
|
+
# Check for Pyodide/JupyterLite
|
|
76
|
+
ipy_str = str(ipy).lower()
|
|
77
|
+
if "pyodide" in ipy_str or "jupyterlite" in ipy_str:
|
|
78
|
+
return "ipython"
|
|
79
|
+
# Check for Pyodide platform
|
|
80
|
+
if sys.platform == "emscripten":
|
|
81
|
+
return "ipython"
|
|
82
|
+
return "ipython"
|
|
83
|
+
else:
|
|
84
|
+
return "browser"
|
|
65
85
|
except ImportError:
|
|
66
|
-
|
|
67
|
-
return renderer
|
|
86
|
+
return "browser"
|
|
68
87
|
|
|
69
88
|
@staticmethod
|
|
70
89
|
def initialize_llm_secrets(unique_id: str) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: maidr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
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
|
|
@@ -26,14 +26,11 @@ Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
28
28
|
Requires-Dist: htmltools (>=0.5)
|
|
29
|
-
Requires-Dist: jupyter (>=1.0.0,<2.0.0)
|
|
30
29
|
Requires-Dist: lxml (>=5.1.0)
|
|
31
30
|
Requires-Dist: matplotlib (>=3.8)
|
|
32
31
|
Requires-Dist: mplfinance (>=0.12.10b0,<0.13.0)
|
|
33
32
|
Requires-Dist: numpy (>=1.26)
|
|
34
33
|
Requires-Dist: seaborn (>=0.12)
|
|
35
|
-
Requires-Dist: statsmodels (>=0.14.4,<0.15.0)
|
|
36
|
-
Requires-Dist: virtualenv (>=20.26.6,<21.0.0)
|
|
37
34
|
Requires-Dist: wrapt (>=1.16.0,<2.0.0)
|
|
38
35
|
Project-URL: Homepage, https://xability.github.io/py-maidr
|
|
39
36
|
Project-URL: Repository, https://github.com/xability/py-maidr
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
maidr/__init__.py,sha256=
|
|
1
|
+
maidr/__init__.py,sha256=q3J6Xlb_5wM0iRIYZnMkvD0ValcEFxltt6-kbGrRKR4,399
|
|
2
2
|
maidr/api.py,sha256=F43mXWsxc7tHdlZqbRlEWkc-RjJVo_zgxCn3NiLBY58,1764
|
|
3
3
|
maidr/core/__init__.py,sha256=WgxLpSEYMc4k3OyEOf1shOxfEq0ASzppEIZYmE91ThQ,25
|
|
4
4
|
maidr/core/context_manager.py,sha256=6cT7ZGOApSpC-SLD2XZWWU_H08i-nfv-JUlzXOtvWYw,3374
|
|
@@ -8,7 +8,7 @@ maidr/core/enum/maidr_key.py,sha256=ljG0omqzd8K8Yk213N7i7PXGvG-IOlnE5v7o6RoGJzc,
|
|
|
8
8
|
maidr/core/enum/plot_type.py,sha256=7Orx3b_0NdpI_PtVJfLyJPh4qBqYMTsYBBr8VwOtiAM,347
|
|
9
9
|
maidr/core/enum/smooth_keywords.py,sha256=VlpIX1BaoX8efwIrT72GIptxguTpiPtJvvJUPMoaFSQ,194
|
|
10
10
|
maidr/core/figure_manager.py,sha256=jXs-Prkeru1Pahj21hjh8BAwXM9ZFUZ3GFfKUfIRX_M,4117
|
|
11
|
-
maidr/core/maidr.py,sha256=
|
|
11
|
+
maidr/core/maidr.py,sha256=kpN5axfJnWyaqXvyA1maioPOFh1rqod3XIvhIefcjOs,14225
|
|
12
12
|
maidr/core/plot/__init__.py,sha256=xDIpRGM-4DfaSSL3nKcXrjdMecCHJ6en4K4nA_fPefQ,83
|
|
13
13
|
maidr/core/plot/barplot.py,sha256=1HfoqyDGKIXkYQnCHN83Ye_faKpNQ3R4wjlbjD5jUyk,2092
|
|
14
14
|
maidr/core/plot/boxplot.py,sha256=i11GdNuz_c-hilmhydu3ah-bzyVdFoBkNvRi5lpMrrY,9946
|
|
@@ -16,7 +16,7 @@ maidr/core/plot/candlestick.py,sha256=8YKjNmxJx7TEvaH5v4lYDzA11VHpVHpZrv9EJG2Ter
|
|
|
16
16
|
maidr/core/plot/grouped_barplot.py,sha256=bRcQcvwkF3Q3aZ3PlhbZ6bHI_AfcqdKUMVvlLL94wXM,2078
|
|
17
17
|
maidr/core/plot/heatmap.py,sha256=yMS-31tS2GW4peds9LtZesMxmmTV_YfqYO5M_t5KasQ,2521
|
|
18
18
|
maidr/core/plot/histogram.py,sha256=QV5W-6ZJQQcZsrM91JJBX-ONktJzH7yg_et5_bBPfQQ,1525
|
|
19
|
-
maidr/core/plot/lineplot.py,sha256=
|
|
19
|
+
maidr/core/plot/lineplot.py,sha256=C3xz6uWXYM_mbTq_geb5bP0JdvhcQf6cpfTs78Y6fCM,3852
|
|
20
20
|
maidr/core/plot/maidr_plot.py,sha256=B6hjsu-jSWlevEqJawgwjMOJr51nBBNh7yqJdSTkNhw,3681
|
|
21
21
|
maidr/core/plot/maidr_plot_factory.py,sha256=5SC8Nc3IfVYn-jQU_SD9vw7R5yhTHTBgQwGnAc7_DmA,2507
|
|
22
22
|
maidr/core/plot/regplot.py,sha256=b7u6bGTz1IxKahplNUrfwIr_OGSwMJ2BuLgFAVjL0s0,2744
|
|
@@ -33,12 +33,12 @@ maidr/patch/heatmap.py,sha256=uxLLg530Ql9KVC5rxk8vnwPHXBWWHwYgJRkyHY-tJzs,1048
|
|
|
33
33
|
maidr/patch/highlight.py,sha256=I1dGFHJAnVd0AHVnMJzk_TE8BC8Uv-I6fTzSrJLU5QM,1155
|
|
34
34
|
maidr/patch/histogram.py,sha256=k3N0RUf1SQ2402pwbaY5QyS98KnLWvr9glCHQw9NTko,2378
|
|
35
35
|
maidr/patch/kdeplot.py,sha256=qv-OKzuop2aTrkZgUe2OnLxvV-KMyeXt1Td0_uZeHzE,2338
|
|
36
|
-
maidr/patch/lineplot.py,sha256=
|
|
36
|
+
maidr/patch/lineplot.py,sha256=og42V0tWBKCnf6idT3pLsIj3QBvKjg8aUN-k1udPRVw,1901
|
|
37
37
|
maidr/patch/regplot.py,sha256=Ciz43C5XZfWK6wtVWrlV0WNz4R__rcgdqVE9OCaXXRk,3236
|
|
38
38
|
maidr/patch/scatterplot.py,sha256=kln6zZwjVsdQzICalo-RnBOJrx1BnIB2xYUwItHvSNY,525
|
|
39
39
|
maidr/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
40
|
maidr/util/dedup_utils.py,sha256=RpgPL5p-3oULUHaTCZJaQKhPHfyPkvBLHMt8lAGpJ5A,438
|
|
41
|
-
maidr/util/environment.py,sha256
|
|
41
|
+
maidr/util/environment.py,sha256=-2LyZUpHojBCMEbkr_xkcC-_IDqtGDALB8683v7kTdI,5253
|
|
42
42
|
maidr/util/mixin/__init__.py,sha256=aGJZNhtWh77yIVPc7ipIZm1OajigjMtCWYKPuDWTC-c,217
|
|
43
43
|
maidr/util/mixin/extractor_mixin.py,sha256=oHtwpmS5kARvaLrSO3DKTPQxyFUw9nOcKN7rzTj1q4g,5192
|
|
44
44
|
maidr/util/mixin/merger_mixin.py,sha256=V0qLw_6DUB7X6CQ3BCMpsCQX_ZuwAhoSTm_E4xAJFKM,712
|
|
@@ -46,7 +46,7 @@ maidr/util/regression_line_utils.py,sha256=P8RQLixTby2JLz73XZgNiu96C2Ct3pNe4ENRW
|
|
|
46
46
|
maidr/util/svg_utils.py,sha256=2gyzBtNKFHs0utrw1iOlxTmznzivOWQMV2aW8zu2c8E,1442
|
|
47
47
|
maidr/widget/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
maidr/widget/shiny.py,sha256=wrrw2KAIpE_A6CNQGBtNHauR1DjenA_n47qlFXX9_rk,745
|
|
49
|
-
maidr-1.
|
|
50
|
-
maidr-1.
|
|
51
|
-
maidr-1.
|
|
52
|
-
maidr-1.
|
|
49
|
+
maidr-1.3.0.dist-info/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
50
|
+
maidr-1.3.0.dist-info/METADATA,sha256=m0inXLNCctWjHu0KGU-tQd7q459C2xskdw3LC8-KTsw,2664
|
|
51
|
+
maidr-1.3.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
52
|
+
maidr-1.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|