maidr 1.6.0__tar.gz → 1.7.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.
- {maidr-1.6.0 → maidr-1.7.0}/CHANGELOG.md +34 -0
- {maidr-1.6.0 → maidr-1.7.0}/PKG-INFO +1 -2
- {maidr-1.6.0 → maidr-1.7.0}/docs/examples.qmd +88 -2
- {maidr-1.6.0 → maidr-1.7.0}/docs/index.qmd +28 -2
- maidr-1.7.0/example/candle_stick/test_data_daily_current_year.csv +11 -0
- maidr-1.7.0/example/candle_stick/test_data_daily_mixed_years.csv +11 -0
- maidr-1.7.0/example/candle_stick/test_data_hourly.csv +11 -0
- maidr-1.7.0/example/candle_stick/test_data_minute.csv +11 -0
- maidr-1.7.0/example/candle_stick/test_data_weekly.csv +11 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/__init__.py +1 -1
- maidr-1.7.0/maidr/core/plot/candlestick.py +233 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/mplfinance_barplot.py +18 -1
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/mplfinance_lineplot.py +11 -3
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/candlestick.py +27 -1
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/mplfinance.py +38 -5
- maidr-1.7.0/maidr/util/datetime_conversion.py +406 -0
- {maidr-1.6.0 → maidr-1.7.0}/pyproject.toml +1 -2
- {maidr-1.6.0 → maidr-1.7.0}/uv.lock +1 -3
- maidr-1.6.0/maidr/core/plot/candlestick.py +0 -141
- {maidr-1.6.0 → maidr-1.7.0}/.commitlintrc.cjs +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.editorconfig +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/copilot-instructions.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/workflows/ci.yml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/workflows/docs.yml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.github/workflows/release.yml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.gitignore +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.pre-commit-config.yaml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.vscode/extensions.json +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/.vscode/settings.json +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/CONDUCT.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/CONTRIBUTING.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/LICENSE +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/README.md +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/.gitignore +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/CNAME +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_environment +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/machow/interlinks/.gitignore +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/machow/interlinks/_extension.yml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/machow/interlinks/interlinks.lua +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/shafayetShafee/line-highlight/_extension.yml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/shafayetShafee/line-highlight/line-highlight.lua +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/shafayetShafee/line-highlight/resources/css/line-highlight.css +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_extensions/shafayetShafee/line-highlight/resources/js/line-highlight.js +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/_quarto.yml +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/docs/styles.css +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/bar/example_bar_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/bar/matplotlib/example_mpl_bar_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/bar/seaborn/example_sns_bar_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/box/example_box_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/box/matplotlib/example_mpl_box.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/box/seaborn/example_sns_box.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/candle_stick/legacy_candlestick_example.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/candle_stick/mplfinance_candlestick_example.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/candle_stick/volcandat.csv +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/count/example_count_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/count/seaborn/example_sns_count_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/dodged/matplotlib/example_mpl_dodged.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/dodged/seaborn/example_sns_dodged.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/facet-subplots/matplotlib/example_mpl_facet_bar_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/facet-subplots/matplotlib/example_mpl_facet_combined_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/facet-subplots/seaborn/example_sns_facet_bar_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/facet-subplots/seaborn/example_sns_facet_combined_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/flask/test_flask_app.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/heatmap/example_heatmap_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/heatmap/matplotlib/example_mpl_heatmap.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/heatmap/seaborn/example_sns_heatmap.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/histogram/example_histogram_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/histogram/matplotlib/example_mpl_hist.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/histogram/matplotlib/histogram_with_kde_matplotlib.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/histogram/seaborn/example_sns_hist.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/histogram/seaborn/histogram_with_kde_seaborn.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/kde/example_kde_plots.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/kde/matplotlib/multiple_kde_matplotlib.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/kde/matplotlib/single_kde_matplotlib.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/kde/seaborn/multiple_kde_seaborn.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/kde/seaborn/single_kde_seaborn.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/line/example_line_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/line/matplotlib/example_mpl_line.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/line/seaborn/example_sns_line.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multilayer/example_mpl_multilayer.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multilayer/example_multilayer_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multiline/example_multiline_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multiline/matplotlib/example_mpl_multiline.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multiline/seaborn/example_sns_multiline.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multipanel/example_multipanel_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multipanel/matplotlib/example_mpl_multipanel.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/multipanel/seaborn/example_sns_multipanel.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/quarto/demo.qmd +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/reg/example_reg_plots.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/reg/matplotlib/example_matplotlib_smooth_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/reg/seaborn/example_sns_reg.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/scatter/example_scatter_plot.ipynb +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/scatter/matplotlib/example_mpl_scatter.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/scatter/seaborn/example_sns_scatter.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/shiny/example_shiny_scatter.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/stacked/matplotlib/example_mpl_stacked.html +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/stacked/matplotlib/example_mpl_stacked.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/stacked/seaborn/example_sns_stacked.html +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/stacked/seaborn/example_sns_stacked.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/example/streamlit/example_streamlit_app.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/api.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/context_manager.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/enum/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/enum/library.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/enum/maidr_key.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/enum/plot_type.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/enum/smooth_keywords.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/figure_manager.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/maidr.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/barplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/boxplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/grouped_barplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/heatmap.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/histogram.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/lineplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/maidr_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/maidr_plot_factory.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/regplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/core/plot/scatterplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/exception/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/exception/extraction_error.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/barplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/boxplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/clear.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/common.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/heatmap.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/highlight.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/histogram.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/kdeplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/lineplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/regplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/patch/scatterplot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/dedup_utils.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/environment.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/mixin/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/mixin/extractor_mixin.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/mixin/merger_mixin.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/mplfinance_utils.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/plot_detection.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/regression_line_utils.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/util/svg_utils.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/widget/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/maidr/widget/shiny.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/conftest.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/core/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/core/enum/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/core/plot/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/core/test_figure_manager.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/core/test_maidr_plot.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/core/test_maidr_plot_factory.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/fixture/__init__.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/fixture/library_factory.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/fixture/matplotlib_factory.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tests/fixture/seaborn_factory.py +0 -0
- {maidr-1.6.0 → maidr-1.7.0}/tox.ini +0 -0
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v1.7.0 (2025-08-21)
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
- Format date in candlestick ([#234](https://github.com/xability/py-maidr/pull/234),
|
|
9
|
+
[`ffe03f7`](https://github.com/xability/py-maidr/commit/ffe03f7a2368ef33a4266692e7b652daafa14a30))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## v1.6.1 (2025-08-13)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- Add new selector logic for candlestick plots
|
|
17
|
+
([#231](https://github.com/xability/py-maidr/pull/231),
|
|
18
|
+
[`66cd73a`](https://github.com/xability/py-maidr/commit/66cd73adb04f77c0b83fd6e2d9cf757ee909bd69))
|
|
19
|
+
|
|
20
|
+
### Continuous Integration
|
|
21
|
+
|
|
22
|
+
- Remove virtualenv dependecny ([#228](https://github.com/xability/py-maidr/pull/228),
|
|
23
|
+
[`b8e1423`](https://github.com/xability/py-maidr/commit/b8e1423c2ecd073bd1037466f68577242872df6b))
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
- Update user manual to reflect all supported plot types with proper technical descriptions
|
|
28
|
+
([#230](https://github.com/xability/py-maidr/pull/230),
|
|
29
|
+
[`bae1163`](https://github.com/xability/py-maidr/commit/bae116322cb580f5c528da2857a7ca3ec2a655a7))
|
|
30
|
+
|
|
31
|
+
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
|
|
32
|
+
|
|
33
|
+
Co-authored-by: jooyoungseo <19754711+jooyoungseo@users.noreply.github.com>
|
|
34
|
+
|
|
35
|
+
Co-authored-by: JooYoung Seo <jseo1005@illinois.edu>
|
|
36
|
+
|
|
37
|
+
|
|
4
38
|
## v1.6.0 (2025-08-04)
|
|
5
39
|
|
|
6
40
|
### Continuous Integration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maidr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
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
|
|
@@ -28,7 +28,6 @@ Requires-Dist: htmltools>=0.5
|
|
|
28
28
|
Requires-Dist: lxml>=5.1.0
|
|
29
29
|
Requires-Dist: mplfinance>=0.12.10b0
|
|
30
30
|
Requires-Dist: numpy>=1.26
|
|
31
|
-
Requires-Dist: virtualenv<21,>=20.26.6
|
|
32
31
|
Requires-Dist: wrapt<2,>=1.16.0
|
|
33
32
|
Provides-Extra: jupyter
|
|
34
33
|
Requires-Dist: ipykernel>=6.0.0; extra == 'jupyter'
|
|
@@ -49,6 +49,33 @@ plt.ylabel("Body Mass (g)")
|
|
|
49
49
|
maidr.show(bar_plot) #<<
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
|
|
53
|
+
### Count Plots
|
|
54
|
+
|
|
55
|
+
```{python}
|
|
56
|
+
#| warning: false
|
|
57
|
+
#| fig-alt: Count plot showing frequency of categorical data
|
|
58
|
+
|
|
59
|
+
import matplotlib.pyplot as plt
|
|
60
|
+
import seaborn as sns
|
|
61
|
+
|
|
62
|
+
import maidr #<<
|
|
63
|
+
|
|
64
|
+
# Load the Titanic dataset
|
|
65
|
+
titanic = sns.load_dataset("titanic")
|
|
66
|
+
|
|
67
|
+
# Create a count plot
|
|
68
|
+
plt.figure(figsize=(6, 6))
|
|
69
|
+
count_plot = sns.countplot(x="class", data=titanic, palette="viridis") #<<
|
|
70
|
+
|
|
71
|
+
plt.title("Passenger Class Distribution on the Titanic")
|
|
72
|
+
plt.xlabel("Passenger Class")
|
|
73
|
+
plt.ylabel("Count")
|
|
74
|
+
|
|
75
|
+
# plt.show()
|
|
76
|
+
maidr.show(count_plot) #<<
|
|
77
|
+
```
|
|
78
|
+
|
|
52
79
|
#### Vertical Stacked Bar Plot
|
|
53
80
|
|
|
54
81
|
```{python}
|
|
@@ -163,6 +190,33 @@ plt.ylabel("Frequency")
|
|
|
163
190
|
maidr.show(hist_plot) #<<
|
|
164
191
|
```
|
|
165
192
|
|
|
193
|
+
### KDE (Kernel Density Estimation) Plots
|
|
194
|
+
|
|
195
|
+
```{python}
|
|
196
|
+
#| warning: false
|
|
197
|
+
#| fig-alt: KDE plot showing probability density distribution
|
|
198
|
+
|
|
199
|
+
import matplotlib.pyplot as plt
|
|
200
|
+
import seaborn as sns
|
|
201
|
+
import numpy as np
|
|
202
|
+
|
|
203
|
+
import maidr #<<
|
|
204
|
+
|
|
205
|
+
# Generate sample data
|
|
206
|
+
np.random.seed(42)
|
|
207
|
+
data = np.random.randn(500)
|
|
208
|
+
|
|
209
|
+
# Create a KDE plot
|
|
210
|
+
plt.figure(figsize=(6, 6))
|
|
211
|
+
kde_plot = sns.kdeplot(data, fill=True, color="blue") #<<
|
|
212
|
+
|
|
213
|
+
plt.title("KDE Plot of Random Data")
|
|
214
|
+
plt.xlabel("Value")
|
|
215
|
+
plt.ylabel("Density")
|
|
216
|
+
|
|
217
|
+
# plt.show()
|
|
218
|
+
maidr.show(kde_plot) #<<
|
|
219
|
+
```
|
|
166
220
|
|
|
167
221
|
### Line Plots
|
|
168
222
|
|
|
@@ -270,8 +324,6 @@ maidr.show(heatmap) #<<
|
|
|
270
324
|
|
|
271
325
|
### Box Plot
|
|
272
326
|
|
|
273
|
-
* **Note**: Visual highlight feature has not been implemented in the box plot yet.
|
|
274
|
-
|
|
275
327
|
```{python}
|
|
276
328
|
#| fig-alt: Box plot of petal length by species from the Iris dataset
|
|
277
329
|
|
|
@@ -321,6 +373,40 @@ plt.ylabel("Sepal Width")
|
|
|
321
373
|
maidr.show(scatter_plot) #<<
|
|
322
374
|
```
|
|
323
375
|
|
|
376
|
+
### Regression Plots
|
|
377
|
+
|
|
378
|
+
```{python}
|
|
379
|
+
#| warning: false
|
|
380
|
+
#| fig-alt: Regression plot with scatter points and fitted line
|
|
381
|
+
|
|
382
|
+
import matplotlib.pyplot as plt
|
|
383
|
+
import seaborn as sns
|
|
384
|
+
import numpy as np
|
|
385
|
+
|
|
386
|
+
import maidr #<<
|
|
387
|
+
|
|
388
|
+
# Generate sample data
|
|
389
|
+
np.random.seed(42)
|
|
390
|
+
x = np.linspace(0, 10, 50)
|
|
391
|
+
y = 2 * x + 1 + np.random.normal(0, 2, 50)
|
|
392
|
+
|
|
393
|
+
# Create a regression plot
|
|
394
|
+
plt.figure(figsize=(6, 6))
|
|
395
|
+
reg_plot = sns.regplot(
|
|
396
|
+
x=x,
|
|
397
|
+
y=y,
|
|
398
|
+
scatter_kws={"s": 50, "alpha": 0.7},
|
|
399
|
+
line_kws={"color": "red", "lw": 2},
|
|
400
|
+
) #<<
|
|
401
|
+
|
|
402
|
+
plt.title("Regression Plot with Fitted Line")
|
|
403
|
+
plt.xlabel("X values")
|
|
404
|
+
plt.ylabel("Y values")
|
|
405
|
+
|
|
406
|
+
# plt.show()
|
|
407
|
+
maidr.show(reg_plot) #<<
|
|
408
|
+
```
|
|
409
|
+
|
|
324
410
|
### Multi-Layered Plots
|
|
325
411
|
|
|
326
412
|
```{python}
|
|
@@ -40,7 +40,7 @@ The following summarizes the key features and design principles of Py maidr:
|
|
|
40
40
|
|
|
41
41
|
7. Reproducibility: maidr supports the generation of accessible data visualizations as part of the reproducible data science workflow with [Quarto scientific publishing system](https://quarto.org/). You can easily create accessible data representations within your reproducible reports, website blogs, slides, e-books, dashboards, and more.
|
|
42
42
|
|
|
43
|
-
8. Scalability: maidr supports a wide range of data visualization types, including bar plots, histograms, line plots, box plots, heatmaps, scatter plots, and more. maidr is designed to be extensible to support new visualization types.
|
|
43
|
+
8. Scalability: maidr supports a wide range of data visualization types, including bar plots, histograms, line plots, box plots, heatmaps, scatter plots, and more. maidr is designed to be extensible to support new visualization types. Multi-figure and multi-layer visualizations are also supported.
|
|
44
44
|
|
|
45
45
|
Our core philosophy is to make data science accessible to everyone, regardless of their visual dis/abilities. We believe that by making data visualizations accessible, we can empower blind and sighted users to work together on data science projects, share insights, and make data-driven decisions collaboratively.
|
|
46
46
|
|
|
@@ -52,10 +52,18 @@ We currently support the following data visualization libraries in Python:, and
|
|
|
52
52
|
|
|
53
53
|
* One-factor bar plot having one x (categorical) and one y (numerical/count) axis.
|
|
54
54
|
|
|
55
|
+
* Stacked bar plot having one x (categorical) and one y (numerical/count) axis with multiple data series stacked vertically.
|
|
56
|
+
|
|
57
|
+
* Dodged (grouped) bar plot having one x (categorical) and one y (numerical/count) axis with multiple data series displayed side-by-side.
|
|
58
|
+
|
|
55
59
|
* One distribution histogram having one x (numerical) and y (numerical/frequency) axis.
|
|
56
60
|
|
|
61
|
+
* KDE (Kernel Density Estimation) plot having one x (numerical) and one y (density) axis showing probability density curves.
|
|
62
|
+
|
|
57
63
|
* Single line plot having one x (numerical) and one y (numerical) axis.
|
|
58
64
|
|
|
65
|
+
* Multi-line plot having one x (numerical) and one y (numerical) axis with multiple data series on the same axes.
|
|
66
|
+
|
|
59
67
|
* Vertical box plot having one x (categorical) and one y (numerical) axis.
|
|
60
68
|
|
|
61
69
|
* Horizontal box plot having one x (numerical) and one y (categorical) axis.
|
|
@@ -66,15 +74,27 @@ We currently support the following data visualization libraries in Python:, and
|
|
|
66
74
|
|
|
67
75
|
* Scatter plot having one x (numerical) and one y (numerical) axis.
|
|
68
76
|
|
|
77
|
+
* Regression plot having one x (numerical) and one y (numerical) axis with scatter points and fitted regression line.
|
|
78
|
+
|
|
79
|
+
* Candlestick chart having one x (time/date) and four y (numerical) axes (open, high, low, close) for financial data visualization (using mplfinance).
|
|
80
|
+
|
|
81
|
+
* Multi-layered plots combining different plot types on the same figure with shared axes.
|
|
82
|
+
|
|
83
|
+
* Multi-panel plots (subplots) with multiple charts in a grid layout having independent axes.
|
|
84
|
+
|
|
85
|
+
* Facet plots showing the same chart type across different data subsets with shared axis scales.
|
|
86
|
+
|
|
69
87
|
|
|
70
88
|
### Seaborn
|
|
71
89
|
|
|
72
90
|
* `sns.barplot()`: One-factor bar plot having one x (categorical) and one y (numerical/count) axis.
|
|
73
91
|
|
|
74
|
-
|
|
92
|
+
* `sns.countplot()`: Count plot having one x (categorical) and one y (count) axis showing the frequency of categorical data.
|
|
75
93
|
|
|
76
94
|
* `sns.histplot()`: One distribution histogram having one x (numerical) and y (numerical/frequency) axis.
|
|
77
95
|
|
|
96
|
+
* `sns.kdeplot()`: KDE (Kernel Density Estimation) plot having one x (numerical) and one y (density) axis showing probability density curves.
|
|
97
|
+
|
|
78
98
|
* `sns.lineplot()`: Single line plot having one x (numerical) and one y (numerical) axis.
|
|
79
99
|
|
|
80
100
|
* `sns.boxplot(..., orient="v")`: Vertical box plot having one x (categorical) and one y (numerical) axis.
|
|
@@ -87,6 +107,12 @@ We currently support the following data visualization libraries in Python:, and
|
|
|
87
107
|
|
|
88
108
|
* `sns.scatterplot()`: Scatter plot having one x (numerical) and one y (numerical) axis.
|
|
89
109
|
|
|
110
|
+
* `sns.regplot()`: Regression plot having one x (numerical) and one y (numerical) axis with scatter points and fitted regression line.
|
|
111
|
+
|
|
112
|
+
### Additional Libraries
|
|
113
|
+
|
|
114
|
+
* **mplfinance**: Candlestick charts having one x (time/date) and four y (numerical) axes (open, high, low, close) for financial data with support for moving averages and volume data.
|
|
115
|
+
|
|
90
116
|
|
|
91
117
|
## Installation
|
|
92
118
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Date,Open,High,Low,Close,Volume
|
|
2
|
+
2024-01-15,3050.72,3066.95,3050.72,3066.91,510301237
|
|
3
|
+
2024-01-16,3078.96,3085.20,3074.87,3078.27,524848878
|
|
4
|
+
2024-01-17,3080.80,3083.95,3072.15,3074.62,585634570
|
|
5
|
+
2024-01-18,3075.10,3078.34,3065.89,3076.78,544288522
|
|
6
|
+
2024-01-19,3087.02,3097.77,3080.23,3085.18,566117910
|
|
7
|
+
2024-01-22,3081.25,3093.09,3073.58,3093.08,460757054
|
|
8
|
+
2024-01-23,3080.33,3088.33,3075.82,3087.01,366044400
|
|
9
|
+
2024-01-24,3089.28,3102.61,3084.73,3091.84,434953689
|
|
10
|
+
2024-01-25,3084.18,3098.06,3078.80,3094.04,454607412
|
|
11
|
+
2024-01-26,3090.75,3098.20,3083.26,3096.63,408390424
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Date,Open,High,Low,Close,Volume
|
|
2
|
+
2023-12-15,3050.72,3066.95,3050.72,3066.91,510301237
|
|
3
|
+
2023-12-18,3078.96,3085.20,3074.87,3078.27,524848878
|
|
4
|
+
2023-12-19,3080.80,3083.95,3072.15,3074.62,585634570
|
|
5
|
+
2023-12-20,3075.10,3078.34,3065.89,3076.78,544288522
|
|
6
|
+
2023-12-21,3087.02,3097.77,3080.23,3085.18,566117910
|
|
7
|
+
2023-12-22,3081.25,3093.09,3073.58,3093.08,460757054
|
|
8
|
+
2024-01-02,3080.33,3088.33,3075.82,3087.01,366044400
|
|
9
|
+
2024-01-03,3089.28,3102.61,3084.73,3091.84,434953689
|
|
10
|
+
2024-01-04,3084.18,3098.06,3078.80,3094.04,454607412
|
|
11
|
+
2024-01-05,3090.75,3098.20,3083.26,3096.63,408390424
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Date,Open,High,Low,Close,Volume
|
|
2
|
+
2024-01-15 09:00:00,3050.72,3066.95,3050.72,3066.91,510301237
|
|
3
|
+
2024-01-15 10:00:00,3078.96,3085.20,3074.87,3078.27,524848878
|
|
4
|
+
2024-01-15 11:00:00,3080.80,3083.95,3072.15,3074.62,585634570
|
|
5
|
+
2024-01-15 12:00:00,3075.10,3078.34,3065.89,3076.78,544288522
|
|
6
|
+
2024-01-15 13:00:00,3087.02,3097.77,3080.23,3085.18,566117910
|
|
7
|
+
2024-01-15 14:00:00,3081.25,3093.09,3073.58,3093.08,460757054
|
|
8
|
+
2024-01-15 15:00:00,3080.33,3088.33,3075.82,3087.01,366044400
|
|
9
|
+
2024-01-15 16:00:00,3089.28,3102.61,3084.73,3091.84,434953689
|
|
10
|
+
2024-01-16 09:00:00,3084.18,3098.06,3078.80,3094.04,454607412
|
|
11
|
+
2024-01-16 10:00:00,3090.75,3098.20,3083.26,3096.63,408390424
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Date,Open,High,Low,Close,Volume
|
|
2
|
+
2024-01-15 09:30:00,3050.72,3066.95,3050.72,3066.91,510301237
|
|
3
|
+
2024-01-15 09:31:00,3078.96,3085.20,3074.87,3078.27,524848878
|
|
4
|
+
2024-01-15 09:32:00,3080.80,3083.95,3072.15,3074.62,585634570
|
|
5
|
+
2024-01-15 09:33:00,3075.10,3078.34,3065.89,3076.78,544288522
|
|
6
|
+
2024-01-15 09:34:00,3087.02,3097.77,3080.23,3085.18,566117910
|
|
7
|
+
2024-01-15 09:35:00,3081.25,3093.09,3073.58,3093.08,460757054
|
|
8
|
+
2024-01-15 09:36:00,3080.33,3088.33,3075.82,3087.01,366044400
|
|
9
|
+
2024-01-15 09:37:00,3089.28,3102.61,3084.73,3091.84,434953689
|
|
10
|
+
2024-01-15 09:38:00,3084.18,3098.06,3078.80,3094.04,454607412
|
|
11
|
+
2024-01-15 09:39:00,3090.75,3098.20,3083.26,3096.63,408390424
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Date,Open,High,Low,Close,Volume
|
|
2
|
+
2024-01-01,3050.72,3066.95,3050.72,3066.91,510301237
|
|
3
|
+
2024-01-08,3078.96,3085.20,3074.87,3078.27,524848878
|
|
4
|
+
2024-01-15,3080.80,3083.95,3072.15,3074.62,585634570
|
|
5
|
+
2024-01-22,3075.10,3078.34,3065.89,3076.78,544288522
|
|
6
|
+
2024-01-29,3087.02,3097.77,3080.23,3085.18,566117910
|
|
7
|
+
2024-02-05,3081.25,3093.09,3073.58,3093.08,460757054
|
|
8
|
+
2024-02-12,3080.33,3088.33,3075.82,3087.01,366044400
|
|
9
|
+
2024-02-19,3089.28,3102.61,3084.73,3091.84,434953689
|
|
10
|
+
2024-02-26,3084.18,3098.06,3078.80,3094.04,454607412
|
|
11
|
+
2024-03-04,3090.75,3098.20,3083.26,3096.63,408390424
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import uuid
|
|
4
|
+
from typing import Union, Dict
|
|
5
|
+
from matplotlib.axes import Axes
|
|
6
|
+
from matplotlib.patches import Rectangle
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from maidr.core.enum import PlotType
|
|
10
|
+
from maidr.core.plot import MaidrPlot
|
|
11
|
+
from maidr.core.enum.maidr_key import MaidrKey
|
|
12
|
+
from maidr.exception import ExtractionError
|
|
13
|
+
from maidr.util.mplfinance_utils import MplfinanceDataExtractor
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CandlestickPlot(MaidrPlot):
|
|
17
|
+
"""
|
|
18
|
+
Specialized candlestick plot class for mplfinance OHLC data.
|
|
19
|
+
|
|
20
|
+
This class handles the extraction and processing of candlestick data from mplfinance
|
|
21
|
+
plots, including proper date conversion and data validation.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, axes: list[Axes], **kwargs) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Initialize the CandlestickPlot.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
axes : list[Axes]
|
|
31
|
+
A list of Matplotlib Axes objects. Expected to contain at least
|
|
32
|
+
one Axes for OHLC data, and optionally a second for volume data.
|
|
33
|
+
**kwargs : dict
|
|
34
|
+
Additional keyword arguments.
|
|
35
|
+
"""
|
|
36
|
+
self.axes = axes
|
|
37
|
+
# Ensure there's at least one axis for the superclass init
|
|
38
|
+
if not axes:
|
|
39
|
+
raise ValueError("Axes list cannot be empty.")
|
|
40
|
+
super().__init__(axes[0], PlotType.CANDLESTICK)
|
|
41
|
+
|
|
42
|
+
# Store custom collections passed from mplfinance patch
|
|
43
|
+
self._maidr_wick_collection = kwargs.get("_maidr_wick_collection", None)
|
|
44
|
+
self._maidr_body_collection = kwargs.get("_maidr_body_collection", None)
|
|
45
|
+
self._maidr_date_nums = kwargs.get("_maidr_date_nums", None)
|
|
46
|
+
self._maidr_original_data = kwargs.get("_maidr_original_data", None) # Store original data
|
|
47
|
+
self._maidr_datetime_converter = kwargs.get("_maidr_datetime_converter", None)
|
|
48
|
+
|
|
49
|
+
# Store the GID for proper selector generation (legacy/shared)
|
|
50
|
+
self._maidr_gid = None
|
|
51
|
+
# Modern-path separate gids for body and wick
|
|
52
|
+
self._maidr_body_gid = None
|
|
53
|
+
self._maidr_wick_gid = None
|
|
54
|
+
if self._maidr_body_collection:
|
|
55
|
+
self._maidr_gid = self._maidr_body_collection.get_gid()
|
|
56
|
+
self._maidr_body_gid = self._maidr_gid
|
|
57
|
+
elif self._maidr_wick_collection:
|
|
58
|
+
self._maidr_gid = self._maidr_wick_collection.get_gid()
|
|
59
|
+
self._maidr_wick_gid = self._maidr_gid
|
|
60
|
+
|
|
61
|
+
def _extract_plot_data(self) -> list[dict]:
|
|
62
|
+
"""
|
|
63
|
+
Extract candlestick data from the plot.
|
|
64
|
+
|
|
65
|
+
This method processes candlestick plots from both modern (mplfinance.plot) and
|
|
66
|
+
legacy (original_flavor) pipelines, extracting OHLC data and setting up
|
|
67
|
+
highlighting elements and GIDs.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
list[dict]
|
|
72
|
+
List of dictionaries containing candlestick data with keys:
|
|
73
|
+
- 'value': Date string
|
|
74
|
+
- 'open': Opening price (float)
|
|
75
|
+
- 'high': High price (float)
|
|
76
|
+
- 'low': Low price (float)
|
|
77
|
+
- 'close': Closing price (float)
|
|
78
|
+
- 'volume': Volume (float, typically 0 for candlestick-only plots)
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
# Get the custom collections from kwargs
|
|
82
|
+
body_collection = self._maidr_body_collection
|
|
83
|
+
wick_collection = self._maidr_wick_collection
|
|
84
|
+
|
|
85
|
+
if body_collection and wick_collection:
|
|
86
|
+
# Store the GIDs from the collections (modern path)
|
|
87
|
+
self._maidr_body_gid = body_collection.get_gid()
|
|
88
|
+
self._maidr_wick_gid = wick_collection.get_gid()
|
|
89
|
+
# Keep legacy gid filled for backward compatibility
|
|
90
|
+
self._maidr_gid = self._maidr_body_gid or self._maidr_wick_gid
|
|
91
|
+
|
|
92
|
+
# Use the original collections for highlighting
|
|
93
|
+
self._elements = [body_collection, wick_collection]
|
|
94
|
+
|
|
95
|
+
# Use datetime converter for enhanced data extraction
|
|
96
|
+
if self._maidr_datetime_converter is not None:
|
|
97
|
+
data = self._maidr_datetime_converter.extract_candlestick_data(
|
|
98
|
+
self.axes[0], wick_collection, body_collection
|
|
99
|
+
)
|
|
100
|
+
return data
|
|
101
|
+
|
|
102
|
+
# Fallback to original detection method
|
|
103
|
+
if not self.axes:
|
|
104
|
+
return []
|
|
105
|
+
|
|
106
|
+
ax_ohlc = self.axes[0]
|
|
107
|
+
|
|
108
|
+
# Look for Rectangle patches (original_flavor candlestick)
|
|
109
|
+
body_rectangles = []
|
|
110
|
+
for patch in ax_ohlc.patches:
|
|
111
|
+
if isinstance(patch, Rectangle):
|
|
112
|
+
body_rectangles.append(patch)
|
|
113
|
+
|
|
114
|
+
if body_rectangles:
|
|
115
|
+
# Set elements for highlighting
|
|
116
|
+
self._elements = body_rectangles
|
|
117
|
+
|
|
118
|
+
# Generate a GID for highlighting if none exists
|
|
119
|
+
if not self._maidr_gid:
|
|
120
|
+
self._maidr_gid = f"maidr-{uuid.uuid4()}"
|
|
121
|
+
# Set GID on all rectangles
|
|
122
|
+
for rect in body_rectangles:
|
|
123
|
+
rect.set_gid(self._maidr_gid)
|
|
124
|
+
# Keep a dedicated body gid for legacy dict selectors
|
|
125
|
+
self._maidr_body_gid = getattr(self, "_maidr_body_gid", None) or self._maidr_gid
|
|
126
|
+
|
|
127
|
+
# Assign a shared gid to wick Line2D (vertical 2-point lines) on the same axis
|
|
128
|
+
wick_lines = []
|
|
129
|
+
for line in ax_ohlc.get_lines():
|
|
130
|
+
try:
|
|
131
|
+
xydata = line.get_xydata()
|
|
132
|
+
if xydata is None:
|
|
133
|
+
continue
|
|
134
|
+
xy_arr = np.asarray(xydata)
|
|
135
|
+
if xy_arr.ndim == 2 and xy_arr.shape[0] == 2 and xy_arr.shape[1] >= 2:
|
|
136
|
+
x0 = float(xy_arr[0, 0])
|
|
137
|
+
x1 = float(xy_arr[1, 0])
|
|
138
|
+
if abs(x0 - x1) < 1e-10:
|
|
139
|
+
wick_lines.append(line)
|
|
140
|
+
except Exception:
|
|
141
|
+
continue
|
|
142
|
+
if wick_lines:
|
|
143
|
+
if not getattr(self, "_maidr_wick_gid", None):
|
|
144
|
+
self._maidr_wick_gid = f"maidr-{uuid.uuid4()}"
|
|
145
|
+
for line in wick_lines:
|
|
146
|
+
line.set_gid(self._maidr_wick_gid)
|
|
147
|
+
|
|
148
|
+
# Use the utility class to extract data
|
|
149
|
+
data = MplfinanceDataExtractor.extract_rectangle_candlestick_data(
|
|
150
|
+
body_rectangles, self._maidr_date_nums, self._maidr_original_data
|
|
151
|
+
)
|
|
152
|
+
return data
|
|
153
|
+
|
|
154
|
+
return []
|
|
155
|
+
|
|
156
|
+
def _extract_axes_data(self) -> dict:
|
|
157
|
+
"""
|
|
158
|
+
Extract the plot's axes data including labels.
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
dict
|
|
163
|
+
Dictionary containing x and y axis labels.
|
|
164
|
+
"""
|
|
165
|
+
x_labels = self.ax.get_xlabel()
|
|
166
|
+
if not x_labels:
|
|
167
|
+
x_labels = self.extract_shared_xlabel(self.ax)
|
|
168
|
+
if not x_labels:
|
|
169
|
+
x_labels = "X"
|
|
170
|
+
return {MaidrKey.X: x_labels, MaidrKey.Y: self.ax.get_ylabel()}
|
|
171
|
+
|
|
172
|
+
def _get_selector(self) -> Union[str, Dict[str, str]]:
|
|
173
|
+
"""Return selectors for highlighting candlestick elements.
|
|
174
|
+
|
|
175
|
+
- Modern path (collections present): return a dict with separate selectors for body, wickLow, wickHigh
|
|
176
|
+
- Legacy path: return a dict with body and shared wick selectors (no open/close keys)
|
|
177
|
+
"""
|
|
178
|
+
# Modern path: build structured selectors using separate gids
|
|
179
|
+
if self._maidr_body_collection and self._maidr_wick_collection and self._maidr_body_gid and self._maidr_wick_gid:
|
|
180
|
+
# Determine candle count N
|
|
181
|
+
N = None
|
|
182
|
+
if self._maidr_original_data is not None:
|
|
183
|
+
try:
|
|
184
|
+
N = len(self._maidr_original_data)
|
|
185
|
+
except Exception:
|
|
186
|
+
N = None
|
|
187
|
+
if N is None and hasattr(self._maidr_wick_collection, "get_paths"):
|
|
188
|
+
try:
|
|
189
|
+
wick_paths = len(list(self._maidr_wick_collection.get_paths()))
|
|
190
|
+
if wick_paths % 2 == 0 and wick_paths > 0:
|
|
191
|
+
N = wick_paths // 2
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
if N is None and hasattr(self._maidr_body_collection, "get_paths"):
|
|
195
|
+
try:
|
|
196
|
+
body_paths = len(list(self._maidr_body_collection.get_paths()))
|
|
197
|
+
if body_paths > 0:
|
|
198
|
+
N = body_paths
|
|
199
|
+
except Exception:
|
|
200
|
+
pass
|
|
201
|
+
if N is None:
|
|
202
|
+
raise ExtractionError(PlotType.CANDLESTICK, self._maidr_wick_collection)
|
|
203
|
+
|
|
204
|
+
selectors = {
|
|
205
|
+
"body": f"g[id='{self._maidr_body_gid}'] > path",
|
|
206
|
+
"wickLow": f"g[id='{self._maidr_wick_gid}'] > path:nth-child(-n+{N})",
|
|
207
|
+
"wickHigh": f"g[id='{self._maidr_wick_gid}'] > path:nth-child(n+{N + 1})",
|
|
208
|
+
}
|
|
209
|
+
return selectors
|
|
210
|
+
|
|
211
|
+
# Legacy path: build shared-id selectors; omit open/close
|
|
212
|
+
legacy_selectors = {}
|
|
213
|
+
if getattr(self, "_maidr_body_gid", None) or self._maidr_gid:
|
|
214
|
+
body_gid = getattr(self, "_maidr_body_gid", None) or self._maidr_gid
|
|
215
|
+
legacy_selectors["body"] = f"g[id='{body_gid}'] > path"
|
|
216
|
+
if getattr(self, "_maidr_wick_gid", None):
|
|
217
|
+
legacy_selectors["wick"] = f"g[id='{self._maidr_wick_gid}'] > path"
|
|
218
|
+
if legacy_selectors:
|
|
219
|
+
return legacy_selectors
|
|
220
|
+
|
|
221
|
+
# Fallback
|
|
222
|
+
return "g[maidr='true'] > path, g[maidr='true'] > rect"
|
|
223
|
+
|
|
224
|
+
def render(self) -> dict:
|
|
225
|
+
"""Initialize the MAIDR schema dictionary with basic plot information."""
|
|
226
|
+
base_schema = super().render()
|
|
227
|
+
base_schema[MaidrKey.TITLE] = "Candlestick Chart"
|
|
228
|
+
base_schema[MaidrKey.AXES] = self._extract_axes_data()
|
|
229
|
+
base_schema[MaidrKey.DATA] = self._extract_plot_data()
|
|
230
|
+
# Include selector only if the plot supports highlighting.
|
|
231
|
+
if self._support_highlighting:
|
|
232
|
+
base_schema[MaidrKey.SELECTOR] = self._get_selector()
|
|
233
|
+
return base_schema
|
|
@@ -31,6 +31,10 @@ class MplfinanceBarPlot(
|
|
|
31
31
|
self._custom_patches = kwargs.get("_maidr_patches", None)
|
|
32
32
|
# Store date numbers for volume bars (from mplfinance)
|
|
33
33
|
self._maidr_date_nums = kwargs.get("_maidr_date_nums", None)
|
|
34
|
+
|
|
35
|
+
# Store datetime converter if available
|
|
36
|
+
self._maidr_datetime_converter = kwargs.get("_maidr_datetime_converter", None)
|
|
37
|
+
|
|
34
38
|
# Store custom title
|
|
35
39
|
|
|
36
40
|
def set_title(self, title: str) -> None:
|
|
@@ -48,6 +52,13 @@ class MplfinanceBarPlot(
|
|
|
48
52
|
)
|
|
49
53
|
data = self._extract_bar_container_data(plot)
|
|
50
54
|
levels = self.extract_level(self.ax)
|
|
55
|
+
|
|
56
|
+
# Ensure we have valid data and levels before processing
|
|
57
|
+
if data is None or levels is None:
|
|
58
|
+
if data is None:
|
|
59
|
+
raise ExtractionError(self.type, plot)
|
|
60
|
+
return []
|
|
61
|
+
|
|
51
62
|
formatted_data = []
|
|
52
63
|
combined_data = list(
|
|
53
64
|
zip(levels, data)
|
|
@@ -78,7 +89,13 @@ class MplfinanceBarPlot(
|
|
|
78
89
|
# Set elements for highlighting (use the patches directly)
|
|
79
90
|
self._elements = sorted_patches
|
|
80
91
|
|
|
81
|
-
# Use
|
|
92
|
+
# Use datetime converter for enhanced data extraction
|
|
93
|
+
if self._maidr_datetime_converter is not None:
|
|
94
|
+
data = self._maidr_datetime_converter.extract_volume_data(self.ax)
|
|
95
|
+
if data: # Only use if successful
|
|
96
|
+
return [{"x": item[0], "y": item[1]} for item in data]
|
|
97
|
+
|
|
98
|
+
# Fallback to existing logic
|
|
82
99
|
return MplfinanceDataExtractor.extract_volume_data(
|
|
83
100
|
sorted_patches, self._maidr_date_nums
|
|
84
101
|
)
|
|
@@ -23,6 +23,9 @@ class MplfinanceLinePlot(MaidrPlot, LineExtractorMixin):
|
|
|
23
23
|
def __init__(self, ax: Axes, **kwargs):
|
|
24
24
|
super().__init__(ax, PlotType.LINE)
|
|
25
25
|
|
|
26
|
+
# Store datetime converter if available
|
|
27
|
+
self._maidr_datetime_converter = kwargs.get("_maidr_datetime_converter", None)
|
|
28
|
+
|
|
26
29
|
def _get_selector(self) -> Union[str, List[str]]:
|
|
27
30
|
"""Return selectors for all lines that have data."""
|
|
28
31
|
all_lines = self.ax.get_lines()
|
|
@@ -101,10 +104,15 @@ class MplfinanceLinePlot(MaidrPlot, LineExtractorMixin):
|
|
|
101
104
|
if np.isnan(x) or np.isnan(y) or np.isinf(x) or np.isinf(y):
|
|
102
105
|
continue
|
|
103
106
|
|
|
104
|
-
#
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
# Use datetime converter for enhanced data extraction
|
|
108
|
+
datetime_converter = getattr(line, "_maidr_datetime_converter", None) or self._maidr_datetime_converter
|
|
109
|
+
if datetime_converter is not None:
|
|
110
|
+
# Convert x-coordinate (matplotlib index) to formatted datetime
|
|
111
|
+
x_value = datetime_converter.get_formatted_datetime(int(round(x)))
|
|
112
|
+
if x_value is None:
|
|
113
|
+
x_value = float(x) # Fallback to numeric
|
|
107
114
|
else:
|
|
115
|
+
# Fallback to existing logic
|
|
108
116
|
# Check if we have date numbers from mplfinance
|
|
109
117
|
if date_nums is not None and i < len(date_nums):
|
|
110
118
|
# Use the date number to convert to date string
|
|
@@ -2,6 +2,7 @@ import wrapt
|
|
|
2
2
|
from typing import Any, Callable, Dict, Tuple
|
|
3
3
|
from matplotlib.patches import Rectangle
|
|
4
4
|
from mplfinance import original_flavor
|
|
5
|
+
import numpy as np
|
|
5
6
|
|
|
6
7
|
from maidr.core.context_manager import ContextManager
|
|
7
8
|
from maidr.core.enum.plot_type import PlotType
|
|
@@ -46,10 +47,35 @@ def candlestick(
|
|
|
46
47
|
# Patch the plotting function.
|
|
47
48
|
plot = wrapped(*args, **kwargs)
|
|
48
49
|
|
|
50
|
+
original_data = None
|
|
51
|
+
date_nums = None
|
|
52
|
+
if len(args) >= 2:
|
|
53
|
+
try:
|
|
54
|
+
quotes = args[1]
|
|
55
|
+
if quotes is not None:
|
|
56
|
+
arr = np.asarray(quotes)
|
|
57
|
+
if arr.ndim == 2 and arr.shape[1] >= 5 and arr.size > 0:
|
|
58
|
+
date_nums = arr[:, 0].tolist()
|
|
59
|
+
original_data = {
|
|
60
|
+
"Open": arr[:, 1].tolist(),
|
|
61
|
+
"High": arr[:, 2].tolist(),
|
|
62
|
+
"Low": arr[:, 3].tolist(),
|
|
63
|
+
"Close": arr[:, 4].tolist(),
|
|
64
|
+
}
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
|
|
49
68
|
axes = []
|
|
50
69
|
for ax in plot:
|
|
51
70
|
axes.append(FigureManager.get_axes(ax))
|
|
52
|
-
|
|
71
|
+
|
|
72
|
+
extra_kwargs: Dict[str, Any] = {}
|
|
73
|
+
if original_data is not None:
|
|
74
|
+
extra_kwargs["_maidr_original_data"] = original_data
|
|
75
|
+
if date_nums is not None:
|
|
76
|
+
extra_kwargs["_maidr_date_nums"] = date_nums
|
|
77
|
+
|
|
78
|
+
FigureManager.create_maidr(axes, PlotType.CANDLESTICK, **extra_kwargs)
|
|
53
79
|
|
|
54
80
|
return plot
|
|
55
81
|
|