numdaplot 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. numdaplot/__init__.py +506 -0
  2. numdaplot/arrays/__init__.py +5 -0
  3. numdaplot/arrays/array.py +92 -0
  4. numdaplot/arrays/array_arithmetic.py +404 -0
  5. numdaplot/arrays/array_calculation.py +143 -0
  6. numdaplot/arrays/array_conversion.py +150 -0
  7. numdaplot/arrays/array_creation.py +371 -0
  8. numdaplot/arrays/array_data.py +281 -0
  9. numdaplot/arrays/array_layout.py +179 -0
  10. numdaplot/arrays/array_logic.py +227 -0
  11. numdaplot/arrays/array_reflected_arithmetic.py +334 -0
  12. numdaplot/arrays/array_refusals.py +339 -0
  13. numdaplot/arrays/array_selection.py +195 -0
  14. numdaplot/arrays/array_sorting.py +59 -0
  15. numdaplot/arrays/axis_number.py +58 -0
  16. numdaplot/arrays/calculation/__init__.py +5 -0
  17. numdaplot/arrays/calculation/counting_statistics.py +325 -0
  18. numdaplot/arrays/calculation/location_statistics.py +268 -0
  19. numdaplot/arrays/calculation/math_function_values.py +183 -0
  20. numdaplot/arrays/calculation/statistic_values.py +209 -0
  21. numdaplot/arrays/calculation/time_function_values.py +419 -0
  22. numdaplot/arrays/conversion/__init__.py +5 -0
  23. numdaplot/arrays/conversion/array_text.py +62 -0
  24. numdaplot/arrays/conversion/equality_check.py +72 -0
  25. numdaplot/arrays/conversion/python_values.py +70 -0
  26. numdaplot/arrays/conversion/time_text.py +290 -0
  27. numdaplot/arrays/creation/__init__.py +5 -0
  28. numdaplot/arrays/creation/date_parts.py +89 -0
  29. numdaplot/arrays/creation/date_parts_values.py +437 -0
  30. numdaplot/arrays/creation/distribution.py +54 -0
  31. numdaplot/arrays/creation/filled_values.py +58 -0
  32. numdaplot/arrays/creation/list_conversion.py +311 -0
  33. numdaplot/arrays/creation/list_shape.py +97 -0
  34. numdaplot/arrays/creation/normal.py +65 -0
  35. numdaplot/arrays/creation/numpy_conversion.py +149 -0
  36. numdaplot/arrays/creation/random_integers.py +104 -0
  37. numdaplot/arrays/creation/random_values.py +97 -0
  38. numdaplot/arrays/creation/range_values.py +73 -0
  39. numdaplot/arrays/creation/spacing.py +84 -0
  40. numdaplot/arrays/creation/spacing_values.py +63 -0
  41. numdaplot/arrays/creation/uniform.py +63 -0
  42. numdaplot/arrays/equality.py +68 -0
  43. numdaplot/arrays/layout/__init__.py +5 -0
  44. numdaplot/arrays/layout/sorting_values.py +113 -0
  45. numdaplot/arrays/layout/unique_values.py +49 -0
  46. numdaplot/arrays/mapping/__init__.py +5 -0
  47. numdaplot/arrays/mapping/mapped_values.py +286 -0
  48. numdaplot/arrays/mapping/unmatched.py +50 -0
  49. numdaplot/arrays/mapping/value_change.py +55 -0
  50. numdaplot/arrays/mapping/value_mapping.py +161 -0
  51. numdaplot/arrays/math_functions/__init__.py +5 -0
  52. numdaplot/arrays/math_functions/absolute.py +27 -0
  53. numdaplot/arrays/math_functions/cosine.py +28 -0
  54. numdaplot/arrays/math_functions/exponential.py +27 -0
  55. numdaplot/arrays/math_functions/logarithm.py +72 -0
  56. numdaplot/arrays/math_functions/math_function.py +58 -0
  57. numdaplot/arrays/math_functions/round.py +58 -0
  58. numdaplot/arrays/math_functions/sine.py +28 -0
  59. numdaplot/arrays/math_functions/square_root.py +27 -0
  60. numdaplot/arrays/operations/__init__.py +5 -0
  61. numdaplot/arrays/operations/boolean_operands.py +48 -0
  62. numdaplot/arrays/operations/combination.py +157 -0
  63. numdaplot/arrays/operations/float_errors.py +170 -0
  64. numdaplot/arrays/operations/integer_bounds.py +175 -0
  65. numdaplot/arrays/operations/integer_rules.py +397 -0
  66. numdaplot/arrays/operations/operand.py +139 -0
  67. numdaplot/arrays/operations/time_arithmetic.py +479 -0
  68. numdaplot/arrays/operations/time_bounds.py +286 -0
  69. numdaplot/arrays/operations/time_result_bounds.py +397 -0
  70. numdaplot/arrays/operations/transformation.py +54 -0
  71. numdaplot/arrays/operations/type_requirements.py +94 -0
  72. numdaplot/arrays/replacement.py +66 -0
  73. numdaplot/arrays/selection/__init__.py +5 -0
  74. numdaplot/arrays/selection/comparison_masks.py +131 -0
  75. numdaplot/arrays/selection/membership_masks.py +118 -0
  76. numdaplot/arrays/selection/missing_mask.py +50 -0
  77. numdaplot/arrays/selection/region_index.py +178 -0
  78. numdaplot/arrays/selection/replaced_values.py +120 -0
  79. numdaplot/arrays/selection/rule_mask.py +83 -0
  80. numdaplot/arrays/selection/time_reference.py +172 -0
  81. numdaplot/arrays/shape.py +74 -0
  82. numdaplot/arrays/type_match.py +51 -0
  83. numdaplot/data_types/__init__.py +5 -0
  84. numdaplot/data_types/library.py +57 -0
  85. numdaplot/data_types/numpy_mapping.py +207 -0
  86. numdaplot/data_types/pandas_mapping.py +114 -0
  87. numdaplot/data_types/time_of_day.py +292 -0
  88. numdaplot/data_types/type.py +224 -0
  89. numdaplot/data_types/value_family.py +149 -0
  90. numdaplot/data_types/value_type.py +147 -0
  91. numdaplot/dates/__init__.py +5 -0
  92. numdaplot/dates/custom_date_format.py +83 -0
  93. numdaplot/dates/date_format.py +120 -0
  94. numdaplot/dates/date_part.py +59 -0
  95. numdaplot/dates/date_part_unit.py +153 -0
  96. numdaplot/dates/date_period.py +57 -0
  97. numdaplot/dates/duration_in.py +58 -0
  98. numdaplot/dates/duration_unit.py +90 -0
  99. numdaplot/dates/period_unit.py +101 -0
  100. numdaplot/dates/time_function.py +56 -0
  101. numdaplot/dates/time_zone.py +68 -0
  102. numdaplot/dates/time_zone_change.py +71 -0
  103. numdaplot/dates/time_zone_mode.py +81 -0
  104. numdaplot/dates/to_duration.py +58 -0
  105. numdaplot/errors/__init__.py +7 -0
  106. numdaplot/errors/broadcast_warning.py +36 -0
  107. numdaplot/errors/calculation_warning.py +35 -0
  108. numdaplot/errors/cell_out_of_range_error.py +77 -0
  109. numdaplot/errors/column_not_found_error.py +64 -0
  110. numdaplot/errors/conflicting_settings_error.py +60 -0
  111. numdaplot/errors/dimension_error.py +62 -0
  112. numdaplot/errors/display_warning.py +32 -0
  113. numdaplot/errors/duplicate_column_error.py +82 -0
  114. numdaplot/errors/duplicate_label_error.py +55 -0
  115. numdaplot/errors/duplicate_statistic_error.py +55 -0
  116. numdaplot/errors/duplicate_value_error.py +54 -0
  117. numdaplot/errors/empty_array_error.py +55 -0
  118. numdaplot/errors/empty_list_error.py +52 -0
  119. numdaplot/errors/empty_region_error.py +34 -0
  120. numdaplot/errors/empty_text_error.py +34 -0
  121. numdaplot/errors/empty_total_error.py +62 -0
  122. numdaplot/errors/empty_values_error.py +34 -0
  123. numdaplot/errors/file_access_error.py +70 -0
  124. numdaplot/errors/file_exists_error.py +62 -0
  125. numdaplot/errors/file_not_found_error.py +56 -0
  126. numdaplot/errors/incompatible_charts_error.py +80 -0
  127. numdaplot/errors/incompatible_types_error.py +104 -0
  128. numdaplot/errors/integer_overflow_error.py +61 -0
  129. numdaplot/errors/invalid_base_error.py +52 -0
  130. numdaplot/errors/invalid_bin_width_error.py +66 -0
  131. numdaplot/errors/invalid_bounds_error.py +58 -0
  132. numdaplot/errors/invalid_chart_data_error.py +81 -0
  133. numdaplot/errors/invalid_color_count_error.py +63 -0
  134. numdaplot/errors/invalid_color_error.py +51 -0
  135. numdaplot/errors/invalid_column_name_error.py +52 -0
  136. numdaplot/errors/invalid_conversion_error.py +119 -0
  137. numdaplot/errors/invalid_count_error.py +61 -0
  138. numdaplot/errors/invalid_date_format_error.py +51 -0
  139. numdaplot/errors/invalid_deviation_error.py +52 -0
  140. numdaplot/errors/invalid_fraction_error.py +51 -0
  141. numdaplot/errors/invalid_label_count_error.py +61 -0
  142. numdaplot/errors/invalid_limits_error.py +111 -0
  143. numdaplot/errors/invalid_opacity_error.py +52 -0
  144. numdaplot/errors/invalid_point_size_error.py +52 -0
  145. numdaplot/errors/invalid_position_error.py +106 -0
  146. numdaplot/errors/invalid_resolution_error.py +51 -0
  147. numdaplot/errors/invalid_rotation_error.py +53 -0
  148. numdaplot/errors/invalid_seed_error.py +53 -0
  149. numdaplot/errors/invalid_separator_error.py +52 -0
  150. numdaplot/errors/invalid_shape_error.py +52 -0
  151. numdaplot/errors/invalid_sheet_name_error.py +54 -0
  152. numdaplot/errors/invalid_size_error.py +58 -0
  153. numdaplot/errors/invalid_step_error.py +77 -0
  154. numdaplot/errors/invalid_suffixes_error.py +61 -0
  155. numdaplot/errors/invalid_time_zone_change_error.py +63 -0
  156. numdaplot/errors/invalid_type_error.py +79 -0
  157. numdaplot/errors/irregular_list_error.py +36 -0
  158. numdaplot/errors/join_relation_error.py +183 -0
  159. numdaplot/errors/missing_dependency_error.py +58 -0
  160. numdaplot/errors/missing_type_error.py +36 -0
  161. numdaplot/errors/missing_value_error.py +62 -0
  162. numdaplot/errors/not_single_value_error.py +53 -0
  163. numdaplot/errors/numdaplot_error.py +25 -0
  164. numdaplot/errors/numdaplot_warning.py +34 -0
  165. numdaplot/errors/occupied_cell_error.py +63 -0
  166. numdaplot/errors/out_of_domain_error.py +70 -0
  167. numdaplot/errors/readability_warning.py +35 -0
  168. numdaplot/errors/refused_operation_error.py +64 -0
  169. numdaplot/errors/refused_setting_error.py +60 -0
  170. numdaplot/errors/rejected_dates.py +60 -0
  171. numdaplot/errors/repeated_key.py +36 -0
  172. numdaplot/errors/shape_mismatch_error.py +67 -0
  173. numdaplot/errors/time_overflow_error.py +131 -0
  174. numdaplot/errors/time_zone_mismatch_error.py +83 -0
  175. numdaplot/errors/unknown_time_zone_error.py +51 -0
  176. numdaplot/errors/unmatched_value_error.py +81 -0
  177. numdaplot/errors/unsupported_image_format_error.py +56 -0
  178. numdaplot/errors/unsupported_index_error.py +38 -0
  179. numdaplot/errors/unsupported_missing_error.py +129 -0
  180. numdaplot/errors/unsupported_type_error.py +62 -0
  181. numdaplot/errors/value_conversion_error.py +215 -0
  182. numdaplot/ordering/__init__.py +5 -0
  183. numdaplot/ordering/missing_position.py +46 -0
  184. numdaplot/ordering/order.py +46 -0
  185. numdaplot/package_version.py +36 -0
  186. numdaplot/plots/__init__.py +5 -0
  187. numdaplot/plots/chart_layer.py +47 -0
  188. numdaplot/plots/charts/__init__.py +5 -0
  189. numdaplot/plots/charts/bar_chart.py +98 -0
  190. numdaplot/plots/charts/bar_layout.py +58 -0
  191. numdaplot/plots/charts/bin_count.py +61 -0
  192. numdaplot/plots/charts/bin_width.py +78 -0
  193. numdaplot/plots/charts/box_chart.py +97 -0
  194. numdaplot/plots/charts/cell_values.py +61 -0
  195. numdaplot/plots/charts/chart.py +59 -0
  196. numdaplot/plots/charts/chart_settings.py +105 -0
  197. numdaplot/plots/charts/color_scale.py +147 -0
  198. numdaplot/plots/charts/heatmap_chart.py +92 -0
  199. numdaplot/plots/charts/histogram_chart.py +93 -0
  200. numdaplot/plots/charts/line_chart.py +100 -0
  201. numdaplot/plots/charts/line_type.py +75 -0
  202. numdaplot/plots/charts/marker_shape.py +113 -0
  203. numdaplot/plots/charts/missing_chart.py +60 -0
  204. numdaplot/plots/charts/missing_map_chart.py +27 -0
  205. numdaplot/plots/charts/orientation.py +58 -0
  206. numdaplot/plots/charts/outliers.py +49 -0
  207. numdaplot/plots/charts/percentages.py +55 -0
  208. numdaplot/plots/charts/pie_chart.py +87 -0
  209. numdaplot/plots/charts/scatter_chart.py +159 -0
  210. numdaplot/plots/charts/value_axis.py +66 -0
  211. numdaplot/plots/data/__init__.py +5 -0
  212. numdaplot/plots/data/array_values.py +128 -0
  213. numdaplot/plots/data/chart_data.py +143 -0
  214. numdaplot/plots/data/chart_values.py +109 -0
  215. numdaplot/plots/data/column_reading.py +468 -0
  216. numdaplot/plots/data/heatmap_values.py +63 -0
  217. numdaplot/plots/data/missing_cells.py +165 -0
  218. numdaplot/plots/data/pie_values.py +215 -0
  219. numdaplot/plots/data/point_values.py +249 -0
  220. numdaplot/plots/data/position_kind.py +83 -0
  221. numdaplot/plots/data/renamed_layers.py +340 -0
  222. numdaplot/plots/data/sample_values.py +160 -0
  223. numdaplot/plots/data/shown_columns.py +248 -0
  224. numdaplot/plots/data/table_values.py +256 -0
  225. numdaplot/plots/data/unique_labels.py +45 -0
  226. numdaplot/plots/drawing/__init__.py +5 -0
  227. numdaplot/plots/drawing/bar_drawing.py +316 -0
  228. numdaplot/plots/drawing/box_drawing.py +344 -0
  229. numdaplot/plots/drawing/cell_merging.py +237 -0
  230. numdaplot/plots/drawing/chart_texts.py +124 -0
  231. numdaplot/plots/drawing/color_bar.py +57 -0
  232. numdaplot/plots/drawing/color_scale_values.py +120 -0
  233. numdaplot/plots/drawing/default_labels.py +41 -0
  234. numdaplot/plots/drawing/drawn_chart.py +50 -0
  235. numdaplot/plots/drawing/grid_axes.py +75 -0
  236. numdaplot/plots/drawing/heatmap_drawing.py +313 -0
  237. numdaplot/plots/drawing/histogram_drawing.py +350 -0
  238. numdaplot/plots/drawing/label_room.py +344 -0
  239. numdaplot/plots/drawing/label_thinning.py +216 -0
  240. numdaplot/plots/drawing/layer_alignment.py +319 -0
  241. numdaplot/plots/drawing/layer_colors.py +123 -0
  242. numdaplot/plots/drawing/line_drawing.py +85 -0
  243. numdaplot/plots/drawing/marker_codes.py +20 -0
  244. numdaplot/plots/drawing/missing_drawing.py +360 -0
  245. numdaplot/plots/drawing/moment_period_formatter.py +253 -0
  246. numdaplot/plots/drawing/pie_drawing.py +185 -0
  247. numdaplot/plots/drawing/plot_axes.py +38 -0
  248. numdaplot/plots/drawing/plot_drawing.py +288 -0
  249. numdaplot/plots/drawing/plot_theme.py +45 -0
  250. numdaplot/plots/drawing/position_axis.py +278 -0
  251. numdaplot/plots/drawing/scatter_drawing.py +364 -0
  252. numdaplot/plots/drawing/series_colors.py +177 -0
  253. numdaplot/plots/drawing/size_inches.py +45 -0
  254. numdaplot/plots/drawing/style_drawing.py +410 -0
  255. numdaplot/plots/drawing/text_contrast.py +44 -0
  256. numdaplot/plots/drawing/tick_rotation.py +354 -0
  257. numdaplot/plots/drawing/time_axis.py +212 -0
  258. numdaplot/plots/drawing/whole_numbers.py +72 -0
  259. numdaplot/plots/figure/__init__.py +5 -0
  260. numdaplot/plots/figure/cell.py +95 -0
  261. numdaplot/plots/figure/figure.py +256 -0
  262. numdaplot/plots/figure/figure_drawing.py +99 -0
  263. numdaplot/plots/figure/figure_style.py +60 -0
  264. numdaplot/plots/figure/layout.py +71 -0
  265. numdaplot/plots/figure/placement.py +150 -0
  266. numdaplot/plots/layer_reading.py +166 -0
  267. numdaplot/plots/output/__init__.py +5 -0
  268. numdaplot/plots/output/image_saving.py +187 -0
  269. numdaplot/plots/output/plot_display.py +181 -0
  270. numdaplot/plots/output/shown_object.py +45 -0
  271. numdaplot/plots/overlay_checks.py +245 -0
  272. numdaplot/plots/plot.py +31 -0
  273. numdaplot/plots/plot_data.py +140 -0
  274. numdaplot/plots/plot_distribution_creation.py +237 -0
  275. numdaplot/plots/plot_output.py +124 -0
  276. numdaplot/plots/plot_overlays.py +273 -0
  277. numdaplot/plots/plot_overview_creation.py +195 -0
  278. numdaplot/plots/plot_series_creation.py +213 -0
  279. numdaplot/plots/style/__init__.py +5 -0
  280. numdaplot/plots/style/axis_settings.py +60 -0
  281. numdaplot/plots/style/color.py +168 -0
  282. numdaplot/plots/style/custom_color.py +65 -0
  283. numdaplot/plots/style/grid_lines.py +49 -0
  284. numdaplot/plots/style/image_options.py +71 -0
  285. numdaplot/plots/style/legend_position.py +149 -0
  286. numdaplot/plots/style/plot_style.py +136 -0
  287. numdaplot/plots/style/size.py +70 -0
  288. numdaplot/plots/style/size_unit.py +62 -0
  289. numdaplot/positions/__init__.py +5 -0
  290. numdaplot/positions/axis.py +54 -0
  291. numdaplot/positions/index.py +51 -0
  292. numdaplot/positions/range.py +90 -0
  293. numdaplot/positions/region.py +92 -0
  294. numdaplot/py.typed +0 -0
  295. numdaplot/ratios/__init__.py +5 -0
  296. numdaplot/ratios/fraction.py +40 -0
  297. numdaplot/ratios/measure.py +48 -0
  298. numdaplot/rules/__init__.py +5 -0
  299. numdaplot/rules/between.py +78 -0
  300. numdaplot/rules/bounds.py +83 -0
  301. numdaplot/rules/case.py +48 -0
  302. numdaplot/rules/contains.py +63 -0
  303. numdaplot/rules/equal.py +43 -0
  304. numdaplot/rules/greater.py +39 -0
  305. numdaplot/rules/greater_or_equal.py +38 -0
  306. numdaplot/rules/is_in.py +67 -0
  307. numdaplot/rules/is_missing.py +25 -0
  308. numdaplot/rules/is_present.py +25 -0
  309. numdaplot/rules/less.py +39 -0
  310. numdaplot/rules/less_or_equal.py +38 -0
  311. numdaplot/rules/not_equal.py +45 -0
  312. numdaplot/rules/rule.py +62 -0
  313. numdaplot/rules/rule_values.py +44 -0
  314. numdaplot/rules/value_rule.py +110 -0
  315. numdaplot/settings/__init__.py +5 -0
  316. numdaplot/settings/argument_types.py +327 -0
  317. numdaplot/settings/field_types.py +593 -0
  318. numdaplot/statistics/__init__.py +5 -0
  319. numdaplot/statistics/count.py +71 -0
  320. numdaplot/statistics/count_distinct.py +27 -0
  321. numdaplot/statistics/counted_missing.py +46 -0
  322. numdaplot/statistics/maximum.py +27 -0
  323. numdaplot/statistics/mean.py +27 -0
  324. numdaplot/statistics/median.py +27 -0
  325. numdaplot/statistics/minimum.py +27 -0
  326. numdaplot/statistics/most_frequent.py +27 -0
  327. numdaplot/statistics/most_frequent_count.py +27 -0
  328. numdaplot/statistics/quantile.py +61 -0
  329. numdaplot/statistics/standard_deviation.py +29 -0
  330. numdaplot/statistics/statistic.py +63 -0
  331. numdaplot/statistics/sum.py +27 -0
  332. numdaplot/tables/__init__.py +5 -0
  333. numdaplot/tables/aggregation/__init__.py +5 -0
  334. numdaplot/tables/aggregation/aggregated_frame.py +189 -0
  335. numdaplot/tables/aggregation/aggregation.py +97 -0
  336. numdaplot/tables/aggregation/calculation.py +123 -0
  337. numdaplot/tables/aggregation/result_column.py +108 -0
  338. numdaplot/tables/aggregation/row_groups.py +96 -0
  339. numdaplot/tables/aggregation/statistic_name.py +122 -0
  340. numdaplot/tables/columns/__init__.py +5 -0
  341. numdaplot/tables/columns/added_column.py +89 -0
  342. numdaplot/tables/columns/boolean_conversion.py +144 -0
  343. numdaplot/tables/columns/boolean_rule.py +59 -0
  344. numdaplot/tables/columns/bracket_end.py +50 -0
  345. numdaplot/tables/columns/bracket_names.py +346 -0
  346. numdaplot/tables/columns/bracketed_column.py +179 -0
  347. numdaplot/tables/columns/brackets.py +234 -0
  348. numdaplot/tables/columns/chosen_columns.py +55 -0
  349. numdaplot/tables/columns/column_choice.py +84 -0
  350. numdaplot/tables/columns/column_mode.py +64 -0
  351. numdaplot/tables/columns/column_names.py +186 -0
  352. numdaplot/tables/columns/conversion.py +103 -0
  353. numdaplot/tables/columns/converted_column.py +669 -0
  354. numdaplot/tables/columns/date_conversion.py +526 -0
  355. numdaplot/tables/columns/date_range.py +135 -0
  356. numdaplot/tables/columns/name_change.py +67 -0
  357. numdaplot/tables/columns/new_column.py +79 -0
  358. numdaplot/tables/columns/number_conversion.py +281 -0
  359. numdaplot/tables/columns/renamed_columns.py +60 -0
  360. numdaplot/tables/columns/renaming.py +81 -0
  361. numdaplot/tables/columns/text_conversion.py +70 -0
  362. numdaplot/tables/columns/time_conversion.py +313 -0
  363. numdaplot/tables/columns/time_zone_conversion.py +128 -0
  364. numdaplot/tables/conflict.py +68 -0
  365. numdaplot/tables/description/__init__.py +5 -0
  366. numdaplot/tables/description/described_frame.py +335 -0
  367. numdaplot/tables/description/description.py +155 -0
  368. numdaplot/tables/duplicates/__init__.py +5 -0
  369. numdaplot/tables/duplicates/deduplicated_frame.py +66 -0
  370. numdaplot/tables/duplicates/deduplication.py +88 -0
  371. numdaplot/tables/duplicates/keep.py +81 -0
  372. numdaplot/tables/files/__init__.py +5 -0
  373. numdaplot/tables/files/column_names.py +60 -0
  374. numdaplot/tables/files/csv_file.py +265 -0
  375. numdaplot/tables/files/csv_read_options.py +89 -0
  376. numdaplot/tables/files/csv_separator.py +41 -0
  377. numdaplot/tables/files/csv_write_options.py +79 -0
  378. numdaplot/tables/files/decimal_count.py +42 -0
  379. numdaplot/tables/files/encoding.py +82 -0
  380. numdaplot/tables/files/excel_file.py +171 -0
  381. numdaplot/tables/files/excel_read_options.py +79 -0
  382. numdaplot/tables/files/excel_sheet.py +50 -0
  383. numdaplot/tables/files/excel_time_cells.py +146 -0
  384. numdaplot/tables/files/excel_write_options.py +63 -0
  385. numdaplot/tables/files/file_access.py +152 -0
  386. numdaplot/tables/files/file_paths.py +106 -0
  387. numdaplot/tables/files/json_decimals.py +387 -0
  388. numdaplot/tables/files/json_file.py +203 -0
  389. numdaplot/tables/files/json_layout.py +63 -0
  390. numdaplot/tables/files/json_read_options.py +64 -0
  391. numdaplot/tables/files/json_write_options.py +71 -0
  392. numdaplot/tables/files/missing_texts.py +63 -0
  393. numdaplot/tables/files/optional_package.py +42 -0
  394. numdaplot/tables/files/pandas_backend.py +11 -0
  395. numdaplot/tables/files/parquet_file.py +91 -0
  396. numdaplot/tables/files/parquet_read_options.py +56 -0
  397. numdaplot/tables/files/sas_file.py +94 -0
  398. numdaplot/tables/files/sas_read_options.py +67 -0
  399. numdaplot/tables/files/stata_file.py +83 -0
  400. numdaplot/tables/files/stata_read_options.py +56 -0
  401. numdaplot/tables/files/xpt_read_options.py +65 -0
  402. numdaplot/tables/filtering/__init__.py +5 -0
  403. numdaplot/tables/filtering/checked_frame.py +60 -0
  404. numdaplot/tables/filtering/column_mask.py +71 -0
  405. numdaplot/tables/filtering/column_match.py +62 -0
  406. numdaplot/tables/filtering/condition.py +94 -0
  407. numdaplot/tables/filtering/filter.py +74 -0
  408. numdaplot/tables/filtering/filter_mode.py +67 -0
  409. numdaplot/tables/filtering/row_mask.py +152 -0
  410. numdaplot/tables/filtering/rule_moments.py +164 -0
  411. numdaplot/tables/frames/__init__.py +5 -0
  412. numdaplot/tables/frames/array_frame.py +95 -0
  413. numdaplot/tables/frames/cleaned_names.py +132 -0
  414. numdaplot/tables/frames/column.py +15 -0
  415. numdaplot/tables/frames/column_values.py +273 -0
  416. numdaplot/tables/frames/frame_equality.py +130 -0
  417. numdaplot/tables/frames/frame_normalization.py +459 -0
  418. numdaplot/tables/frames/named_column_errors.py +85 -0
  419. numdaplot/tables/frames/pandas_decimals.py +113 -0
  420. numdaplot/tables/frames/region_positions.py +113 -0
  421. numdaplot/tables/frames/table_text.py +222 -0
  422. numdaplot/tables/frames/time_columns.py +345 -0
  423. numdaplot/tables/frames/time_range_errors.py +117 -0
  424. numdaplot/tables/frames/time_zones.py +271 -0
  425. numdaplot/tables/joining/__init__.py +5 -0
  426. numdaplot/tables/joining/join.py +110 -0
  427. numdaplot/tables/joining/join_keys.py +367 -0
  428. numdaplot/tables/joining/join_mode.py +93 -0
  429. numdaplot/tables/joining/join_relation.py +149 -0
  430. numdaplot/tables/joining/join_suffixes.py +71 -0
  431. numdaplot/tables/joining/joined_frame.py +166 -0
  432. numdaplot/tables/joining/joined_names.py +107 -0
  433. numdaplot/tables/joining/joined_rows.py +235 -0
  434. numdaplot/tables/joining/key_types.py +57 -0
  435. numdaplot/tables/joining/relation.py +78 -0
  436. numdaplot/tables/missing/__init__.py +5 -0
  437. numdaplot/tables/missing/missing_count.py +59 -0
  438. numdaplot/tables/missing/missing_counts.py +214 -0
  439. numdaplot/tables/missing/missing_drop.py +98 -0
  440. numdaplot/tables/missing/missing_mode.py +63 -0
  441. numdaplot/tables/missing/missing_ratio.py +71 -0
  442. numdaplot/tables/missing/missing_removal.py +257 -0
  443. numdaplot/tables/missing/missing_summary.py +174 -0
  444. numdaplot/tables/missing/ratio_comparison.py +70 -0
  445. numdaplot/tables/pivot/__init__.py +5 -0
  446. numdaplot/tables/pivot/pivot_table.py +104 -0
  447. numdaplot/tables/pivot/pivoted_frame.py +244 -0
  448. numdaplot/tables/preview/__init__.py +5 -0
  449. numdaplot/tables/preview/notebook_display.py +238 -0
  450. numdaplot/tables/preview/preview.py +100 -0
  451. numdaplot/tables/preview/preview_rows.py +55 -0
  452. numdaplot/tables/preview/shown_columns.py +62 -0
  453. numdaplot/tables/preview/side.py +82 -0
  454. numdaplot/tables/sorting/__init__.py +5 -0
  455. numdaplot/tables/sorting/sort_key.py +71 -0
  456. numdaplot/tables/sorting/sorted_frame.py +81 -0
  457. numdaplot/tables/sorting/sorting.py +82 -0
  458. numdaplot/tables/table.py +71 -0
  459. numdaplot/tables/table_calculation.py +172 -0
  460. numdaplot/tables/table_columns.py +214 -0
  461. numdaplot/tables/table_conversion.py +351 -0
  462. numdaplot/tables/table_data.py +321 -0
  463. numdaplot/tables/table_display.py +56 -0
  464. numdaplot/tables/table_joining.py +80 -0
  465. numdaplot/tables/table_layout.py +105 -0
  466. numdaplot/tables/table_missing.py +146 -0
  467. numdaplot/tables/table_reading.py +451 -0
  468. numdaplot/tables/table_refusals.py +295 -0
  469. numdaplot/tables/table_selection.py +163 -0
  470. numdaplot/tables/table_writing.py +269 -0
  471. numdaplot-0.1.0.dist-info/METADATA +176 -0
  472. numdaplot-0.1.0.dist-info/RECORD +474 -0
  473. numdaplot-0.1.0.dist-info/WHEEL +4 -0
  474. numdaplot-0.1.0.dist-info/licenses/LICENSE +28 -0
