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,367 @@
1
+ """
2
+ Checks and alignment of the key columns of a join.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ import numpy
8
+ import pandas
9
+
10
+ from numdaplot.data_types.numpy_mapping import from_numpy_dtype, to_numpy_dtype
11
+ from numdaplot.data_types.pandas_mapping import to_pandas_dtype
12
+ from numdaplot.data_types.type import Type
13
+ from numdaplot.data_types.value_family import ValueFamily, find_family
14
+ from numdaplot.errors.column_not_found_error import ColumnNotFoundError
15
+ from numdaplot.errors.incompatible_types_error import IncompatibleTypesError
16
+ from numdaplot.errors.time_zone_mismatch_error import TimeZoneMismatchError
17
+ from numdaplot.tables.columns.column_names import require_known_columns
18
+ from numdaplot.tables.frames.column import Column
19
+ from numdaplot.tables.frames.column_values import find_column_type
20
+ from numdaplot.tables.frames.named_column_errors import NamedColumnErrors
21
+ from numdaplot.tables.frames.time_zones import find_column_time_zone
22
+ from numdaplot.tables.joining.key_types import KeyTypes
23
+
24
+ OTHER_TABLE_NAME = "the other Table"
25
+ JOIN_OPERATION = "Join"
26
+ KEY_OPERATION = "Joining on {key_name!r}"
27
+ FLOAT_DTYPE = numpy.dtype(numpy.float64)
28
+
29
+
30
+ def align_key_frames(
31
+ frame: pandas.DataFrame, other_frame: pandas.DataFrame, keys: list[str], key_types: KeyTypes
32
+ ) -> tuple[pandas.DataFrame, pandas.DataFrame]:
33
+ """
34
+ Return the key columns of both Tables of a join, each key converted to one type on both sides.
35
+
36
+ .. versionadded:: 0.1.0
37
+
38
+ Parameters
39
+ ----------
40
+ frame
41
+ The columns of the joined Table.
42
+ other_frame
43
+ The columns of the other Table.
44
+ keys
45
+ The names of the key columns.
46
+ key_types
47
+ How close the types of each key must be.
48
+
49
+ Returns
50
+ -------
51
+ tuple[pandas.DataFrame, pandas.DataFrame]
52
+ The key columns of the joined Table and of the other Table, of the same types.
53
+
54
+ Raises
55
+ ------
56
+ ColumnNotFoundError
57
+ When a key is missing from one of the Tables.
58
+ IncompatibleTypesError
59
+ When the two columns of a key are of different families, of different types with ``KeyTypes.SAME_TYPE``, or
60
+ a date and a datetime.
61
+ TimeZoneMismatchError
62
+ When the two columns of a key hold datetimes of different time zones, or with and without one.
63
+
64
+ Examples
65
+ --------
66
+ >>> import pandas
67
+ >>> import numdaplot as ndp
68
+ >>> from numdaplot.tables.joining.join_keys import align_key_frames
69
+ >>> frame = pandas.DataFrame({"id": pandas.array([1, 2], dtype="Int64")})
70
+ >>> other_frame = pandas.DataFrame({"id": [1.0, 2.5]})
71
+ >>> key_frame, other_key_frame = align_key_frames(frame, other_frame, ["id"], ndp.KeyTypes.SAME_FAMILY)
72
+ >>> key_frame["id"].tolist()
73
+ [1.0, 2.0]
74
+ """
75
+ column_names = frame.columns.tolist()
76
+ other_names = other_frame.columns.tolist()
77
+ require_known_columns(keys, column_names)
78
+ require_other_keys(keys, other_names)
79
+ key_columns = dict[str, Column]()
80
+ other_key_columns = dict[str, Column]()
81
+
82
+ for key_name in keys:
83
+ column = frame[key_name]
84
+ other_column = other_frame[key_name]
85
+ key_type = find_key_type(column, other_column, key_types)
86
+ key_column = convert_key_column(column, key_type)
87
+ other_key_column = convert_key_column(other_column, key_type)
88
+ key_columns[key_name] = key_column
89
+ other_key_columns[key_name] = other_key_column
90
+
91
+ key_frame = pandas.DataFrame(key_columns)
92
+ other_key_frame = pandas.DataFrame(other_key_columns)
93
+
94
+ return key_frame, other_key_frame
95
+
96
+
97
+ def require_other_keys(keys: list[str], other_names: list[str]) -> None:
98
+ """
99
+ Check that the other Table of a join has every key column.
100
+
101
+ .. versionadded:: 0.1.0
102
+
103
+ Parameters
104
+ ----------
105
+ keys
106
+ The names of the key columns.
107
+ other_names
108
+ The column names of the other Table.
109
+
110
+ Raises
111
+ ------
112
+ ColumnNotFoundError
113
+ At the first key the other Table does not have, naming it.
114
+
115
+ Examples
116
+ --------
117
+ >>> import numdaplot as ndp
118
+ >>> from numdaplot.tables.joining.join_keys import require_other_keys
119
+ >>> try:
120
+ ... require_other_keys(["Num_Acc"], ["num_acc"])
121
+ ... except ndp.ColumnNotFoundError as error:
122
+ ... print(error)
123
+ No column of the other Table is named 'Num_Acc'.
124
+ """
125
+ known_names = set(other_names)
126
+
127
+ for key_name in keys:
128
+ if key_name not in known_names:
129
+ raise ColumnNotFoundError(key_name, OTHER_TABLE_NAME)
130
+
131
+
132
+ def find_key_type(column: Column, other_column: Column, key_types: KeyTypes) -> Type:
133
+ """
134
+ Return the type both columns of a key take for the join.
135
+
136
+ .. versionadded:: 0.1.0
137
+
138
+ Parameters
139
+ ----------
140
+ column
141
+ The key column of the joined Table.
142
+ other_column
143
+ The key column of the other Table.
144
+ key_types
145
+ How close their types must be.
146
+
147
+ Returns
148
+ -------
149
+ Type
150
+ Their type when they share it, except categories of different categories, which give ``TEXT``. Otherwise
151
+ the number type holding both, or ``TEXT`` for a text and a category.
152
+
153
+ Raises
154
+ ------
155
+ IncompatibleTypesError
156
+ When the columns are of different families, of different types with ``KeyTypes.SAME_TYPE``, or a date and
157
+ a datetime.
158
+ TimeZoneMismatchError
159
+ When the columns hold datetimes of different time zones, or with and without one.
160
+
161
+ Examples
162
+ --------
163
+ >>> import pandas
164
+ >>> import numdaplot as ndp
165
+ >>> from numdaplot.tables.joining.join_keys import find_key_type
166
+ >>> integers = pandas.Series([1], dtype="Int32")
167
+ >>> find_key_type(integers, pandas.Series([1], dtype="Int64"), ndp.KeyTypes.SAME_FAMILY)
168
+ <Type.INT64: 4>
169
+ """
170
+ column_type = find_column_type(column)
171
+ other_type = find_column_type(other_column)
172
+ require_key_types(column, column_type, other_type, key_types)
173
+ require_same_time_zone(column, other_column)
174
+ if column_type == other_type:
175
+ shared_type = find_shared_key_type(column, other_column, column_type)
176
+ return shared_type
177
+
178
+ family = find_family(column_type)
179
+ if family == ValueFamily.TEXT:
180
+ return Type.TEXT
181
+
182
+ numpy_dtype = to_numpy_dtype(column_type)
183
+ other_numpy_dtype = to_numpy_dtype(other_type)
184
+ common_numpy_dtype = numpy.result_type(numpy_dtype, other_numpy_dtype)
185
+ common_type = from_numpy_dtype(common_numpy_dtype)
186
+
187
+ return common_type
188
+
189
+
190
+ def require_key_types(column: Column, column_type: Type, other_type: Type, key_types: KeyTypes) -> None:
191
+ """
192
+ Check that the two columns of a key can match.
193
+
194
+ .. versionadded:: 0.1.0
195
+
196
+ Parameters
197
+ ----------
198
+ column
199
+ The key column of the joined Table, named in the error message.
200
+ column_type
201
+ Its type.
202
+ other_type
203
+ The type of the key column of the other Table.
204
+ key_types
205
+ How close the types must be.
206
+
207
+ Raises
208
+ ------
209
+ IncompatibleTypesError
210
+ When the types are of different families, different with ``KeyTypes.SAME_TYPE``, or a date and a datetime,
211
+ whose family is the same.
212
+
213
+ Examples
214
+ --------
215
+ >>> import pandas
216
+ >>> import numdaplot as ndp
217
+ >>> from numdaplot.tables.joining.join_keys import require_key_types
218
+ >>> days = pandas.Series(pandas.to_datetime(["2026-01-01"]), name="day").astype("datetime64[s]")
219
+ >>> try:
220
+ ... require_key_types(days, ndp.Type.DATE, ndp.Type.DATETIME, ndp.KeyTypes.SAME_FAMILY)
221
+ ... except ndp.IncompatibleTypesError as error:
222
+ ... print(error)
223
+ Cannot apply Join to the DATE column 'day' and DATETIME.
224
+ """
225
+ if column_type == other_type:
226
+ return
227
+
228
+ family = find_family(column_type)
229
+ other_family = find_family(other_type)
230
+ is_same_family = family == other_family
231
+ is_moment = family == ValueFamily.MOMENT
232
+ needs_same_type = key_types == KeyTypes.SAME_TYPE
233
+ can_match = is_same_family and not is_moment and not needs_same_type
234
+ if can_match:
235
+ return
236
+
237
+ with NamedColumnErrors(column):
238
+ raise IncompatibleTypesError(JOIN_OPERATION, [column_type.name, other_type.name])
239
+
240
+
241
+ def require_same_time_zone(column: Column, other_column: Column) -> None:
242
+ """
243
+ Check that the two columns of a key hold datetimes of the same time zone, or both without one.
244
+
245
+ .. versionadded:: 0.1.0
246
+
247
+ Parameters
248
+ ----------
249
+ column
250
+ The key column of the joined Table, named in the error message.
251
+ other_column
252
+ The key column of the other Table.
253
+
254
+ Raises
255
+ ------
256
+ TimeZoneMismatchError
257
+ When only one has a time zone, naming the state the other column needs, or their time zones differ: change
258
+ them first with ``TimeZoneChange``.
259
+
260
+ Examples
261
+ --------
262
+ >>> import pandas
263
+ >>> import numdaplot as ndp
264
+ >>> from numdaplot.tables.joining.join_keys import require_same_time_zone
265
+ >>> utc_times = pandas.Series(pandas.to_datetime(["2026-07-01 10:30"]), name="time").dt.tz_localize("UTC")
266
+ >>> try:
267
+ ... require_same_time_zone(utc_times, utc_times.dt.tz_convert("Europe/Paris"))
268
+ ... except ndp.TimeZoneMismatchError as error:
269
+ ... print(error)
270
+ Joining on 'time' needs datetimes in one time zone, got UTC and Europe/Paris.
271
+ """
272
+ time_zone = find_column_time_zone(column)
273
+ other_time_zone = find_column_time_zone(other_column)
274
+ if time_zone == other_time_zone:
275
+ return
276
+
277
+ operation = KEY_OPERATION.format(key_name=column.name)
278
+ if time_zone is None:
279
+ raise TimeZoneMismatchError(operation, False)
280
+
281
+ if other_time_zone is None:
282
+ raise TimeZoneMismatchError(operation, True)
283
+
284
+ zone_names = [time_zone.name, other_time_zone.name]
285
+ raise TimeZoneMismatchError(operation, True, zone_names)
286
+
287
+
288
+ def find_shared_key_type(column: Column, other_column: Column, key_type: Type) -> Type:
289
+ """
290
+ Return the type of a key whose two columns have the same type.
291
+
292
+ .. versionadded:: 0.1.0
293
+
294
+ Parameters
295
+ ----------
296
+ column
297
+ The key column of the joined Table.
298
+ other_column
299
+ The key column of the other Table.
300
+ key_type
301
+ Their type.
302
+
303
+ Returns
304
+ -------
305
+ Type
306
+ The type itself, or ``TEXT`` for two categories that do not have the same categories.
307
+
308
+ Examples
309
+ --------
310
+ >>> import pandas
311
+ >>> import numdaplot as ndp
312
+ >>> from numdaplot.tables.joining.join_keys import find_shared_key_type
313
+ >>> paris = pandas.Series(["Paris"], dtype="category")
314
+ >>> find_shared_key_type(paris, pandas.Series(["Lyon"], dtype="category"), ndp.Type.CATEGORY)
315
+ <Type.TEXT: 12>
316
+ """
317
+ if key_type != Type.CATEGORY:
318
+ return key_type
319
+
320
+ categories = column.cat.categories
321
+ other_categories = other_column.cat.categories
322
+ has_same_categories = categories.equals(other_categories)
323
+ if has_same_categories:
324
+ return key_type
325
+
326
+ return Type.TEXT
327
+
328
+
329
+ def convert_key_column(column: Column, key_type: Type) -> Column:
330
+ """
331
+ Return a key column converted to the type both sides of the key take.
332
+
333
+ .. versionadded:: 0.1.0
334
+
335
+ Parameters
336
+ ----------
337
+ column
338
+ A key column.
339
+ key_type
340
+ The type of the key for the join.
341
+
342
+ Returns
343
+ -------
344
+ Column
345
+ The column itself when it has that type, otherwise a converted copy, missing values staying missing.
346
+
347
+ Examples
348
+ --------
349
+ >>> import pandas
350
+ >>> import numdaplot as ndp
351
+ >>> from numdaplot.tables.joining.join_keys import convert_key_column
352
+ >>> convert_key_column(pandas.Series([1, None], dtype="Int64"), ndp.Type.FLOAT64).tolist()
353
+ [1.0, nan]
354
+ """
355
+ column_type = find_column_type(column)
356
+ if column_type == key_type:
357
+ return column
358
+
359
+ if key_type == Type.FLOAT64:
360
+ numbers = column.to_numpy(dtype=FLOAT_DTYPE, na_value=numpy.nan)
361
+ number_column = pandas.Series(numbers, name=column.name)
362
+ return number_column
363
+
364
+ key_dtype = to_pandas_dtype(key_type)
365
+ converted_column = column.astype(key_dtype)
366
+
367
+ return converted_column
@@ -0,0 +1,93 @@
1
+ """
2
+ Which rows a join of two Tables keeps.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from enum import Enum, auto
8
+
9
+
10
+ class JoinMode(Enum):
11
+ """
12
+ Which rows a join keeps, used by ``Join``: the rows of both Tables whose keys match, and the rows left alone.
13
+
14
+ A row whose keys match several rows of the other Table appears once per match. A missing key never matches.
15
+
16
+ .. versionadded:: 0.1.0
17
+
18
+ Examples
19
+ --------
20
+ >>> import numdaplot as ndp
21
+ >>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
22
+ >>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
23
+ >>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.OUTER))
24
+ id dep age
25
+ INT64 TEXT INT64
26
+ 0 1 75 34
27
+ 1 2 69 <NA>
28
+ 2 3 <NA> 51
29
+ """
30
+
31
+ INNER = auto()
32
+ """
33
+ Only the rows whose keys match a row of the other Table. Default value.
34
+
35
+ Examples
36
+ --------
37
+ >>> import numdaplot as ndp
38
+ >>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
39
+ >>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
40
+ >>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.INNER))
41
+ id dep age
42
+ INT64 TEXT INT64
43
+ 0 1 75 34
44
+ """
45
+
46
+ LEFT = auto()
47
+ """
48
+ Every row of the joined Table, with missing values where the other Table has no match.
49
+
50
+ Examples
51
+ --------
52
+ >>> import numdaplot as ndp
53
+ >>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
54
+ >>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
55
+ >>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.LEFT))
56
+ id dep age
57
+ INT64 TEXT INT64
58
+ 0 1 75 34
59
+ 1 2 69 <NA>
60
+ """
61
+
62
+ RIGHT = auto()
63
+ """
64
+ Every row of the other Table, with missing values where the joined Table has no match.
65
+
66
+ Examples
67
+ --------
68
+ >>> import numdaplot as ndp
69
+ >>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
70
+ >>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
71
+ >>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.RIGHT))
72
+ id dep age
73
+ INT64 TEXT INT64
74
+ 0 1 75 34
75
+ 1 3 <NA> 51
76
+ """
77
+
78
+ OUTER = auto()
79
+ """
80
+ Every row of both Tables, with missing values where one has no match.
81
+
82
+ Examples
83
+ --------
84
+ >>> import numdaplot as ndp
85
+ >>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
86
+ >>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
87
+ >>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.OUTER))
88
+ id dep age
89
+ INT64 TEXT INT64
90
+ 0 1 75 34
91
+ 1 2 69 <NA>
92
+ 2 3 <NA> 51
93
+ """
@@ -0,0 +1,149 @@
1
+ """
2
+ Check of the number of times each key appears in the Tables of a join.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ import pandas
10
+
11
+ from numdaplot.arrays.conversion.python_values import to_python_list
12
+ from numdaplot.errors.join_relation_error import JoinRelationError
13
+ from numdaplot.errors.repeated_key import RepeatedKey
14
+ from numdaplot.tables.frames.column_values import convert_column_values
15
+ from numdaplot.tables.joining.relation import Relation
16
+
17
+ UNIQUE_LEFT_RELATIONS = frozenset({Relation.ONE_TO_ONE, Relation.ONE_TO_MANY})
18
+ UNIQUE_RIGHT_RELATIONS = frozenset({Relation.ONE_TO_ONE, Relation.MANY_TO_ONE})
19
+ LEFT_TABLE_NAME = "the left Table"
20
+ RIGHT_TABLE_NAME = "the right Table"
21
+ RELATION_NAME = "Relation.{member_name}"
22
+ ROWS_AXIS = 1
23
+ EVERY_REPEAT = False
24
+ FIRST_ROW_COUNT = 1
25
+
26
+
27
+ def require_relation(key_frame: pandas.DataFrame, other_key_frame: pandas.DataFrame, relation: Relation) -> None:
28
+ """
29
+ Check that each key appears at most once in the Tables where the relation of a join expects it once.
30
+
31
+ The left Table is checked first, then the right Table.
32
+
33
+ .. versionadded:: 0.1.0
34
+
35
+ Parameters
36
+ ----------
37
+ key_frame
38
+ The key columns of the left Table, the one joined.
39
+ other_key_frame
40
+ The key columns of the right Table, the other one.
41
+ relation
42
+ How many times each key may appear on each side.
43
+
44
+ Raises
45
+ ------
46
+ JoinRelationError
47
+ At the first key repeated in a Table where the relation expects it once.
48
+
49
+ Examples
50
+ --------
51
+ >>> import pandas
52
+ >>> import numdaplot as ndp
53
+ >>> from numdaplot.tables.joining.join_relation import require_relation
54
+ >>> key_frame = pandas.DataFrame({"id": pandas.Series([1], dtype="Int64")})
55
+ >>> other_key_frame = pandas.DataFrame({"id": pandas.Series([1, 1], dtype="Int64")})
56
+ >>> try:
57
+ ... require_relation(key_frame, other_key_frame, ndp.Relation.ONE_TO_ONE)
58
+ ... except ndp.JoinRelationError as error:
59
+ ... print(error)
60
+ Expected each key of the right Table to appear once for Relation.ONE_TO_ONE, but 'id' 1 appears 2 times.
61
+ """
62
+ if relation in UNIQUE_LEFT_RELATIONS:
63
+ require_unique_keys(key_frame, relation, LEFT_TABLE_NAME)
64
+
65
+ if relation in UNIQUE_RIGHT_RELATIONS:
66
+ require_unique_keys(other_key_frame, relation, RIGHT_TABLE_NAME)
67
+
68
+
69
+ def require_unique_keys(key_frame: pandas.DataFrame, relation: Relation, table_name: str) -> None:
70
+ """
71
+ Check that each key, or combination of keys, appears at most once in a Table, missing keys aside.
72
+
73
+ .. versionadded:: 0.1.0
74
+
75
+ Parameters
76
+ ----------
77
+ key_frame
78
+ The key columns of a Table.
79
+ relation
80
+ The relation checked, named in the error message.
81
+ table_name
82
+ The Table checked, named in the error message.
83
+
84
+ Raises
85
+ ------
86
+ JoinRelationError
87
+ At the first repeated key, in the order of the rows, with its number of rows.
88
+
89
+ Examples
90
+ --------
91
+ >>> import pandas
92
+ >>> import numdaplot as ndp
93
+ >>> from numdaplot.tables.joining.join_relation import require_unique_keys
94
+ >>> key_frame = pandas.DataFrame({"id": pandas.Series([1, None, None], dtype="Int64")})
95
+ >>> require_unique_keys(key_frame, ndp.Relation.ONE_TO_ONE, "the left Table")
96
+ """
97
+ missing_keys = key_frame.isna()
98
+ has_missing_key = missing_keys.any(axis=ROWS_AXIS)
99
+ present_frame = key_frame[~has_missing_key]
100
+ repeated_rows = present_frame.duplicated(keep=EVERY_REPEAT)
101
+ has_repeat = bool(repeated_rows.any())
102
+ if not has_repeat:
103
+ return
104
+
105
+ repeated_frame = present_frame[repeated_rows]
106
+ first_repeat_frame = repeated_frame.iloc[:FIRST_ROW_COUNT]
107
+ first_repeat = first_repeat_frame.iloc[0]
108
+ matching_cells = present_frame == first_repeat
109
+ matching_rows = matching_cells.all(axis=ROWS_AXIS)
110
+ repeat_count = int(matching_rows.sum())
111
+ key_names = key_frame.columns.tolist()
112
+ key_values = read_key_values(first_repeat_frame)
113
+ repeated_key = RepeatedKey(key_names, key_values, repeat_count)
114
+ relation_name = RELATION_NAME.format(member_name=relation.name)
115
+ raise JoinRelationError(relation_name, table_name, repeated_key)
116
+
117
+
118
+ def read_key_values(key_row_frame: pandas.DataFrame) -> list[Any]:
119
+ """
120
+ Return the values of the single row of key columns as Python values.
121
+
122
+ .. versionadded:: 0.1.0
123
+
124
+ Parameters
125
+ ----------
126
+ key_row_frame
127
+ One row of the key columns of a Table.
128
+
129
+ Returns
130
+ -------
131
+ list[Any]
132
+ The value of each key column, such as ``202500000001`` or ``datetime.date(2026, 1, 1)``.
133
+
134
+ Examples
135
+ --------
136
+ >>> import pandas
137
+ >>> from numdaplot.tables.joining.join_relation import read_key_values
138
+ >>> seat = pandas.Series(["A"], dtype="string")
139
+ >>> read_key_values(pandas.DataFrame({"id": pandas.Series([7], dtype="Int64"), "seat": seat}))
140
+ [7, 'A']
141
+ """
142
+ key_values = list[Any]()
143
+
144
+ for _, column in key_row_frame.items():
145
+ column_values = convert_column_values(column)
146
+ python_values = to_python_list(column_values)
147
+ key_values.append(python_values[0])
148
+
149
+ return key_values
@@ -0,0 +1,71 @@
1
+ """
2
+ Suffixes telling apart the columns that two joined Tables both have.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+
9
+ from numdaplot.errors.invalid_suffixes_error import InvalidSuffixesError
10
+ from numdaplot.settings.field_types import require_field_types
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class JoinSuffixes:
15
+ """
16
+ Suffixes added to the names of the columns both Tables of a join have, besides the keys, used by ``Join``.
17
+
18
+ Only those columns get a suffix, as in pandas. A suffixed name that another column already has raises
19
+ ``DuplicateColumnError`` at the join.
20
+
21
+ .. versionadded:: 0.1.0
22
+
23
+ Parameters
24
+ ----------
25
+ left
26
+ The suffix of the columns of the joined Table, such as ``"_2024"``.
27
+ right
28
+ The suffix of the columns of the other Table, such as ``"_2025"``.
29
+
30
+ Raises
31
+ ------
32
+ InvalidTypeError
33
+ When a setting is not of the type its annotation names.
34
+ InvalidSuffixesError
35
+ When a suffix is empty, or both suffixes are the same.
36
+
37
+ Examples
38
+ --------
39
+ >>> import numdaplot as ndp
40
+ >>> before = ndp.Table.from_arrays({"dep": ndp.Array.from_list(["75"]), "deaths": ndp.Array.from_list([40])})
41
+ >>> after = ndp.Table.from_arrays({"dep": ndp.Array.from_list(["75"]), "deaths": ndp.Array.from_list([35])})
42
+ >>> years = ndp.JoinSuffixes(left="_2024", right="_2025")
43
+ >>> before.join(ndp.Join(other=after, keys=["dep"], suffixes=years))
44
+ dep deaths_2024 deaths_2025
45
+ TEXT INT64 INT64
46
+ 0 75 40 35
47
+ """
48
+
49
+ left: str
50
+ right: str
51
+
52
+ def __post_init__(self) -> None:
53
+ """
54
+ Check that the suffixes are not empty and differ.
55
+
56
+ .. versionadded:: 0.1.0
57
+
58
+ Raises
59
+ ------
60
+ InvalidTypeError
61
+ When a setting is not of the type its annotation names.
62
+ InvalidSuffixesError
63
+ When a suffix is empty, or both suffixes are the same.
64
+ """
65
+ require_field_types(self)
66
+
67
+ has_empty_suffix = self.left == "" or self.right == ""
68
+ are_same = self.left == self.right
69
+ is_invalid = has_empty_suffix or are_same
70
+ if is_invalid:
71
+ raise InvalidSuffixesError(self.left, self.right)