maidr 0.23.1__tar.gz → 0.25.0__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 (43) hide show
  1. {maidr-0.23.1 → maidr-0.25.0}/PKG-INFO +1 -1
  2. {maidr-0.23.1 → maidr-0.25.0}/maidr/__init__.py +1 -1
  3. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/enum/maidr_key.py +2 -0
  4. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/maidr.py +7 -4
  5. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/boxplot.py +108 -2
  6. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/lineplot.py +2 -1
  7. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/highlight.py +4 -3
  8. {maidr-0.23.1 → maidr-0.25.0}/pyproject.toml +1 -1
  9. {maidr-0.23.1 → maidr-0.25.0}/LICENSE +0 -0
  10. {maidr-0.23.1 → maidr-0.25.0}/README.md +0 -0
  11. {maidr-0.23.1 → maidr-0.25.0}/maidr/api.py +0 -0
  12. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/__init__.py +0 -0
  13. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/context_manager.py +0 -0
  14. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/enum/__init__.py +0 -0
  15. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/enum/library.py +0 -0
  16. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/enum/plot_type.py +0 -0
  17. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/figure_manager.py +0 -0
  18. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/__init__.py +0 -0
  19. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/barplot.py +0 -0
  20. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/grouped_barplot.py +0 -0
  21. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/heatmap.py +0 -0
  22. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/histogram.py +0 -0
  23. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/maidr_plot.py +0 -0
  24. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/maidr_plot_factory.py +0 -0
  25. {maidr-0.23.1 → maidr-0.25.0}/maidr/core/plot/scatterplot.py +0 -0
  26. {maidr-0.23.1 → maidr-0.25.0}/maidr/exception/__init__.py +0 -0
  27. {maidr-0.23.1 → maidr-0.25.0}/maidr/exception/extraction_error.py +0 -0
  28. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/__init__.py +0 -0
  29. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/barplot.py +0 -0
  30. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/boxplot.py +0 -0
  31. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/clear.py +0 -0
  32. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/common.py +0 -0
  33. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/heatmap.py +0 -0
  34. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/histogram.py +0 -0
  35. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/lineplot.py +0 -0
  36. {maidr-0.23.1 → maidr-0.25.0}/maidr/patch/scatterplot.py +0 -0
  37. {maidr-0.23.1 → maidr-0.25.0}/maidr/util/__init__.py +0 -0
  38. {maidr-0.23.1 → maidr-0.25.0}/maidr/util/environment.py +0 -0
  39. {maidr-0.23.1 → maidr-0.25.0}/maidr/util/mixin/__init__.py +0 -0
  40. {maidr-0.23.1 → maidr-0.25.0}/maidr/util/mixin/extractor_mixin.py +0 -0
  41. {maidr-0.23.1 → maidr-0.25.0}/maidr/util/mixin/merger_mixin.py +0 -0
  42. {maidr-0.23.1 → maidr-0.25.0}/maidr/widget/__init__.py +0 -0
  43. {maidr-0.23.1 → maidr-0.25.0}/maidr/widget/shiny.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: maidr
3
- Version: 0.23.1
3
+ Version: 0.25.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
@@ -1,4 +1,4 @@
1
- __version__ = "0.23.1"
1
+ __version__ = "0.25.0"
2
2
 
3
3
  from .api import close, render, save_html, show, stacked
4
4
  from .core import Maidr
@@ -30,6 +30,8 @@ class MaidrKey(str, Enum):
30
30
  Q2 = "q2"
31
31
  Q3 = "q3"
32
32
  UPPER_OUTLIER = "upperOutliers"
33
+ IQ = "iq"
34
+ MEDIAN = "median"
33
35
 
34
36
  # Grouped bar and heatmap plot keys.
35
37
  FILL = "fill"
@@ -122,7 +122,10 @@ class Maidr:
122
122
 
123
123
  def _create_html_tag(self) -> Tag:
124
124
  """Create the MAIDR HTML using HTML tags."""
125
- tagged_elements = [element for plot in self._plots for element in plot.elements]
125
+ tagged_elements: list[Any] = [
126
+ element for plot in self._plots for element in plot.elements
127
+ ]
128
+
126
129
  selector_ids = []
127
130
  for i, plot in enumerate(self._plots):
128
131
  for _ in plot.elements:
@@ -149,7 +152,7 @@ class Maidr:
149
152
  for i, plot in enumerate(self._plots):
150
153
  schema = plot.schema
151
154
 
152
- if MaidrKey.SELECTOR in schema:
155
+ if MaidrKey.SELECTOR in schema and plot.type != PlotType.BOX:
153
156
  if isinstance(schema[MaidrKey.SELECTOR], str):