@@ -0,0 +1,316 @@
1
+ """
2
+ Drawing of a BarChart.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ # The matplotlib stubs leave the keyword arguments of most drawing methods untyped.
8
+ # pyright: reportUnknownMemberType=false
9
+
10
+ from dataclasses import dataclass
11
+ from typing import cast
12
+
13
+ import numpy
14
+ from matplotlib.axes import Axes
15
+ from numpy.typing import NDArray
16
+
17
+ from numdaplot.plots.chart_layer import ChartLayer
18
+ from numdaplot.plots.charts.bar_chart import BarChart
19
+ from numdaplot.plots.charts.bar_layout import BarLayout
20
+ from numdaplot.plots.charts.orientation import Orientation
21
+ from numdaplot.plots.data.chart_values import ChartValues
22
+ from numdaplot.plots.drawing.default_labels import find_position_label
23
+ from numdaplot.plots.drawing.drawn_chart import DrawnChart
24
+ from numdaplot.plots.drawing.grid_axes import GridAxes
25
+ from numdaplot.plots.drawing.position_axis import place_categories
26
+ from numdaplot.plots.drawing.series_colors import choose_series_colors
27
+
28
+ GROUP_WIDTH = 0.8
29
+ HALF = 0.5
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class BarStyle:
34
+ """
35
+ The look of the bars of one series.
36
+
37
+ .. versionadded:: 0.1.0
38
+
39
+ Parameters
40
+ ----------
41
+ thickness
42
+ The thickness of each bar, a position being 1 wide.
43
+ color_code
44
+ The ``#rrggbb`` code of the bars.
45
+
46
+ Examples
47
+ --------
48
+ >>> from numdaplot.plots.drawing.bar_drawing import BarStyle
49
+ >>> BarStyle(0.4, "#1f77b4").thickness
50
+ 0.4
51
+ """
52
+
53
+ thickness: float
54
+ color_code: str
55
+
56
+
57
+ @dataclass(frozen=True, eq=False)
58
+ class BarSeries:
59
+ """
60
+ The bars of one series, ready to be drawn.
61
+
62
+ .. versionadded:: 0.1.0
63
+
64
+ Parameters
65
+ ----------
66
+ name
67
+ The name shown in the legend.
68
+ coordinates
69
+ The coordinate of the middle of each bar along the axis of the ``x`` values.
70
+ lengths
71
+ The length of each bar, NaN for a missing value, which draws no bar.
72
+ bases
73
+ Where each bar starts along the axis of the values: 0, or the top of the bars below it when stacked.
74
+ style
75
+ The thickness of the bars and their color code.
76
+
77
+ Examples
78
+ --------
79
+ >>> import numpy
80
+ >>> from numdaplot.plots.drawing.bar_drawing import BarSeries, BarStyle
81
+ >>> BarSeries("price", numpy.array([0.0]), numpy.array([12.0]), numpy.array([0.0]), BarStyle(0.8, "#1f77b4")).name
82
+ 'price'
83
+ """
84
+
85
+ name: str
86
+ coordinates: NDArray[numpy.float64]
87
+ lengths: NDArray[numpy.float64]
88
+ bases: NDArray[numpy.float64]
89
+ style: BarStyle
90
+
91
+
92
+ @dataclass(frozen=True, eq=False)
93
+ class StackTops:
94
+ """
95
+ Where the next stacked bar starts at each position, above zero and below zero.
96
+
97
+ .. versionadded:: 0.1.0
98
+
99
+ Parameters
100
+ ----------
101
+ positive
102
+ The top of the positive bars already stacked.
103
+ negative
104
+ The bottom of the negative bars already stacked.
105
+
106
+ Examples
107
+ --------
108
+ >>> import numpy
109
+ >>> from numdaplot.plots.drawing.bar_drawing import StackTops
110
+ >>> StackTops(numpy.zeros(2), numpy.zeros(2)).positive
111
+ array([0., 0.])
112
+ """
113
+
114
+ positive: NDArray[numpy.float64]
115
+ negative: NDArray[numpy.float64]
116
+
117
+
118
+ def draw_bar_chart(axes: Axes, layer: ChartLayer) -> DrawnChart:
119
+ """
120
+ Draw each series of a BarChart as bars, one position per ``x`` value.
121
+
122
+ A missing value draws no bar. Horizontal bars are drawn from the top, in the order of the rows.
123
+
124
+ .. versionadded:: 0.1.0
125
+
126
+ Parameters
127
+ ----------
128
+ axes
129
+ The matplotlib axes drawn on.
130
+ layer
131
+ A BarChart and its values.
132
+
133
+ Returns
134
+ -------
135
+ DrawnChart
136
+ The default labels, where the ``x`` values are, and grid lines across the axis of the values only.
137
+
138
+ Raises
139
+ ------
140
+ InvalidColorCountError
141
+ When the colors of the chart are not one per series.
142
+
143
+ Examples
144
+ --------
145
+ >>> import numdaplot as ndp
146
+ >>> from matplotlib.figure import Figure
147
+ >>> from numdaplot.plots.chart_layer import ChartLayer
148
+ >>> from numdaplot.plots.data.array_values import read_array_values
149
+ >>> from numdaplot.plots.drawing.bar_drawing import draw_bar_chart
150
+ >>> prices = ndp.Array.from_list([12.0, None, 15.5])
151
+ >>> axes = Figure().add_subplot()
152
+ >>> drawn_chart = draw_bar_chart(axes, ChartLayer(ndp.BarChart(), read_array_values(prices, "BarChart")))
153
+ >>> [float(bar.get_height()) for bar in axes.patches]
154
+ [12.0, 15.5]
155
+ """
156
+ chart = cast(BarChart, layer.chart)
157
+ values = cast(ChartValues, layer.values)
158
+ series_count = len(values.series)
159
+ color_codes = choose_series_colors(chart.colors, series_count)
160
+ is_horizontal = chart.orientation == Orientation.HORIZONTAL
161
+ is_stacked = chart.layout == BarLayout.STACKED
162
+ coordinates = place_categories(axes, values.positions, is_horizontal)
163
+ position_count = len(coordinates)
164
+ stack_tops = StackTops(numpy.zeros(position_count), numpy.zeros(position_count))
165
+ bases = numpy.zeros(position_count)
166
+ thickness = GROUP_WIDTH / series_count
167
+ if is_stacked:
168
+ thickness = GROUP_WIDTH
169
+
170
+ for i, series in enumerate(values.series):
171
+ bar_coordinates = find_group_coordinates(coordinates, i, series_count)
172
+ if is_stacked:
173
+ bar_coordinates = coordinates
174
+ bases, stack_tops = stack_bars(series.values, stack_tops)
175
+
176
+ bar_style = BarStyle(thickness, color_codes[i])
177
+ bar_series = BarSeries(series.name, bar_coordinates, series.values, bases, bar_style)
178
+ draw_series_bars(axes, bar_series, is_horizontal)
179
+
180
+ if is_horizontal:
181
+ axes.invert_yaxis()
182
+
183
+ x_label = find_position_label(values.positions)
184
+ drawn_chart = DrawnChart(x_label, values.value_name, is_horizontal, GridAxes.VALUES, None)
185
+
186
+ return drawn_chart
187
+
188
+
189
+ def find_group_coordinates(
190
+ coordinates: NDArray[numpy.float64], series_number: int, series_count: int
191
+ ) -> NDArray[numpy.float64]:
192
+ """
193
+ Return the middle of the bars of one series when the series are side by side.
194
+
195
+ .. versionadded:: 0.1.0
196
+
197
+ Parameters
198
+ ----------
199
+ coordinates
200
+ The middle of each position.
201
+ series_number
202
+ The number of the series, from 0.
203
+ series_count
204
+ The number of series sharing each position.
205
+
206
+ Returns
207
+ -------
208
+ NDArray[numpy.float64]
209
+ The middle of each bar of the series.
210
+
211
+ Examples
212
+ --------
213
+ >>> import numpy
214
+ >>> from numdaplot.plots.drawing.bar_drawing import find_group_coordinates
215
+ >>> find_group_coordinates(numpy.array([0.0, 1.0]), 0, 2)
216
+ array([-0.2, 0.8])
217
+ """
218
+ thickness = GROUP_WIDTH / series_count
219
+ middle_number = series_number + HALF
220
+ group_offset = middle_number * thickness
221
+ group_start = GROUP_WIDTH * HALF
222
+ offset = group_offset - group_start
223
+ shifted_coordinates = coordinates + offset
224
+ # Some versions of the numpy stubs widen the sum of float64 values to any floating type.
225
+ group_coordinates = numpy.asarray(shifted_coordinates, dtype=numpy.float64)
226
+
227
+ return group_coordinates
228
+
229
+
230
+ def stack_bars(lengths: NDArray[numpy.float64], stack_tops: StackTops) -> tuple[NDArray[numpy.float64], StackTops]:
231
+ """
232
+ Return where the bars of a series start when stacked, and the tops of the stacks once they are added.
233
+
234
+ Positive values stack above zero and negative values below it. A missing value adds nothing.
235
+
236
+ .. versionadded:: 0.1.0
237
+
238
+ Parameters
239
+ ----------
240
+ lengths
241
+ The values of the series, NaN where a value is missing.
242
+ stack_tops
243
+ The tops of the stacks before this series.
244
+
245
+ Returns
246
+ -------
247
+ tuple[NDArray[numpy.float64], StackTops]
248
+ The base of each bar, and the new tops.
249
+
250
+ Examples
251
+ --------
252
+ >>> import numpy
253
+ >>> from numdaplot.plots.drawing.bar_drawing import StackTops, stack_bars
254
+ >>> bases, stack_tops = stack_bars(numpy.array([2.0, -1.0]), StackTops(numpy.array([1.0, 1.0]), numpy.zeros(2)))
255
+ >>> bases
256
+ array([1., 0.])
257
+ >>> stack_tops.positive
258
+ array([3., 1.])
259
+ """
260
+ present_lengths = numpy.nan_to_num(lengths)
261
+ is_positive = present_lengths >= 0
262
+ bases = numpy.where(is_positive, stack_tops.positive, stack_tops.negative)
263
+ tops = bases + present_lengths
264
+ positive_tops = numpy.where(is_positive, tops, stack_tops.positive)
265
+ negative_tops = numpy.where(is_positive, stack_tops.negative, tops)
266
+ new_tops = StackTops(positive_tops, negative_tops)
267
+
268
+ return bases, new_tops
269
+
270
+
271
+ def draw_series_bars(axes: Axes, bar_series: BarSeries, is_horizontal: bool) -> None:
272
+ """
273
+ Draw the bars of one series, except at its missing values.
274
+
275
+ .. versionadded:: 0.1.0
276
+
277
+ Parameters
278
+ ----------
279
+ axes
280
+ The matplotlib axes drawn on.
281
+ bar_series
282
+ The bars of the series.
283
+ is_horizontal
284
+ True to draw horizontal bars.
285
+
286
+ Examples
287
+ --------
288
+ >>> import numpy
289
+ >>> from matplotlib.figure import Figure
290
+ >>> from numdaplot.plots.drawing.bar_drawing import BarSeries, BarStyle, draw_series_bars
291
+ >>> axes = Figure().add_subplot()
292
+ >>> bar_style = BarStyle(0.8, "#1f77b4")
293
+ >>> bar_series = BarSeries("price", numpy.arange(2.0), numpy.array([3.0, 4.0]), numpy.zeros(2), bar_style)
294
+ >>> draw_series_bars(axes, bar_series, True)
295
+ >>> [float(bar.get_width()) for bar in axes.patches]
296
+ [3.0, 4.0]
297
+ """
298
+ is_present = ~numpy.isnan(bar_series.lengths)
299
+ coordinates = bar_series.coordinates[is_present]
300
+ lengths = bar_series.lengths[is_present]
301
+ bases = bar_series.bases[is_present]
302
+ bar_style = bar_series.style
303
+ if is_horizontal:
304
+ axes.barh(
305
+ coordinates,
306
+ lengths,
307
+ height=bar_style.thickness,
308
+ left=bases,
309
+ color=bar_style.color_code,
310
+ label=bar_series.name,
311
+ )
312
+ return
313
+
314
+ axes.bar(
315
+ coordinates, lengths, width=bar_style.thickness, bottom=bases, color=bar_style.color_code, label=bar_series.name
316
+ )
@@ -0,0 +1,344 @@
1
+ """
2
+ Drawing of a BoxChart.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ # The matplotlib stubs leave the keyword arguments of most drawing methods untyped.
8
+ # pyright: reportUnknownMemberType=false
9
+
10
+ from dataclasses import dataclass
11
+ from typing import Any, cast
12
+
13
+ import numpy
14
+ import pandas
15
+ from matplotlib.axes import Axes
16
+ from numpy.typing import NDArray
17
+
18
+ from numdaplot.plots.chart_layer import ChartLayer
19
+ from numdaplot.plots.charts.box_chart import BoxChart
20
+ from numdaplot.plots.charts.outliers import Outliers
21
+ from numdaplot.plots.data.chart_values import Positions, Series
22
+ from numdaplot.plots.data.position_kind import PositionKind
23
+ from numdaplot.plots.data.sample_values import SampleValues, drop_missing_numbers
24
+ from numdaplot.plots.drawing.bar_drawing import GROUP_WIDTH, find_group_coordinates
25
+ from numdaplot.plots.drawing.default_labels import COLUMN_LABEL
26
+ from numdaplot.plots.drawing.drawn_chart import DrawnChart
27
+ from numdaplot.plots.drawing.grid_axes import GridAxes
28
+ from numdaplot.plots.drawing.plot_theme import BACKGROUND_COLOR
29
+ from numdaplot.plots.drawing.position_axis import place_categories
30
+ from numdaplot.plots.drawing.series_colors import choose_series_colors
31
+ from numdaplot.plots.drawing.time_axis import measures_times, place_hour_ticks
32
+
33
+ # Share of its place a box fills, leaving a gap between two boxes side by side.
34
+ BOX_SHARE = 0.8
35
+ # Width of a box alone at its position, a position being 1 wide.
36
+ COLUMN_BOX_WIDTH = 0.5
37
+ HALF_POSITION = 0.5
38
+ MEDIAN_LINE_WIDTH = 1.5
39
+ OUTLIER_MARKER = "o"
40
+ OUTLIER_SIZE = 4.0
41
+ TEXT_DTYPE = numpy.dtype(object)
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class BoxLook:
46
+ """
47
+ The look shared by the boxes of one column.
48
+
49
+ .. versionadded:: 0.1.0
50
+
51
+ Parameters
52
+ ----------
53
+ color_code
54
+ The ``#rrggbb`` code of the boxes.
55
+ width
56
+ The width of each box, a position being 1 wide.
57
+ shows_outliers
58
+ True to draw the outliers.
59
+ label
60
+ The name shown in the legend, or None to leave the boxes out of it.
61
+
62
+ Examples
63
+ --------
64
+ >>> from numdaplot.plots.drawing.box_drawing import BoxLook
65
+ >>> BoxLook("#1f77b4", 0.8, True, None).width
66
+ 0.8
67
+ """
68
+
69
+ color_code: str
70
+ width: float
71
+ shows_outliers: bool
72
+ label: str | None
73
+
74
+
75
+ def draw_box_chart(axes: Axes, layer: ChartLayer) -> DrawnChart:
76
+ """
77
+ Draw the values of each column as a box, one per column, or one per column side by side in each group.
78
+
79
+ Each position is 1 wide, with half a position of margin at both ends, as for bars.
80
+
81
+ .. versionadded:: 0.1.0
82
+
83
+ Parameters
84
+ ----------
85
+ axes
86
+ The matplotlib axes drawn on.
87
+ layer
88
+ A BoxChart, its columns and their groups.
89
+
90
+ Returns
91
+ -------
92
+ DrawnChart
93
+ The ``group_by`` column and the single column as default labels, and grid lines across the axis of the
94
+ values only, labeled ``HH:MM`` for times of day.
95
+
96
+ Raises
97
+ ------
98
+ InvalidColorCountError
99
+ When the colors of the chart are not one per column.
100
+
101
+ Examples
102
+ --------
103
+ >>> import numdaplot as ndp
104
+ >>> from matplotlib.figure import Figure
105
+ >>> from numdaplot.plots.chart_layer import ChartLayer
106
+ >>> from numdaplot.plots.data.sample_values import read_sample_values
107
+ >>> from numdaplot.plots.drawing.box_drawing import draw_box_chart
108
+ >>> prices = ndp.Array.from_list([[12.0, 9.5], [14.0, 10.0], [13.5, 8.0]])
109
+ >>> axes = Figure().add_subplot()
110
+ >>> layer = ChartLayer(ndp.BoxChart(), read_sample_values(prices, None, None, "BoxChart"))
111
+ >>> drawn_chart = draw_box_chart(axes, layer)
112
+ >>> [label.get_text() for label in axes.get_xticklabels()]
113
+ ['0', '1']
114
+ """
115
+ chart = cast(BoxChart, layer.chart)
116
+ values = cast(SampleValues, layer.values)
117
+ series_count = len(values.series)
118
+ color_codes = choose_series_colors(chart.colors, series_count)
119
+ shows_outliers = chart.outliers == Outliers.SHOWN
120
+ if values.groups is None:
121
+ position_count = draw_column_boxes(axes, values.series, color_codes, shows_outliers)
122
+ else:
123
+ position_count = draw_group_boxes(axes, values, color_codes, shows_outliers)
124
+
125
+ last_edge = position_count - HALF_POSITION
126
+ axes.set_xlim(-HALF_POSITION, last_edge)
127
+
128
+ is_time = measures_times(values.value_type)
129
+ if is_time:
130
+ series_values = [series.values for series in values.series]
131
+ hours = numpy.concatenate(series_values)
132
+ place_hour_ticks(axes.yaxis, hours)
133
+
134
+ x_label = COLUMN_LABEL
135
+ if values.group_name is not None:
136
+ x_label = values.group_name
137
+
138
+ drawn_chart = DrawnChart(x_label, values.value_name, False, GridAxes.VALUES, None)
139
+
140
+ return drawn_chart
141
+
142
+
143
+ def draw_column_boxes(axes: Axes, series_list: list[Series], color_codes: list[str], shows_outliers: bool) -> int:
144
+ """
145
+ Draw one box per column, each at its own position labeled with the column name.
146
+
147
+ .. versionadded:: 0.1.0
148
+
149
+ Parameters
150
+ ----------
151
+ axes
152
+ The matplotlib axes drawn on.
153
+ series_list
154
+ The columns drawn.
155
+ color_codes
156
+ One ``#rrggbb`` code per column.
157
+ shows_outliers
158
+ True to draw the outliers.
159
+
160
+ Returns
161
+ -------
162
+ int
163
+ The number of positions, one per column.
164
+
165
+ Examples
166
+ --------
167
+ >>> import numpy
168
+ >>> from matplotlib.figure import Figure
169
+ >>> from numdaplot.plots.data.chart_values import Series
170
+ >>> from numdaplot.plots.drawing.box_drawing import draw_column_boxes
171
+ >>> axes = Figure().add_subplot()
172
+ >>> draw_column_boxes(axes, [Series("price", numpy.array([1.0, 2.0, 4.0]))], ["#1f77b4"], True)
173
+ 1
174
+ >>> [label.get_text() for label in axes.get_xticklabels()]
175
+ ['price']
176
+ """
177
+ column_names = [series.name for series in series_list]
178
+ name_values = numpy.array(column_names, dtype=TEXT_DTYPE)
179
+ positions = Positions(PositionKind.TEXTS, name_values, None)
180
+ coordinates = place_categories(axes, positions, False)
181
+
182
+ for i, series in enumerate(series_list):
183
+ samples = [series.values]
184
+ box_coordinates = coordinates[i : i + 1]
185
+ box_look = BoxLook(color_codes[i], COLUMN_BOX_WIDTH, shows_outliers, None)
186
+ draw_boxes(axes, samples, box_coordinates, box_look)
187
+
188
+ position_count = len(coordinates)
189
+
190
+ return position_count
191
+
192
+
193
+ def draw_group_boxes(axes: Axes, values: SampleValues, color_codes: list[str], shows_outliers: bool) -> int:
194
+ """
195
+ Draw one position per group in alphabetical order, with the boxes of the columns side by side.
196
+
197
+ Rows whose group is missing are left out. The columns are named in the legend.
198
+
199
+ .. versionadded:: 0.1.0
200
+
201
+ Parameters
202
+ ----------
203
+ axes
204
+ The matplotlib axes drawn on.
205
+ values
206
+ The columns, the group of each row and the ``group_by`` column.
207
+ color_codes
208
+ One ``#rrggbb`` code per column.
209
+ shows_outliers
210
+ True to draw the outliers.
211
+
212
+ Returns
213
+ -------
214
+ int
215
+ The number of positions, one per group.
216
+
217
+ Examples
218
+ --------
219
+ >>> import numdaplot as ndp
220
+ >>> from matplotlib.figure import Figure
221
+ >>> from numdaplot.plots.data.sample_values import read_sample_values
222
+ >>> from numdaplot.plots.drawing.box_drawing import draw_group_boxes
223
+ >>> cities = ndp.Array.from_list(["Paris", "Lyon", "Paris", "Lyon"])
224
+ >>> prices = ndp.Array.from_list([12.0, 9.5, 14.0, 10.0])
225
+ >>> flats = ndp.Table.from_arrays({"city": cities, "price": prices})
226
+ >>> axes = Figure().add_subplot()
227
+ >>> draw_group_boxes(axes, read_sample_values(flats, ["price"], "city", "BoxChart"), ["#1f77b4"], True)
228
+ 2
229
+ >>> [label.get_text() for label in axes.get_xticklabels()]
230
+ ['Lyon', 'Paris']
231
+ """
232
+ groups = cast(NDArray[Any], values.groups)
233
+ group_names = sort_groups(groups)
234
+ positions = Positions(PositionKind.TEXTS, group_names, values.group_name)
235
+ coordinates = place_categories(axes, positions, False)
236
+ series_count = len(values.series)
237
+ slot_width = GROUP_WIDTH / series_count
238
+ box_width = slot_width * BOX_SHARE
239
+
240
+ for i, series in enumerate(values.series):
241
+ box_coordinates = find_group_coordinates(coordinates, i, series_count)
242
+ samples = [series.values[groups == group_name] for group_name in group_names]
243
+ box_look = BoxLook(color_codes[i], box_width, shows_outliers, series.name)
244
+ draw_boxes(axes, samples, box_coordinates, box_look)
245
+
246
+ position_count = len(coordinates)
247
+
248
+ return position_count
249
+
250
+
251
+ def sort_groups(groups: NDArray[Any]) -> NDArray[Any]:
252
+ """
253
+ Return each group once, in alphabetical order, without the missing one.
254
+
255
+ .. versionadded:: 0.1.0
256
+
257
+ Parameters
258
+ ----------
259
+ groups
260
+ The group of each row, None where it is missing.
261
+
262
+ Returns
263
+ -------
264
+ NDArray
265
+ The group names, in a numpy array of Python texts.
266
+
267
+ Examples
268
+ --------
269
+ >>> import numpy
270
+ >>> from numdaplot.plots.drawing.box_drawing import sort_groups
271
+ >>> sort_groups(numpy.array(["Pau", None, "Lyon", "Pau"], dtype=object))
272
+ array(['Lyon', 'Pau'], dtype=object)
273
+ """
274
+ present = pandas.notna(groups)
275
+ present_groups = groups[present]
276
+ unique_groups = set[str](present_groups)
277
+ sorted_groups = sorted(unique_groups)
278
+ group_names = numpy.array(sorted_groups, dtype=TEXT_DTYPE)
279
+
280
+ return group_names
281
+
282
+
283
+ def draw_boxes(
284
+ axes: Axes, samples: list[NDArray[numpy.float64]], coordinates: NDArray[numpy.float64], box_look: BoxLook
285
+ ) -> None:
286
+ """
287
+ Draw the boxes of one column, one per sample, skipping the samples without value.
288
+
289
+ .. versionadded:: 0.1.0
290
+
291
+ Parameters
292
+ ----------
293
+ axes
294
+ The matplotlib axes drawn on.
295
+ samples
296
+ The numbers of each box, NaN where a value is missing.
297
+ coordinates
298
+ The middle of each box along the horizontal axis.
299
+ box_look
300
+ The color, the width, the outliers and the legend name of the boxes.
301
+
302
+ Examples
303
+ --------
304
+ >>> import numpy
305
+ >>> from matplotlib.figure import Figure
306
+ >>> from numdaplot.plots.drawing.box_drawing import BoxLook, draw_boxes
307
+ >>> axes = Figure().add_subplot()
308
+ >>> samples = [numpy.array([1.0, 2.0, 4.0]), numpy.array([numpy.nan])]
309
+ >>> draw_boxes(axes, samples, numpy.array([0.0, 1.0]), BoxLook("#1f77b4", 0.8, True, None))
310
+ >>> len(axes.patches)
311
+ 1
312
+ """
313
+ present_samples = [drop_missing_numbers(sample) for sample in samples]
314
+ drawn_numbers = [i for i, sample in enumerate(present_samples) if sample.size > 0]
315
+ drawn_count = len(drawn_numbers)
316
+ if drawn_count == 0:
317
+ return
318
+
319
+ drawn_samples = [present_samples[i] for i in drawn_numbers]
320
+ drawn_coordinates = coordinates[drawn_numbers]
321
+ color_code = box_look.color_code
322
+ box_style = {"facecolor": color_code, "edgecolor": color_code}
323
+ line_style = {"color": color_code}
324
+ median_style = {"color": BACKGROUND_COLOR, "linewidth": MEDIAN_LINE_WIDTH}
325
+ outlier_style = {
326
+ "marker": OUTLIER_MARKER,
327
+ "markerfacecolor": color_code,
328
+ "markeredgecolor": color_code,
329
+ "markersize": OUTLIER_SIZE,
330
+ }
331
+ axes.boxplot(
332
+ drawn_samples,
333
+ positions=drawn_coordinates,
334
+ widths=box_look.width,
335
+ patch_artist=True,
336
+ showfliers=box_look.shows_outliers,
337
+ manage_ticks=False,
338
+ label=box_look.label,
339
+ boxprops=box_style,
340
+ whiskerprops=line_style,
341
+ capprops=line_style,
342
+ medianprops=median_style,
343
+ flierprops=outlier_style,
344
+ )