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,150 @@
1
+ """
2
+ A Plot placed in the grid of a Figure, and the checks of its place.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+
9
+ from numdaplot.errors.cell_out_of_range_error import CellOutOfRangeError
10
+ from numdaplot.errors.occupied_cell_error import OccupiedCellError
11
+ from numdaplot.plots.figure.cell import Cell
12
+ from numdaplot.plots.figure.layout import Layout
13
+ from numdaplot.plots.plot import Plot
14
+
15
+
16
+ @dataclass(frozen=True, eq=False)
17
+ class Placement:
18
+ """
19
+ A Plot and the cells it covers in a Figure.
20
+
21
+ .. versionadded:: 0.1.0
22
+
23
+ Parameters
24
+ ----------
25
+ plot
26
+ The Plot placed.
27
+ cell
28
+ Its first cell and the number of cells it spans.
29
+
30
+ Examples
31
+ --------
32
+ >>> import numdaplot as ndp
33
+ >>> from numdaplot.plots.figure.placement import Placement
34
+ >>> plot = ndp.Plot.line(ndp.Array.from_list([12.0, 15.5]))
35
+ >>> Placement(plot, ndp.Cell(row=0, column=1)).cell.column
36
+ 1
37
+ """
38
+
39
+ plot: Plot
40
+ cell: Cell
41
+
42
+
43
+ def require_cell_inside(cell: Cell, layout: Layout) -> None:
44
+ """
45
+ Check that every cell a Plot covers is inside the grid of a Figure.
46
+
47
+ .. versionadded:: 0.1.0
48
+
49
+ Parameters
50
+ ----------
51
+ cell
52
+ The first cell and the spans of the Plot.
53
+ layout
54
+ The grid of the Figure.
55
+
56
+ Raises
57
+ ------
58
+ CellOutOfRangeError
59
+ When a cell it spans is after the last row or column. ``Cell`` already refuses a negative row or column.
60
+
61
+ Examples
62
+ --------
63
+ >>> import numdaplot as ndp
64
+ >>> from numdaplot.plots.figure.placement import require_cell_inside
65
+ >>> try:
66
+ ... require_cell_inside(ndp.Cell(row=1, column=0, column_span=3), ndp.Layout(rows=2, columns=2))
67
+ ... except ndp.CellOutOfRangeError as error:
68
+ ... print(error)
69
+ Cell (1, 0) is outside a Layout of 2 rows and 2 columns.
70
+ """
71
+ row_end = cell.row + cell.row_span
72
+ column_end = cell.column + cell.column_span
73
+ is_outside = row_end > layout.rows or column_end > layout.columns
74
+ if is_outside:
75
+ raise CellOutOfRangeError(cell.row, cell.column, layout.rows, layout.columns)
76
+
77
+
78
+ def require_free_cells(cell: Cell, placements: list[Placement]) -> None:
79
+ """
80
+ Check that no cell a Plot covers already holds another Plot.
81
+
82
+ .. versionadded:: 0.1.0
83
+
84
+ Parameters
85
+ ----------
86
+ cell
87
+ The first cell and the spans of the Plot placed.
88
+ placements
89
+ The Plots already in the Figure.
90
+
91
+ Raises
92
+ ------
93
+ OccupiedCellError
94
+ At the first cell, row by row, already covered by another Plot.
95
+
96
+ Examples
97
+ --------
98
+ >>> import numdaplot as ndp
99
+ >>> from numdaplot.plots.figure.placement import Placement, require_free_cells
100
+ >>> plot = ndp.Plot.line(ndp.Array.from_list([12.0, 15.5]))
101
+ >>> wide_placement = Placement(plot, ndp.Cell(row=0, column=0, column_span=2))
102
+ >>> try:
103
+ ... require_free_cells(ndp.Cell(row=0, column=1), [wide_placement])
104
+ ... except ndp.OccupiedCellError as error:
105
+ ... print(error)
106
+ Cell (0, 1) already holds a Plot.
107
+ """
108
+ covered_cells = set[tuple[int, int]]()
109
+
110
+ for placement in placements:
111
+ placement_cells = list_covered_cells(placement.cell)
112
+ covered_cells.update(placement_cells)
113
+
114
+ new_cells = list_covered_cells(cell)
115
+
116
+ for row, column in new_cells:
117
+ if (row, column) in covered_cells:
118
+ raise OccupiedCellError(row, column)
119
+
120
+
121
+ def list_covered_cells(cell: Cell) -> list[tuple[int, int]]:
122
+ """
123
+ Return the row and the column of every cell a Plot covers, row by row.
124
+
125
+ .. versionadded:: 0.1.0
126
+
127
+ Parameters
128
+ ----------
129
+ cell
130
+ The first cell and the spans of the Plot.
131
+
132
+ Returns
133
+ -------
134
+ list[tuple[int, int]]
135
+ The covered cells.
136
+
137
+ Examples
138
+ --------
139
+ >>> import numdaplot as ndp
140
+ >>> from numdaplot.plots.figure.placement import list_covered_cells
141
+ >>> list_covered_cells(ndp.Cell(row=1, column=0, column_span=2))
142
+ [(1, 0), (1, 1)]
143
+ """
144
+ row_end = cell.row + cell.row_span
145
+ column_end = cell.column + cell.column_span
146
+ rows = range(cell.row, row_end)
147
+ columns = range(cell.column, column_end)
148
+ covered_cells = [(row, column) for row in rows for column in columns]
149
+
150
+ return covered_cells
@@ -0,0 +1,166 @@
1
+ """
2
+ Reading of the charts a Plot draws on its axes: lines, bars and points.
3
+
4
+ ``Plot.line``, ``Plot.bar`` and ``Plot.scatter`` read their first chart with these functions, and
5
+ ``Plot.add_line``, ``Plot.add_bar`` and ``Plot.add_scatter`` the charts they add.
6
+
7
+ .. versionadded:: 0.1.0
8
+ """
9
+
10
+ from numdaplot.arrays.array import Array
11
+ from numdaplot.plots.chart_layer import ChartLayer
12
+ from numdaplot.plots.charts.bar_chart import BarChart
13
+ from numdaplot.plots.charts.line_chart import LineChart
14
+ from numdaplot.plots.charts.scatter_chart import ScatterChart
15
+ from numdaplot.plots.data.array_values import read_array_values
16
+ from numdaplot.plots.data.chart_data import read_chart_values, require_column_setting, require_no_column_settings
17
+ from numdaplot.plots.data.point_values import hide_missing_points, read_point_values, require_scale_on_numbers
18
+ from numdaplot.plots.data.table_values import read_table_values
19
+ from numdaplot.plots.drawing.series_colors import require_color_count
20
+ from numdaplot.tables.table import Table
21
+
22
+ LINE_NAME = "LineChart"
23
+ BAR_NAME = "BarChart"
24
+ SCATTER_NAME = "ScatterChart"
25
+ X_SETTING = "x"
26
+ Y_SETTING = "y"
27
+ COLOR_BY_SETTING = "color_by"
28
+ SIZE_BY_SETTING = "size_by"
29
+
30
+
31
+ def read_line_layer(data: Table | Array, chart: LineChart) -> ChartLayer:
32
+ """
33
+ Return a LineChart with the values it draws from a Table or an Array.
34
+
35
+ .. versionadded:: 0.1.0
36
+
37
+ Parameters
38
+ ----------
39
+ data
40
+ The Table or the Array drawn.
41
+ chart
42
+ The columns drawn and the look of the lines.
43
+
44
+ Returns
45
+ -------
46
+ ChartLayer
47
+ The chart and its values.
48
+
49
+ Raises
50
+ ------
51
+ InvalidChartDataError
52
+ When a Table has no ``y`` columns, or an Array has ``x`` or ``y`` columns.
53
+ InvalidColorCountError
54
+ When the colors of the chart are not one per line.
55
+
56
+ Examples
57
+ --------
58
+ >>> import numdaplot as ndp
59
+ >>> from numdaplot.plots.layer_reading import read_line_layer
60
+ >>> grid = ndp.Array.from_list([[1.0, 2.0], [3.0, 4.0]])
61
+ >>> len(read_line_layer(grid, ndp.LineChart()).values.series)
62
+ 2
63
+ """
64
+ values = read_chart_values(data, chart.x, chart.y, LINE_NAME)
65
+ series_count = len(values.series)
66
+ require_color_count(chart.colors, series_count)
67
+ layer = ChartLayer(chart, values)
68
+
69
+ return layer
70
+
71
+
72
+ def read_bar_layer(data: Table | Array, chart: BarChart) -> ChartLayer:
73
+ """
74
+ Return a BarChart with the values it draws from a Table or an Array.
75
+
76
+ .. versionadded:: 0.1.0
77
+
78
+ Parameters
79
+ ----------
80
+ data
81
+ The Table or the Array drawn.
82
+ chart
83
+ The columns drawn and the look of the bars.
84
+
85
+ Returns
86
+ -------
87
+ ChartLayer
88
+ The chart and its values.
89
+
90
+ Raises
91
+ ------
92
+ InvalidChartDataError
93
+ When a Table has no ``y`` columns, or an Array has ``x`` or ``y`` columns.
94
+ InvalidColorCountError
95
+ When the colors of the chart are not one per series.
96
+
97
+ Examples
98
+ --------
99
+ >>> import numdaplot as ndp
100
+ >>> from numdaplot.plots.layer_reading import read_bar_layer
101
+ >>> prices = ndp.Array.from_list([12.0, 15.5])
102
+ >>> read_bar_layer(prices, ndp.BarChart()).values.series[0].values
103
+ array([12. , 15.5])
104
+ """
105
+ values = read_chart_values(data, chart.x, chart.y, BAR_NAME)
106
+ series_count = len(values.series)
107
+ require_color_count(chart.colors, series_count)
108
+ layer = ChartLayer(chart, values)
109
+
110
+ return layer
111
+
112
+
113
+ def read_scatter_layer(data: Table | Array, chart: ScatterChart) -> ChartLayer:
114
+ """
115
+ Return a ScatterChart with the values it draws from a Table or an Array.
116
+
117
+ .. versionadded:: 0.1.0
118
+
119
+ Parameters
120
+ ----------
121
+ data
122
+ The Table or the Array drawn.
123
+ chart
124
+ The columns drawn and the look of the points.
125
+
126
+ Returns
127
+ -------
128
+ ChartLayer
129
+ The chart, its values, and for a Table the values coloring and sizing its points.
130
+
131
+ Raises
132
+ ------
133
+ InvalidChartDataError
134
+ When a Table has no ``y`` column, or an Array has a column setting.
135
+ InvalidColorCountError
136
+ When ``color`` is given for an Array of several columns.
137
+
138
+ Examples
139
+ --------
140
+ >>> import numdaplot as ndp
141
+ >>> from numdaplot.plots.layer_reading import read_scatter_layer
142
+ >>> grid = ndp.Array.from_list([[1.0, 2.0], [3.0, 4.0]])
143
+ >>> len(read_scatter_layer(grid, ndp.ScatterChart()).values.series)
144
+ 2
145
+ """
146
+ if isinstance(data, Array):
147
+ column_settings = dict[str, object](
148
+ {X_SETTING: chart.x, Y_SETTING: chart.y, COLOR_BY_SETTING: chart.color_by, SIZE_BY_SETTING: chart.size_by}
149
+ )
150
+ require_no_column_settings(SCATTER_NAME, column_settings)
151
+ array_values = read_array_values(data, SCATTER_NAME)
152
+ series_count = len(array_values.series)
153
+ if chart.color is not None:
154
+ require_color_count([chart.color], series_count)
155
+
156
+ array_layer = ChartLayer(chart, array_values)
157
+ return array_layer
158
+
159
+ y_name = require_column_setting(SCATTER_NAME, Y_SETTING, chart.y)
160
+ table_values = read_table_values(data, chart.x, [y_name], SCATTER_NAME)
161
+ point_values = read_point_values(data, chart.color_by, chart.size_by, table_values.rows)
162
+ require_scale_on_numbers(chart.scale, point_values.colors)
163
+ shown_values = hide_missing_points(table_values, point_values)
164
+ table_layer = ChartLayer(chart, shown_values, point_values)
165
+
166
+ return table_layer
@@ -0,0 +1,5 @@
1
+ """
2
+ Image files and display of Plots.
3
+
4
+ .. versionadded:: 0.1.0
5
+ """
@@ -0,0 +1,187 @@
1
+ """
2
+ Image files 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 pathlib import Path
11
+
12
+ from matplotlib.figure import Figure
13
+
14
+ from numdaplot.errors.refused_setting_error import RefusedSettingError
15
+ from numdaplot.errors.unsupported_image_format_error import UnsupportedImageFormatError
16
+ from numdaplot.plots.drawing.plot_drawing import FigureDrawing, build_figure
17
+ from numdaplot.plots.style.image_options import DEFAULT_DPI, ImageOptions
18
+ from numdaplot.tables.conflict import Conflict
19
+ from numdaplot.tables.files.file_access import WRITE_OPERATION, FileAccessErrors
20
+ from numdaplot.tables.files.file_paths import FilePath, require_free_path
21
+
22
+ IMAGE_FORMATS = {".png": "png", ".svg": "svg", ".pdf": "pdf"}
23
+ RESOLUTION_EXTENSION = ".png"
24
+ OPTIONS_NAME = "ImageOptions"
25
+ IMAGE_OWNER = "A {extension} image"
26
+
27
+
28
+ def find_image_format(path: Path) -> str:
29
+ """
30
+ Return the image format named by the extension of a path.
31
+
32
+ .. versionadded:: 0.1.0
33
+
34
+ Parameters
35
+ ----------
36
+ path
37
+ The path of the image, ending with ``.png``, ``.svg`` or ``.pdf`` in lowercase or uppercase.
38
+
39
+ Returns
40
+ -------
41
+ str
42
+ The matplotlib name of the format: ``png``, ``svg`` or ``pdf``.
43
+
44
+ Raises
45
+ ------
46
+ UnsupportedImageFormatError
47
+ When the path has another extension or none.
48
+
49
+ Examples
50
+ --------
51
+ >>> from pathlib import Path
52
+ >>> from numdaplot.plots.output.image_saving import find_image_format
53
+ >>> find_image_format(Path("sales.SVG"))
54
+ 'svg'
55
+ """
56
+ extension = path.suffix.lower()
57
+ if extension not in IMAGE_FORMATS:
58
+ raise UnsupportedImageFormatError(path.suffix)
59
+
60
+ image_format = IMAGE_FORMATS[extension]
61
+
62
+ return image_format
63
+
64
+
65
+ def choose_resolution(path: Path, options: ImageOptions | None) -> int:
66
+ """
67
+ Return the number of dots per inch an image is saved with.
68
+
69
+ .. versionadded:: 0.1.0
70
+
71
+ Parameters
72
+ ----------
73
+ path
74
+ The path of the image, with a supported extension.
75
+ options
76
+ The settings of a PNG image, or None.
77
+
78
+ Returns
79
+ -------
80
+ int
81
+ The resolution of the options, 100 without them.
82
+
83
+ Raises
84
+ ------
85
+ RefusedSettingError
86
+ When options are given for an SVG or PDF image, which has no resolution.
87
+
88
+ Examples
89
+ --------
90
+ >>> from pathlib import Path
91
+ >>> import numdaplot as ndp
92
+ >>> from numdaplot.plots.output.image_saving import choose_resolution
93
+ >>> try:
94
+ ... choose_resolution(Path("sales.svg"), ndp.ImageOptions(dpi=200))
95
+ ... except ndp.RefusedSettingError as error:
96
+ ... print(error)
97
+ A .svg image does not accept ImageOptions.
98
+ """
99
+ if options is None:
100
+ return DEFAULT_DPI
101
+
102
+ extension = path.suffix.lower()
103
+ if extension != RESOLUTION_EXTENSION:
104
+ image_name = IMAGE_OWNER.format(extension=extension)
105
+ raise RefusedSettingError(OPTIONS_NAME, image_name)
106
+
107
+ return options.dpi
108
+
109
+
110
+ def save_figure(figure: Figure, path: Path, image_format: str, resolution: int) -> None:
111
+ """
112
+ Save a matplotlib figure as an image.
113
+
114
+ .. versionadded:: 0.1.0
115
+
116
+ Parameters
117
+ ----------
118
+ figure
119
+ The figure to save.
120
+ path
121
+ The path of the image.
122
+ image_format
123
+ The matplotlib name of the format, as ``find_image_format`` gives it.
124
+ resolution
125
+ The number of dots per inch, as ``choose_resolution`` gives it.
126
+
127
+ Examples
128
+ --------
129
+ >>> import tempfile
130
+ >>> from pathlib import Path
131
+ >>> from matplotlib.figure import Figure
132
+ >>> from numdaplot.plots.output.image_saving import save_figure
133
+ >>> path = Path(tempfile.mkdtemp()) / "empty.pdf"
134
+ >>> save_figure(Figure(), path, "pdf", 100)
135
+ >>> path.read_bytes()[:4]
136
+ b'%PDF'
137
+ """
138
+ with FileAccessErrors(WRITE_OPERATION, path):
139
+ figure.savefig(path, format=image_format, dpi=resolution)
140
+
141
+
142
+ def write_image(drawing: FigureDrawing, path: FilePath, options: ImageOptions | None, on_conflict: Conflict) -> None:
143
+ """
144
+ Save what a Plot or a Figure draws as an image, in the format named by the extension of the path.
145
+
146
+ .. versionadded:: 0.1.0
147
+
148
+ Parameters
149
+ ----------
150
+ drawing
151
+ What is drawn, and the size of the image.
152
+ path
153
+ The path of the image, ending with ``.png``, ``.svg`` or ``.pdf``.
154
+ options
155
+ The resolution of a PNG image, 100 dots per inch when omitted. SVG and PDF images take none.
156
+ on_conflict
157
+ ``ERROR`` refuses to overwrite an existing file, ``REPLACE`` overwrites it.
158
+
159
+ Raises
160
+ ------
161
+ UnsupportedImageFormatError
162
+ When the path does not end with ``.png``, ``.svg`` or ``.pdf``.
163
+ RefusedSettingError
164
+ When options are given for an SVG or PDF image.
165
+ FileExistsError
166
+ When a file exists at the path and ``on_conflict`` is ``ERROR``.
167
+ FileAccessError
168
+ When the file system refuses the file: missing folder, missing permission and so on.
169
+
170
+ Examples
171
+ --------
172
+ >>> import tempfile
173
+ >>> from pathlib import Path
174
+ >>> import numdaplot as ndp
175
+ >>> from numdaplot.plots.drawing.plot_drawing import FigureDrawing
176
+ >>> from numdaplot.plots.output.image_saving import write_image
177
+ >>> path = Path(tempfile.mkdtemp()) / "title.svg"
178
+ >>> write_image(FigureDrawing(lambda target: target.suptitle("Sales"), (3.0, 2.0)), path, None, ndp.Conflict.ERROR)
179
+ >>> path.read_text().startswith("<?xml")
180
+ True
181
+ """
182
+ file_path = Path(path)
183
+ image_format = find_image_format(file_path)
184
+ resolution = choose_resolution(file_path, options)
185
+ require_free_path(file_path, on_conflict)
186
+ figure = build_figure(drawing)
187
+ save_figure(figure, file_path, image_format, resolution)
@@ -0,0 +1,181 @@
1
+ """
2
+ Display of a Plot or a Figure in a Jupyter notebook or in a matplotlib window.
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
+ import warnings
11
+ from importlib import import_module
12
+ from io import BytesIO
13
+
14
+ from matplotlib.backends.registry import BackendFilter, backend_registry
15
+ from matplotlib.figure import Figure
16
+
17
+ from numdaplot.arrays.operations.float_errors import INTERNAL_FILES
18
+ from numdaplot.errors.display_warning import DisplayWarning
19
+ from numdaplot.plots.drawing.plot_drawing import FIGURE_LAYOUT, FigureDrawing, build_figure
20
+ from numdaplot.plots.output.shown_object import ShownObject
21
+ from numdaplot.plots.style.image_options import DEFAULT_DPI
22
+ from numdaplot.tables.preview.notebook_display import is_notebook
23
+
24
+ IPYTHON_DISPLAY_MODULE = "IPython.display"
25
+ PNG_FORMAT = "png"
26
+ NO_WINDOW_MESSAGE = (
27
+ "No window can be opened, matplotlib has no graphical backend here. Install tkinter (python3-tk on Debian and "
28
+ "Ubuntu) to see the {object_name}, or save it with {class_name}.save."
29
+ )
30
+
31
+
32
+ def show_drawing(drawing: FigureDrawing, shown_object: ShownObject) -> None:
33
+ """
34
+ Show what a Plot or a Figure draws: as an image in a Jupyter notebook, in a matplotlib window anywhere else.
35
+
36
+ .. versionadded:: 0.1.0
37
+
38
+ Parameters
39
+ ----------
40
+ drawing
41
+ What is drawn, and the size of the figure.
42
+ shown_object
43
+ Whether a Plot or a Figure is shown, named by the warning emitted when no window can be opened.
44
+
45
+ Examples
46
+ --------
47
+ >>> from numdaplot.plots.drawing.plot_drawing import FigureDrawing
48
+ >>> from numdaplot.plots.output.plot_display import show_drawing
49
+ >>> from numdaplot.plots.output.shown_object import ShownObject
50
+ >>> show_drawing(FigureDrawing(lambda target: target.suptitle("Sales"), (3.0, 2.0)), ShownObject.PLOT)
51
+ """
52
+ runs_in_notebook = is_notebook()
53
+ if not runs_in_notebook:
54
+ show_drawing_in_window(drawing, shown_object)
55
+ return
56
+
57
+ figure = build_figure(drawing)
58
+ show_figure_in_notebook(figure)
59
+
60
+
61
+ def show_figure_in_notebook(figure: Figure) -> None:
62
+ """
63
+ Show a matplotlib figure as a PNG image in the output of a Jupyter notebook cell.
64
+
65
+ .. versionadded:: 0.1.0
66
+
67
+ Parameters
68
+ ----------
69
+ figure
70
+ The figure to show.
71
+ """
72
+ image_buffer = BytesIO()
73
+ figure.savefig(image_buffer, format=PNG_FORMAT, dpi=DEFAULT_DPI)
74
+ image_bytes = image_buffer.getvalue()
75
+ display_module = import_module(IPYTHON_DISPLAY_MODULE)
76
+ image = display_module.Image(data=image_bytes)
77
+ display_module.display(image)
78
+
79
+
80
+ def show_drawing_in_window(drawing: FigureDrawing, shown_object: ShownObject) -> None:
81
+ """
82
+ Show what a Plot or a Figure draws in a matplotlib window.
83
+
84
+ The call waits until the window is closed, unless matplotlib runs interactively. With a matplotlib backend
85
+ that opens no window, such as the one of a server, nothing is drawn and a ``DisplayWarning`` is emitted.
86
+
87
+ .. versionadded:: 0.1.0
88
+
89
+ Parameters
90
+ ----------
91
+ drawing
92
+ What is drawn, and the size of the figure.
93
+ shown_object
94
+ Whether a Plot or a Figure is shown, named by the warning emitted when no window can be opened.
95
+
96
+ Examples
97
+ --------
98
+ >>> from numdaplot.plots.drawing.plot_drawing import FigureDrawing
99
+ >>> from numdaplot.plots.output.plot_display import show_drawing_in_window
100
+ >>> from numdaplot.plots.output.shown_object import ShownObject
101
+ >>> drawing = FigureDrawing(lambda target: target.suptitle("Sales"), (3.0, 2.0))
102
+ >>> show_drawing_in_window(drawing, ShownObject.FIGURE)
103
+ """
104
+ # pyplot chooses a matplotlib backend when imported, so it is only imported to open a window.
105
+ from matplotlib import pyplot
106
+
107
+ backend_name = pyplot.get_backend()
108
+ can_open_window = is_window_backend(backend_name)
109
+ if not can_open_window:
110
+ warn_without_window(shown_object)
111
+ return
112
+
113
+ figure = pyplot.figure(figsize=drawing.size_inches, dpi=DEFAULT_DPI, layout=FIGURE_LAYOUT)
114
+ drawing.draw_on(figure)
115
+ pyplot.show()
116
+ is_interactive = pyplot.isinteractive()
117
+ if not is_interactive:
118
+ pyplot.close(figure)
119
+
120
+
121
+ def is_window_backend(backend_name: str) -> bool:
122
+ """
123
+ Return whether a matplotlib backend opens windows.
124
+
125
+ Only the backends matplotlib lists as non-interactive, such as ``agg`` chosen when no window can be opened,
126
+ are refused: a backend added by another package is trusted.
127
+
128
+ .. versionadded:: 0.1.0
129
+
130
+ Parameters
131
+ ----------
132
+ backend_name
133
+ The name matplotlib gives to its backend, such as ``tkagg`` or ``agg``, in any case.
134
+
135
+ Returns
136
+ -------
137
+ bool
138
+ False for a matplotlib backend without window, True otherwise.
139
+
140
+ Examples
141
+ --------
142
+ >>> from numdaplot.plots.output.plot_display import is_window_backend
143
+ >>> is_window_backend("Agg")
144
+ False
145
+ >>> is_window_backend("TkAgg")
146
+ True
147
+ """
148
+ lowered_name = backend_name.lower()
149
+ non_interactive_names = backend_registry.list_builtin(BackendFilter.NON_INTERACTIVE)
150
+ is_window = lowered_name not in non_interactive_names
151
+
152
+ return is_window
153
+
154
+
155
+ def warn_without_window(shown_object: ShownObject) -> None:
156
+ """
157
+ Emit a ``DisplayWarning`` pointing at the line of the calling code that asked to show a Plot or a Figure.
158
+
159
+ .. versionadded:: 0.1.0
160
+
161
+ Parameters
162
+ ----------
163
+ shown_object
164
+ Whether a Plot or a Figure could not be shown.
165
+
166
+ Examples
167
+ --------
168
+ >>> import warnings
169
+ >>> from numdaplot.plots.output.plot_display import warn_without_window
170
+ >>> from numdaplot.plots.output.shown_object import ShownObject
171
+ >>> with warnings.catch_warnings(record=True) as caught_warnings:
172
+ ... warnings.simplefilter("always")
173
+ ... warn_without_window(ShownObject.FIGURE)
174
+ >>> print(caught_warnings[0].message)
175
+ No window can be opened, matplotlib has no graphical backend here. Install tkinter (python3-tk on Debian and
176
+ Ubuntu) to see the figure, or save it with Figure.save.
177
+ """
178
+ class_name = shown_object.value
179
+ object_name = class_name.lower()
180
+ message = NO_WINDOW_MESSAGE.format(object_name=object_name, class_name=class_name)
181
+ warnings.warn(message, DisplayWarning, skip_file_prefixes=INTERNAL_FILES)