154
157
  schema[MaidrKey.SELECTOR] = schema[MaidrKey.SELECTOR].replace(
155
158
  "maidr='true'", f"maidr='{self.selector_ids[i]}'"
@@ -238,7 +241,7 @@ class Maidr:
238
241
  def _inject_plot(plot: HTML, maidr: str, maidr_id) -> Tag:
239
242
  """Embed the plot and associated MAIDR scripts into the HTML structure."""
240
243
  # MAIDR_TS_CDN_URL = "http://localhost:8080/maidr.js" # DEMO URL
241
- MAIDR_TS_CDN_URL = "https://cdn.jsdelivr.net/npm/maidr-ts/dist/maidr.js"
244
+ MAIDR_TS_CDN_URL = "https://cdn.jsdelivr.net/npm/maidr/dist/maidr.js"
242
245
 
243
246
  script = f"""
244
247
  if (!document.querySelector('script[src="{MAIDR_TS_CDN_URL}"]'))
@@ -260,7 +263,7 @@ class Maidr:
260
263
  base_html = tags.div(
261
264
  tags.link(
262
265
  rel="stylesheet",
263
- href="https://cdn.jsdelivr.net/npm/maidr/dist/maidr_style.min.css",
266
+ href="https://cdn.jsdelivr.net/npm/maidr/dist/maidr_style.css",
264
267
  ),
265
268
  tags.script(script, type="text/javascript"),
266
269
  tags.div(plot),
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import uuid
4
+
3
5
  from matplotlib.axes import Axes
4
6
 
5
7
  from maidr.core.enum import MaidrKey, PlotType
@@ -119,6 +121,40 @@ class BoxPlotExtractor:
119
121
  return data
120
122
 
121
123
 
124
+ class BoxPlotElementsExtractor:
125
+ def __init__(self, orientation: str = "vert"):
126
+ self.orientation = orientation
127
+
128
+ def extract_whiskers(self, whiskers: list) -> list[dict]:
129
+ return self._extract_extremes(whiskers, MaidrKey.Q1, MaidrKey.Q3)
130
+
131
+ def extract_caps(self, caps: list) -> list[dict]:
132
+ return self._extract_extremes(caps, MaidrKey.MIN, MaidrKey.MAX)
133
+
134
+ def _extract_extremes(
135
+ self, extremes: list, start_key: MaidrKey, end_key: MaidrKey
136
+ ) -> list[dict]:
137
+ elements = []
138
+
139
+ for start, end in zip(extremes[::2], extremes[1::2]):
140
+ elements.append(
141
+ {
142
+ start_key.value: start,
143
+ end_key.value: end,
144
+ }
145
+ )
146
+
147
+ return elements
148
+
149
+ def extract_outliers(self, fliers: list, caps: list):
150
+ elements = []
151
+
152
+ for outlier, _ in zip(fliers, caps):
153
+ elements.append(outlier)
154
+
155
+ return elements
156
+
157
+
122
158
  class BoxPlot(
123
159
  MaidrPlot,
124
160
  ContainerExtractorMixin,
@@ -131,7 +167,33 @@ class BoxPlot(
131
167
  self._bxp_stats = kwargs.pop("bxp_stats", None)
132
168
  self._orientation = kwargs.pop("orientation", "vert")
133
169
  self._bxp_extractor = BoxPlotExtractor(orientation=self._orientation)
134
- self._support_highlighting = False
170
+ self._bxp_elements_extractor = BoxPlotElementsExtractor(
171
+ orientation=self._orientation
172
+ )
173
+ self._support_highlighting = True
174
+ self.elements_map = {
175
+ "min": [],
176
+ "max": [],
177
+ "median": [],
178
+ "boxes": [],
179
+ "outliers": [],
180
+ }
181
+
182
+ def _get_selector(self) -> list[dict]:
183
+ mins, maxs, medians, boxes, outliers = self.elements_map.values()
184
+ selector = []
185
+ for min, max, median, box, outlier in zip(mins, maxs, medians, boxes, outliers):
186
+ selector.append(
187
+ {
188
+ MaidrKey.LOWER_OUTLIER.value: ["g[id=" + outlier + "] > g > use"],
189
+ MaidrKey.MIN.value: "g[id=" + min + "] > path",
190
+ MaidrKey.MAX.value: "g[id=" + max + "] > path",
191
+ MaidrKey.Q2.value: "g[id=" + median + "] > path",
192
+ MaidrKey.IQ.value: "g[id=" + box + "] > path",
193
+ MaidrKey.UPPER_OUTLIER.value: ["g[id=" + outlier + "] > g > use"],
194
+ }
195
+ )
196
+ return selector if self._orientation == "vert" else list(reversed(selector))
135
197
 
136
198
  def render(self) -> dict:
137
199
  base_schema = super().render()
@@ -150,11 +212,14 @@ class BoxPlot(
150
212
  if bxp_stats is None:
151
213
  return None
152
214
 
153
- bxp_maidr = []
154
215
  whiskers = self._bxp_extractor.extract_whiskers(bxp_stats["whiskers"])
155
216
  caps = self._bxp_extractor.extract_caps(bxp_stats["caps"])
156
217
  medians = self._bxp_extractor.extract_medians(bxp_stats["medians"])
157
218
  outliers = self._bxp_extractor.extract_outliers(bxp_stats["fliers"], caps)
219
+
220
+ caps_elements = self._bxp_elements_extractor.extract_caps(bxp_stats["caps"])
221
+ bxp_maidr = []
222
+
158
223
  levels = (
159
224
  self.extract_level(self.ax, MaidrKey.X)
160
225
  if self._orientation == "vert"
@@ -163,6 +228,47 @@ class BoxPlot(
163
228
  if levels is None:
164
229
  levels = []
165
230
 
231
+ _pairs = [(e["min"], e["max"]) for e in caps_elements if e]
232
+
233
+ if _pairs:
234
+ mins, maxs = map(list, zip(*_pairs))
235
+ else:
236
+ mins, maxs = [], []
237
+
238
+ elements = []
239
+
240
+ for element in mins:
241
+ gid = "maidr-" + str(uuid.uuid4())
242
+ element.set_gid(gid)
243
+ self.elements_map["min"].append(gid)
244
+ elements.append(element)
245
+
246
+ for element in maxs:
247
+ gid = "maidr-" + str(uuid.uuid4())
248
+ element.set_gid(gid)
249
+ self.elements_map["max"].append(gid)
250
+ elements.append(element)
251
+
252
+ for element in bxp_stats["medians"]:
253
+ gid = "maidr-" + str(uuid.uuid4())
254
+ element.set_gid(gid)
255
+ self.elements_map["median"].append(gid)
256
+ elements.append(element)
257
+
258
+ for element in bxp_stats["boxes"]:
259
+ gid = "maidr-" + str(uuid.uuid4())
260
+ element.set_gid(gid)
261
+ self.elements_map["boxes"].append(gid)
262
+ elements.append(element)
263
+
264
+ for element in bxp_stats["fliers"]:
265
+ gid = "maidr-" + str(uuid.uuid4())
266
+ element.set_gid(gid)
267
+ self.elements_map["outliers"].append(gid)
268
+ elements.append(element)
269
+
270
+ self._elements.extend(elements)
271
+
166
272
  for whisker, cap, median, outlier, level in zip(
167
273
  whiskers, caps, medians, outliers, levels
168
274
  ):
@@ -90,7 +90,8 @@ class MultiLinePlot(MaidrPlot, LineExtractorMixin):
90
90
  {
91
91
  MaidrKey.X: float(x),
92
92
  MaidrKey.Y: float(y),
93
- # Replace labels starting with '_child' with an empty string to exclude
93
+ # Replace labels starting with '_child'
94
+ # with an empty string to exclude
94
95
  # internal or non-relevant labels from being used as identifiers.
95
96
  MaidrKey.FILL: (label if not label.startswith("_child") else ""),
96
97
  }
@@ -5,7 +5,6 @@ import uuid
5
5
  import wrapt
6
6
  from matplotlib.backends.backend_svg import XMLWriter
7
7
  from matplotlib.collections import PathCollection, QuadMesh
8
- from matplotlib.figure import Figure
9
8
  from matplotlib.lines import Line2D
10
9
  from matplotlib.patches import Patch
11
10
 
@@ -20,8 +19,10 @@ def inject_maidr_attribute(wrapped, instance, args, kwargs):
20
19
 
21
20
 
22
21
  def tag_elements(wrapped, instance, args, kwargs):
23
- id = str(uuid.uuid4())
24
- instance.set_gid(id)
22
+ id = str(instance.get_gid())
23
+ if not id.startswith("maidr-"):
24
+ id = "maidr-" + str(uuid.uuid4())
25
+ instance.set_gid(id)
25
26
  with HighlightContextManager.set_maidr_element(instance, id):
26
27
  return wrapped(*args, **kwargs)
27
28
 
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "maidr"
7
- version = "0.23.1"
7
+ version = "0.25.0"
8
8
  description = "Multimodal Access and Interactive Data Representations"
9
9
  authors = [
10
10
  "JooYoung Seo <jseo1005@illinois.edu>",
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