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,286 @@
1
+ """
2
+ Refusal of dates, datetimes and durations that a count of nanoseconds cannot hold.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from datetime import date, datetime, time, timedelta
8
+ from typing import Any
9
+
10
+ import numpy
11
+ from numpy.typing import NDArray
12
+
13
+ from numdaplot.arrays.operations.integer_bounds import find_value_bounds
14
+ from numdaplot.arrays.operations.operand import Operand
15
+ from numdaplot.data_types.type import Type
16
+ from numdaplot.errors.time_overflow_error import TimeOverflowError
17
+
18
+ NANOSECOND_TYPES = frozenset({Type.DATETIME, Type.DURATION})
19
+ TIME_KINDS = frozenset({"M", "m"})
20
+ NANOSECOND_DTYPES = frozenset({numpy.dtype("datetime64[ns]"), numpy.dtype("timedelta64[ns]")})
21
+ SECOND_DTYPE_FORMAT = "{kind}8[s]"
22
+ COUNT_DTYPE = numpy.dtype(numpy.int64)
23
+ COUNT_LIMITS = numpy.iinfo(COUNT_DTYPE)
24
+ # numpy keeps the lowest count for NaT, so the range is the same on both sides of zero.
25
+ HIGHEST_NANOSECONDS = int(COUNT_LIMITS.max)
26
+ LOWEST_NANOSECONDS = -HIGHEST_NANOSECONDS
27
+ FIRST_COUNT_TOO_LARGE = 2.0**63
28
+ NANOSECONDS_PER_SECOND = 10**9
29
+ HIGHEST_SECONDS = HIGHEST_NANOSECONDS // NANOSECONDS_PER_SECOND
30
+ LOWEST_SECONDS = -HIGHEST_SECONDS
31
+ LOWEST_DATETIME = datetime(1677, 9, 21, 0, 12, 43, 145225)
32
+ HIGHEST_DATETIME = datetime(2262, 4, 11, 23, 47, 16, 854775)
33
+ LONGEST_DURATION = timedelta(days=106751, seconds=85636, microseconds=854775)
34
+
35
+
36
+ def is_python_time_in_range(value: object) -> bool:
37
+ """
38
+ Return whether a Python value is not a date, a datetime or a duration beyond a count of nanoseconds.
39
+
40
+ .. versionadded:: 0.1.0
41
+
42
+ Parameters
43
+ ----------
44
+ value
45
+ A single Python value.
46
+
47
+ Returns
48
+ -------
49
+ bool
50
+ False for a date, a datetime or a duration out of range, True for any other value.
51
+
52
+ Examples
53
+ --------
54
+ >>> from datetime import datetime
55
+ >>> from numdaplot.arrays.operations.time_bounds import is_python_time_in_range
56
+ >>> is_python_time_in_range(datetime(2026, 1, 31))
57
+ True
58
+ >>> is_python_time_in_range(datetime(3000, 1, 31))
59
+ False
60
+ """
61
+ if isinstance(value, timedelta):
62
+ duration_in_range = -LONGEST_DURATION <= value <= LONGEST_DURATION
63
+ return duration_in_range
64
+
65
+ if isinstance(value, datetime):
66
+ clock_time = value.replace(tzinfo=None)
67
+ datetime_in_range = LOWEST_DATETIME <= clock_time <= HIGHEST_DATETIME
68
+ return datetime_in_range
69
+
70
+ if isinstance(value, date):
71
+ midnight = datetime.combine(value, time.min)
72
+ date_in_range = LOWEST_DATETIME <= midnight <= HIGHEST_DATETIME
73
+ return date_in_range
74
+
75
+ return True
76
+
77
+
78
+ def require_stored_times_fit(single_values: list[object], stored_type: Type, operation_name: str) -> None:
79
+ """
80
+ Check that Python values stored as datetimes or durations fit a count of nanoseconds.
81
+
82
+ .. versionadded:: 0.1.0
83
+
84
+ Parameters
85
+ ----------
86
+ single_values
87
+ Single Python values.
88
+ stored_type
89
+ The type the values are stored as. Other types than ``DATETIME`` and ``DURATION`` are not checked.
90
+ operation_name
91
+ The operation shown in the error message.
92
+
93
+ Raises
94
+ ------
95
+ TimeOverflowError
96
+ When a value is out of range.
97
+
98
+ Examples
99
+ --------
100
+ >>> from datetime import datetime
101
+ >>> import numdaplot as ndp
102
+ >>> from numdaplot.arrays.operations.time_bounds import require_stored_times_fit
103
+ >>> try:
104
+ ... require_stored_times_fit([datetime(3000, 1, 31)], ndp.Type.DATETIME, "from_list")
105
+ ... except ndp.TimeOverflowError as error:
106
+ ... print(error)
107
+ The operation from_list gives values outside the range of DATETIME, from 1677 to 2262.
108
+ """
109
+ if stored_type not in NANOSECOND_TYPES:
110
+ return
111
+
112
+ for value in single_values:
113
+ value_in_range = is_python_time_in_range(value)
114
+ if not value_in_range:
115
+ raise TimeOverflowError(operation_name, stored_type.name)
116
+
117
+
118
+ def require_nanoseconds_fit(operand: Operand, data_type: Type, operation_name: str) -> None:
119
+ """
120
+ Check that the dates, datetimes or durations of an operand can be counted in nanoseconds.
121
+
122
+ .. versionadded:: 0.1.0
123
+
124
+ Parameters
125
+ ----------
126
+ operand
127
+ The values of an Array, or a single value. Other values than times are not checked.
128
+ data_type
129
+ The type named by the error message.
130
+ operation_name
131
+ The operation shown in the error message.
132
+
133
+ Raises
134
+ ------
135
+ TimeOverflowError
136
+ When a value is out of range. An Array in a coarser unit is compared to the second.
137
+
138
+ Examples
139
+ --------
140
+ >>> import numpy
141
+ >>> import numdaplot as ndp
142
+ >>> from numdaplot.arrays.operations.time_bounds import require_nanoseconds_fit
143
+ >>> try:
144
+ ... require_nanoseconds_fit(numpy.array(["3000-01-31"], dtype="datetime64[D]"), ndp.Type.DATE, "+")
145
+ ... except ndp.TimeOverflowError as error:
146
+ ... print(error)
147
+ The operation + gives values outside the range of DATE, from 1677 to 2262 in a calculation.
148
+ """
149
+ if not isinstance(operand, numpy.ndarray):
150
+ operand_in_range = is_python_time_in_range(operand)
151
+ if not operand_in_range:
152
+ raise TimeOverflowError(operation_name, data_type.name)
153
+
154
+ return
155
+
156
+ if operand.dtype.kind not in TIME_KINDS or operand.dtype in NANOSECOND_DTYPES:
157
+ return
158
+
159
+ count_bounds = find_present_bounds(operand)
160
+ if count_bounds is None:
161
+ return
162
+
163
+ second_dtype = SECOND_DTYPE_FORMAT.format(kind=operand.dtype.kind)
164
+ bound_counts = numpy.array(count_bounds, dtype=COUNT_DTYPE)
165
+ bound_times = bound_counts.astype(operand.dtype)
166
+ bound_seconds = bound_times.astype(second_dtype)
167
+ second_counts = bound_seconds.astype(COUNT_DTYPE)
168
+ low_seconds, high_seconds = find_value_bounds(second_counts)
169
+ if low_seconds < LOWEST_SECONDS or high_seconds > HIGHEST_SECONDS:
170
+ raise TimeOverflowError(operation_name, data_type.name)
171
+
172
+
173
+ def find_present_bounds(values: Any) -> tuple[int, int] | None:
174
+ """
175
+ Return the lowest and the highest values of a calculation, times being counted in their unit.
176
+
177
+ .. versionadded:: 0.1.0
178
+
179
+ Parameters
180
+ ----------
181
+ values
182
+ Times or integers, an array or a single value.
183
+
184
+ Returns
185
+ -------
186
+ tuple[int, int] or None
187
+ The bounds of the present values, or ``None`` when no value is present.
188
+
189
+ Examples
190
+ --------
191
+ >>> import numpy
192
+ >>> from numdaplot.arrays.operations.time_bounds import find_present_bounds
193
+ >>> find_present_bounds(numpy.array([5, "NaT", 2], dtype="timedelta64[ns]"))
194
+ (2, 5)
195
+ >>> find_present_bounds(3)
196
+ (3, 3)
197
+ """
198
+ array = numpy.asarray(values)
199
+ if array.size == 0:
200
+ return None
201
+
202
+ if array.dtype.kind not in TIME_KINDS:
203
+ number_bounds = find_value_bounds(array)
204
+ return number_bounds
205
+
206
+ counts = array.view(COUNT_DTYPE)
207
+ low_count, high_count = find_value_bounds(counts)
208
+ if low_count != COUNT_LIMITS.min:
209
+ return low_count, high_count
210
+
211
+ is_present = counts != COUNT_LIMITS.min
212
+ present_counts = counts[is_present]
213
+ if present_counts.size == 0:
214
+ return None
215
+
216
+ present_bounds = find_value_bounds(present_counts)
217
+
218
+ return present_bounds
219
+
220
+
221
+ def require_whole_durations_fit(values: NDArray[Any], nanoseconds_per_unit: int, function_name: str) -> None:
222
+ """
223
+ Check that integers read as durations in a unit fit a count of nanoseconds.
224
+
225
+ .. versionadded:: 0.1.0
226
+
227
+ Parameters
228
+ ----------
229
+ values
230
+ Integers.
231
+ nanoseconds_per_unit
232
+ The number of nanoseconds in the unit of the integers.
233
+ function_name
234
+ The function shown in the error message.
235
+
236
+ Raises
237
+ ------
238
+ TimeOverflowError
239
+ When a duration is out of range.
240
+
241
+ Examples
242
+ --------
243
+ >>> import numpy
244
+ >>> from numdaplot.arrays.operations.time_bounds import require_whole_durations_fit
245
+ >>> require_whole_durations_fit(numpy.array([1, 2]), 1000, "ToDuration")
246
+ """
247
+ if values.size == 0:
248
+ return
249
+
250
+ low_value, high_value = find_value_bounds(values)
251
+ low_count = low_value * nanoseconds_per_unit
252
+ high_count = high_value * nanoseconds_per_unit
253
+ if low_count < LOWEST_NANOSECONDS or high_count > HIGHEST_NANOSECONDS:
254
+ raise TimeOverflowError(function_name, Type.DURATION.name)
255
+
256
+
257
+ def require_decimal_durations_fit(nanoseconds: NDArray[Any], function_name: str) -> None:
258
+ """
259
+ Check that decimal numbers of nanoseconds fit a count of nanoseconds, an infinite number being out of range.
260
+
261
+ .. versionadded:: 0.1.0
262
+
263
+ Parameters
264
+ ----------
265
+ nanoseconds
266
+ Decimal numbers of nanoseconds, NaN for a missing value.
267
+ function_name
268
+ The function shown in the error message.
269
+
270
+ Raises
271
+ ------
272
+ TimeOverflowError
273
+ When a duration is out of range.
274
+
275
+ Examples
276
+ --------
277
+ >>> import numpy
278
+ >>> from numdaplot.arrays.operations.time_bounds import require_decimal_durations_fit
279
+ >>> require_decimal_durations_fit(numpy.array([1.5, numpy.nan]), "ToDuration")
280
+ """
281
+ magnitudes = numpy.abs(nanoseconds)
282
+ # A comparison with NaN is False, so a missing value is never out of range.
283
+ is_too_large = magnitudes >= FIRST_COUNT_TOO_LARGE
284
+ has_too_large = bool(numpy.any(is_too_large))
285
+ if has_too_large:
286
+ raise TimeOverflowError(function_name, Type.DURATION.name)
@@ -0,0 +1,397 @@
1
+ """
2
+ Refusal of the results of calculations on times that a count of nanoseconds cannot hold.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from typing import Any, cast
8
+
9
+ import numpy
10
+ from numpy.typing import NDArray
11
+
12
+ from numdaplot.arrays.operations.integer_bounds import find_result_bounds, find_value_bounds
13
+ from numdaplot.arrays.operations.integer_rules import require_combination_fits
14
+ from numdaplot.arrays.operations.operand import Operand
15
+ from numdaplot.arrays.operations.time_bounds import (
16
+ COUNT_DTYPE,
17
+ COUNT_LIMITS,
18
+ FIRST_COUNT_TOO_LARGE,
19
+ HIGHEST_NANOSECONDS,
20
+ LOWEST_NANOSECONDS,
21
+ TIME_KINDS,
22
+ find_present_bounds,
23
+ )
24
+ from numdaplot.data_types.type import Type
25
+ from numdaplot.errors.integer_overflow_error import IntegerOverflowError
26
+ from numdaplot.errors.time_overflow_error import TimeOverflowError
27
+
28
+ DECIMAL_KIND = "f"
29
+ UNSIGNED_KIND = "u"
30
+ IGNORE_MODE = "ignore"
31
+
32
+
33
+ def widen_large_integers(values: Any) -> Any:
34
+ """
35
+ Return numbers beside a duration as decimals when they do not fit a signed count of nanoseconds.
36
+
37
+ .. versionadded:: 0.1.0
38
+
39
+ Parameters
40
+ ----------
41
+ values
42
+ Times in nanoseconds or numbers, an array or a single value.
43
+
44
+ Returns
45
+ -------
46
+ Any
47
+ Decimals for integers too large, signed integers for ``UINT64`` that fit, the values themselves otherwise.
48
+
49
+ Raises
50
+ ------
51
+ OverflowError
52
+ When a Python integer is too large for a decimal.
53
+
54
+ Examples
55
+ --------
56
+ >>> import numpy
57
+ >>> from numdaplot.arrays.operations.time_result_bounds import widen_large_integers
58
+ >>> widen_large_integers(2**70)
59
+ 1.1805916207174113e+21
60
+ >>> widen_large_integers(numpy.array([2], dtype="uint64"))
61
+ array([2])
62
+ """
63
+ if isinstance(values, int):
64
+ if LOWEST_NANOSECONDS <= values <= HIGHEST_NANOSECONDS:
65
+ return values
66
+
67
+ return float(values)
68
+
69
+ if not isinstance(values, numpy.ndarray):
70
+ return values
71
+
72
+ # isinstance leaves the array type unknown, because the values are typed Any.
73
+ array = cast(NDArray[Any], values)
74
+ if array.dtype.kind != UNSIGNED_KIND or array.size == 0:
75
+ return array
76
+
77
+ _, highest_value = find_value_bounds(array)
78
+ if highest_value > HIGHEST_NANOSECONDS:
79
+ large_decimals = array.astype(numpy.float64)
80
+ return large_decimals
81
+
82
+ signed_values = array.astype(COUNT_DTYPE)
83
+
84
+ return signed_values
85
+
86
+
87
+ def can_integers_overflow(operands: list[Any], function: numpy.ufunc) -> bool:
88
+ """
89
+ Return whether the bounds of a calculation on times and integers leave the range of nanoseconds.
90
+
91
+ .. versionadded:: 0.1.0
92
+
93
+ Parameters
94
+ ----------
95
+ operands
96
+ The left and the right operands, with their times in nanoseconds.
97
+ function
98
+ ``numpy.add``, ``numpy.subtract`` or ``numpy.multiply``.
99
+
100
+ Returns
101
+ -------
102
+ bool
103
+ False when every result is in range, True when each result must be looked at.
104
+
105
+ Examples
106
+ --------
107
+ >>> import numpy
108
+ >>> from numdaplot.arrays.operations.time_result_bounds import can_integers_overflow
109
+ >>> durations = numpy.array([1000], dtype="timedelta64[ns]")
110
+ >>> can_integers_overflow([durations, 2], numpy.multiply)
111
+ False
112
+ >>> can_integers_overflow([durations, 2**62], numpy.multiply)
113
+ True
114
+ """
115
+ left_operand, right_operand = operands
116
+ left_bounds = find_present_bounds(left_operand)
117
+ right_bounds = find_present_bounds(right_operand)
118
+ if left_bounds is None or right_bounds is None:
119
+ return False
120
+
121
+ low_result, high_result = find_result_bounds(left_bounds, right_bounds, function)
122
+ bounds_fit = LOWEST_NANOSECONDS <= low_result and high_result <= HIGHEST_NANOSECONDS
123
+
124
+ return not bounds_fit
125
+
126
+
127
+ def find_strongest_factor(factors: NDArray[Any], function: numpy.ufunc) -> float | None:
128
+ """
129
+ Return what most moves a duration away from zero among decimal factors or divisors.
130
+
131
+ A factor that is NaN or infinite and a divisor of 0 have no result to refuse, so they are not counted.
132
+
133
+ .. versionadded:: 0.1.0
134
+
135
+ Parameters
136
+ ----------
137
+ factors
138
+ The decimals.
139
+ function
140
+ ``numpy.multiply`` or ``numpy.true_divide``.
141
+
142
+ Returns
143
+ -------
144
+ float or None
145
+ The number a duration is multiplied by at most, or ``None`` when no decimal gives a result.
146
+
147
+ Examples
148
+ --------
149
+ >>> import numpy
150
+ >>> from numdaplot.arrays.operations.time_result_bounds import find_strongest_factor
151
+ >>> find_strongest_factor(numpy.array([2.0, -4.0, numpy.nan]), numpy.multiply)
152
+ 4.0
153
+ >>> find_strongest_factor(numpy.array([2.0, 0.5, 0.0]), numpy.true_divide)
154
+ 2.0
155
+ """
156
+ decimals = factors.astype(numpy.float64)
157
+ magnitudes = numpy.abs(decimals)
158
+ if magnitudes.size == 0:
159
+ return None
160
+
161
+ multiplies = function == numpy.multiply
162
+ if multiplies:
163
+ largest_magnitude = float(magnitudes.max())
164
+ is_finite = bool(numpy.isfinite(largest_magnitude))
165
+ if is_finite:
166
+ return largest_magnitude
167
+
168
+ is_usable = numpy.isfinite(magnitudes) & (magnitudes != 0)
169
+ usable_magnitudes = magnitudes[is_usable]
170
+ if usable_magnitudes.size == 0:
171
+ return None
172
+
173
+ if multiplies:
174
+ largest_usable = float(usable_magnitudes.max())
175
+ return largest_usable
176
+
177
+ smallest_divisor = float(usable_magnitudes.min())
178
+ with numpy.errstate(all=IGNORE_MODE):
179
+ strongest_factor = 1 / numpy.float64(smallest_divisor)
180
+
181
+ return float(strongest_factor)
182
+
183
+
184
+ def can_decimal_factor_overflow(left_counts: Any, right_counts: Any, function: numpy.ufunc) -> bool:
185
+ """
186
+ Return whether the largest duration and the strongest decimal factor leave the range of nanoseconds.
187
+
188
+ .. versionadded:: 0.1.0
189
+
190
+ Parameters
191
+ ----------
192
+ left_counts
193
+ The left operand: durations in nanoseconds, or decimals.
194
+ right_counts
195
+ The right operand: durations in nanoseconds, or decimals.
196
+ function
197
+ ``numpy.multiply`` or ``numpy.true_divide``.
198
+
199
+ Returns
200
+ -------
201
+ bool
202
+ False when every result is in range, True when each result must be looked at.
203
+
204
+ Examples
205
+ --------
206
+ >>> import numpy
207
+ >>> from numdaplot.arrays.operations.time_result_bounds import can_decimal_factor_overflow
208
+ >>> durations = numpy.array([1000], dtype="timedelta64[ns]")
209
+ >>> can_decimal_factor_overflow(durations, 2.5, numpy.multiply)
210
+ False
211
+ >>> can_decimal_factor_overflow(durations, 1e-300, numpy.true_divide)
212
+ True
213
+ """
214
+ left_array = numpy.asarray(left_counts)
215
+ right_array = numpy.asarray(right_counts)
216
+ durations, factors = left_array, right_array
217
+ if left_array.dtype.kind == DECIMAL_KIND:
218
+ durations, factors = right_array, left_array
219
+
220
+ duration_bounds = find_present_bounds(durations)
221
+ if duration_bounds is None:
222
+ return False
223
+
224
+ strongest_factor = find_strongest_factor(factors, function)
225
+ if strongest_factor is None:
226
+ return False
227
+
228
+ low_duration, high_duration = duration_bounds
229
+ low_magnitude = abs(low_duration)
230
+ high_magnitude = abs(high_duration)
231
+ longest_count = max(low_magnitude, high_magnitude)
232
+ longest_duration = float(longest_count)
233
+ with numpy.errstate(all=IGNORE_MODE):
234
+ largest_estimate = longest_duration * strongest_factor
235
+
236
+ return bool(largest_estimate >= FIRST_COUNT_TOO_LARGE)
237
+
238
+
239
+ def to_counts(values: Any) -> NDArray[Any]:
240
+ """
241
+ Return values of a calculation with their times as integers, a missing time counting as 0.
242
+
243
+ .. versionadded:: 0.1.0
244
+
245
+ Parameters
246
+ ----------
247
+ values
248
+ Times in nanoseconds or numbers, an array or a single value.
249
+
250
+ Returns
251
+ -------
252
+ NDArray
253
+ The counts of nanoseconds, or the numbers.
254
+
255
+ Examples
256
+ --------
257
+ >>> import numpy
258
+ >>> from numdaplot.arrays.operations.time_result_bounds import to_counts
259
+ >>> to_counts(numpy.array([5, "NaT"], dtype="timedelta64[ns]"))
260
+ array([5, 0])
261
+ """
262
+ array = numpy.asarray(values)
263
+ if array.dtype.kind not in TIME_KINDS:
264
+ return array
265
+
266
+ counts = array.astype(COUNT_DTYPE)
267
+ missing = numpy.isnat(array)
268
+ present_counts = numpy.where(missing, 0, counts)
269
+
270
+ return present_counts
271
+
272
+
273
+ def require_decimal_factor_fits(operands: list[Any], function: numpy.ufunc, result_type: Type, symbol: str) -> None:
274
+ """
275
+ Check that a duration multiplied or divided by decimals fits a count of nanoseconds.
276
+
277
+ A factor that is NaN or infinite and a divisor of 0 have no result to refuse: they give missing values.
278
+
279
+ .. versionadded:: 0.1.0
280
+
281
+ Parameters
282
+ ----------
283
+ operands
284
+ The counts of the left and the right operands, one of them holding the decimals.
285
+ function
286
+ ``numpy.multiply`` or ``numpy.true_divide``.
287
+ result_type
288
+ The type named by the error message.
289
+ symbol
290
+ The operator shown in the error message.
291
+
292
+ Raises
293
+ ------
294
+ TimeOverflowError
295
+ When a result is out of range.
296
+
297
+ Examples
298
+ --------
299
+ >>> import numpy
300
+ >>> import numdaplot as ndp
301
+ >>> from numdaplot.arrays.operations.time_result_bounds import require_decimal_factor_fits
302
+ >>> operands = [numpy.array([2**62]), numpy.array([4.0])]
303
+ >>> try:
304
+ ... require_decimal_factor_fits(operands, numpy.multiply, ndp.Type.DURATION, "*")
305
+ ... except ndp.TimeOverflowError as error:
306
+ ... print(error)
307
+ The operation * gives values outside the range of DURATION, about 292 years before or after zero.
308
+ """
309
+ left_counts, right_counts = operands
310
+ factors = right_counts
311
+ if left_counts.dtype.kind == DECIMAL_KIND:
312
+ factors = left_counts
313
+
314
+ left_decimals = left_counts.astype(numpy.float64)
315
+ right_decimals = right_counts.astype(numpy.float64)
316
+ with numpy.errstate(all=IGNORE_MODE):
317
+ estimates = function(left_decimals, right_decimals)
318
+
319
+ has_result = numpy.isfinite(factors)
320
+ if function == numpy.true_divide:
321
+ has_result = has_result & (factors != 0)
322
+
323
+ magnitudes = numpy.abs(estimates)
324
+ is_too_large = (magnitudes >= FIRST_COUNT_TOO_LARGE) & has_result
325
+ has_too_large = bool(numpy.any(is_too_large))
326
+ if has_too_large:
327
+ raise TimeOverflowError(symbol, result_type.name)
328
+
329
+
330
+ def require_time_result_fits(operands: list[Any], function: numpy.ufunc, result_type: Type, symbol: str) -> None:
331
+ """
332
+ Check that the results of a calculation on times fit a count of nanoseconds, before computing them.
333
+
334
+ .. versionadded:: 0.1.0
335
+
336
+ Parameters
337
+ ----------
338
+ operands
339
+ The left and the right operands, with their times in nanoseconds.
340
+ function
341
+ The numpy function about to be applied.
342
+ result_type
343
+ The type named by the error message.
344
+ symbol
345
+ The operator shown in the error message.
346
+
347
+ Raises
348
+ ------
349
+ TimeOverflowError
350
+ When a result is out of range.
351
+
352
+ Examples
353
+ --------
354
+ >>> import numpy
355
+ >>> import numdaplot as ndp
356
+ >>> from numdaplot.arrays.operations.time_result_bounds import require_time_result_fits
357
+ >>> durations = numpy.array([1], dtype="timedelta64[D]").astype("timedelta64[ns]")
358
+ >>> try:
359
+ ... require_time_result_fits([durations, 200000], numpy.multiply, ndp.Type.DURATION, "*")
360
+ ... except ndp.TimeOverflowError as error:
361
+ ... print(error)
362
+ The operation * gives values outside the range of DURATION, about 292 years before or after zero.
363
+ """
364
+ left_operand, right_operand = operands
365
+ left_kind = numpy.asarray(left_operand).dtype.kind
366
+ right_kind = numpy.asarray(right_operand).dtype.kind
367
+ has_decimal = DECIMAL_KIND in (left_kind, right_kind)
368
+ if has_decimal:
369
+ can_overflow = can_decimal_factor_overflow(left_operand, right_operand, function)
370
+ if can_overflow:
371
+ left_counts = to_counts(left_operand)
372
+ right_counts = to_counts(right_operand)
373
+ require_decimal_factor_fits([left_counts, right_counts], function, result_type, symbol)
374
+
375
+ return
376
+
377
+ # Dividing by an integer never moves a count away from zero.
378
+ if function == numpy.true_divide:
379
+ return
380
+
381
+ can_overflow = can_integers_overflow(operands, function)
382
+ if not can_overflow:
383
+ return
384
+
385
+ left_counts = to_counts(left_operand)
386
+ right_counts = to_counts(right_operand)
387
+ count_operands = list[Operand]([left_counts, right_counts])
388
+ wrapped_counts = function(left_counts, right_counts)
389
+ try:
390
+ require_combination_fits(count_operands, function, wrapped_counts, symbol)
391
+ except IntegerOverflowError as error:
392
+ raise TimeOverflowError(symbol, result_type.name) from error
393
+
394
+ reaches_missing_marker = wrapped_counts == COUNT_LIMITS.min
395
+ has_marker = bool(numpy.any(reaches_missing_marker))
396
+ if has_marker:
397
+ raise TimeOverflowError(symbol, result_type.name)