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,82 @@
1
+ """
2
+ Text encodings of the files a Table reads and writes.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from enum import Enum
8
+
9
+
10
+ class Encoding(Enum):
11
+ r"""
12
+ Text encoding of a file, used by the CSV, SAS and SAS transport options.
13
+
14
+ ``CsvReadOptions``, ``CsvWriteOptions``, ``SasReadOptions`` and ``XptReadOptions`` take it.
15
+
16
+ The value of each member is the name Python gives to the encoding.
17
+
18
+ .. versionadded:: 0.1.0
19
+
20
+ Examples
21
+ --------
22
+ >>> import tempfile
23
+ >>> from pathlib import Path
24
+ >>> import numdaplot as ndp
25
+ >>> folder = Path(tempfile.mkdtemp())
26
+ >>> path = folder / "cities.csv"
27
+ >>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="latin-1")
28
+ >>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.LATIN_1))
29
+ >>> cities.column("city").to_list() == ["B\u00e9ziers"]
30
+ True
31
+ """
32
+
33
+ UTF_8 = "utf-8"
34
+ r"""
35
+ UTF-8, the most common encoding. Default value.
36
+
37
+ Examples
38
+ --------
39
+ >>> import tempfile
40
+ >>> from pathlib import Path
41
+ >>> import numdaplot as ndp
42
+ >>> folder = Path(tempfile.mkdtemp())
43
+ >>> path = folder / "cities.csv"
44
+ >>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="utf-8")
45
+ >>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.UTF_8))
46
+ >>> cities.column("city").to_list() == ["B\u00e9ziers"]
47
+ True
48
+ """
49
+
50
+ UTF_8_BOM = "utf-8-sig"
51
+ r"""
52
+ UTF-8 starting with a byte order mark, as written by Excel when it saves a CSV file.
53
+
54
+ Examples
55
+ --------
56
+ >>> import tempfile
57
+ >>> from pathlib import Path
58
+ >>> import numdaplot as ndp
59
+ >>> folder = Path(tempfile.mkdtemp())
60
+ >>> path = folder / "cities.csv"
61
+ >>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="utf-8-sig")
62
+ >>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.UTF_8_BOM))
63
+ >>> cities.column("city").to_list() == ["B\u00e9ziers"]
64
+ True
65
+ """
66
+
67
+ LATIN_1 = "latin-1"
68
+ r"""
69
+ Latin-1 (ISO 8859-1), used by older software in Western Europe.
70
+
71
+ Examples
72
+ --------
73
+ >>> import tempfile
74
+ >>> from pathlib import Path
75
+ >>> import numdaplot as ndp
76
+ >>> folder = Path(tempfile.mkdtemp())
77
+ >>> path = folder / "cities.csv"
78
+ >>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="latin-1")
79
+ >>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.LATIN_1))
80
+ >>> cities.column("city").to_list() == ["B\u00e9ziers"]
81
+ True
82
+ """
@@ -0,0 +1,171 @@
1
+ """
2
+ Reading and writing Excel files.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any, cast
9
+
10
+ import pandas
11
+
12
+ from numdaplot.tables.columns.column_names import require_column_names
13
+ from numdaplot.tables.files.excel_read_options import ExcelReadOptions
14
+ from numdaplot.tables.files.excel_time_cells import restore_time_columns
15
+ from numdaplot.tables.files.excel_write_options import ExcelWriteOptions
16
+ from numdaplot.tables.files.missing_texts import find_missing_settings
17
+ from numdaplot.tables.files.optional_package import require_package
18
+ from numdaplot.tables.files.pandas_backend import NULLABLE_DTYPE_BACKEND
19
+ from numdaplot.tables.frames.time_zones import require_no_time_zone
20
+
21
+ EXCEL_PACKAGE = "openpyxl"
22
+ EXCEL_EXTRA = "excel"
23
+ FIRST_SHEET = 0
24
+ DEFAULT_SHEET_NAME = "Sheet1"
25
+ HEADER_ROW_COUNT = 1
26
+ NO_MISSING_TEXTS = list[str]()
27
+ EXCEL_OPERATION = "An Excel file"
28
+
29
+
30
+ def read_excel_file(path: Path, options: ExcelReadOptions) -> pandas.DataFrame:
31
+ """
32
+ Return the columns of a sheet of an Excel file whose first row holds the column names.
33
+
34
+ .. versionadded:: 0.1.0
35
+
36
+ Parameters
37
+ ----------
38
+ path
39
+ The path of an existing Excel file.
40
+ options
41
+ The sheet to read, the first one when omitted, and the texts read as missing.
42
+
43
+ Returns
44
+ -------
45
+ pandas.DataFrame
46
+ The columns as pandas reads them, empty for an empty sheet. A column of time cells only, or of duration cells
47
+ only, holds Python times or durations.
48
+
49
+ Raises
50
+ ------
51
+ MissingDependencyError
52
+ When ``openpyxl`` is not installed.
53
+ TimeZoneMismatchError
54
+ When a column holds datetimes with a time zone, which Excel files cannot store.
55
+ InvalidColumnNameError
56
+ When a cell of the first row is empty or is not a text.
57
+ DuplicateColumnError
58
+ When a column name appears twice.
59
+
60
+ Examples
61
+ --------
62
+ >>> import tempfile
63
+ >>> from pathlib import Path
64
+ >>> import pandas
65
+ >>> import numdaplot as ndp
66
+ >>> from numdaplot.tables.files.excel_file import read_excel_file
67
+ >>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
68
+ >>> pandas.DataFrame({"price": [1.5]}).to_excel(path, index=False)
69
+ >>> read_excel_file(path, ndp.ExcelReadOptions())
70
+ price
71
+ 0 1.5
72
+ """
73
+ require_package(EXCEL_PACKAGE, EXCEL_EXTRA)
74
+ sheet = find_read_sheet(options)
75
+ # The pandas stubs leave the types of the Excel engines unknown.
76
+ excel_pandas = cast(Any, pandas)
77
+ # A column name is never a missing value, so the first row is read without any missing text.
78
+ header_settings = find_missing_settings(NO_MISSING_TEXTS)
79
+ raw_header_frame = excel_pandas.read_excel(
80
+ path, sheet_name=sheet, header=None, nrows=HEADER_ROW_COUNT, **header_settings
81
+ )
82
+ header_frame = cast(pandas.DataFrame, raw_header_frame)
83
+ if header_frame.empty:
84
+ empty_frame = pandas.DataFrame()
85
+ return empty_frame
86
+
87
+ header_row = header_frame.iloc[0]
88
+ header = header_row.tolist()
89
+ require_column_names(header)
90
+ missing_settings = find_missing_settings(options.missing_texts)
91
+ raw_frame = excel_pandas.read_excel(
92
+ path, sheet_name=sheet, dtype_backend=NULLABLE_DTYPE_BACKEND, **missing_settings
93
+ )
94
+ read_frame = cast(pandas.DataFrame, raw_frame)
95
+ frame = restore_time_columns(read_frame, path, sheet, missing_settings)
96
+
97
+ return frame
98
+
99
+
100
+ def find_read_sheet(options: ExcelReadOptions) -> str | int:
101
+ """
102
+ Return the sheet pandas reads: its name, or the position of the first sheet.
103
+
104
+ .. versionadded:: 0.1.0
105
+
106
+ Parameters
107
+ ----------
108
+ options
109
+ The settings of the Excel file.
110
+
111
+ Returns
112
+ -------
113
+ str or int
114
+ The name of the sheet, or 0 when no sheet is named.
115
+
116
+ Examples
117
+ --------
118
+ >>> import numdaplot as ndp
119
+ >>> from numdaplot.tables.files.excel_file import find_read_sheet
120
+ >>> find_read_sheet(ndp.ExcelReadOptions())
121
+ 0
122
+ """
123
+ if options.sheet is None:
124
+ return FIRST_SHEET
125
+
126
+ return options.sheet
127
+
128
+
129
+ def write_excel_file(frame: pandas.DataFrame, path: Path, options: ExcelWriteOptions) -> None:
130
+ """
131
+ Write the columns of a Table in a sheet of an Excel file, column names on the first row.
132
+
133
+ .. versionadded:: 0.1.0
134
+
135
+ Parameters
136
+ ----------
137
+ frame
138
+ The columns of a Table.
139
+ path
140
+ The path of the file, replaced when it exists.
141
+ options
142
+ The name of the sheet, ``"Sheet1"`` when omitted.
143
+
144
+ Raises
145
+ ------
146
+ MissingDependencyError
147
+ When ``openpyxl`` is not installed.
148
+ TimeZoneMismatchError
149
+ When a column holds datetimes with a time zone, which Excel files cannot store.
150
+
151
+ Examples
152
+ --------
153
+ >>> import tempfile
154
+ >>> from pathlib import Path
155
+ >>> import pandas
156
+ >>> import numdaplot as ndp
157
+ >>> from numdaplot.tables.files.excel_file import write_excel_file
158
+ >>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
159
+ >>> write_excel_file(pandas.DataFrame({"price": [1.5]}), path, ndp.ExcelWriteOptions(sheet="Sales"))
160
+ >>> pandas.ExcelFile(path).sheet_names
161
+ ['Sales']
162
+ """
163
+ require_no_time_zone(frame, EXCEL_OPERATION)
164
+ require_package(EXCEL_PACKAGE, EXCEL_EXTRA)
165
+ sheet_name = DEFAULT_SHEET_NAME
166
+ if options.sheet is not None:
167
+ sheet_name = options.sheet
168
+
169
+ # The pandas stubs leave the types of the Excel engines unknown.
170
+ excel_frame = cast(Any, frame)
171
+ excel_frame.to_excel(path, sheet_name=sheet_name, index=False)
@@ -0,0 +1,79 @@
1
+ r"""
2
+ Settings of the Excel files a Table reads.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+
9
+ from numdaplot.settings.field_types import require_field_types
10
+ from numdaplot.tables.files.column_names import ColumnNames
11
+ from numdaplot.tables.files.excel_sheet import require_sheet_name
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class ExcelReadOptions:
16
+ r"""
17
+ Settings of an Excel file read by ``Table.from_excel``.
18
+
19
+ .. versionadded:: 0.1.0
20
+
21
+ Parameters
22
+ ----------
23
+ sheet
24
+ The name of the sheet read, the first sheet when omitted.
25
+ column_names
26
+ Whether the column names are cleaned, ``ColumnNames.CLEANED`` by default: the spaces, tabs and line breaks at
27
+ the start and the end of each name are removed. ``ColumnNames.KEPT`` keeps the names as written.
28
+ missing_texts
29
+ The texts read as missing values, compared with the whole value of each cell. When omitted, the texts pandas
30
+ reads as missing: ``""``, ``"#N/A"``, ``"#N/A N/A"``, ``"#NA"``, ``"-1.#IND"``, ``"-1.#QNAN"``, ``"-NaN"``,
31
+ ``"-nan"``, ``"1.#IND"``, ``"1.#QNAN"``, ``"<NA>"``, ``"N/A"``, ``"NA"``, ``"NULL"``, ``"NaN"``, ``"None"``,
32
+ ``"n/a"``, ``"nan"`` and ``"null"``. A given list replaces them: ``[]`` reads no value as missing, not even
33
+ an empty one: an empty cell is then read as an empty text.
34
+
35
+ Raises
36
+ ------
37
+ InvalidTypeError
38
+ When a setting is not of the type its annotation names.
39
+ InvalidSheetNameError
40
+ When the name is empty, longer than 31 characters, or holds ``[ ] : * ? / \``, which Excel refuses.
41
+
42
+ Examples
43
+ --------
44
+ >>> import tempfile
45
+ >>> from pathlib import Path
46
+ >>> import numdaplot as ndp
47
+ >>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
48
+ >>> prices = ndp.Table.from_arrays({"price": ndp.Array.from_list([1.5])})
49
+ >>> prices.to_excel(path, ndp.ExcelWriteOptions(sheet="Sales"))
50
+ >>> ndp.Table.from_excel(path, ndp.ExcelReadOptions(sheet="Sales"))
51
+ price
52
+ FLOAT64
53
+ 0 1.5
54
+ """
55
+
56
+ sheet: str | None = None
57
+ column_names: ColumnNames = ColumnNames.CLEANED
58
+ missing_texts: list[str] | None = None
59
+
60
+ def __post_init__(self) -> None:
61
+ """
62
+ Check the type of every setting, and that Excel accepts the sheet name.
63
+
64
+ .. versionadded:: 0.1.0
65
+
66
+ Raises
67
+ ------
68
+ InvalidTypeError
69
+ When a setting is not of the type its annotation names.
70
+ InvalidSheetNameError
71
+ When the name is empty, longer than 31 characters, or holds a character Excel refuses.
72
+ """
73
+ require_field_types(self)
74
+
75
+ require_sheet_name(self.sheet)
76
+
77
+ if self.missing_texts is not None:
78
+ missing_texts_copy = list(self.missing_texts)
79
+ object.__setattr__(self, "missing_texts", missing_texts_copy)
@@ -0,0 +1,50 @@
1
+ r"""
2
+ Check of the name of an Excel sheet.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from numdaplot.errors.invalid_sheet_name_error import InvalidSheetNameError
8
+
9
+ MAXIMUM_SHEET_LENGTH = 31
10
+ FORBIDDEN_SHEET_CHARACTERS = frozenset("[]:*?/\\")
11
+
12
+
13
+ def require_sheet_name(sheet: str | None) -> None:
14
+ r"""
15
+ Check that Excel accepts a sheet name, when it is given.
16
+
17
+ .. versionadded:: 0.1.0
18
+
19
+ Parameters
20
+ ----------
21
+ sheet
22
+ The name of the sheet, or None for the default sheet.
23
+
24
+ Raises
25
+ ------
26
+ InvalidSheetNameError
27
+ When the name is empty, longer than 31 characters, or holds ``[ ] : * ? / \``, which Excel refuses.
28
+
29
+ Examples
30
+ --------
31
+ >>> import numdaplot as ndp
32
+ >>> from numdaplot.tables.files.excel_sheet import require_sheet_name
33
+ >>> try:
34
+ ... require_sheet_name("Sales/2026")
35
+ ... except ndp.InvalidSheetNameError as error:
36
+ ... print(error)
37
+ Expected a sheet name of 1 to 31 characters without [ ] : * ? / \, got 'Sales/2026'.
38
+ """
39
+ if sheet is None:
40
+ return
41
+
42
+ sheet_length = len(sheet)
43
+ has_valid_length = 0 < sheet_length <= MAXIMUM_SHEET_LENGTH
44
+ sheet_characters = set(sheet)
45
+ forbidden_characters = sheet_characters & FORBIDDEN_SHEET_CHARACTERS
46
+ forbidden_count = len(forbidden_characters)
47
+ has_forbidden_character = forbidden_count > 0
48
+ is_valid = has_valid_length and not has_forbidden_character
49
+ if not is_valid:
50
+ raise InvalidSheetNameError(sheet)
@@ -0,0 +1,146 @@
1
+ """
2
+ Time and duration cells of an Excel file, which pandas reads as texts.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any, cast
9
+
10
+ import pandas
11
+ from pandas.api.types import infer_dtype
12
+
13
+ PYTHON_OBJECT_DTYPE = object
14
+ TIME_KINDS = frozenset({"time", "timedelta"})
15
+
16
+
17
+ def restore_time_columns(
18
+ frame: pandas.DataFrame, path: Path, sheet: str | int, missing_settings: dict[str, Any]
19
+ ) -> pandas.DataFrame:
20
+ """
21
+ Return the columns of a sheet with the columns of time or duration cells read again as Python values.
22
+
23
+ The types of pandas that accept missing values write a time or a duration cell as a text. Only the text columns
24
+ are read again, as Python values: a column of times of day only, or of durations only, keeps them, and becomes a
25
+ ``TIME`` or a ``DURATION`` column. The other columns are kept as read.
26
+
27
+ .. versionadded:: 0.1.0
28
+
29
+ Parameters
30
+ ----------
31
+ frame
32
+ The columns of the sheet, read with the types of pandas that accept missing values.
33
+ path
34
+ The path of the Excel file.
35
+ sheet
36
+ The name or the position of the sheet.
37
+ missing_settings
38
+ The settings of pandas reading the missing values, the same as for ``frame``.
39
+
40
+ Returns
41
+ -------
42
+ pandas.DataFrame
43
+ The same columns, a column of times or durations holding Python values.
44
+
45
+ Examples
46
+ --------
47
+ >>> import tempfile
48
+ >>> from datetime import time
49
+ >>> from pathlib import Path
50
+ >>> import openpyxl
51
+ >>> import pandas
52
+ >>> from numdaplot.tables.files.excel_time_cells import restore_time_columns
53
+ >>> path = Path(tempfile.mkdtemp()) / "hours.xlsx"
54
+ >>> book = openpyxl.Workbook()
55
+ >>> book.active.append(["hrmn"])
56
+ >>> book.active.append([time(15, 35)])
57
+ >>> book.save(path)
58
+ >>> frame = pandas.read_excel(path, dtype_backend="numpy_nullable")
59
+ >>> restore_time_columns(frame, path, 0, {})["hrmn"].tolist()
60
+ [datetime.time(15, 35)]
61
+ """
62
+ text_names = find_text_columns(frame)
63
+ if text_names == []:
64
+ return frame
65
+
66
+ # The pandas stubs leave the types of the Excel engines unknown.
67
+ excel_pandas = cast(Any, pandas)
68
+ raw_object_frame = excel_pandas.read_excel(
69
+ path, sheet_name=sheet, dtype=PYTHON_OBJECT_DTYPE, usecols=text_names, **missing_settings
70
+ )
71
+ object_frame = cast(pandas.DataFrame, raw_object_frame)
72
+ restored_frame = frame.copy()
73
+
74
+ for text_name in text_names:
75
+ object_column = object_frame[text_name]
76
+ holds_time_cells = holds_only_time_cells(object_column)
77
+ if holds_time_cells:
78
+ restored_frame[text_name] = object_column
79
+
80
+ return restored_frame
81
+
82
+
83
+ def find_text_columns(frame: pandas.DataFrame) -> list[str]:
84
+ """
85
+ Return the names of the text columns of a sheet read with the types of pandas that accept missing values.
86
+
87
+ .. versionadded:: 0.1.0
88
+
89
+ Parameters
90
+ ----------
91
+ frame
92
+ The columns of a sheet.
93
+
94
+ Returns
95
+ -------
96
+ list[str]
97
+ The names of the columns of texts, in their order.
98
+
99
+ Examples
100
+ --------
101
+ >>> import pandas
102
+ >>> from numdaplot.tables.files.excel_time_cells import find_text_columns
103
+ >>> frame = pandas.DataFrame({"city": pandas.Series(["Pau"], dtype="string"), "count": [1]})
104
+ >>> find_text_columns(frame)
105
+ ['city']
106
+ """
107
+ text_names = list[str]()
108
+
109
+ for column_name, column in frame.items():
110
+ if isinstance(column.dtype, pandas.StringDtype):
111
+ text_names.append(str(column_name))
112
+
113
+ return text_names
114
+
115
+
116
+ def holds_only_time_cells(column: pandas.Series) -> bool:
117
+ """
118
+ Return whether a column of Python values holds times of day only, or durations only, besides missing values.
119
+
120
+ .. versionadded:: 0.1.0
121
+
122
+ Parameters
123
+ ----------
124
+ column
125
+ A column read as Python values.
126
+
127
+ Returns
128
+ -------
129
+ bool
130
+ True for ``datetime.time`` values only or ``datetime.timedelta`` values only, False for a mix with texts or
131
+ an empty column.
132
+
133
+ Examples
134
+ --------
135
+ >>> from datetime import time
136
+ >>> import pandas
137
+ >>> from numdaplot.tables.files.excel_time_cells import holds_only_time_cells
138
+ >>> holds_only_time_cells(pandas.Series([time(8), None], dtype=object))
139
+ True
140
+ >>> holds_only_time_cells(pandas.Series([time(8), "unknown"], dtype=object))
141
+ False
142
+ """
143
+ inferred_kind = infer_dtype(column, skipna=True)
144
+ is_time_kind = inferred_kind in TIME_KINDS
145
+
146
+ return is_time_kind
@@ -0,0 +1,63 @@
1
+ r"""
2
+ Settings of the Excel files a Table writes.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+
9
+ from numdaplot.settings.field_types import require_field_types
10
+ from numdaplot.tables.files.excel_sheet import require_sheet_name
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class ExcelWriteOptions:
15
+ r"""
16
+ Settings of an Excel file written by ``Table.to_excel``.
17
+
18
+ .. versionadded:: 0.1.0
19
+
20
+ Parameters
21
+ ----------
22
+ sheet
23
+ The name of the written sheet, ``"Sheet1"`` when omitted.
24
+
25
+ Raises
26
+ ------
27
+ InvalidTypeError
28
+ When a setting is not of the type its annotation names.
29
+ InvalidSheetNameError
30
+ When the name is empty, longer than 31 characters, or holds ``[ ] : * ? / \``, which Excel refuses.
31
+
32
+ Examples
33
+ --------
34
+ >>> import tempfile
35
+ >>> from pathlib import Path
36
+ >>> import numdaplot as ndp
37
+ >>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
38
+ >>> prices = ndp.Table.from_arrays({"price": ndp.Array.from_list([1.5])})
39
+ >>> prices.to_excel(path, ndp.ExcelWriteOptions(sheet="Sales"))
40
+ >>> ndp.Table.from_excel(path, ndp.ExcelReadOptions(sheet="Sales"))
41
+ price
42
+ FLOAT64
43
+ 0 1.5
44
+ """
45
+
46
+ sheet: str | None = None
47
+
48
+ def __post_init__(self) -> None:
49
+ """
50
+ Check the type of every setting, and that Excel accepts the sheet name.
51
+
52
+ .. versionadded:: 0.1.0
53
+
54
+ Raises
55
+ ------
56
+ InvalidTypeError
57
+ When a setting is not of the type its annotation names.
58
+ InvalidSheetNameError
59
+ When the name is empty, longer than 31 characters, or holds a character Excel refuses.
60
+ """
61
+ require_field_types(self)
62
+
63
+ require_sheet_name(self.sheet)