maidr 1.7.3__tar.gz → 1.8.1__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 (162) hide show
  1. {maidr-1.7.3 → maidr-1.8.1}/CHANGELOG.md +27 -0
  2. {maidr-1.7.3 → maidr-1.8.1}/PKG-INFO +1 -1
  3. {maidr-1.7.3 → maidr-1.8.1}/maidr/__init__.py +1 -1
  4. maidr-1.8.1/maidr/api.py +155 -0
  5. maidr-1.8.1/maidr/core/plot/grouped_barplot.py +124 -0
  6. {maidr-1.7.3 → maidr-1.8.1}/pyproject.toml +3 -2
  7. {maidr-1.7.3 → maidr-1.8.1}/uv.lock +1426 -1083
  8. maidr-1.7.3/maidr/api.py +0 -64
  9. maidr-1.7.3/maidr/core/plot/grouped_barplot.py +0 -69
  10. {maidr-1.7.3 → maidr-1.8.1}/.commitlintrc.cjs +0 -0
  11. {maidr-1.7.3 → maidr-1.8.1}/.editorconfig +0 -0
  12. {maidr-1.7.3 → maidr-1.8.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  13. {maidr-1.7.3 → maidr-1.8.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  14. {maidr-1.7.3 → maidr-1.8.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  15. {maidr-1.7.3 → maidr-1.8.1}/.github/copilot-instructions.md +0 -0
  16. {maidr-1.7.3 → maidr-1.8.1}/.github/workflows/ci.yml +0 -0
  17. {maidr-1.7.3 → maidr-1.8.1}/.github/workflows/docs.yml +0 -0
  18. {maidr-1.7.3 → maidr-1.8.1}/.github/workflows/release.yml +0 -0
  19. {maidr-1.7.3 → maidr-1.8.1}/.gitignore +0 -0
  20. {maidr-1.7.3 → maidr-1.8.1}/.pre-commit-config.yaml +0 -0
  21. {maidr-1.7.3 → maidr-1.8.1}/.vscode/extensions.json +0 -0
  22. {maidr-1.7.3 → maidr-1.8.1}/.vscode/settings.json +0 -0
  23. {maidr-1.7.3 → maidr-1.8.1}/CONDUCT.md +0 -0
  24. {maidr-1.7.3 → maidr-1.8.1}/CONTRIBUTING.md +0 -0
  25. {maidr-1.7.3 → maidr-1.8.1}/LICENSE +0 -0
  26. {maidr-1.7.3 → maidr-1.8.1}/README.md +0 -0
  27. {maidr-1.7.3 → maidr-1.8.1}/docs/.gitignore +0 -0
  28. {maidr-1.7.3 → maidr-1.8.1}/docs/CNAME +0 -0
  29. {maidr-1.7.3 → maidr-1.8.1}/docs/_environment +0 -0
  30. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/machow/interlinks/.gitignore +0 -0
  31. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/machow/interlinks/_extension.yml +0 -0
  32. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/machow/interlinks/interlinks.lua +0 -0
  33. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/shafayetShafee/line-highlight/_extension.yml +0 -0
  34. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/shafayetShafee/line-highlight/line-highlight.lua +0 -0
  35. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/shafayetShafee/line-highlight/resources/css/line-highlight.css +0 -0
  36. {maidr-1.7.3 → maidr-1.8.1}/docs/_extensions/shafayetShafee/line-highlight/resources/js/line-highlight.js +0 -0
  37. {maidr-1.7.3 → maidr-1.8.1}/docs/_quarto.yml +0 -0
  38. {maidr-1.7.3 → maidr-1.8.1}/docs/examples.qmd +0 -0
  39. {maidr-1.7.3 → maidr-1.8.1}/docs/index.qmd +0 -0
  40. {maidr-1.7.3 → maidr-1.8.1}/docs/styles.css +0 -0
  41. {maidr-1.7.3 → maidr-1.8.1}/example/bar/example_bar_plot.ipynb +0 -0
  42. {maidr-1.7.3 → maidr-1.8.1}/example/bar/matplotlib/example_mpl_bar_plot.py +0 -0
  43. {maidr-1.7.3 → maidr-1.8.1}/example/bar/seaborn/example_sns_bar_plot.py +0 -0
  44. {maidr-1.7.3 → maidr-1.8.1}/example/box/example_box_plot.ipynb +0 -0
  45. {maidr-1.7.3 → maidr-1.8.1}/example/box/matplotlib/example_mpl_box.py +0 -0
  46. {maidr-1.7.3 → maidr-1.8.1}/example/box/seaborn/example_sns_box.py +0 -0
  47. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/legacy_candlestick_example.py +0 -0
  48. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/mplfinance_candlestick_example.py +0 -0
  49. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/test_data_daily_current_year.csv +0 -0
  50. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/test_data_daily_mixed_years.csv +0 -0
  51. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/test_data_hourly.csv +0 -0
  52. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/test_data_minute.csv +0 -0
  53. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/test_data_weekly.csv +0 -0
  54. {maidr-1.7.3 → maidr-1.8.1}/example/candle_stick/volcandat.csv +0 -0
  55. {maidr-1.7.3 → maidr-1.8.1}/example/count/example_count_plot.ipynb +0 -0
  56. {maidr-1.7.3 → maidr-1.8.1}/example/count/seaborn/example_sns_count_plot.py +0 -0
  57. {maidr-1.7.3 → maidr-1.8.1}/example/dodged/matplotlib/example_mpl_dodged.py +0 -0
  58. {maidr-1.7.3 → maidr-1.8.1}/example/dodged/seaborn/example_sns_dodged.py +0 -0
  59. {maidr-1.7.3 → maidr-1.8.1}/example/facet-subplots/matplotlib/example_mpl_facet_bar_plot.py +0 -0
  60. {maidr-1.7.3 → maidr-1.8.1}/example/facet-subplots/matplotlib/example_mpl_facet_combined_plot.py +0 -0
  61. {maidr-1.7.3 → maidr-1.8.1}/example/facet-subplots/seaborn/example_sns_facet_bar_plot.py +0 -0
  62. {maidr-1.7.3 → maidr-1.8.1}/example/facet-subplots/seaborn/example_sns_facet_combined_plot.py +0 -0
  63. {maidr-1.7.3 → maidr-1.8.1}/example/flask/test_flask_app.py +0 -0
  64. {maidr-1.7.3 → maidr-1.8.1}/example/heatmap/example_heatmap_plot.ipynb +0 -0
  65. {maidr-1.7.3 → maidr-1.8.1}/example/heatmap/matplotlib/example_mpl_heatmap.py +0 -0
  66. {maidr-1.7.3 → maidr-1.8.1}/example/heatmap/seaborn/example_sns_heatmap.py +0 -0
  67. {maidr-1.7.3 → maidr-1.8.1}/example/histogram/example_histogram_plot.ipynb +0 -0
  68. {maidr-1.7.3 → maidr-1.8.1}/example/histogram/matplotlib/example_mpl_hist.py +0 -0
  69. {maidr-1.7.3 → maidr-1.8.1}/example/histogram/matplotlib/histogram_with_kde_matplotlib.py +0 -0
  70. {maidr-1.7.3 → maidr-1.8.1}/example/histogram/seaborn/example_sns_hist.py +0 -0
  71. {maidr-1.7.3 → maidr-1.8.1}/example/histogram/seaborn/histogram_with_kde_seaborn.py +0 -0
  72. {maidr-1.7.3 → maidr-1.8.1}/example/kde/example_kde_plots.ipynb +0 -0
  73. {maidr-1.7.3 → maidr-1.8.1}/example/kde/matplotlib/multiple_kde_matplotlib.py +0 -0
  74. {maidr-1.7.3 → maidr-1.8.1}/example/kde/matplotlib/single_kde_matplotlib.py +0 -0
  75. {maidr-1.7.3 → maidr-1.8.1}/example/kde/seaborn/multiple_kde_seaborn.py +0 -0
  76. {maidr-1.7.3 → maidr-1.8.1}/example/kde/seaborn/single_kde_seaborn.py +0 -0
  77. {maidr-1.7.3 → maidr-1.8.1}/example/line/example_line_plot.ipynb +0 -0
  78. {maidr-1.7.3 → maidr-1.8.1}/example/line/matplotlib/example_mpl_line.py +0 -0
  79. {maidr-1.7.3 → maidr-1.8.1}/example/line/seaborn/example_sns_line.py +0 -0
  80. {maidr-1.7.3 → maidr-1.8.1}/example/multilayer/example_mpl_multilayer.py +0 -0
  81. {maidr-1.7.3 → maidr-1.8.1}/example/multilayer/example_multilayer_plot.ipynb +0 -0
  82. {maidr-1.7.3 → maidr-1.8.1}/example/multiline/example_multiline_plot.ipynb +0 -0
  83. {maidr-1.7.3 → maidr-1.8.1}/example/multiline/matplotlib/example_mpl_multiline.py +0 -0
  84. {maidr-1.7.3 → maidr-1.8.1}/example/multiline/seaborn/example_sns_multiline.py +0 -0
  85. {maidr-1.7.3 → maidr-1.8.1}/example/multipanel/example_multipanel_plot.ipynb +0 -0
  86. {maidr-1.7.3 → maidr-1.8.1}/example/multipanel/matplotlib/example_mpl_multipanel.py +0 -0
  87. {maidr-1.7.3 → maidr-1.8.1}/example/multipanel/seaborn/example_sns_multipanel.py +0 -0
  88. {maidr-1.7.3 → maidr-1.8.1}/example/quarto/demo.qmd +0 -0
  89. {maidr-1.7.3 → maidr-1.8.1}/example/reg/example_reg_plots.ipynb +0 -0
  90. {maidr-1.7.3 → maidr-1.8.1}/example/reg/matplotlib/example_matplotlib_smooth_plot.py +0 -0
  91. {maidr-1.7.3 → maidr-1.8.1}/example/reg/seaborn/example_sns_reg.py +0 -0
  92. {maidr-1.7.3 → maidr-1.8.1}/example/scatter/example_scatter_plot.ipynb +0 -0
  93. {maidr-1.7.3 → maidr-1.8.1}/example/scatter/matplotlib/example_mpl_scatter.py +0 -0
  94. {maidr-1.7.3 → maidr-1.8.1}/example/scatter/seaborn/example_sns_scatter.py +0 -0
  95. {maidr-1.7.3 → maidr-1.8.1}/example/shiny/example_shiny_scatter.py +0 -0
  96. {maidr-1.7.3 → maidr-1.8.1}/example/stacked/matplotlib/example_mpl_stacked.py +0 -0
  97. {maidr-1.7.3 → maidr-1.8.1}/example/stacked/seaborn/example_sns_stacked.py +0 -0
  98. {maidr-1.7.3 → maidr-1.8.1}/example/streamlit/example_streamlit_app.py +0 -0
  99. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/__init__.py +0 -0
  100. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/context_manager.py +0 -0
  101. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/enum/__init__.py +0 -0
  102. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/enum/library.py +0 -0
  103. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/enum/maidr_key.py +0 -0
  104. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/enum/plot_type.py +0 -0
  105. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/enum/smooth_keywords.py +0 -0
  106. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/figure_manager.py +0 -0
  107. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/maidr.py +0 -0
  108. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/__init__.py +0 -0
  109. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/barplot.py +0 -0
  110. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/boxplot.py +0 -0
  111. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/candlestick.py +0 -0
  112. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/heatmap.py +0 -0
  113. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/histogram.py +0 -0
  114. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/lineplot.py +0 -0
  115. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/maidr_plot.py +0 -0
  116. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/maidr_plot_factory.py +0 -0
  117. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/mplfinance_barplot.py +0 -0
  118. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/mplfinance_lineplot.py +0 -0
  119. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/regplot.py +0 -0
  120. {maidr-1.7.3 → maidr-1.8.1}/maidr/core/plot/scatterplot.py +0 -0
  121. {maidr-1.7.3 → maidr-1.8.1}/maidr/exception/__init__.py +0 -0
  122. {maidr-1.7.3 → maidr-1.8.1}/maidr/exception/extraction_error.py +0 -0
  123. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/__init__.py +0 -0
  124. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/barplot.py +0 -0
  125. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/boxplot.py +0 -0
  126. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/candlestick.py +0 -0
  127. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/clear.py +0 -0
  128. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/common.py +0 -0
  129. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/heatmap.py +0 -0
  130. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/highlight.py +0 -0
  131. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/histogram.py +0 -0
  132. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/kdeplot.py +0 -0
  133. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/lineplot.py +0 -0
  134. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/mplfinance.py +0 -0
  135. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/regplot.py +0 -0
  136. {maidr-1.7.3 → maidr-1.8.1}/maidr/patch/scatterplot.py +0 -0
  137. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/__init__.py +0 -0
  138. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/datetime_conversion.py +0 -0
  139. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/dedup_utils.py +0 -0
  140. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/environment.py +0 -0
  141. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/mixin/__init__.py +0 -0
  142. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/mixin/extractor_mixin.py +0 -0
  143. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/mixin/merger_mixin.py +0 -0
  144. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/mplfinance_utils.py +0 -0
  145. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/plot_detection.py +0 -0
  146. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/regression_line_utils.py +0 -0
  147. {maidr-1.7.3 → maidr-1.8.1}/maidr/util/svg_utils.py +0 -0
  148. {maidr-1.7.3 → maidr-1.8.1}/maidr/widget/__init__.py +0 -0
  149. {maidr-1.7.3 → maidr-1.8.1}/maidr/widget/shiny.py +0 -0
  150. {maidr-1.7.3 → maidr-1.8.1}/tests/__init__.py +0 -0
  151. {maidr-1.7.3 → maidr-1.8.1}/tests/conftest.py +0 -0
  152. {maidr-1.7.3 → maidr-1.8.1}/tests/core/__init__.py +0 -0
  153. {maidr-1.7.3 → maidr-1.8.1}/tests/core/enum/__init__.py +0 -0
  154. {maidr-1.7.3 → maidr-1.8.1}/tests/core/plot/__init__.py +0 -0
  155. {maidr-1.7.3 → maidr-1.8.1}/tests/core/test_figure_manager.py +0 -0
  156. {maidr-1.7.3 → maidr-1.8.1}/tests/core/test_maidr_plot.py +0 -0
  157. {maidr-1.7.3 → maidr-1.8.1}/tests/core/test_maidr_plot_factory.py +0 -0
  158. {maidr-1.7.3 → maidr-1.8.1}/tests/fixture/__init__.py +0 -0
  159. {maidr-1.7.3 → maidr-1.8.1}/tests/fixture/library_factory.py +0 -0
  160. {maidr-1.7.3 → maidr-1.8.1}/tests/fixture/matplotlib_factory.py +0 -0
  161. {maidr-1.7.3 → maidr-1.8.1}/tests/fixture/seaborn_factory.py +0 -0
  162. {maidr-1.7.3 → maidr-1.8.1}/tox.ini +0 -0
@@ -1,6 +1,33 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v1.8.1 (2025-10-16)
5
+
6
+ ### Bug Fixes
7
+
8
+ - Address container label issue in seaborn dodged plots
9
+ ([#256](https://github.com/xability/py-maidr/pull/256),
10
+ [`3b09039`](https://github.com/xability/py-maidr/commit/3b09039ba33a10903797559a27d53869ba6b9d2f))
11
+
12
+
13
+ ## v1.8.0 (2025-09-17)
14
+
15
+ ### Features
16
+
17
+ - Remove maidr.show params ([#244](https://github.com/xability/py-maidr/pull/244),
18
+ [`493cf57`](https://github.com/xability/py-maidr/commit/493cf5713068b1514b4836e46763c3619a51dd23))
19
+
20
+ ### Refactoring
21
+
22
+ - **maidr.api**: Improve lazy figure detection, eliminate code duplication, and resolve merge
23
+ conflicts ([#241](https://github.com/xability/py-maidr/pull/241),
24
+ [`15a966e`](https://github.com/xability/py-maidr/commit/15a966ea2ca9170ddf8bc28634705fb6233a1d58))
25
+
26
+ Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
27
+
28
+ Co-authored-by: jooyoungseo <19754711+jooyoungseo@users.noreply.github.com>
29
+
30
+
4
31
  ## v1.7.3 (2025-09-15)
5
32
 
6
33
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maidr
3
- Version: 1.7.3
3
+ Version: 1.8.1
4
4
  Summary: Multimodal Access and Interactive Data Representations
5
5
  Project-URL: Homepage, https://xability.github.io/py-maidr
6
6
  Project-URL: Repository, https://github.com/xability/py-maidr
@@ -1,4 +1,4 @@
1
- __version__ = "1.7.3"
1
+ __version__ = "1.8.1"
2
2
 
3
3
  from .api import close, render, save_html, show, stacked
4
4
  from .core import Maidr
@@ -0,0 +1,155 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal
4
+
5
+ from htmltools import Tag
6
+ from matplotlib.axes import Axes
7
+ from matplotlib.container import BarContainer
8
+
9
+ from maidr.core import Maidr
10
+ from maidr.core.enum import PlotType
11
+ from maidr.core.figure_manager import FigureManager
12
+
13
+
14
+ def _get_plot_or_current(plot: Any | None) -> Any:
15
+ """
16
+ Get the plot object or current matplotlib figure if plot is None.
17
+
18
+ Parameters
19
+ ----------
20
+ plot : Any or None
21
+ The plot object. If None, returns the current matplotlib figure.
22
+
23
+ Returns
24
+ -------
25
+ Any
26
+ The plot object or current matplotlib figure.
27
+ """
28
+ if plot is None:
29
+ # Lazy import matplotlib.pyplot when needed
30
+ import matplotlib.pyplot as plt
31
+
32
+ return plt.gcf()
33
+ return plot
34
+
35
+
36
+ def render(plot: Any | None = None) -> Tag:
37
+ """
38
+ Render a MAIDR plot to HTML.
39
+
40
+ Parameters
41
+ ----------
42
+ plot : Any or None, optional
43
+ The plot object to render. If None, uses the current matplotlib figure.
44
+
45
+ Returns
46
+ -------
47
+ htmltools.Tag
48
+ The rendered HTML representation of the plot.
49
+ """
50
+ plot = _get_plot_or_current(plot)
51
+
52
+ ax = FigureManager.get_axes(plot)
53
+ if isinstance(ax, list):
54
+ for axes in ax:
55
+ maidr = FigureManager.get_maidr(axes.get_figure())
56
+ return maidr.render()
57
+ else:
58
+ maidr = FigureManager.get_maidr(ax.get_figure())
59
+ return maidr.render()
60
+
61
+
62
+ def show(
63
+ plot: Any | None = None,
64
+ renderer: Literal["auto", "ipython", "browser"] = "auto",
65
+ clear_fig: bool = True,
66
+ ) -> object:
67
+ """
68
+ Display a MAIDR plot.
69
+
70
+ Parameters
71
+ ----------
72
+ plot : Any or None, optional
73
+ The plot object to display. If None, uses the current matplotlib figure.
74
+ renderer : {"auto", "ipython", "browser"}, default "auto"
75
+ The renderer to use for display.
76
+ clear_fig : bool, default True
77
+ Whether to clear the figure after displaying.
78
+
79
+ Returns
80
+ -------
81
+ object
82
+ The display result.
83
+ """
84
+ plot = _get_plot_or_current(plot)
85
+
86
+ ax = FigureManager.get_axes(plot)
87
+ if isinstance(ax, list):
88
+ for axes in ax:
89
+ maidr = FigureManager.get_maidr(axes.get_figure())
90
+ return maidr.show(renderer)
91
+ else:
92
+ maidr = FigureManager.get_maidr(ax.get_figure())
93
+ return maidr.show(renderer, clear_fig=clear_fig)
94
+
95
+
96
+ def save_html(
97
+ plot: Any | None = None,
98
+ *,
99
+ file: str,
100
+ lib_dir: str | None = "lib",
101
+ include_version: bool = True
102
+ ) -> str:
103
+ """
104
+ Save a MAIDR plot as HTML file.
105
+
106
+ Parameters
107
+ ----------
108
+ plot : Any or None, optional
109
+ The plot object to save. If None, uses the current matplotlib figure.
110
+ file : str
111
+ The file path where to save the HTML.
112
+ lib_dir : str or None, default "lib"
113
+ Directory name for libraries.
114
+ include_version : bool, default True
115
+ Whether to include version information.
116
+
117
+ Returns
118
+ -------
119
+ str
120
+ The path to the saved HTML file.
121
+ """
122
+ plot = _get_plot_or_current(plot)
123
+
124
+ ax = FigureManager.get_axes(plot)
125
+ htmls = []
126
+ if isinstance(ax, list):
127
+ for axes in ax:
128
+ maidr = FigureManager.get_maidr(axes.get_figure())
129
+ htmls.append(maidr._create_html_doc(use_iframe=False))
130
+ return htmls[-1].save_html(
131
+ file, libdir=lib_dir, include_version=include_version
132
+ )
133
+ else:
134
+ maidr = FigureManager.get_maidr(ax.get_figure())
135
+ return maidr.save_html(file, lib_dir=lib_dir, include_version=include_version)
136
+
137
+
138
+ def stacked(plot: Axes | BarContainer) -> Maidr:
139
+ ax = FigureManager.get_axes(plot)
140
+ return FigureManager.create_maidr(ax, PlotType.STACKED)
141
+
142
+
143
+ def close(plot: Any | None = None) -> None:
144
+ """
145
+ Close a MAIDR plot and clean up resources.
146
+
147
+ Parameters
148
+ ----------
149
+ plot : Any or None, optional
150
+ The plot object to close. If None, uses the current matplotlib figure.
151
+ """
152
+ plot = _get_plot_or_current(plot)
153
+
154
+ ax = FigureManager.get_axes(plot)
155
+ FigureManager.destroy(ax.get_figure())
@@ -0,0 +1,124 @@
1
+ from __future__ import annotations
2
+
3
+ from matplotlib.axes import Axes
4
+ from matplotlib.container import BarContainer
5
+
6
+ from maidr.core.enum import MaidrKey, PlotType
7
+ from maidr.core.plot import MaidrPlot
8
+ from maidr.exception import ExtractionError
9
+ from maidr.util.mixin import (
10
+ ContainerExtractorMixin,
11
+ DictMergerMixin,
12
+ LevelExtractorMixin,
13
+ )
14
+
15
+
16
+ class GroupedBarPlot(
17
+ MaidrPlot, ContainerExtractorMixin, LevelExtractorMixin, DictMergerMixin
18
+ ):
19
+ def __init__(self, ax: Axes, plot_type: PlotType, **kwargs) -> None:
20
+ super().__init__(ax, plot_type)
21
+
22
+ def _extract_axes_data(self) -> dict:
23
+ base_ax_schema = super()._extract_axes_data()
24
+ grouped_ax_schema = {
25
+ MaidrKey.X.value: self.ax.get_xlabel(),
26
+ MaidrKey.Y.value: self.ax.get_ylabel(),
27
+ }
28
+ return self.merge_dict(base_ax_schema, grouped_ax_schema)
29
+
30
+ def _extract_plot_data(self):
31
+ plot = self.extract_container(self.ax, BarContainer, include_all=True)
32
+ data = self._extract_grouped_bar_data(plot)
33
+
34
+ if data is None:
35
+ raise ExtractionError(self.type, plot)
36
+
37
+ return data
38
+
39
+ def _extract_grouped_bar_data(
40
+ self, plot: list[BarContainer] | None
41
+ ) -> list[dict] | None:
42
+ if plot is None:
43
+ return None
44
+
45
+ x_level = self.extract_level(self.ax)
46
+ if x_level is None:
47
+ return None
48
+
49
+ data = []
50
+
51
+ self._elements.extend(
52
+ [patch for container in plot for patch in container.patches]
53
+ )
54
+
55
+ # Get hue categories from legend
56
+ hue_categories = self._extract_hue_categories_from_legend()
57
+
58
+ for i, container in enumerate(plot):
59
+ if len(x_level) != len(container.patches):
60
+ return None
61
+ container_data = []
62
+
63
+ # Use hue category if available, otherwise fall back to container label
64
+ fill_value = hue_categories[i] if i < len(hue_categories) else container.get_label()
65
+
66
+ for x, y in zip(x_level, container.patches):
67
+ container_data.append(
68
+ {
69
+ MaidrKey.X.value: x,
70
+ MaidrKey.FILL.value: fill_value,
71
+ MaidrKey.Y.value: float(y.get_height()),
72
+ }
73
+ )
74
+ data.append(container_data)
75
+
76
+ return data
77
+
78
+ def _extract_hue_categories_from_legend(self) -> list[str]:
79
+ """
80
+ Extract hue categories from the axes legend.
81
+
82
+ This method reads the legend text elements from the axes legend,
83
+ trims whitespace from each text, and returns a list of cleaned
84
+ category names. This is used to get the actual category names
85
+ instead of using the generic container labels like '_container0', '_container1'.
86
+
87
+ Parameters
88
+ ----------
89
+ None
90
+ This method uses the instance's axes object.
91
+
92
+ Returns
93
+ -------
94
+ list[str]
95
+ List of trimmed hue category names from the legend.
96
+ Returns empty list if no legend is found or if legend has no text elements.
97
+
98
+ Examples
99
+ --------
100
+ >>> # For a seaborn barplot with hue='category' and legend showing 'Below', 'Above'
101
+ >>> plot = GroupedBarPlot(ax, PlotType.DODGED)
102
+ >>> categories = plot._extract_hue_categories_from_legend()
103
+ >>> print(categories)
104
+ ['Below', 'Above']
105
+
106
+ >>> # If no legend exists
107
+ >>> categories = plot._extract_hue_categories_from_legend()
108
+ >>> print(categories)
109
+ []
110
+ """
111
+ legend = self.ax.get_legend()
112
+ if legend is None:
113
+ return []
114
+
115
+ # Get legend text elements
116
+ legend_texts = legend.get_texts()
117
+ if not legend_texts:
118
+ return []
119
+
120
+ # Extract text content from legend elements and trim whitespace
121
+ hue_categories = [text.get_text().strip() for text in legend_texts]
122
+
123
+ # Filter out empty strings and return
124
+ return [category for category in hue_categories if category]
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "maidr"
7
- version = "1.7.3"
7
+ version = "1.8.1"
8
8
  description = "Multimodal Access and Interactive Data Representations"
9
9
  authors = [
10
10
  { name = "JooYoung Seo", email = "jseo1005@illinois.edu" },
@@ -82,7 +82,8 @@ dev = [
82
82
  "python-semantic-release==9.21.0",
83
83
  "pytest-mock>=3.12.0,<4",
84
84
  "tox>=4.13.0,<5",
85
- "quartodoc>=0.8.0,<0.9"
85
+ "quartodoc>=0.8.0,<0.9",
86
+ "griffe>=0.48,<1.0"
86
87
  ]
87
88
 
88
89
  [tool.ruff]