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,354 @@
1
+ """
2
+ Rotation of the labels of the ``x`` and ``y`` values of a Plot.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ # The matplotlib stubs leave the keyword arguments of most drawing methods untyped.
8
+ # pyright: reportUnknownMemberType=false
9
+
10
+ from typing import Literal
11
+
12
+ from matplotlib.axes import Axes
13
+ from matplotlib.axis import Axis
14
+ from matplotlib.dates import ConciseDateFormatter
15
+ from matplotlib.ticker import ScalarFormatter
16
+
17
+ from numdaplot.plots.drawing.drawn_chart import DrawnChart
18
+ from numdaplot.plots.drawing.label_room import (
19
+ LABEL_GAP_RATIO,
20
+ find_current_length,
21
+ find_font_pixels,
22
+ find_tick_locations,
23
+ find_tick_room,
24
+ find_widest_label,
25
+ read_label_texts,
26
+ )
27
+ from numdaplot.plots.drawing.label_thinning import MINIMUM_TICKS, thin_labels
28
+ from numdaplot.plots.drawing.position_axis import find_axis
29
+
30
+ TEXT_ROTATION = 45.0
31
+ NO_ROTATION = 0.0
32
+ ANCHOR_ROTATION_MODE = "anchor"
33
+ MINUS_SIGN = "\N{MINUS SIGN}"
34
+ HYPHEN_MINUS = "-"
35
+
36
+
37
+ def rotate_x_labels(axes: Axes, drawn_chart: DrawnChart, rotation: float | None) -> None:
38
+ """
39
+ Rotate the labels of the ``x`` values, wherever the chart places them, keeping those that stay readable.
40
+
41
+ .. versionadded:: 0.1.0
42
+
43
+ Parameters
44
+ ----------
45
+ axes
46
+ The matplotlib axes of the Plot.
47
+ drawn_chart
48
+ Which axis holds the ``x`` values.
49
+ rotation
50
+ The angle in degrees. When None, 45 degrees for texts, moments and numbers without enough room, and no
51
+ rotation for other numbers and for labels on the vertical axis.
52
+
53
+ Warns
54
+ -----
55
+ ReadabilityWarning
56
+ When labels left out may be texts.
57
+
58
+ Examples
59
+ --------
60
+ >>> from matplotlib.figure import Figure
61
+ >>> from numdaplot.plots.drawing.drawn_chart import DrawnChart
62
+ >>> from numdaplot.plots.drawing.grid_axes import GridAxes
63
+ >>> from numdaplot.plots.drawing.tick_rotation import rotate_x_labels
64
+ >>> axes = Figure().add_subplot()
65
+ >>> axes.xaxis.set_ticks([0.0, 1.0], ["Paris", "Lyon"]) # doctest: +ELLIPSIS
66
+ [...]
67
+ >>> rotate_x_labels(axes, DrawnChart(None, None, False, GridAxes.NONE, None), None)
68
+ >>> axes.get_xticklabels()[0].get_rotation()
69
+ 45.0
70
+ """
71
+ if drawn_chart.x_on_vertical_axis:
72
+ vertical_rotation = NO_ROTATION if rotation is None else rotation
73
+ thin_labels(axes.yaxis, True, vertical_rotation)
74
+ apply_rotation(axes, True, vertical_rotation)
75
+ return
76
+
77
+ horizontal_rotation = choose_rotation(axes.xaxis, rotation)
78
+ thin_labels(axes.xaxis, False, horizontal_rotation)
79
+ apply_rotation(axes, False, horizontal_rotation)
80
+
81
+
82
+ def rotate_y_labels(axes: Axes, drawn_chart: DrawnChart, rotation: float | None) -> None:
83
+ """
84
+ Rotate the labels of the ``y`` values, wherever the chart places them, keeping those that stay readable.
85
+
86
+ .. versionadded:: 0.1.0
87
+
88
+ Parameters
89
+ ----------
90
+ axes
91
+ The matplotlib axes of the Plot.
92
+ drawn_chart
93
+ Which axis holds the ``x`` values: the ``y`` values are on the other one.
94
+ rotation
95
+ The angle in degrees. When None, the labels stay horizontal.
96
+
97
+ Warns
98
+ -----
99
+ ReadabilityWarning
100
+ When labels left out may be texts.
101
+
102
+ Examples
103
+ --------
104
+ >>> from matplotlib.figure import Figure
105
+ >>> from numdaplot.plots.drawing.drawn_chart import DrawnChart
106
+ >>> from numdaplot.plots.drawing.grid_axes import GridAxes
107
+ >>> from numdaplot.plots.drawing.tick_rotation import rotate_y_labels
108
+ >>> axes = Figure().add_subplot()
109
+ >>> rotate_y_labels(axes, DrawnChart(None, None, False, GridAxes.NONE, None), 30.0)
110
+ >>> axes.get_yticklabels()[0].get_rotation()
111
+ 30.0
112
+ """
113
+ y_on_vertical_axis = not drawn_chart.x_on_vertical_axis
114
+ y_axis = find_axis(axes, y_on_vertical_axis)
115
+ thinning_rotation = NO_ROTATION if rotation is None else rotation
116
+ thin_labels(y_axis, y_on_vertical_axis, thinning_rotation)
117
+ if rotation is None:
118
+ return
119
+
120
+ apply_rotation(axes, y_on_vertical_axis, rotation)
121
+
122
+
123
+ def apply_rotation(axes: Axes, on_vertical_axis: bool, rotation: float) -> None:
124
+ """
125
+ Rotate the labels of an axis around their end closest to the axis.
126
+
127
+ .. versionadded:: 0.1.0
128
+
129
+ Parameters
130
+ ----------
131
+ axes
132
+ The matplotlib axes of the Plot.
133
+ on_vertical_axis
134
+ True for the vertical axis, whose labels already end at their tick.
135
+ rotation
136
+ The angle in degrees.
137
+
138
+ Examples
139
+ --------
140
+ >>> from matplotlib.figure import Figure
141
+ >>> from numdaplot.plots.drawing.tick_rotation import apply_rotation
142
+ >>> axes = Figure().add_subplot()
143
+ >>> apply_rotation(axes, False, 45.0)
144
+ >>> axes.get_xticklabels()[0].get_horizontalalignment()
145
+ 'right'
146
+ """
147
+ axis = find_axis(axes, on_vertical_axis)
148
+ axis.set_tick_params(labelrotation=rotation)
149
+ alignment = choose_alignment(rotation)
150
+
151
+ for label in axis.get_ticklabels():
152
+ label.set_rotation_mode(ANCHOR_ROTATION_MODE)
153
+ if not on_vertical_axis:
154
+ label.set_horizontalalignment(alignment)
155
+
156
+
157
+ def choose_rotation(axis: Axis, rotation: float | None) -> float:
158
+ """
159
+ Return the angle of the labels of a horizontal axis.
160
+
161
+ .. versionadded:: 0.1.0
162
+
163
+ Parameters
164
+ ----------
165
+ axis
166
+ The horizontal axis, with its ticks.
167
+ rotation
168
+ The angle chosen in degrees, or None.
169
+
170
+ Returns
171
+ -------
172
+ float
173
+ The angle chosen, else 45 degrees for texts, moments and numbers without enough room, and no rotation for
174
+ other numbers.
175
+
176
+ Examples
177
+ --------
178
+ >>> from matplotlib.figure import Figure
179
+ >>> from numdaplot.plots.drawing.tick_rotation import choose_rotation
180
+ >>> axes = Figure().add_subplot()
181
+ >>> choose_rotation(axes.xaxis, None), choose_rotation(axes.xaxis, 30.0)
182
+ (0.0, 30.0)
183
+ """
184
+ if rotation is not None:
185
+ return rotation
186
+
187
+ has_text = has_text_labels(axis)
188
+ if has_text:
189
+ return TEXT_ROTATION
190
+
191
+ labels_touch = do_labels_touch(axis)
192
+ if labels_touch:
193
+ return TEXT_ROTATION
194
+
195
+ return NO_ROTATION
196
+
197
+
198
+ def do_labels_touch(axis: Axis) -> bool:
199
+ """
200
+ Return whether horizontal labels fixed on each tick of a horizontal axis leave too little room between them.
201
+
202
+ The axes do not have their final width yet. Their current width is a little lower, which makes the answer prudent.
203
+
204
+ .. versionadded:: 0.1.0
205
+
206
+ Parameters
207
+ ----------
208
+ axis
209
+ The horizontal axis, with its ticks.
210
+
211
+ Returns
212
+ -------
213
+ bool
214
+ True when the widest label and a gap of half its font size exceed the room between the closest ticks. Labels
215
+ chosen by matplotlib according to the room, such as those of a line chart, never touch.
216
+
217
+ Examples
218
+ --------
219
+ >>> from matplotlib.figure import Figure
220
+ >>> from numdaplot.plots.drawing.tick_rotation import do_labels_touch
221
+ >>> axes = Figure().add_subplot()
222
+ >>> years = [float(year) for year in range(24)]
223
+ >>> axes.xaxis.set_ticks(years, [str(2000 + year) for year in range(24)]) # doctest: +ELLIPSIS
224
+ [...]
225
+ >>> do_labels_touch(axes.xaxis)
226
+ True
227
+ """
228
+ formatter = axis.get_major_formatter()
229
+ if isinstance(formatter, ScalarFormatter):
230
+ return False
231
+
232
+ tick_locations = find_tick_locations(axis)
233
+ tick_count = len(tick_locations)
234
+ if tick_count < MINIMUM_TICKS:
235
+ return False
236
+
237
+ current_length = find_current_length(axis, False)
238
+ room = find_tick_room(axis, False, current_length)
239
+ widest_label = find_widest_label(axis)
240
+ font_pixels = find_font_pixels(axis)
241
+ needed_room = widest_label + font_pixels * LABEL_GAP_RATIO
242
+ labels_touch = bool(needed_room > room)
243
+
244
+ return labels_touch
245
+
246
+
247
+ def has_text_labels(axis: Axis) -> bool:
248
+ """
249
+ Return whether the labels of an axis are moments, or texts that are not all numbers.
250
+
251
+ Numbers can be written as texts, such as the years or the row numbers below bars: they stay numbers.
252
+
253
+ .. versionadded:: 0.1.0
254
+
255
+ Parameters
256
+ ----------
257
+ axis
258
+ An axis, with its ticks.
259
+
260
+ Returns
261
+ -------
262
+ bool
263
+ True when at least one label is not a number. An axis without label holds no text.
264
+
265
+ Examples
266
+ --------
267
+ >>> from matplotlib.figure import Figure
268
+ >>> from numdaplot.plots.drawing.tick_rotation import has_text_labels
269
+ >>> axes = Figure().add_subplot()
270
+ >>> axes.xaxis.set_ticks([0.0, 1.0], ["2025", "2026"]) # doctest: +ELLIPSIS
271
+ [...]
272
+ >>> has_text_labels(axes.xaxis)
273
+ False
274
+ """
275
+ formatter = axis.get_major_formatter()
276
+ if isinstance(formatter, ScalarFormatter):
277
+ return False
278
+
279
+ if isinstance(formatter, ConciseDateFormatter):
280
+ return True
281
+
282
+ label_texts = read_label_texts(axis)
283
+
284
+ for label_text in label_texts:
285
+ is_number = is_number_text(label_text)
286
+ if not is_number:
287
+ return True
288
+
289
+ return False
290
+
291
+
292
+ def is_number_text(text: str) -> bool:
293
+ """
294
+ Return whether a label is a number, as matplotlib or numdaplot writes it.
295
+
296
+ .. versionadded:: 0.1.0
297
+
298
+ Parameters
299
+ ----------
300
+ text
301
+ The text of a label.
302
+
303
+ Returns
304
+ -------
305
+ bool
306
+ True for a number, with the minus sign matplotlib writes, or for an empty label.
307
+
308
+ Examples
309
+ --------
310
+ >>> from numdaplot.plots.drawing.tick_rotation import is_number_text
311
+ >>> is_number_text("2025"), is_number_text("-1.5"), is_number_text("Paris")
312
+ (True, True, False)
313
+ """
314
+ if text == "":
315
+ return True
316
+
317
+ python_text = text.replace(MINUS_SIGN, HYPHEN_MINUS)
318
+ try:
319
+ float(python_text)
320
+ except ValueError:
321
+ return False
322
+
323
+ return True
324
+
325
+
326
+ def choose_alignment(rotation: float) -> Literal["left", "center", "right"]:
327
+ """
328
+ Return the side of a rotated label that stays under its tick.
329
+
330
+ .. versionadded:: 0.1.0
331
+
332
+ Parameters
333
+ ----------
334
+ rotation
335
+ The angle of the label in degrees.
336
+
337
+ Returns
338
+ -------
339
+ Literal["left", "center", "right"]
340
+ The end of the text for a positive angle, its start for a negative one, its middle without rotation.
341
+
342
+ Examples
343
+ --------
344
+ >>> from numdaplot.plots.drawing.tick_rotation import choose_alignment
345
+ >>> choose_alignment(45.0), choose_alignment(-45.0), choose_alignment(0.0)
346
+ ('right', 'left', 'center')
347
+ """
348
+ if rotation > NO_ROTATION:
349
+ return "right"
350
+
351
+ if rotation < NO_ROTATION:
352
+ return "left"
353
+
354
+ return "center"
@@ -0,0 +1,212 @@
1
+ """
2
+ Axes of times of day, counted in hours since midnight and labeled ``HH:MM``.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ import numpy
10
+ from matplotlib.axes import Axes
11
+ from matplotlib.axis import Axis
12
+ from matplotlib.ticker import FuncFormatter, MultipleLocator
13
+ from numpy.typing import NDArray
14
+
15
+ from numdaplot.data_types.type import Type
16
+ from numdaplot.data_types.value_family import ValueFamily, find_family
17
+ from numdaplot.plots.chart_layer import ChartLayer
18
+ from numdaplot.plots.data.chart_values import ChartValues
19
+
20
+ MINUTES_PER_HOUR = 60
21
+ MINUTES_PER_DAY = 1440
22
+ OUTSIDE_DAY_LABEL = ""
23
+ HOUR_LABEL = "{hour:02d}:{minute:02d}"
24
+ # The step between two labels, in hours, for the widest span of times it fits, in hours.
25
+ HOUR_STEPS = ((1.0, 0.25), (3.0, 0.5), (6.0, 1.0), (12.0, 2.0))
26
+ LONGEST_HOUR_STEP = 3.0
27
+
28
+
29
+ def format_hour(hours: float, _position: object = None) -> str:
30
+ """
31
+ Return a number of hours since midnight as ``HH:MM``, rounded to the minute.
32
+
33
+ The ticks that the margins of an axis place before 00:00 or after 24:00 are left without label.
34
+
35
+ .. versionadded:: 0.1.0
36
+
37
+ Parameters
38
+ ----------
39
+ hours
40
+ The hours since midnight, such as 15.5.
41
+ _position
42
+ The position of the label, given by matplotlib and not used.
43
+
44
+ Returns
45
+ -------
46
+ str
47
+ The time, such as ``15:30``, or an empty text outside 00:00 to 24:00.
48
+
49
+ Examples
50
+ --------
51
+ >>> from numdaplot.plots.drawing.time_axis import format_hour
52
+ >>> format_hour(15.5), format_hour(0.0), format_hour(24.0), format_hour(-3.0)
53
+ ('15:30', '00:00', '24:00', '')
54
+ """
55
+ minutes = hours * MINUTES_PER_HOUR
56
+ whole_minutes = round(minutes)
57
+ is_outside_day = whole_minutes < 0 or whole_minutes > MINUTES_PER_DAY
58
+ if is_outside_day:
59
+ return OUTSIDE_DAY_LABEL
60
+
61
+ hour, minute = divmod(whole_minutes, MINUTES_PER_HOUR)
62
+ hour_label = HOUR_LABEL.format(hour=hour, minute=minute)
63
+
64
+ return hour_label
65
+
66
+
67
+ def choose_hour_step(hours: NDArray[numpy.float64]) -> float:
68
+ """
69
+ Return the step between two labels of an axis of times, from the span of the times.
70
+
71
+ .. versionadded:: 0.1.0
72
+
73
+ Parameters
74
+ ----------
75
+ hours
76
+ The hours since midnight shown on the axis, NaN where missing.
77
+
78
+ Returns
79
+ -------
80
+ float
81
+ A quarter of an hour for an hour or less, then half an hour, one, two or three hours.
82
+
83
+ Examples
84
+ --------
85
+ >>> import numpy
86
+ >>> from numdaplot.plots.drawing.time_axis import choose_hour_step
87
+ >>> choose_hour_step(numpy.array([8.0, 23.0])), choose_hour_step(numpy.array([8.0, 8.5]))
88
+ (3.0, 0.25)
89
+ """
90
+ present_hours = hours[~numpy.isnan(hours)]
91
+ if present_hours.size == 0:
92
+ return LONGEST_HOUR_STEP
93
+
94
+ earliest_hour = present_hours.min()
95
+ latest_hour = present_hours.max()
96
+ span = float(latest_hour - earliest_hour)
97
+ for widest_span, step in HOUR_STEPS:
98
+ if span <= widest_span:
99
+ return step
100
+
101
+ return LONGEST_HOUR_STEP
102
+
103
+
104
+ def place_hour_ticks(axis: Axis, hours: NDArray[Any]) -> None:
105
+ """
106
+ Place labels ``HH:MM`` on an axis counted in hours since midnight, at a regular step.
107
+
108
+ .. versionadded:: 0.1.0
109
+
110
+ Parameters
111
+ ----------
112
+ axis
113
+ A matplotlib axis.
114
+ hours
115
+ The hours since midnight shown on the axis.
116
+
117
+ Examples
118
+ --------
119
+ >>> import numpy
120
+ >>> from matplotlib.figure import Figure
121
+ >>> from numdaplot.plots.drawing.time_axis import place_hour_ticks
122
+ >>> axes = Figure().add_subplot()
123
+ >>> _ = axes.plot([8.0, 14.0], [1.0, 2.0])
124
+ >>> place_hour_ticks(axes.xaxis, numpy.array([8.0, 14.0]))
125
+ >>> axes.figure.canvas.draw()
126
+ >>> [label.get_text() for label in axes.get_xticklabels()][1:4]
127
+ ['08:00', '09:00', '10:00']
128
+ """
129
+ step = choose_hour_step(hours)
130
+ locator = MultipleLocator(step)
131
+ formatter = FuncFormatter(format_hour)
132
+ axis.set_major_locator(locator)
133
+ axis.set_major_formatter(formatter)
134
+
135
+
136
+ def measures_times(value_type: Type) -> bool:
137
+ """
138
+ Return whether the values of a chart are times of day, drawn on an axis labeled ``HH:MM``.
139
+
140
+ .. versionadded:: 0.1.0
141
+
142
+ Parameters
143
+ ----------
144
+ value_type
145
+ The type of the values of the chart.
146
+
147
+ Returns
148
+ -------
149
+ bool
150
+ True for ``TIME``.
151
+
152
+ Examples
153
+ --------
154
+ >>> import numdaplot as ndp
155
+ >>> from numdaplot.plots.drawing.time_axis import measures_times
156
+ >>> measures_times(ndp.Type.TIME), measures_times(ndp.Type.FLOAT64)
157
+ (True, False)
158
+ """
159
+ value_family = find_family(value_type)
160
+ is_time = value_family == ValueFamily.TIME
161
+
162
+ return is_time
163
+
164
+
165
+ def place_value_hours(axes: Axes, layers: list[ChartLayer]) -> None:
166
+ """
167
+ Label ``HH:MM`` the vertical axis of the lines and points measuring times of day, from all their values.
168
+
169
+ Histograms and boxes, which are drawn alone, label their own axis of values.
170
+
171
+ .. versionadded:: 0.1.0
172
+
173
+ Parameters
174
+ ----------
175
+ axes
176
+ The matplotlib axes the charts are drawn on.
177
+ layers
178
+ The charts drawn on these axes and their values.
179
+
180
+ Examples
181
+ --------
182
+ >>> from datetime import time
183
+ >>> from matplotlib.figure import Figure
184
+ >>> import numdaplot as ndp
185
+ >>> from numdaplot.plots.chart_layer import ChartLayer
186
+ >>> from numdaplot.plots.data.array_values import read_array_values
187
+ >>> from numdaplot.plots.drawing.time_axis import place_value_hours
188
+ >>> hours = ndp.Array.from_list([time(8), time(14)])
189
+ >>> axes = Figure().add_subplot()
190
+ >>> place_value_hours(axes, [ChartLayer(ndp.LineChart(), read_array_values(hours, "LineChart"))])
191
+ >>> axes.yaxis.get_major_formatter()(8.5)
192
+ '08:30'
193
+ """
194
+ hour_series = list[NDArray[numpy.float64]]()
195
+
196
+ for layer in layers:
197
+ values = layer.values
198
+ if not isinstance(values, ChartValues):
199
+ continue
200
+
201
+ is_time = measures_times(values.value_type)
202
+ if not is_time:
203
+ continue
204
+
205
+ for series in values.series:
206
+ hour_series.append(series.values)
207
+
208
+ if hour_series == []:
209
+ return
210
+
211
+ hours = numpy.concatenate(hour_series)
212
+ place_hour_ticks(axes.yaxis, hours)
@@ -0,0 +1,72 @@
1
+ """
2
+ Ticks of an axis holding whole numbers only.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ import numpy
8
+ from matplotlib.axis import Axis
9
+ from matplotlib.ticker import MaxNLocator
10
+ from numpy.typing import NDArray
11
+
12
+
13
+ def has_only_whole_numbers(numbers: NDArray[numpy.float64]) -> bool:
14
+ """
15
+ Return whether every present number is a whole number.
16
+
17
+ .. versionadded:: 0.1.0
18
+
19
+ Parameters
20
+ ----------
21
+ numbers
22
+ float64 numbers, NaN where a value is missing.
23
+
24
+ Returns
25
+ -------
26
+ bool
27
+ True when no present number has a fraction, such as days or counts.
28
+
29
+ Examples
30
+ --------
31
+ >>> import numpy
32
+ >>> from numdaplot.plots.drawing.whole_numbers import has_only_whole_numbers
33
+ >>> has_only_whole_numbers(numpy.array([1.0, numpy.nan, 3.0]))
34
+ True
35
+ """
36
+ present = ~numpy.isnan(numbers)
37
+ present_numbers = numbers[present]
38
+ rounded_numbers = numpy.round(present_numbers)
39
+ is_whole = rounded_numbers == present_numbers
40
+ all_whole = bool(numpy.all(is_whole))
41
+
42
+ return all_whole
43
+
44
+
45
+ def place_whole_ticks(axis: Axis, numbers: NDArray[numpy.float64]) -> None:
46
+ """
47
+ Place the ticks of an axis on whole numbers only, when every number it shows is whole.
48
+
49
+ .. versionadded:: 0.1.0
50
+
51
+ Parameters
52
+ ----------
53
+ axis
54
+ A matplotlib axis.
55
+ numbers
56
+ The numbers shown along the axis.
57
+
58
+ Examples
59
+ --------
60
+ >>> import numpy
61
+ >>> from matplotlib.figure import Figure
62
+ >>> from numdaplot.plots.drawing.whole_numbers import place_whole_ticks
63
+ >>> axes = Figure().add_subplot()
64
+ >>> lines = axes.plot([1.0, 2.0], [5.0, 6.0])
65
+ >>> place_whole_ticks(axes.xaxis, numpy.array([1.0, 2.0]))
66
+ >>> all(float(tick).is_integer() for tick in axes.get_xticks())
67
+ True
68
+ """
69
+ all_whole = has_only_whole_numbers(numbers)
70
+ if all_whole:
71
+ whole_locator = MaxNLocator(integer=True)
72
+ axis.set_major_locator(whole_locator)
@@ -0,0 +1,5 @@
1
+ """
2
+ Figures placing several Plots on a grid of cells.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """