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,152 @@
1
+ """
2
+ Errors of the file system while reading or writing a file.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from pathlib import Path
8
+ from types import TracebackType
9
+
10
+ from numdaplot.errors.file_access_error import FileAccessError
11
+ from numdaplot.errors.numdaplot_error import NumdaplotError
12
+
13
+ READ_OPERATION = "read"
14
+ WRITE_OPERATION = "write to"
15
+ PERMISSION_REASON = "permission denied"
16
+ MISSING_FOLDER_REASON = "the folder {folder} does not exist"
17
+ FOLDER_IS_FILE_REASON = "the folder {folder} is a file"
18
+
19
+
20
+ class FileAccessErrors:
21
+ """
22
+ Context turning an error of the file system during a block into a ``FileAccessError``.
23
+
24
+ .. versionadded:: 0.1.0
25
+
26
+ Parameters
27
+ ----------
28
+ operation
29
+ What the block does: ``READ_OPERATION`` or ``WRITE_OPERATION``.
30
+ path
31
+ The path of the file.
32
+
33
+ Examples
34
+ --------
35
+ >>> from pathlib import Path
36
+ >>> import numdaplot as ndp
37
+ >>> from numdaplot.tables.files.file_access import FileAccessErrors, WRITE_OPERATION
38
+ >>> path = Path("missing_folder/sales.csv")
39
+ >>> try:
40
+ ... with FileAccessErrors(WRITE_OPERATION, path):
41
+ ... path.write_text("sales")
42
+ ... except ndp.FileAccessError as error:
43
+ ... print(error)
44
+ Cannot write to missing_folder/sales.csv: the folder missing_folder does not exist.
45
+ """
46
+
47
+ def __init__(self, operation: str, path: Path) -> None:
48
+ """
49
+ Keep the operation and the path of the block.
50
+
51
+ .. versionadded:: 0.1.0
52
+
53
+ Parameters
54
+ ----------
55
+ operation
56
+ What the block does: ``READ_OPERATION`` or ``WRITE_OPERATION``.
57
+ path
58
+ The path of the file.
59
+ """
60
+ self.operation = operation
61
+ self.path = path
62
+
63
+ def __enter__(self) -> None:
64
+ """
65
+ Start the block.
66
+
67
+ .. versionadded:: 0.1.0
68
+ """
69
+
70
+ def __exit__(
71
+ self,
72
+ error_type: type[BaseException] | None,
73
+ error: BaseException | None,
74
+ traceback: TracebackType | None,
75
+ ) -> None:
76
+ """
77
+ Raise a ``FileAccessError`` for an error of the file system. Any other error goes on unchanged.
78
+
79
+ .. versionadded:: 0.1.0
80
+
81
+ Parameters
82
+ ----------
83
+ error_type
84
+ The type of the error raised by the block, or None.
85
+ error
86
+ The error raised by the block, or None.
87
+ traceback
88
+ Its traceback, or None.
89
+
90
+ Raises
91
+ ------
92
+ FileAccessError
93
+ When the block raised an ``OSError`` that is not already an error of numdaplot.
94
+ """
95
+ if not isinstance(error, OSError):
96
+ return
97
+
98
+ if isinstance(error, NumdaplotError):
99
+ return
100
+
101
+ reason = find_access_reason(self.path, error)
102
+ path_text = str(self.path)
103
+ raise FileAccessError(self.operation, path_text, reason) from error
104
+
105
+
106
+ def find_access_reason(path: Path, error: OSError) -> str:
107
+ """
108
+ Return why the file system refused a file.
109
+
110
+ .. versionadded:: 0.1.0
111
+
112
+ Parameters
113
+ ----------
114
+ path
115
+ The path of the file.
116
+ error
117
+ The error of the file system.
118
+
119
+ Returns
120
+ -------
121
+ str
122
+ A missing permission or a wrong folder in words, else what the system says.
123
+
124
+ Examples
125
+ --------
126
+ >>> from pathlib import Path
127
+ >>> from numdaplot.tables.files.file_access import find_access_reason
128
+ >>> find_access_reason(Path("missing_folder/sales.csv"), OSError("Disk is full"))
129
+ 'the folder missing_folder does not exist'
130
+ >>> find_access_reason(Path("sales.csv"), OSError(28, "No space left on device"))
131
+ 'No space left on device'
132
+ """
133
+ if isinstance(error, PermissionError):
134
+ return PERMISSION_REASON
135
+
136
+ folder = path.parent
137
+ folder_exists = folder.exists()
138
+ if not folder_exists:
139
+ missing_folder_reason = MISSING_FOLDER_REASON.format(folder=folder)
140
+ return missing_folder_reason
141
+
142
+ folder_is_folder = folder.is_dir()
143
+ if not folder_is_folder:
144
+ folder_is_file_reason = FOLDER_IS_FILE_REASON.format(folder=folder)
145
+ return folder_is_file_reason
146
+
147
+ if error.strerror is not None:
148
+ return error.strerror
149
+
150
+ system_reason = str(error)
151
+
152
+ return system_reason
@@ -0,0 +1,106 @@
1
+ """
2
+ Paths of the files a Table reads and writes.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ from numdaplot.errors.file_exists_error import FileExistsError
10
+ from numdaplot.errors.file_not_found_error import FileNotFoundError
11
+ from numdaplot.tables.conflict import Conflict
12
+
13
+ type FilePath = str | Path
14
+ """
15
+ The path of a file, as a text or a ``pathlib.Path``.
16
+
17
+ It is a name used by the documentation and the annotations, not an object to create: pass the value itself,
18
+ such as ``"sales.csv"`` or ``Path("data/sales.csv")``.
19
+
20
+ .. versionadded:: 0.1.0
21
+
22
+ Examples
23
+ --------
24
+ >>> from pathlib import Path
25
+ >>> from tempfile import TemporaryDirectory
26
+ >>> import numdaplot as ndp
27
+ >>> cities = ndp.Array.from_list(["Paris", "Lyon"])
28
+ >>> sales = ndp.Table.from_arrays({"city": cities})
29
+ >>> with TemporaryDirectory() as folder:
30
+ ... sales.to_csv(Path(folder) / "sales.csv")
31
+ ... ndp.Table.from_csv(Path(folder) / "sales.csv").column("city").to_list()
32
+ ['Paris', 'Lyon']
33
+ """
34
+
35
+
36
+ def require_existing_file(path: Path) -> None:
37
+ """
38
+ Check that a file exists at a path.
39
+
40
+ .. versionadded:: 0.1.0
41
+
42
+ Parameters
43
+ ----------
44
+ path
45
+ The path of the file to read.
46
+
47
+ Raises
48
+ ------
49
+ FileNotFoundError
50
+ When there is no file at the path, the numdaplot error that is also the Python one.
51
+
52
+ Examples
53
+ --------
54
+ >>> import numdaplot as ndp
55
+ >>> from pathlib import Path
56
+ >>> from numdaplot.tables.files.file_paths import require_existing_file
57
+ >>> try:
58
+ ... require_existing_file(Path("missing.csv"))
59
+ ... except ndp.FileNotFoundError as error:
60
+ ... print(error)
61
+ No file found at missing.csv.
62
+ """
63
+ is_file = path.is_file()
64
+ if not is_file:
65
+ path_text = str(path)
66
+ raise FileNotFoundError(path_text)
67
+
68
+
69
+ def require_free_path(path: Path, on_conflict: Conflict) -> None:
70
+ """
71
+ Check that a file can be written at a path.
72
+
73
+ .. versionadded:: 0.1.0
74
+
75
+ Parameters
76
+ ----------
77
+ path
78
+ The path of the file to write.
79
+ on_conflict
80
+ ``ERROR`` refuses to overwrite an existing file, ``REPLACE`` allows it.
81
+
82
+ Raises
83
+ ------
84
+ FileExistsError
85
+ When a file exists at the path and ``on_conflict`` is ``ERROR``.
86
+
87
+ Examples
88
+ --------
89
+ >>> import tempfile
90
+ >>> from pathlib import Path
91
+ >>> import numdaplot as ndp
92
+ >>> from numdaplot.tables.files.file_paths import require_free_path
93
+ >>> with tempfile.NamedTemporaryFile(suffix=".csv") as file:
94
+ ... path = Path(file.name)
95
+ ... require_free_path(path, ndp.Conflict.REPLACE)
96
+ ... try:
97
+ ... require_free_path(path, ndp.Conflict.ERROR)
98
+ ... except ndp.FileExistsError:
99
+ ... print("refused")
100
+ refused
101
+ """
102
+ file_exists = path.exists()
103
+ refuses_existing_file = file_exists and on_conflict == Conflict.ERROR
104
+ if refuses_existing_file:
105
+ path_text = str(path)
106
+ raise FileExistsError(path_text)
@@ -0,0 +1,387 @@
1
+ """
2
+ Exact writing of the decimal columns of a Table in a JSON file.
3
+
4
+ pandas writes decimals with 10 digits after the point at most, which changes values such as ``1 / 3``.
5
+
6
+ .. versionadded:: 0.1.0
7
+ """
8
+
9
+ import json
10
+ from typing import Any, cast
11
+
12
+ import numpy
13
+ import pandas
14
+ from numpy.typing import NDArray
15
+
16
+ from numdaplot.data_types.numpy_mapping import from_numpy_dtype
17
+ from numdaplot.errors.value_conversion_error import ValueConversionError
18
+ from numdaplot.tables.frames.column import Column
19
+ from numdaplot.tables.frames.named_column_errors import NamedColumnErrors
20
+
21
+ DECIMAL_KIND = "f"
22
+ DOUBLE_DTYPE = numpy.dtype(numpy.float64)
23
+ JSON_FORMAT_NAME = "JSON"
24
+ JSON_NULL = "null"
25
+ NAN_TEXT = "nan"
26
+ DECIMAL_FORMAT = "%.{decimals}f"
27
+ CELL_SEPARATOR = ":"
28
+ CELL_JOINER = ","
29
+ OBJECT_START = "{"
30
+ OBJECT_END = "}"
31
+ LINE_END = "\n"
32
+ RECORDS_ORIENTATION = "records"
33
+ ISO_DATE_FORMAT = "iso"
34
+ FIRST_CHARACTER_AFTER_BRACE = 1
35
+ LAST_CHARACTER_BEFORE_BRACE = -1
36
+
37
+
38
+ def is_decimal_column(column: Column) -> bool:
39
+ """
40
+ Return whether a column holds decimals, stored by pandas with or without missing values.
41
+
42
+ .. versionadded:: 0.1.0
43
+
44
+ Parameters
45
+ ----------
46
+ column
47
+ A column.
48
+
49
+ Returns
50
+ -------
51
+ bool
52
+ True for a column of 32 or 64 bit decimals.
53
+
54
+ Examples
55
+ --------
56
+ >>> import pandas
57
+ >>> from numdaplot.tables.files.json_decimals import is_decimal_column
58
+ >>> is_decimal_column(pandas.Series([1.5], dtype="Float64")), is_decimal_column(pandas.Series([1]))
59
+ (True, False)
60
+ """
61
+ is_decimal = column.dtype.kind == DECIMAL_KIND
62
+
63
+ return is_decimal
64
+
65
+
66
+ def read_decimals(column: Column) -> NDArray[Any]:
67
+ """
68
+ Return the decimals of a column, in their number of bits, NaN for a missing value.
69
+
70
+ .. versionadded:: 0.1.0
71
+
72
+ Parameters
73
+ ----------
74
+ column
75
+ A decimal column.
76
+
77
+ Returns
78
+ -------
79
+ NDArray
80
+ The values.
81
+
82
+ Examples
83
+ --------
84
+ >>> import pandas
85
+ >>> from numdaplot.tables.files.json_decimals import read_decimals
86
+ >>> read_decimals(pandas.Series([1.5, None], dtype="Float32"))
87
+ array([1.5, nan], dtype=float32)
88
+ """
89
+ dtype_name = str(column.dtype)
90
+ numpy_dtype = numpy.dtype(dtype_name.lower())
91
+ values = column.to_numpy(dtype=numpy_dtype, na_value=numpy.nan)
92
+
93
+ return values
94
+
95
+
96
+ def has_decimal_column(frame: pandas.DataFrame) -> bool:
97
+ """
98
+ Return whether a frame holds a column of decimals.
99
+
100
+ .. versionadded:: 0.1.0
101
+
102
+ Parameters
103
+ ----------
104
+ frame
105
+ The columns of a Table.
106
+
107
+ Returns
108
+ -------
109
+ bool
110
+ True when at least one column holds decimals.
111
+
112
+ Examples
113
+ --------
114
+ >>> import pandas
115
+ >>> from numdaplot.tables.files.json_decimals import has_decimal_column
116
+ >>> has_decimal_column(pandas.DataFrame({"count": [1], "price": [1.5]}))
117
+ True
118
+ """
119
+ column_names = list[str](frame.columns)
120
+
121
+ for column_name in column_names:
122
+ column = frame[column_name]
123
+ is_decimal = is_decimal_column(column)
124
+ if is_decimal:
125
+ return True
126
+
127
+ return False
128
+
129
+
130
+ def require_finite_values(values: NDArray[Any]) -> None:
131
+ """
132
+ Check that decimals hold no infinite value, which JSON cannot write.
133
+
134
+ .. versionadded:: 0.1.0
135
+
136
+ Parameters
137
+ ----------
138
+ values
139
+ The decimals, NaN for a missing value.
140
+
141
+ Raises
142
+ ------
143
+ ValueConversionError
144
+ At the first infinite value.
145
+
146
+ Examples
147
+ --------
148
+ >>> import numpy
149
+ >>> import numdaplot as ndp
150
+ >>> from numdaplot.tables.files.json_decimals import require_finite_values
151
+ >>> try:
152
+ ... require_finite_values(numpy.array([1.5, numpy.inf]))
153
+ ... except ndp.ValueConversionError as error:
154
+ ... print(error)
155
+ Cannot store the FLOAT64 value inf as JSON without losing information.
156
+ """
157
+ is_infinite = numpy.isinf(values)
158
+ has_infinite = bool(is_infinite.any())
159
+ if not has_infinite:
160
+ return
161
+
162
+ infinite_values = values[is_infinite]
163
+ first_infinite = float(infinite_values[0])
164
+ column_type = from_numpy_dtype(values.dtype)
165
+ raise ValueConversionError(column_type.name, JSON_FORMAT_NAME, first_infinite)
166
+
167
+
168
+ def write_shortest_texts(values: NDArray[Any]) -> list[str]:
169
+ """
170
+ Return decimals as the shortest texts giving the same values in their number of bits.
171
+
172
+ .. versionadded:: 0.1.0
173
+
174
+ Parameters
175
+ ----------
176
+ values
177
+ The finite decimals, NaN for a missing value.
178
+
179
+ Returns
180
+ -------
181
+ list[str]
182
+ One JSON number per value, ``null`` for a missing value.
183
+
184
+ Examples
185
+ --------
186
+ >>> import numpy
187
+ >>> from numdaplot.tables.files.json_decimals import write_shortest_texts
188
+ >>> write_shortest_texts(numpy.array([1 / 3, numpy.nan]))
189
+ ['0.3333333333333333', 'null']
190
+ >>> write_shortest_texts(numpy.array([0.1], dtype="float32"))
191
+ ['0.1']
192
+ """
193
+ if values.dtype == DOUBLE_DTYPE:
194
+ python_values = cast(list[float], values.tolist())
195
+ texts = list(map(repr, python_values))
196
+ else:
197
+ # A Python float would write the value of a 32 bit decimal widened to 64 bits, such as 0.10000000149011612.
198
+ numpy_texts = values.astype(str)
199
+ texts = cast(list[str], numpy_texts.tolist())
200
+
201
+ missing_positions = numpy.flatnonzero(numpy.isnan(values))
202
+ for position in missing_positions:
203
+ missing_position = int(position)
204
+ texts[missing_position] = JSON_NULL
205
+
206
+ return texts
207
+
208
+
209
+ def write_rounded_texts(values: NDArray[Any], decimals: int) -> list[str]:
210
+ """
211
+ Return decimals rounded to a number of decimals, keeping their zeros as in a CSV file.
212
+
213
+ .. versionadded:: 0.1.0
214
+
215
+ Parameters
216
+ ----------
217
+ values
218
+ The finite decimals, NaN for a missing value.
219
+ decimals
220
+ The number of decimals.
221
+
222
+ Returns
223
+ -------
224
+ list[str]
225
+ One JSON number per value, ``null`` for a missing value.
226
+
227
+ Examples
228
+ --------
229
+ >>> import numpy
230
+ >>> from numdaplot.tables.files.json_decimals import write_rounded_texts
231
+ >>> write_rounded_texts(numpy.array([1.5, numpy.nan]), 2)
232
+ ['1.50', 'null']
233
+ """
234
+ decimal_format = DECIMAL_FORMAT.format(decimals=decimals)
235
+ python_values = cast(list[float], values.tolist())
236
+ rounded_texts = [JSON_NULL if value != value else decimal_format % value for value in python_values]
237
+
238
+ return rounded_texts
239
+
240
+
241
+ def write_decimal_cells(column: Column, column_name: str, decimals: int | None) -> list[str]:
242
+ """
243
+ Return the name and the value of a decimal column, as they appear in each object of a JSON file.
244
+
245
+ .. versionadded:: 0.1.0
246
+
247
+ Parameters
248
+ ----------
249
+ column
250
+ A decimal column.
251
+ column_name
252
+ The name of the column.
253
+ decimals
254
+ The number of decimals written, every digit of each value when ``None``.
255
+
256
+ Returns
257
+ -------
258
+ list[str]
259
+ One text per row.
260
+
261
+ Raises
262
+ ------
263
+ ValueConversionError
264
+ At the first infinite value.
265
+
266
+ Examples
267
+ --------
268
+ >>> import pandas
269
+ >>> from numdaplot.tables.files.json_decimals import write_decimal_cells
270
+ >>> write_decimal_cells(pandas.Series([0.1 + 0.2]), "price", None)
271
+ ['"price":0.30000000000000004']
272
+ """
273
+ values = read_decimals(column)
274
+ with NamedColumnErrors(column):
275
+ require_finite_values(values)
276
+
277
+ if decimals is None:
278
+ value_texts = write_shortest_texts(values)
279
+ else:
280
+ value_texts = write_rounded_texts(values, decimals)
281
+
282
+ name_text = json.dumps(column_name, ensure_ascii=False)
283
+ cell_start = name_text + CELL_SEPARATOR
284
+ cells = [cell_start + value_text for value_text in value_texts]
285
+
286
+ return cells
287
+
288
+
289
+ def write_other_cells(frame: pandas.DataFrame) -> list[str]:
290
+ """
291
+ Return the names and the values of columns without decimals, as they appear in each object of a JSON file.
292
+
293
+ .. versionadded:: 0.1.0
294
+
295
+ Parameters
296
+ ----------
297
+ frame
298
+ Columns without decimals.
299
+
300
+ Returns
301
+ -------
302
+ list[str]
303
+ One text per row, written by pandas: ``null``, ISO 8601 dates and durations.
304
+
305
+ Examples
306
+ --------
307
+ >>> import pandas
308
+ >>> from numdaplot.tables.files.json_decimals import write_other_cells
309
+ >>> write_other_cells(pandas.DataFrame({"city": ["Paris", None], "count": [1, 2]}))
310
+ ['"city":"Paris","count":1', '"city":null,"count":2']
311
+ """
312
+ # Some versions of the pandas stubs leave the parameter types of to_json unknown.
313
+ json_frame = cast(Any, frame)
314
+ lines_text = cast(
315
+ str,
316
+ json_frame.to_json(orient=RECORDS_ORIENTATION, lines=True, force_ascii=False, date_format=ISO_DATE_FORMAT),
317
+ )
318
+ stripped_text = lines_text.removesuffix(LINE_END)
319
+ # JSON writes a line break inside a text as an escape, so each line is one object.
320
+ lines = stripped_text.split(LINE_END)
321
+ cells = [line[FIRST_CHARACTER_AFTER_BRACE:LAST_CHARACTER_BEFORE_BRACE] for line in lines]
322
+
323
+ return cells
324
+
325
+
326
+ def write_exact_objects(frame: pandas.DataFrame, decimals: int | None) -> list[str]:
327
+ """
328
+ Return one JSON object per row, the columns staying in their order.
329
+
330
+ Neighbor columns without decimals are written together by pandas, which is much faster than one by one.
331
+
332
+ .. versionadded:: 0.1.0
333
+
334
+ Parameters
335
+ ----------
336
+ frame
337
+ The columns of a Table, at least one holding decimals.
338
+ decimals
339
+ The number of decimals written, every digit of each value when ``None``.
340
+
341
+ Returns
342
+ -------
343
+ list[str]
344
+ One object per row.
345
+
346
+ Raises
347
+ ------
348
+ ValueConversionError
349
+ At the first infinite value.
350
+
351
+ Examples
352
+ --------
353
+ >>> import pandas
354
+ >>> from numdaplot.tables.files.json_decimals import write_exact_objects
355
+ >>> write_exact_objects(pandas.DataFrame({"city": ["Paris"], "price": [1 / 3]}), None)
356
+ ['{"city":"Paris","price":0.3333333333333333}']
357
+ """
358
+ if frame.empty:
359
+ return []
360
+
361
+ cell_groups = list[list[str]]()
362
+ other_names = list[str]()
363
+
364
+ for column_name in list[str](frame.columns):
365
+ column = frame[column_name]
366
+ is_decimal = is_decimal_column(column)
367
+ if not is_decimal:
368
+ other_names.append(column_name)
369
+ continue
370
+
371
+ if other_names != []:
372
+ other_cells = write_other_cells(frame[other_names])
373
+ cell_groups.append(other_cells)
374
+ other_names = list[str]()
375
+
376
+ decimal_cells = write_decimal_cells(column, column_name, decimals)
377
+ cell_groups.append(decimal_cells)
378
+
379
+ if other_names != []:
380
+ last_cells = write_other_cells(frame[other_names])
381
+ cell_groups.append(last_cells)
382
+
383
+ row_cells = zip(*cell_groups, strict=True)
384
+ rows = map(CELL_JOINER.join, row_cells)
385
+ objects = [OBJECT_START + row + OBJECT_END for row in rows]
386
+
387
+ return objects