DaSPi 2.4.0__tar.gz → 2.5.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 (185) hide show
  1. {daspi-2.4.0 → daspi-2.5.0}/PKG-INFO +1 -1
  2. {daspi-2.4.0 → daspi-2.5.0}/daspi/__init__.py +6 -0
  3. {daspi-2.4.0 → daspi-2.5.0}/daspi/anova/model.py +124 -11
  4. {daspi-2.4.0 → daspi-2.5.0}/daspi/constants.py +39 -0
  5. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/chart.py +2 -3
  6. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/plotter.py +181 -0
  7. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/precast.py +309 -30
  8. {daspi-2.4.0 → daspi-2.5.0}/daspi/strings.py +35 -0
  9. {daspi-2.4.0 → daspi-2.5.0}/pyproject.toml +1 -1
  10. {daspi-2.4.0 → daspi-2.5.0}/tests/anova_model_test.py +14 -0
  11. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_alignments_basic.png +0 -0
  12. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_all_alignments.png +0 -0
  13. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_angles_basic.png +0 -0
  14. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_callable_formatters.png +0 -0
  15. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_combined_all_features.png +0 -0
  16. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_extreme_angles.png +0 -0
  17. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_formatters_basic.png +0 -0
  18. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_formatters_scientific.png +0 -0
  19. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_multivariate_formatting.png +0 -0
  20. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_orientation_mapping.png +0 -0
  21. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Formatting_Features_Test_percentage_formatter.png +0 -0
  22. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_comparison_with_violin.png +0 -0
  23. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_custom_color.png +0 -0
  24. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_custom_width.png +0 -0
  25. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_joint_chart_mixed_plots.png +0 -0
  26. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_multivariate_chart_facets.png +0 -0
  27. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_resolution_high.png +0 -0
  28. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_single_chart_horizontal.png +0 -0
  29. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_single_chart_no_fade.png +0 -0
  30. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_single_chart_no_fill.png +0 -0
  31. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_single_chart_simple.png +0 -0
  32. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/GaussianKDEContourUnivariate_single_chart_with_hue.png +0 -0
  33. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_bar_stacking.png +0 -0
  34. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_pareto_marked.png +0 -0
  35. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_probability_dists-prob.png +0 -0
  36. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_regression_kde.png +0 -0
  37. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/MultivariateChart_full-stripes.png +0 -0
  38. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/MultivariateChart_full.png +0 -0
  39. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_bivariate-univariate-charts_contour-mean-test.png +0 -0
  40. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_bivariate-univariate-charts_mean-test.png +0 -0
  41. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_bivariate-univariate-charts_simple.png +0 -0
  42. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_bivariate-univariate-charts_smoothed.png +0 -0
  43. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_bivariate-univariate-charts_user.png +0 -0
  44. daspi-2.5.0/tests/charts/Precasts_goodness_of_fit_charts_basic.png +0 -0
  45. daspi-2.5.0/tests/charts/Precasts_goodness_of_fit_charts_refit-epoch-7.png +0 -0
  46. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_pair_comparison_charts_basic.png +0 -0
  47. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_parameter_relevance_charts_basic.png +0 -0
  48. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_process-capabity-analysis-charts_hue.png +0 -0
  49. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_residual_charts_basic.png +0 -0
  50. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_KDE-cumulative_multiple.png +0 -0
  51. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_KDE_multiple.png +0 -0
  52. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_KDE_ridge.png +0 -0
  53. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_beeswarm_multiple.png +0 -0
  54. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_beeswarm_simple.png +0 -0
  55. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_blandaltman_simple.png +0 -0
  56. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_blandaltman_user.png +0 -0
  57. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_box_fill.png +0 -0
  58. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_box_multiple.png +0 -0
  59. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_box_simple.png +0 -0
  60. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_categorical-float-features_simple.png +0 -0
  61. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_errorbar_mean-test.png +0 -0
  62. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_errorbar_sem.png +0 -0
  63. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_errorbar_std-test.png +0 -0
  64. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_errorbar_var-test.png +0 -0
  65. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_fitted-density_cdf-multiple.png +0 -0
  66. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_jitter_multiple.png +0 -0
  67. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_jitter_simple.png +0 -0
  68. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_line_hue.png +0 -0
  69. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_line_hue_size.png +0 -0
  70. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_pareto-threshold_simple.png +0 -0
  71. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_pareto_simple.png +0 -0
  72. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_pareto_transposed.png +0 -0
  73. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_quantiles_multiple.png +0 -0
  74. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_quantiles_simple.png +0 -0
  75. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_full.png +0 -0
  76. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_hue-shape.png +0 -0
  77. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_hue-size.png +0 -0
  78. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_hue.png +0 -0
  79. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_shape.png +0 -0
  80. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_size-shape.png +0 -0
  81. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_size.png +0 -0
  82. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violin_mono.png +0 -0
  83. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violin_multiple.png +0 -0
  84. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violin_simple.png +0 -0
  85. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_plotter_test.py +150 -0
  86. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_visual_test.py +53 -0
  87. {daspi-2.4.0 → daspi-2.5.0}/LICENSE +0 -0
  88. {daspi-2.4.0 → daspi-2.5.0}/README.md +0 -0
  89. {daspi-2.4.0 → daspi-2.5.0}/daspi/_typing.py +0 -0
  90. {daspi-2.4.0 → daspi-2.5.0}/daspi/_version.py +0 -0
  91. {daspi-2.4.0 → daspi-2.5.0}/daspi/anova/__init__.py +0 -0
  92. {daspi-2.4.0 → daspi-2.5.0}/daspi/anova/convert.py +0 -0
  93. {daspi-2.4.0 → daspi-2.5.0}/daspi/anova/tables.py +0 -0
  94. {daspi-2.4.0 → daspi-2.5.0}/daspi/config.py +0 -0
  95. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/__init__.py +0 -0
  96. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/ancova.csv +0 -0
  97. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/anova.csv +0 -0
  98. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/anova2.csv +0 -0
  99. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/anova2_unbalanced.csv +0 -0
  100. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/anova3.csv +0 -0
  101. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/anova3_unbalanced.csv +0 -0
  102. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/carpet_full-factorial.csv +0 -0
  103. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/covariate.csv +0 -0
  104. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/drop_card.csv +0 -0
  105. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/eeprom_full-factorial.csv +0 -0
  106. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/eeprom_partial-factorial.csv +0 -0
  107. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/grnr_adjustment.csv +0 -0
  108. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/grnr_layer_thickness.csv +0 -0
  109. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/grnr_spc.csv +0 -0
  110. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/iris.csv +0 -0
  111. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/mpg.csv +0 -0
  112. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/painkillers-dissolution.csv +0 -0
  113. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/partial_factorial.csv +0 -0
  114. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/penguins.csv +0 -0
  115. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/process_capability.mpx +0 -0
  116. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/salt_sticks.csv +0 -0
  117. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/shoe-sole.csv +0 -0
  118. {daspi-2.4.0 → daspi-2.5.0}/daspi/datasets/tips.csv +0 -0
  119. {daspi-2.4.0 → daspi-2.5.0}/daspi/doe/__init__.py +0 -0
  120. {daspi-2.4.0 → daspi-2.5.0}/daspi/doe/build.py +0 -0
  121. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/__init__.py +0 -0
  122. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/appearance.py +0 -0
  123. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/classify.py +0 -0
  124. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/facets.py +0 -0
  125. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/styles/daspi-dark.mplstyle +0 -0
  126. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/styles/daspi.mplstyle +0 -0
  127. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/styles/ggplot2.mplstyle +0 -0
  128. {daspi-2.4.0 → daspi-2.5.0}/daspi/plotlib/styles/seaborn.mplstyle +0 -0
  129. {daspi-2.4.0 → daspi-2.5.0}/daspi/requirements.txt +0 -0
  130. {daspi-2.4.0 → daspi-2.5.0}/daspi/statistics/__init__.py +0 -0
  131. {daspi-2.4.0 → daspi-2.5.0}/daspi/statistics/confidence.py +0 -0
  132. {daspi-2.4.0 → daspi-2.5.0}/daspi/statistics/estimation.py +0 -0
  133. {daspi-2.4.0 → daspi-2.5.0}/daspi/statistics/hypothesis.py +0 -0
  134. {daspi-2.4.0 → daspi-2.5.0}/daspi/statistics/montecarlo.py +0 -0
  135. {daspi-2.4.0 → daspi-2.5.0}/tests/ANOVA_SS_Fehler.mpx +0 -0
  136. {daspi-2.4.0 → daspi-2.5.0}/tests/ANOVA_SS_Fehler.mpx.bak +0 -0
  137. {daspi-2.4.0 → daspi-2.5.0}/tests/GageRnR.mpx +0 -0
  138. {daspi-2.4.0 → daspi-2.5.0}/tests/GageRnR.mpx.bak +0 -0
  139. {daspi-2.4.0 → daspi-2.5.0}/tests/__init__.py +0 -0
  140. {daspi-2.4.0 → daspi-2.5.0}/tests/anova_convert_test.py +0 -0
  141. {daspi-2.4.0 → daspi-2.5.0}/tests/anova_tables_test.py +0 -0
  142. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_kdes_kde-mean.png +0 -0
  143. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_kdes_mixed-kde.png +0 -0
  144. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/JointChart_probability_norm-prob.png +0 -0
  145. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_gage_rnr_model_basic.png +0 -0
  146. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/Precasts_gage_study_model_basic.png +0 -0
  147. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_KDE-cumulative_simple.png +0 -0
  148. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_KDE_simple.png +0 -0
  149. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_fitted-density_pdf-data.png +0 -0
  150. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_fitted-density_pdf-norm.png +0 -0
  151. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_simple-stripes-65ci.png +0 -0
  152. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_simple-stripes-99ci.png +0 -0
  153. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_simple-stripes.png +0 -0
  154. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_simple.png +0 -0
  155. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_scatter_transposed.png +0 -0
  156. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violine-contour_simple.png +0 -0
  157. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violine_mono.png +0 -0
  158. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violine_multiple.png +0 -0
  159. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/SingleChart_violine_simple.png +0 -0
  160. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/_debug_kde_bottom_crop.png +0 -0
  161. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/_debug_violin_bottom_crop.png +0 -0
  162. {daspi-2.4.0 → daspi-2.5.0}/tests/charts/_debug_violin_top_crop.png +0 -0
  163. {daspi-2.4.0 → daspi-2.5.0}/tests/config_test.py +0 -0
  164. {daspi-2.4.0 → daspi-2.5.0}/tests/data/anova3_result.csv +0 -0
  165. {daspi-2.4.0 → daspi-2.5.0}/tests/data/dists_10-samples.csv +0 -0
  166. {daspi-2.4.0 → daspi-2.5.0}/tests/data/dists_25-samples.csv +0 -0
  167. {daspi-2.4.0 → daspi-2.5.0}/tests/data/gage_rnr.csv +0 -0
  168. {daspi-2.4.0 → daspi-2.5.0}/tests/data/gage_study.csv +0 -0
  169. {daspi-2.4.0 → daspi-2.5.0}/tests/data/generate_dists.py +0 -0
  170. {daspi-2.4.0 → daspi-2.5.0}/tests/data/grnr_d-optimal.csv +0 -0
  171. {daspi-2.4.0 → daspi-2.5.0}/tests/data/uncertainties.csv +0 -0
  172. {daspi-2.4.0 → daspi-2.5.0}/tests/doe_build_test.py +0 -0
  173. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_appearance_test.py +0 -0
  174. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_chart_test.py +0 -0
  175. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_classify_test.py +0 -0
  176. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_facets_test.py +0 -0
  177. {daspi-2.4.0 → daspi-2.5.0}/tests/plotlib_templates_test.py +0 -0
  178. {daspi-2.4.0 → daspi-2.5.0}/tests/r2_pred.mpx +0 -0
  179. {daspi-2.4.0 → daspi-2.5.0}/tests/r2_pred.mpx.bak +0 -0
  180. {daspi-2.4.0 → daspi-2.5.0}/tests/statistics_confidence_test.py +0 -0
  181. {daspi-2.4.0 → daspi-2.5.0}/tests/statistics_estimation_test.py +0 -0
  182. {daspi-2.4.0 → daspi-2.5.0}/tests/statistics_hypothesis_test.py +0 -0
  183. {daspi-2.4.0 → daspi-2.5.0}/tests/statistics_montecarlo_test.py +0 -0
  184. {daspi-2.4.0 → daspi-2.5.0}/tests/strings_test.py +0 -0
  185. {daspi-2.4.0 → daspi-2.5.0}/tests/test_full_factorial_design_builder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: DaSPi
