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,479 @@
1
+ """
2
+ Arithmetic between dates, datetimes, durations and numbers.
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.conversion.time_text import format_durations
13
+ from numdaplot.arrays.operations.operand import Operand, convert_time_value, find_operand_type
14
+ from numdaplot.arrays.operations.time_bounds import require_nanoseconds_fit
15
+ from numdaplot.arrays.operations.time_result_bounds import require_time_result_fits, widen_large_integers
16
+ from numdaplot.data_types.numpy_mapping import to_numpy_dtype
17
+ from numdaplot.data_types.type import Type
18
+ from numdaplot.data_types.value_family import ValueFamily, find_family
19
+ from numdaplot.errors.incompatible_types_error import IncompatibleTypesError
20
+ from numdaplot.errors.refused_operation_error import RefusedOperationError
21
+ from numdaplot.errors.time_overflow_error import TimeOverflowError
22
+ from numdaplot.errors.value_conversion_error import ValueConversionError
23
+
24
+ TIME_FAMILIES = frozenset({ValueFamily.MOMENT, ValueFamily.DURATION, ValueFamily.TIME})
25
+ # The family of the result of each accepted operation, by function and families of the left and right operands.
26
+ type TimeOperation = tuple[numpy.ufunc, ValueFamily, ValueFamily]
27
+ TIME_RESULTS = dict[TimeOperation, ValueFamily](
28
+ {
29
+ (numpy.add, ValueFamily.MOMENT, ValueFamily.DURATION): ValueFamily.MOMENT,
30
+ (numpy.add, ValueFamily.DURATION, ValueFamily.MOMENT): ValueFamily.MOMENT,
31
+ (numpy.add, ValueFamily.DURATION, ValueFamily.DURATION): ValueFamily.DURATION,
32
+ (numpy.subtract, ValueFamily.MOMENT, ValueFamily.MOMENT): ValueFamily.DURATION,
33
+ (numpy.subtract, ValueFamily.MOMENT, ValueFamily.DURATION): ValueFamily.MOMENT,
34
+ (numpy.subtract, ValueFamily.DURATION, ValueFamily.DURATION): ValueFamily.DURATION,
35
+ (numpy.multiply, ValueFamily.DURATION, ValueFamily.NUMBER): ValueFamily.DURATION,
36
+ (numpy.multiply, ValueFamily.NUMBER, ValueFamily.DURATION): ValueFamily.DURATION,
37
+ (numpy.true_divide, ValueFamily.DURATION, ValueFamily.NUMBER): ValueFamily.DURATION,
38
+ (numpy.add, ValueFamily.TIME, ValueFamily.DURATION): ValueFamily.TIME,
39
+ (numpy.add, ValueFamily.DURATION, ValueFamily.TIME): ValueFamily.TIME,
40
+ (numpy.subtract, ValueFamily.TIME, ValueFamily.DURATION): ValueFamily.TIME,
41
+ (numpy.subtract, ValueFamily.TIME, ValueFamily.TIME): ValueFamily.DURATION,
42
+ (numpy.add, ValueFamily.MOMENT, ValueFamily.TIME): ValueFamily.MOMENT,
43
+ (numpy.add, ValueFamily.TIME, ValueFamily.MOMENT): ValueFamily.MOMENT,
44
+ }
45
+ )
46
+ DURATION_DIVISION = (numpy.true_divide, ValueFamily.DURATION, ValueFamily.DURATION)
47
+ DURATION_DIVISION_OPERATION = "Dividing a duration by a duration"
48
+ DURATION_DIVISION_ALTERNATIVE = "apply(ndp.DurationIn(unit=...))"
49
+ TIMEDELTA_PRODUCT_OPERATION = "Multiplying numbers by a single duration"
50
+ TIMEDELTA_PRODUCT_ALTERNATIVE = "apply(ndp.ToDuration(unit=...))"
51
+ NANOSECOND_DTYPES = {
52
+ ValueFamily.MOMENT: to_numpy_dtype(Type.DATETIME),
53
+ ValueFamily.DURATION: to_numpy_dtype(Type.DURATION),
54
+ ValueFamily.TIME: to_numpy_dtype(Type.DURATION),
55
+ }
56
+ ONE_DAY = numpy.timedelta64(1, "D")
57
+ NO_DURATION = numpy.timedelta64(0, "ns")
58
+
59
+
60
+ def involves_time(left: Operand, right: Operand) -> bool:
61
+ """
62
+ Return whether one of two operands holds dates, datetimes or durations.
63
+
64
+ .. versionadded:: 0.1.0
65
+
66
+ Parameters
67
+ ----------
68
+ left
69
+ The values of an Array, or a single value.
70
+ right
71
+ The values of an Array, or a single value.
72
+
73
+ Returns
74
+ -------
75
+ bool
76
+ True when at least one side is a date, a datetime or a duration.
77
+
78
+ Examples
79
+ --------
80
+ >>> from datetime import timedelta
81
+ >>> import numpy
82
+ >>> from numdaplot.arrays.operations.time_arithmetic import involves_time
83
+ >>> involves_time(numpy.array([1, 2]), timedelta(days=1))
84
+ True
85
+ """
86
+ left_type = find_operand_type(left)
87
+ right_type = find_operand_type(right)
88
+ left_family = find_family(left_type)
89
+ right_family = find_family(right_type)
90
+ has_time = left_family in TIME_FAMILIES or right_family in TIME_FAMILIES
91
+
92
+ return has_time
93
+
94
+
95
+ def combine_time_values(left: Operand, right: Operand, function: numpy.ufunc, symbol: str) -> NDArray[Any]:
96
+ """
97
+ Return the result of an arithmetic function between dates, datetimes, durations and numbers.
98
+
99
+ Dates and datetimes give durations when subtracted; a duration added to or subtracted from a date gives
100
+ a date, and from a datetime a datetime; durations add, subtract, and multiply or divide by numbers.
101
+ A date counts as midnight next to a datetime. Times of day give durations when subtracted, move by a
102
+ duration within the same day, and give a datetime when added to a date.
103
+
104
+ .. versionadded:: 0.1.0
105
+
106
+ Parameters
107
+ ----------
108
+ left
109
+ The values of an Array, or a single value.
110
+ right
111
+ The values of an Array, or a single value. At least one side holds dates, datetimes or durations.
112
+ function
113
+ The numpy function, such as ``numpy.add``.
114
+ symbol
115
+ The operator shown in error messages, such as ``"+"``.
116
+
117
+ Returns
118
+ -------
119
+ NDArray
120
+ Dates, datetimes in nanoseconds or durations in nanoseconds.
121
+
122
+ Raises
123
+ ------
124
+ RefusedOperationError
125
+ When a duration is divided by a duration, or numbers are multiplied by a single duration.
126
+ ValueConversionError
127
+ When a duration added to or subtracted from dates is not a whole number of days.
128
+ IncompatibleTypesError
129
+ When the operation does not apply to these types, such as a date plus a number, or a datetime plus a time of
130
+ day.
131
+ TimeOverflowError
132
+ When an operand or a result is outside the range of nanoseconds, about 1677 to 2262 for dates and
133
+ datetimes, and about 292 years for durations, or a time of day moves past midnight.
134
+
135
+ Examples
136
+ --------
137
+ >>> from datetime import timedelta
138
+ >>> import numpy
139
+ >>> from numdaplot.arrays.operations.time_arithmetic import combine_time_values
140
+ >>> combine_time_values(numpy.array(["2026-01-31"], dtype="datetime64[D]"), timedelta(days=1), numpy.add, "+")
141
+ array(['2026-02-01'], dtype='datetime64[D]')
142
+ """
143
+ left_type = find_operand_type(left)
144
+ right_type = find_operand_type(right)
145
+ left_family = find_family(left_type)
146
+ right_family = find_family(right_type)
147
+ operation_key = (function, left_family, right_family)
148
+ require_time_operation(left, right, operation_key)
149
+ if operation_key not in TIME_RESULTS:
150
+ raise IncompatibleTypesError(symbol, [left_type.name, right_type.name])
151
+
152
+ require_date_next_to_time(left_type, right_type, symbol)
153
+ result_family = TIME_RESULTS[operation_key]
154
+ shifts_date = Type.DATE in (left_type, right_type) and ValueFamily.DURATION in (left_family, right_family)
155
+ keeps_date = shifts_date and result_family == ValueFamily.MOMENT
156
+ result_type = find_time_result_type(result_family, keeps_date)
157
+ operands = [left, right]
158
+ combined_values = combine_nanoseconds(operands, function, result_type, symbol)
159
+ if result_type == Type.TIME:
160
+ times = store_time_result(combined_values, symbol)
161
+ return times
162
+
163
+ if not keeps_date:
164
+ return combined_values
165
+
166
+ date_shift = to_nanoseconds(right, right_family)
167
+ if left_family == ValueFamily.DURATION:
168
+ date_shift = to_nanoseconds(left, left_family)
169
+
170
+ require_whole_days(date_shift)
171
+ date_dtype = to_numpy_dtype(Type.DATE)
172
+ shifted_dates = combined_values.astype(date_dtype)
173
+
174
+ return shifted_dates
175
+
176
+
177
+ def combine_nanoseconds(operands: list[Operand], function: numpy.ufunc, result_type: Type, symbol: str) -> NDArray[Any]:
178
+ """
179
+ Return an arithmetic function applied to operands counted in nanoseconds, refusing results that do not fit.
180
+
181
+ .. versionadded:: 0.1.0
182
+
183
+ Parameters
184
+ ----------
185
+ operands
186
+ The left and the right operand, values of Arrays or single values.
187
+ function
188
+ The numpy function, such as ``numpy.add``.
189
+ result_type
190
+ The type of the result, named by the errors.
191
+ symbol
192
+ The operator shown in error messages, such as ``"+"``.
193
+
194
+ Returns
195
+ -------
196
+ NDArray
197
+ The result, dates and datetimes in ``datetime64[ns]`` and durations in ``timedelta64[ns]``.
198
+
199
+ Raises
200
+ ------
201
+ TimeOverflowError
202
+ When an operand or the result is outside the range of nanoseconds.
203
+
204
+ Examples
205
+ --------
206
+ >>> from datetime import timedelta
207
+ >>> import numpy
208
+ >>> import numdaplot as ndp
209
+ >>> from numdaplot.arrays.operations.time_arithmetic import combine_nanoseconds
210
+ >>> durations = numpy.array([1], dtype="timedelta64[s]")
211
+ >>> combine_nanoseconds([durations, timedelta(seconds=1)], numpy.add, ndp.Type.DURATION, "+")
212
+ array([2000000000], dtype='timedelta64[ns]')
213
+ """
214
+ left, right = operands
215
+ left_type = find_operand_type(left)
216
+ right_type = find_operand_type(right)
217
+ require_nanoseconds_fit(left, left_type, symbol)
218
+ require_nanoseconds_fit(right, right_type, symbol)
219
+ left_family = find_family(left_type)
220
+ right_family = find_family(right_type)
221
+ left_values = to_nanoseconds(left, left_family)
222
+ right_values = to_nanoseconds(right, right_family)
223
+ # A time of day moved by a duration is first computed as a duration, then checked against midnight.
224
+ fitted_type = Type.DURATION if result_type == Type.TIME else result_type
225
+ try:
226
+ left_numbers = widen_large_integers(left_values)
227
+ right_numbers = widen_large_integers(right_values)
228
+ number_operands = [left_numbers, right_numbers]
229
+ require_time_result_fits(number_operands, function, fitted_type, symbol)
230
+ combined_values = function(left_numbers, right_numbers)
231
+ except OverflowError as error:
232
+ raise TimeOverflowError(symbol, fitted_type.name) from error
233
+
234
+ return combined_values
235
+
236
+
237
+ def store_time_result(durations: NDArray[Any], symbol: str) -> NDArray[numpy.timedelta64]:
238
+ """
239
+ Return times of day computed as durations since midnight, refusing those past midnight.
240
+
241
+ .. versionadded:: 0.1.0
242
+
243
+ Parameters
244
+ ----------
245
+ durations
246
+ The times since midnight in ``timedelta64[ns]``, NaT where missing.
247
+ symbol
248
+ The operator shown in error messages, such as ``"+"``.
249
+
250
+ Returns
251
+ -------
252
+ NDArray[numpy.timedelta64]
253
+ The times of day in ``timedelta64[us]``.
254
+
255
+ Raises
256
+ ------
257
+ TimeOverflowError
258
+ When a time is before midnight or from the next midnight on.
259
+
260
+ Examples
261
+ --------
262
+ >>> import numpy
263
+ >>> from numdaplot.arrays.operations.time_arithmetic import store_time_result
264
+ >>> store_time_result(numpy.array([3600000000000], dtype="timedelta64[ns]"), "+")
265
+ array([3600000000], dtype='timedelta64[us]')
266
+ """
267
+ is_missing = numpy.isnat(durations)
268
+ is_before_midnight = durations < NO_DURATION
269
+ is_next_day = durations >= ONE_DAY
270
+ is_outside_day = (is_before_midnight | is_next_day) & ~is_missing
271
+ has_outside_day = bool(is_outside_day.any())
272
+ if has_outside_day:
273
+ raise TimeOverflowError(symbol, Type.TIME.name)
274
+
275
+ time_dtype = to_numpy_dtype(Type.TIME)
276
+ times = durations.astype(time_dtype)
277
+
278
+ return times
279
+
280
+
281
+ def require_date_next_to_time(left_type: Type, right_type: Type, symbol: str) -> None:
282
+ """
283
+ Check that a time of day is only added to dates, never to datetimes, which already have a time.
284
+
285
+ .. versionadded:: 0.1.0
286
+
287
+ Parameters
288
+ ----------
289
+ left_type
290
+ The type of the left operand.
291
+ right_type
292
+ The type of the right operand.
293
+ symbol
294
+ The operator shown in error messages, such as ``"+"``.
295
+
296
+ Raises
297
+ ------
298
+ IncompatibleTypesError
299
+ When a time of day is combined with datetimes.
300
+
301
+ Examples
302
+ --------
303
+ >>> import numdaplot as ndp
304
+ >>> from numdaplot.arrays.operations.time_arithmetic import require_date_next_to_time
305
+ >>> try:
306
+ ... require_date_next_to_time(ndp.Type.DATETIME, ndp.Type.TIME, "+")
307
+ ... except ndp.IncompatibleTypesError as error:
308
+ ... print(error)
309
+ Cannot apply + to DATETIME and TIME.
310
+ """
311
+ operand_types = (left_type, right_type)
312
+ combines_datetime_with_time = Type.TIME in operand_types and Type.DATETIME in operand_types
313
+ if combines_datetime_with_time:
314
+ raise IncompatibleTypesError(symbol, [left_type.name, right_type.name])
315
+
316
+
317
+ def find_time_result_type(result_family: ValueFamily, keeps_date: bool) -> Type:
318
+ """
319
+ Return the type of the result of an accepted operation on times.
320
+
321
+ .. versionadded:: 0.1.0
322
+
323
+ Parameters
324
+ ----------
325
+ result_family
326
+ The family of the result, ``MOMENT`` or ``DURATION``.
327
+ keeps_date
328
+ Whether the result stays a date.
329
+
330
+ Returns
331
+ -------
332
+ Type
333
+ ``DURATION``, ``TIME``, ``DATE`` or ``DATETIME``.
334
+
335
+ Examples
336
+ --------
337
+ >>> from numdaplot.arrays.operations.time_arithmetic import find_time_result_type
338
+ >>> from numdaplot.data_types.value_family import ValueFamily
339
+ >>> find_time_result_type(ValueFamily.MOMENT, True)
340
+ <Type.DATE: 14>
341
+ """
342
+ if result_family == ValueFamily.DURATION:
343
+ return Type.DURATION
344
+
345
+ if result_family == ValueFamily.TIME:
346
+ return Type.TIME
347
+
348
+ if keeps_date:
349
+ return Type.DATE
350
+
351
+ return Type.DATETIME
352
+
353
+
354
+ def require_time_operation(left: Operand, right: Operand, operation_key: TimeOperation) -> None:
355
+ """
356
+ Check that an operation is not one of the duration operations written another way in numdaplot.
357
+
358
+ .. versionadded:: 0.1.0
359
+
360
+ Parameters
361
+ ----------
362
+ left
363
+ The values of an Array, or a single value.
364
+ right
365
+ The values of an Array, or a single value.
366
+ operation_key
367
+ The numpy function, then the families of the left and right operands.
368
+
369
+ Raises
370
+ ------
371
+ RefusedOperationError
372
+ When a duration is divided by a duration, which ``DurationIn`` does, or numbers are multiplied
373
+ by a single duration, which ``ToDuration`` does.
374
+
375
+ Examples
376
+ --------
377
+ >>> from datetime import timedelta
378
+ >>> import numpy
379
+ >>> import numdaplot as ndp
380
+ >>> from numdaplot.arrays.operations.time_arithmetic import require_time_operation
381
+ >>> from numdaplot.data_types.value_family import ValueFamily
382
+ >>> key = (numpy.multiply, ValueFamily.NUMBER, ValueFamily.DURATION)
383
+ >>> try:
384
+ ... require_time_operation(numpy.array([3]), timedelta(days=1), key)
385
+ ... except ndp.RefusedOperationError as error:
386
+ ... print(error)
387
+ Multiplying numbers by a single duration is not available, use apply(ndp.ToDuration(unit=...)) instead.
388
+ """
389
+ if operation_key == DURATION_DIVISION:
390
+ raise RefusedOperationError(DURATION_DIVISION_OPERATION, DURATION_DIVISION_ALTERNATIVE)
391
+
392
+ function, left_family, right_family = operation_key
393
+ if function != numpy.multiply:
394
+ return
395
+
396
+ left_is_single_duration = left_family == ValueFamily.DURATION and not isinstance(left, numpy.ndarray)
397
+ right_is_single_duration = right_family == ValueFamily.DURATION and not isinstance(right, numpy.ndarray)
398
+ multiplies_single_duration = left_is_single_duration or right_is_single_duration
399
+ if multiplies_single_duration:
400
+ raise RefusedOperationError(TIMEDELTA_PRODUCT_OPERATION, TIMEDELTA_PRODUCT_ALTERNATIVE)
401
+
402
+
403
+ def to_nanoseconds(operand: Operand, family: ValueFamily) -> Any:
404
+ """
405
+ Return an operand with its dates, datetimes or durations counted in nanoseconds.
406
+
407
+ .. versionadded:: 0.1.0
408
+
409
+ Parameters
410
+ ----------
411
+ operand
412
+ The values of an Array, or a single value.
413
+ family
414
+ The family of the operand.
415
+
416
+ Returns
417
+ -------
418
+ Any
419
+ Datetimes or durations in nanoseconds, or the operand itself when it holds numbers.
420
+
421
+ Examples
422
+ --------
423
+ >>> from datetime import date
424
+ >>> from numdaplot.arrays.operations.time_arithmetic import to_nanoseconds
425
+ >>> from numdaplot.data_types.value_family import ValueFamily
426
+ >>> to_nanoseconds(date(2026, 1, 31), ValueFamily.MOMENT)
427
+ np.datetime64('2026-01-31T00:00:00.000000000')
428
+ """
429
+ if family not in NANOSECOND_DTYPES:
430
+ return operand
431
+
432
+ numpy_operand = cast(Any, operand)
433
+ if not isinstance(operand, numpy.ndarray):
434
+ numpy_operand = convert_time_value(operand)
435
+
436
+ nanosecond_dtype = NANOSECOND_DTYPES[family]
437
+ nanosecond_operand = numpy_operand.astype(nanosecond_dtype)
438
+
439
+ return nanosecond_operand
440
+
441
+
442
+ def require_whole_days(durations: NDArray[numpy.timedelta64] | numpy.timedelta64) -> None:
443
+ """
444
+ Check that durations added to or subtracted from dates are whole numbers of days.
445
+
446
+ .. versionadded:: 0.1.0
447
+
448
+ Parameters
449
+ ----------
450
+ durations
451
+ Durations in nanoseconds, an array or a single value.
452
+
453
+ Raises
454
+ ------
455
+ ValueConversionError
456
+ When a duration is not a whole number of days, citing the first one.
457
+
458
+ Examples
459
+ --------
460
+ >>> import numpy
461
+ >>> import numdaplot as ndp
462
+ >>> from numdaplot.arrays.operations.time_arithmetic import require_whole_days
463
+ >>> try:
464
+ ... require_whole_days(numpy.array([36], dtype="timedelta64[h]").astype("timedelta64[ns]"))
465
+ ... except ndp.ValueConversionError as error:
466
+ ... print(error)
467
+ Cannot store the DURATION value '1 days 12:00:00' as DATE without losing information.
468
+ """
469
+ duration_values = numpy.atleast_1d(durations)
470
+ present_durations = duration_values[~numpy.isnat(duration_values)]
471
+ remainders = present_durations % ONE_DAY
472
+ partial_days = present_durations[remainders != NO_DURATION]
473
+ partial_count = len(partial_days)
474
+ if partial_count == 0:
475
+ return
476
+
477
+ partial_texts = format_durations(partial_days)
478
+ first_partial_text = str(partial_texts[0])
479
+ raise ValueConversionError(Type.DURATION.name, Type.DATE.name, first_partial_text)