3
- Version: 2.4.0
3
+ Version: 2.5.0
4
4
  Summary: Visualize and analyze your data with DaSPi. This package is designed for users who want to find relevant influencing factors in processes and validate improvements.
5
5
  Author-Email: Reto Jäggli <reto@jaeggli.email>
6
6
  License: MIT
@@ -101,6 +101,7 @@ if TYPE_CHECKING:
101
101
  SpreadWidth,
102
102
  StandardErrorMean,
103
103
  Stem,
104
+ StripeArea,
104
105
  StripeLine,
105
106
  StripeSpan,
106
107
  TransformPlotter,
@@ -111,6 +112,7 @@ if TYPE_CHECKING:
111
112
  BivariateUnivariateCharts,
112
113
  GageRnRCharts,
113
114
  GageStudyCharts,
115
+ GoodnessOfFitCharts,
114
116
  PairComparisonCharts,
115
117
  PairwiseMatrixCharts,
116
118
  ParameterRelevanceCharts,
@@ -259,6 +261,7 @@ _LAZY_SUBMODULES: dict[str, str] = {
259
261
  'SpreadWidth': '.plotlib.plotter',
260
262
  'StandardErrorMean': '.plotlib.plotter',
261
263
  'Stem': '.plotlib.plotter',
264
+ 'StripeArea': '.plotlib.plotter',
262
265
  'StripeLine': '.plotlib.plotter',
263
266
  'StripeSpan': '.plotlib.plotter',
264
267
  'TransformPlotter': '.plotlib.plotter',
@@ -267,6 +270,7 @@ _LAZY_SUBMODULES: dict[str, str] = {
267
270
  'BivariateUnivariateCharts': '.plotlib.precast',
268
271
  'GageRnRCharts': '.plotlib.precast',
269
272
  'GageStudyCharts': '.plotlib.precast',
273
+ 'GoodnessOfFitCharts': '.plotlib.precast',
270
274
  'PairComparisonCharts': '.plotlib.precast',
271
275
  'PairwiseMatrixCharts': '.plotlib.precast',
272
276
  'ParameterRelevanceCharts': '.plotlib.precast',
@@ -401,6 +405,7 @@ __all__ = [
401
405
  'MeanTest',
402
406
  'MeasurementUncertainty',
403
407
  'MultivariateChart',
408
+ 'GoodnessOfFitCharts',
404
409
  'PairComparisonCharts',
405
410
  'PairwiseMatrixCharts',
406
411
  'ParallelCoordinate',
@@ -424,6 +429,7 @@ __all__ = [
424
429
  'SpreadWidth',
425
430
  'StandardErrorMean',
426
431
  'Stem',
432
+ 'StripeArea',
427
433
  'StripeLine',
428
434
  'StripeSpan',
429
435
  'StripesFacets',
@@ -374,8 +374,7 @@ class LinearModel(BaseHTMLReprModel):
374
374
  target='dissolution',
375
375
  factors=['employee', 'stirrer', 'brand', 'catalyst', 'water'],
376
376
  covariates=['temperature', 'preparation'],
377
- order=2,
378
- covariates=None)
377
+ order=2,)
379
378
 
380
379
  # Store goodnes of fit values for each elimination step
381
380
  df_gof = pd.concat(model.recursive_elimination())
@@ -883,7 +882,11 @@ class LinearModel(BaseHTMLReprModel):
883
882
  DataFrame
884
883
  The goodness-of-fit metrics table as DataFrame containing
885
884
  the following columns:
886
- - 'formula' = current formula
885
+ - 'epoch' = the given `index`, i.e. the step at which a term
886
+ was added or removed during recursive elimination
887
+ - 'formula' = current formula, can be used to refit the
888
+ model at this step, see `formula_at_epoch` and
889
+ `refit_at_epoch`
887
890
  - 's' = Uncertainty of the model as square root of MS_Residual
888
891
  - 'aic' = Akaike's information criteria
889
892
  - 'r2' = R-squared of the model
@@ -895,17 +898,127 @@ class LinearModel(BaseHTMLReprModel):
895
898
  """
896
899
  self.anova(typ='III', vif=False)
897
900
  data = {
898
- 'formula': self.formula,
899
- 'hierarchical': self.is_hierarchical(),
900
- 'least_parameter': self.least_parameter(),
901
- 'p_least': self.p_values().max(),
901
+ ANOVA.EPOCH: index + 1 if isinstance(index, int) else index,
902
+ ANOVA.FORMULA: self.formula,
903
+ ANOVA.HIERARCHICAL: self.is_hierarchical(),
904
+ ANOVA.LEAST_PARAMETER: self.least_parameter(),
905
+ ANOVA.P_LEAST: self.p_values().max(),
902
906
  's': self.uncertainty,
903
- 'aic': self.model.aic,
904
- 'r2': self.model.rsquared,
905
- 'r2_adj': self.model.rsquared_adj,
906
- 'r2_pred': self.r2_pred()}
907
+ ANOVA.AIC: self.model.aic,
908
+ ANOVA.R2: self.model.rsquared,
909
+ ANOVA.R2_ADJ: self.model.rsquared_adj,
910
+ ANOVA.R2_PRED: self.r2_pred()}
907
911
  return pd.DataFrame(data, index=[index])
908
912
 
913
+ @staticmethod
914
+ def formula_at_epoch(df_gof: DataFrame, epoch: int) -> str:
915
+ """Extract the model formula recorded at a given elimination
916
+ step from a goodness-of-fit table.
917
+
918
+ Parameters
919
+ ----------
920
+ df_gof : DataFrame
921
+ The goodness-of-fit table collected during recursive
922
+ elimination, i.e. the concatenated result of
923
+ `recursive_elimination`. Must contain the columns 'epoch'
924
+ and 'formula', see `gof_metrics`.
925
+ epoch : int
926
+ The elimination step whose formula should be extracted.
927
+
928
+ Returns
929
+ -------
930
+ str
931
+ The model formula used at the given `epoch`.
932
+
933
+ Examples
934
+ --------
935
+ ```python
936
+ import pandas as pd
937
+ import daspi as dsp
938
+
939
+ df = dsp.load_dataset('painkillers-dissolution')
940
+ lm = dsp.LinearModel(
941
+ source=df,
942
+ target='dissolution',
943
+ factors=['employee', 'stirrer', 'brand', 'catalyst', 'water'],
944
+ covariates=['temperature', 'preparation'],
945
+ order=2)
946
+ df_gof = pd.concat(lm.recursive_elimination())
947
+ dsp.LinearModel.formula_at_epoch(df_gof, epoch=5)
948
+ ```
949
+ """
950
+ rows = df_gof[df_gof[ANOVA.EPOCH] == epoch]
951
+ assert not rows.empty, (
952
+ f'No entry found for epoch={epoch} in df_gof, got epochs '
953
+ f'{sorted(df_gof[ANOVA.EPOCH].unique())}')
954
+ return str(rows[ANOVA.FORMULA].iloc[0])
955
+
956
+ def refit_at_epoch(self, df_gof: DataFrame, epoch: int, **kwds) -> Self:
957
+ """Refit this model using the formula recorded at a given
958
+ elimination step of a goodness-of-fit table.
959
+
960
+ This is a convenience method combining `formula_at_epoch` and
961
+ `fit`, allowing you to go back to any intermediate step of a
962
+ previously run `recursive_elimination` once you have picked a
963
+ preferred epoch, e.g. by inspecting a
964
+ `daspi.GoodnessOfFitCharts` plot.
965
+
966
+ Parameters
967
+ ----------
968
+ df_gof : DataFrame
969
+ The goodness-of-fit table collected during recursive
970
+ elimination, i.e. the concatenated result of
971
+ `recursive_elimination`. Must contain the columns 'epoch'
972
+ and 'formula', see `gof_metrics`.
973
+ epoch : int
974
+ The elimination step whose formula should be used to refit
975
+ the model.
976
+ **kwds
977
+ Additional keyword arguments for `ols` function of
978
+ `statsmodels.formula.api`, passed to `fit`.
979
+
980
+ Returns
981
+ -------
982
+ Self
983
+ The current instance of the model, refitted with the
984
+ formula of the given `epoch`, for method chaining.
985
+
986
+ Notes
987
+ -----
988
+ This also resyncs the `excluded` attribute so that the
989
+ `formula` property and methods relying on it (`eliminate`,
990
+ `include`, `recursive_elimination`) stay consistent with the
991
+ formula used for refitting.
992
+
993
+ Examples
994
+ --------
995
+ ```python
996
+ import pandas as pd
997
+ import daspi as dsp
998
+
999
+ df = dsp.load_dataset('painkillers-dissolution')
1000
+ lm = dsp.LinearModel(
1001
+ source=df,
1002
+ target='dissolution',
1003
+ factors=['employee', 'stirrer', 'brand', 'catalyst', 'water'],
1004
+ covariates=['temperature', 'preparation'],
1005
+ order=2)
1006
+ df_gof = pd.concat(lm.recursive_elimination())
1007
+ lm.refit_at_epoch(df_gof, epoch=5)
1008
+ dsp.ParameterRelevanceCharts(lm).plot().stripes().label()
1009
+ ```
1010
+ """
1011
+ formula = self.formula_at_epoch(df_gof, epoch)
1012
+ terms = [t.strip() for t in formula.split('~', 1)[1].split('+')]
1013
+ drop_intercept = '-1' in terms
1014
+ terms = [t for t in terms if t != '-1']
1015
+ self.excluded = {t for t in self._initial_terms if t not in terms}
1016
+ if drop_intercept:
1017
+ self.excluded.add(ANOVA.INTERCEPT)
1018
+ else:
1019
+ self.excluded.discard(ANOVA.INTERCEPT)
1020
+ return self.fit(**kwds)
1021
+
909
1022
  def summary(
910
1023
  self,
911
1024
  anova_typ: Literal['', 'I', 'II', 'III'] | None = None,
@@ -843,6 +843,45 @@ class _Anova_:
843
843
  """Default column name for the Variance Inflation Factor values used
844
844
  to detect multicollinearity in an ANOVA table."""
845
845
 
846
+ EPOCH: Literal['epoch'] = 'epoch'
847
+ """Column name for the step at which a term was added or removed
848
+ during recursive elimination in a goodness-of-fit table, see
849
+ `LinearModel.gof_metrics`."""
850
+
851
+ FORMULA: Literal['formula'] = 'formula'
852
+ """Column name for the model formula at a given elimination step in
853
+ a goodness-of-fit table, see `LinearModel.gof_metrics` and
854
+ `LinearModel.formula_at_epoch`."""
855
+
856
+ HIERARCHICAL: Literal['hierarchical'] = 'hierarchical'
857
+ """Column name for the flag indicating whether the model is
858
+ hierarchical in a goodness-of-fit table, see
859
+ `LinearModel.gof_metrics`."""
860
+
861
+ LEAST_PARAMETER: Literal['least_parameter'] = 'least_parameter'
862
+ """Column name for the least significant term in a goodness-of-fit
863
+ table, see `LinearModel.gof_metrics`."""
864
+
865
+ P_LEAST: Literal['p_least'] = 'p_least'
866
+ """Column name for the p-value of the least significant term in a
867
+ goodness-of-fit table, see `LinearModel.gof_metrics`."""
868
+
869
+ AIC: Literal['aic'] = 'aic'
870
+ """Column name for Akaike's information criterion in a
871
+ goodness-of-fit table, see `LinearModel.gof_metrics`."""
872
+
873
+ R2: Literal['r2'] = 'r2'
874
+ """Column name for R-squared in a goodness-of-fit table, see
875
+ `LinearModel.gof_metrics`."""
876
+
877
+ R2_ADJ: Literal['r2_adj'] = 'r2_adj'
878
+ """Column name for adjusted R-squared in a goodness-of-fit table,
879
+ see `LinearModel.gof_metrics`."""
880
+
881
+ R2_PRED: Literal['r2_pred'] = 'r2_pred'
882
+ """Column name for predicted R-squared in a goodness-of-fit table,
883
+ see `LinearModel.gof_metrics`."""
884
+
846
885
  SMALLEST_INTERACTION_ORDER: int = 2
847
886
  """Smallest possible interaction order, i.e. the interaction between
848
887
  two factors (A:B)."""
@@ -934,9 +934,8 @@ class SingleChart(Chart):
934
934
  if not isinstance(combination, tuple):
935
935
  combination = (combination, )
936
936
  self._last_variate = deepcopy(self._current_variate)
937
- for key, name in zip(self.variate_names, combination):
938
- self._current_variate[key] = name
939
-
937
+ self._current_variate |= dict(zip(self.variate_names, combination))
938
+
940
939
  def dodge(self) -> None:
941
940
  """Converts the feature data to tick positions, taking dodging
942
941
  into account."""
@@ -169,6 +169,7 @@ __all__ = [
169
169
  'StandardErrorMean',
170
170
  'Stem',
171
171
  'Stripe',
172
+ 'StripeArea',
172
173
  'StripeLine',
173
174
  'StripeSpan',
174
175
  'TransformPlotter',
@@ -8314,6 +8315,186 @@ class StripeSpan(Stripe):
8314
8315
  self._axes.append(ax)
8315
8316
 
8316
8317
 
8318
+ class StripeArea(Stripe):
8319
+ """Concrete implementation of `Stripe` for filling the area between
8320
+ two boundary curves using `fill_between`/`fill_betweenx`.
8321
+
8322
+ Unlike `StripeSpan`, which draws a constant band across the full
8323
+ plotting area with `axhspan`/`axvspan`, `StripeArea` fills the
8324
+ region between two boundary curves that may vary along the
8325
+ orthogonal axis (e.g. a confidence band around a fitted line, or
8326
+ spec limits that change over the feature range). The `where`
8327
+ parameter allows the fill to be restricted to specific sections of
8328
+ the data range, exactly like the `where` argument of Matplotlib's
8329
+ `fill_between`/`fill_betweenx`.
8330
+
8331
+ Parameters
8332
+ ----------
8333
+ label : str
8334
+ The label of the stripe as it appears in the legend.
8335
+ base : array-like
8336
+ The data coordinates along the orthogonal axis (x for
8337
+ horizontal stripes, y for vertical stripes) that the lower and
8338
+ upper boundary values correspond to.
8339
+ lower_values : array-like or float
8340
+ The lower boundary of the filled area for each `base` value.
8341
+ Scalars are broadcast across `base`.
8342
+ upper_values : array-like or float
8343
+ The upper boundary of the filled area for each `base` value.
8344
+ Scalars are broadcast across `base`.
8345
+ where : array-like of bool or None, optional
8346
+ Boolean mask defining where the area should be filled, passed
8347
+ directly to `fill_between`/`fill_betweenx`. If None, the area is
8348
+ filled across the entire `base` range. Defaults to None.
8349
+ interpolate : bool, optional
8350
+ Whether to interpolate the boundaries at the edges of masked
8351
+ regions defined by `where`, passed to
8352
+ `fill_between`/`fill_betweenx`. Defaults to False.
8353
+ step : {'pre', 'post', 'mid'} or None, optional
8354
+ If not None, fill between `base` and the boundaries using steps
8355
+ of the given style, passed to `fill_between`/`fill_betweenx`.
8356
+ Defaults to None.
8357
+ orientation : {'horizontal', 'vertical'}, optional
8358
+ The orientation of the stripe. Defaults to 'horizontal'.
8359
+ color : str, optional
8360
+ The fill color of the stripe. Defaults to `COLOR.STRIPE`.
8361
+ alpha : float, optional
8362
+ Transparency level of the stripe. Defaults to `COLOR.CI_ALPHA`.
8363
+ zorder : float, optional
8364
+ Drawing order of the stripe. Defaults to 0.7.
8365
+ border_linewidth : float, optional
8366
+ Width of the border line. Can also be set via `lw` or
8367
+ `linewidth` in `**kwds`. Defaults to 0.
8368
+ **kwds :
8369
+ Additional keyword arguments for fine-tuning appearance.
8370
+ Priority order:
8371
+ - Line width: `lw`, `linewidth`, then `border_linewidth`
8372
+ - Color: `c`, then `color`
8373
+
8374
+ Examples
8375
+ --------
8376
+ Apply to an existing Axes object:
8377
+
8378
+ ```python
8379
+ import numpy as np
8380
+ import matplotlib.pyplot as plt
8381
+ from daspi import StripeArea, COLOR
8382
+
8383
+ fig, ax = plt.subplots()
8384
+ x = np.linspace(0, 10, 100)
8385
+ lower = np.sin(x) - 0.3
8386
+ upper = np.sin(x) + 0.3
8387
+ band = StripeArea(
8388
+ label='band',
8389
+ base=x,
8390
+ lower_values=lower,
8391
+ upper_values=upper,
8392
+ where=x > 5,
8393
+ color=COLOR.STRIPE)
8394
+ band(ax=ax)
8395
+ ax.legend([band.handle], [band.label])
8396
+ ```
8397
+
8398
+ Notes
8399
+ -----
8400
+ This class is part of the DaSPi visualization toolkit and is
8401
+ designed to integrate seamlessly with other chart components. It
8402
+ ensures that each stripe is only drawn once per Axes instance.
8403
+ """
8404
+
8405
+ __slots__ = (
8406
+ 'base',
8407
+ 'border_linewidth',
8408
+ 'interpolate',
8409
+ 'lower_values',
8410
+ 'step',
8411
+ 'upper_values',
8412
+ 'where')
8413
+
8414
+ base: NDArray
8415
+ """The data coordinates along the orthogonal axis the boundary
8416
+ values correspond to."""
8417
+ border_linewidth: float
8418
+ """Width of the border line. Could also be set during initialisation
8419
+ via `lw` or `linewidth`."""
8420
+ interpolate: bool
8421
+ """Whether to interpolate the boundaries at the edges of masked
8422
+ regions defined by `where`."""
8423
+ lower_values: NDArray
8424
+ """The lower boundary of the filled area for each `base` value."""
8425
+ step: Literal['pre', 'post', 'mid'] | None
8426
+ """If not None, fill using steps of the given style."""
8427
+ upper_values: NDArray
8428
+ """The upper boundary of the filled area for each `base` value."""
8429
+ where: NDArray | None
8430
+ """Boolean mask defining where the area should be filled."""
8431
+
8432
+ def __init__(
8433
+ self,
8434
+ label: str,
8435
+ base: ArrayLike,
8436
+ lower_values: ArrayLike | float,
8437
+ upper_values: ArrayLike | float,
8438
+ where: ArrayLike | None = None,
8439
+ interpolate: bool = False,
8440
+ step: Literal['pre', 'post', 'mid'] | None = None,
8441
+ orientation: Literal['horizontal', 'vertical'] = 'horizontal',
8442
+ color: str = COLOR.STRIPE,
8443
+ alpha: float = COLOR.CI_ALPHA,
8444
+ zorder: float = 0.7,
8445
+ border_linewidth: float = 0,
8446
+ **kwds) -> None:
8447
+ self.base = np.asarray(base, dtype=float)
8448
+ self.lower_values = np.broadcast_to(
8449
+ np.asarray(lower_values, dtype=float), self.base.shape)
8450
+ self.upper_values = np.broadcast_to(
8451
+ np.asarray(upper_values, dtype=float), self.base.shape)
8452
+ self.where = None if where is None else np.asarray(where, dtype=bool)
8453
+ self.interpolate = interpolate
8454
+ self.step = step
8455
+
8456
+ position = float(np.mean(self.lower_values + self.upper_values) / 2)
8457
+ width = float(np.mean(self.upper_values - self.lower_values))
8458
+ super().__init__(
8459
+ label=label,
8460
+ orientation=orientation,
8461
+ position=position,
8462
+ width=width,
8463
+ color=kwds.get('c', color),
8464
+ alpha=alpha,
8465
+ zorder=zorder,
8466
+ show_position=False)
8467
+ self.border_linewidth = kwds.get(
8468
+ 'lw', kwds.get('linewidth', border_linewidth))
8469
+
8470
+ @property
8471
+ def handle(self) -> Patch:
8472
+ """Get the handle of the stripe used for legend."""
8473
+ handle = Patch(color=self.color, alpha=self.alpha)
8474
+ return handle
8475
+
8476
+ def __call__(self, ax: Axes) -> None:
8477
+ """Draw the stripe on the given Axes object."""
8478
+ if ax in self._axes:
8479
+ return
8480
+
8481
+ kwds = {
8482
+ 'color': self.color,
8483
+ 'alpha': self.alpha,
8484
+ 'linewidth': self.border_linewidth,
8485
+ 'zorder': self.zorder,
8486
+ 'where': self.where,
8487
+ 'interpolate': self.interpolate,
8488
+ 'step': self.step}
8489
+ if self.orientation == 'horizontal':
8490
+ ax.fill_between(
8491
+ self.base, self.lower_values, self.upper_values, **kwds)
8492
+ else:
8493
+ ax.fill_betweenx(
8494
+ self.base, self.lower_values, self.upper_values, **kwds)
8495
+ self._axes.append(ax)
8496
+
8497
+
8317
8498
  class BlandAltman(Plotter):
8318
8499
  """Generate a Bland-Altman plot to compare two sets of measurements.
8319
8500