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.
- numdaplot/__init__.py +506 -0
- numdaplot/arrays/__init__.py +5 -0
- numdaplot/arrays/array.py +92 -0
- numdaplot/arrays/array_arithmetic.py +404 -0
- numdaplot/arrays/array_calculation.py +143 -0
- numdaplot/arrays/array_conversion.py +150 -0
- numdaplot/arrays/array_creation.py +371 -0
- numdaplot/arrays/array_data.py +281 -0
- numdaplot/arrays/array_layout.py +179 -0
- numdaplot/arrays/array_logic.py +227 -0
- numdaplot/arrays/array_reflected_arithmetic.py +334 -0
- numdaplot/arrays/array_refusals.py +339 -0
- numdaplot/arrays/array_selection.py +195 -0
- numdaplot/arrays/array_sorting.py +59 -0
- numdaplot/arrays/axis_number.py +58 -0
- numdaplot/arrays/calculation/__init__.py +5 -0
- numdaplot/arrays/calculation/counting_statistics.py +325 -0
- numdaplot/arrays/calculation/location_statistics.py +268 -0
- numdaplot/arrays/calculation/math_function_values.py +183 -0
- numdaplot/arrays/calculation/statistic_values.py +209 -0
- numdaplot/arrays/calculation/time_function_values.py +419 -0
- numdaplot/arrays/conversion/__init__.py +5 -0
- numdaplot/arrays/conversion/array_text.py +62 -0
- numdaplot/arrays/conversion/equality_check.py +72 -0
- numdaplot/arrays/conversion/python_values.py +70 -0
- numdaplot/arrays/conversion/time_text.py +290 -0
- numdaplot/arrays/creation/__init__.py +5 -0
- numdaplot/arrays/creation/date_parts.py +89 -0
- numdaplot/arrays/creation/date_parts_values.py +437 -0
- numdaplot/arrays/creation/distribution.py +54 -0
- numdaplot/arrays/creation/filled_values.py +58 -0
- numdaplot/arrays/creation/list_conversion.py +311 -0
- numdaplot/arrays/creation/list_shape.py +97 -0
- numdaplot/arrays/creation/normal.py +65 -0
- numdaplot/arrays/creation/numpy_conversion.py +149 -0
- numdaplot/arrays/creation/random_integers.py +104 -0
- numdaplot/arrays/creation/random_values.py +97 -0
- numdaplot/arrays/creation/range_values.py +73 -0
- numdaplot/arrays/creation/spacing.py +84 -0
- numdaplot/arrays/creation/spacing_values.py +63 -0
- numdaplot/arrays/creation/uniform.py +63 -0
- numdaplot/arrays/equality.py +68 -0
- numdaplot/arrays/layout/__init__.py +5 -0
- numdaplot/arrays/layout/sorting_values.py +113 -0
- numdaplot/arrays/layout/unique_values.py +49 -0
- numdaplot/arrays/mapping/__init__.py +5 -0
- numdaplot/arrays/mapping/mapped_values.py +286 -0
- numdaplot/arrays/mapping/unmatched.py +50 -0
- numdaplot/arrays/mapping/value_change.py +55 -0
- numdaplot/arrays/mapping/value_mapping.py +161 -0
- numdaplot/arrays/math_functions/__init__.py +5 -0
- numdaplot/arrays/math_functions/absolute.py +27 -0
- numdaplot/arrays/math_functions/cosine.py +28 -0
- numdaplot/arrays/math_functions/exponential.py +27 -0
- numdaplot/arrays/math_functions/logarithm.py +72 -0
- numdaplot/arrays/math_functions/math_function.py +58 -0
- numdaplot/arrays/math_functions/round.py +58 -0
- numdaplot/arrays/math_functions/sine.py +28 -0
- numdaplot/arrays/math_functions/square_root.py +27 -0
- numdaplot/arrays/operations/__init__.py +5 -0
- numdaplot/arrays/operations/boolean_operands.py +48 -0
- numdaplot/arrays/operations/combination.py +157 -0
- numdaplot/arrays/operations/float_errors.py +170 -0
- numdaplot/arrays/operations/integer_bounds.py +175 -0
- numdaplot/arrays/operations/integer_rules.py +397 -0
- numdaplot/arrays/operations/operand.py +139 -0
- numdaplot/arrays/operations/time_arithmetic.py +479 -0
- numdaplot/arrays/operations/time_bounds.py +286 -0
- numdaplot/arrays/operations/time_result_bounds.py +397 -0
- numdaplot/arrays/operations/transformation.py +54 -0
- numdaplot/arrays/operations/type_requirements.py +94 -0
- numdaplot/arrays/replacement.py +66 -0
- numdaplot/arrays/selection/__init__.py +5 -0
- numdaplot/arrays/selection/comparison_masks.py +131 -0
- numdaplot/arrays/selection/membership_masks.py +118 -0
- numdaplot/arrays/selection/missing_mask.py +50 -0
- numdaplot/arrays/selection/region_index.py +178 -0
- numdaplot/arrays/selection/replaced_values.py +120 -0
- numdaplot/arrays/selection/rule_mask.py +83 -0
- numdaplot/arrays/selection/time_reference.py +172 -0
- numdaplot/arrays/shape.py +74 -0
- numdaplot/arrays/type_match.py +51 -0
- numdaplot/data_types/__init__.py +5 -0
- numdaplot/data_types/library.py +57 -0
- numdaplot/data_types/numpy_mapping.py +207 -0
- numdaplot/data_types/pandas_mapping.py +114 -0
- numdaplot/data_types/time_of_day.py +292 -0
- numdaplot/data_types/type.py +224 -0
- numdaplot/data_types/value_family.py +149 -0
- numdaplot/data_types/value_type.py +147 -0
- numdaplot/dates/__init__.py +5 -0
- numdaplot/dates/custom_date_format.py +83 -0
- numdaplot/dates/date_format.py +120 -0
- numdaplot/dates/date_part.py +59 -0
- numdaplot/dates/date_part_unit.py +153 -0
- numdaplot/dates/date_period.py +57 -0
- numdaplot/dates/duration_in.py +58 -0
- numdaplot/dates/duration_unit.py +90 -0
- numdaplot/dates/period_unit.py +101 -0
- numdaplot/dates/time_function.py +56 -0
- numdaplot/dates/time_zone.py +68 -0
- numdaplot/dates/time_zone_change.py +71 -0
- numdaplot/dates/time_zone_mode.py +81 -0
- numdaplot/dates/to_duration.py +58 -0
- numdaplot/errors/__init__.py +7 -0
- numdaplot/errors/broadcast_warning.py +36 -0
- numdaplot/errors/calculation_warning.py +35 -0
- numdaplot/errors/cell_out_of_range_error.py +77 -0
- numdaplot/errors/column_not_found_error.py +64 -0
- numdaplot/errors/conflicting_settings_error.py +60 -0
- numdaplot/errors/dimension_error.py +62 -0
- numdaplot/errors/display_warning.py +32 -0
- numdaplot/errors/duplicate_column_error.py +82 -0
- numdaplot/errors/duplicate_label_error.py +55 -0
- numdaplot/errors/duplicate_statistic_error.py +55 -0
- numdaplot/errors/duplicate_value_error.py +54 -0
- numdaplot/errors/empty_array_error.py +55 -0
- numdaplot/errors/empty_list_error.py +52 -0
- numdaplot/errors/empty_region_error.py +34 -0
- numdaplot/errors/empty_text_error.py +34 -0
- numdaplot/errors/empty_total_error.py +62 -0
- numdaplot/errors/empty_values_error.py +34 -0
- numdaplot/errors/file_access_error.py +70 -0
- numdaplot/errors/file_exists_error.py +62 -0
- numdaplot/errors/file_not_found_error.py +56 -0
- numdaplot/errors/incompatible_charts_error.py +80 -0
- numdaplot/errors/incompatible_types_error.py +104 -0
- numdaplot/errors/integer_overflow_error.py +61 -0
- numdaplot/errors/invalid_base_error.py +52 -0
- numdaplot/errors/invalid_bin_width_error.py +66 -0
- numdaplot/errors/invalid_bounds_error.py +58 -0
- numdaplot/errors/invalid_chart_data_error.py +81 -0
- numdaplot/errors/invalid_color_count_error.py +63 -0
- numdaplot/errors/invalid_color_error.py +51 -0
- numdaplot/errors/invalid_column_name_error.py +52 -0
- numdaplot/errors/invalid_conversion_error.py +119 -0
- numdaplot/errors/invalid_count_error.py +61 -0
- numdaplot/errors/invalid_date_format_error.py +51 -0
- numdaplot/errors/invalid_deviation_error.py +52 -0
- numdaplot/errors/invalid_fraction_error.py +51 -0
- numdaplot/errors/invalid_label_count_error.py +61 -0
- numdaplot/errors/invalid_limits_error.py +111 -0
- numdaplot/errors/invalid_opacity_error.py +52 -0
- numdaplot/errors/invalid_point_size_error.py +52 -0
- numdaplot/errors/invalid_position_error.py +106 -0
- numdaplot/errors/invalid_resolution_error.py +51 -0
- numdaplot/errors/invalid_rotation_error.py +53 -0
- numdaplot/errors/invalid_seed_error.py +53 -0
- numdaplot/errors/invalid_separator_error.py +52 -0
- numdaplot/errors/invalid_shape_error.py +52 -0
- numdaplot/errors/invalid_sheet_name_error.py +54 -0
- numdaplot/errors/invalid_size_error.py +58 -0
- numdaplot/errors/invalid_step_error.py +77 -0
- numdaplot/errors/invalid_suffixes_error.py +61 -0
- numdaplot/errors/invalid_time_zone_change_error.py +63 -0
- numdaplot/errors/invalid_type_error.py +79 -0
- numdaplot/errors/irregular_list_error.py +36 -0
- numdaplot/errors/join_relation_error.py +183 -0
- numdaplot/errors/missing_dependency_error.py +58 -0
- numdaplot/errors/missing_type_error.py +36 -0
- numdaplot/errors/missing_value_error.py +62 -0
- numdaplot/errors/not_single_value_error.py +53 -0
- numdaplot/errors/numdaplot_error.py +25 -0
- numdaplot/errors/numdaplot_warning.py +34 -0
- numdaplot/errors/occupied_cell_error.py +63 -0
- numdaplot/errors/out_of_domain_error.py +70 -0
- numdaplot/errors/readability_warning.py +35 -0
- numdaplot/errors/refused_operation_error.py +64 -0
- numdaplot/errors/refused_setting_error.py +60 -0
- numdaplot/errors/rejected_dates.py +60 -0
- numdaplot/errors/repeated_key.py +36 -0
- numdaplot/errors/shape_mismatch_error.py +67 -0
- numdaplot/errors/time_overflow_error.py +131 -0
- numdaplot/errors/time_zone_mismatch_error.py +83 -0
- numdaplot/errors/unknown_time_zone_error.py +51 -0
- numdaplot/errors/unmatched_value_error.py +81 -0
- numdaplot/errors/unsupported_image_format_error.py +56 -0
- numdaplot/errors/unsupported_index_error.py +38 -0
- numdaplot/errors/unsupported_missing_error.py +129 -0
- numdaplot/errors/unsupported_type_error.py +62 -0
- numdaplot/errors/value_conversion_error.py +215 -0
- numdaplot/ordering/__init__.py +5 -0
- numdaplot/ordering/missing_position.py +46 -0
- numdaplot/ordering/order.py +46 -0
- numdaplot/package_version.py +36 -0
- numdaplot/plots/__init__.py +5 -0
- numdaplot/plots/chart_layer.py +47 -0
- numdaplot/plots/charts/__init__.py +5 -0
- numdaplot/plots/charts/bar_chart.py +98 -0
- numdaplot/plots/charts/bar_layout.py +58 -0
- numdaplot/plots/charts/bin_count.py +61 -0
- numdaplot/plots/charts/bin_width.py +78 -0
- numdaplot/plots/charts/box_chart.py +97 -0
- numdaplot/plots/charts/cell_values.py +61 -0
- numdaplot/plots/charts/chart.py +59 -0
- numdaplot/plots/charts/chart_settings.py +105 -0
- numdaplot/plots/charts/color_scale.py +147 -0
- numdaplot/plots/charts/heatmap_chart.py +92 -0
- numdaplot/plots/charts/histogram_chart.py +93 -0
- numdaplot/plots/charts/line_chart.py +100 -0
- numdaplot/plots/charts/line_type.py +75 -0
- numdaplot/plots/charts/marker_shape.py +113 -0
- numdaplot/plots/charts/missing_chart.py +60 -0
- numdaplot/plots/charts/missing_map_chart.py +27 -0
- numdaplot/plots/charts/orientation.py +58 -0
- numdaplot/plots/charts/outliers.py +49 -0
- numdaplot/plots/charts/percentages.py +55 -0
- numdaplot/plots/charts/pie_chart.py +87 -0
- numdaplot/plots/charts/scatter_chart.py +159 -0
- numdaplot/plots/charts/value_axis.py +66 -0
- numdaplot/plots/data/__init__.py +5 -0
- numdaplot/plots/data/array_values.py +128 -0
- numdaplot/plots/data/chart_data.py +143 -0
- numdaplot/plots/data/chart_values.py +109 -0
- numdaplot/plots/data/column_reading.py +468 -0
- numdaplot/plots/data/heatmap_values.py +63 -0
- numdaplot/plots/data/missing_cells.py +165 -0
- numdaplot/plots/data/pie_values.py +215 -0
- numdaplot/plots/data/point_values.py +249 -0
- numdaplot/plots/data/position_kind.py +83 -0
- numdaplot/plots/data/renamed_layers.py +340 -0
- numdaplot/plots/data/sample_values.py +160 -0
- numdaplot/plots/data/shown_columns.py +248 -0
- numdaplot/plots/data/table_values.py +256 -0
- numdaplot/plots/data/unique_labels.py +45 -0
- numdaplot/plots/drawing/__init__.py +5 -0
- numdaplot/plots/drawing/bar_drawing.py +316 -0
- numdaplot/plots/drawing/box_drawing.py +344 -0
- numdaplot/plots/drawing/cell_merging.py +237 -0
- numdaplot/plots/drawing/chart_texts.py +124 -0
- numdaplot/plots/drawing/color_bar.py +57 -0
- numdaplot/plots/drawing/color_scale_values.py +120 -0
- numdaplot/plots/drawing/default_labels.py +41 -0
- numdaplot/plots/drawing/drawn_chart.py +50 -0
- numdaplot/plots/drawing/grid_axes.py +75 -0
- numdaplot/plots/drawing/heatmap_drawing.py +313 -0
- numdaplot/plots/drawing/histogram_drawing.py +350 -0
- numdaplot/plots/drawing/label_room.py +344 -0
- numdaplot/plots/drawing/label_thinning.py +216 -0
- numdaplot/plots/drawing/layer_alignment.py +319 -0
- numdaplot/plots/drawing/layer_colors.py +123 -0
- numdaplot/plots/drawing/line_drawing.py +85 -0
- numdaplot/plots/drawing/marker_codes.py +20 -0
- numdaplot/plots/drawing/missing_drawing.py +360 -0
- numdaplot/plots/drawing/moment_period_formatter.py +253 -0
- numdaplot/plots/drawing/pie_drawing.py +185 -0
- numdaplot/plots/drawing/plot_axes.py +38 -0
- numdaplot/plots/drawing/plot_drawing.py +288 -0
- numdaplot/plots/drawing/plot_theme.py +45 -0
- numdaplot/plots/drawing/position_axis.py +278 -0
- numdaplot/plots/drawing/scatter_drawing.py +364 -0
- numdaplot/plots/drawing/series_colors.py +177 -0
- numdaplot/plots/drawing/size_inches.py +45 -0
- numdaplot/plots/drawing/style_drawing.py +410 -0
- numdaplot/plots/drawing/text_contrast.py +44 -0
- numdaplot/plots/drawing/tick_rotation.py +354 -0
- numdaplot/plots/drawing/time_axis.py +212 -0
- numdaplot/plots/drawing/whole_numbers.py +72 -0
- numdaplot/plots/figure/__init__.py +5 -0
- numdaplot/plots/figure/cell.py +95 -0
- numdaplot/plots/figure/figure.py +256 -0
- numdaplot/plots/figure/figure_drawing.py +99 -0
- numdaplot/plots/figure/figure_style.py +60 -0
- numdaplot/plots/figure/layout.py +71 -0
- numdaplot/plots/figure/placement.py +150 -0
- numdaplot/plots/layer_reading.py +166 -0
- numdaplot/plots/output/__init__.py +5 -0
- numdaplot/plots/output/image_saving.py +187 -0
- numdaplot/plots/output/plot_display.py +181 -0
- numdaplot/plots/output/shown_object.py +45 -0
- numdaplot/plots/overlay_checks.py +245 -0
- numdaplot/plots/plot.py +31 -0
- numdaplot/plots/plot_data.py +140 -0
- numdaplot/plots/plot_distribution_creation.py +237 -0
- numdaplot/plots/plot_output.py +124 -0
- numdaplot/plots/plot_overlays.py +273 -0
- numdaplot/plots/plot_overview_creation.py +195 -0
- numdaplot/plots/plot_series_creation.py +213 -0
- numdaplot/plots/style/__init__.py +5 -0
- numdaplot/plots/style/axis_settings.py +60 -0
- numdaplot/plots/style/color.py +168 -0
- numdaplot/plots/style/custom_color.py +65 -0
- numdaplot/plots/style/grid_lines.py +49 -0
- numdaplot/plots/style/image_options.py +71 -0
- numdaplot/plots/style/legend_position.py +149 -0
- numdaplot/plots/style/plot_style.py +136 -0
- numdaplot/plots/style/size.py +70 -0
- numdaplot/plots/style/size_unit.py +62 -0
- numdaplot/positions/__init__.py +5 -0
- numdaplot/positions/axis.py +54 -0
- numdaplot/positions/index.py +51 -0
- numdaplot/positions/range.py +90 -0
- numdaplot/positions/region.py +92 -0
- numdaplot/py.typed +0 -0
- numdaplot/ratios/__init__.py +5 -0
- numdaplot/ratios/fraction.py +40 -0
- numdaplot/ratios/measure.py +48 -0
- numdaplot/rules/__init__.py +5 -0
- numdaplot/rules/between.py +78 -0
- numdaplot/rules/bounds.py +83 -0
- numdaplot/rules/case.py +48 -0
- numdaplot/rules/contains.py +63 -0
- numdaplot/rules/equal.py +43 -0
- numdaplot/rules/greater.py +39 -0
- numdaplot/rules/greater_or_equal.py +38 -0
- numdaplot/rules/is_in.py +67 -0
- numdaplot/rules/is_missing.py +25 -0
- numdaplot/rules/is_present.py +25 -0
- numdaplot/rules/less.py +39 -0
- numdaplot/rules/less_or_equal.py +38 -0
- numdaplot/rules/not_equal.py +45 -0
- numdaplot/rules/rule.py +62 -0
- numdaplot/rules/rule_values.py +44 -0
- numdaplot/rules/value_rule.py +110 -0
- numdaplot/settings/__init__.py +5 -0
- numdaplot/settings/argument_types.py +327 -0
- numdaplot/settings/field_types.py +593 -0
- numdaplot/statistics/__init__.py +5 -0
- numdaplot/statistics/count.py +71 -0
- numdaplot/statistics/count_distinct.py +27 -0
- numdaplot/statistics/counted_missing.py +46 -0
- numdaplot/statistics/maximum.py +27 -0
- numdaplot/statistics/mean.py +27 -0
- numdaplot/statistics/median.py +27 -0
- numdaplot/statistics/minimum.py +27 -0
- numdaplot/statistics/most_frequent.py +27 -0
- numdaplot/statistics/most_frequent_count.py +27 -0
- numdaplot/statistics/quantile.py +61 -0
- numdaplot/statistics/standard_deviation.py +29 -0
- numdaplot/statistics/statistic.py +63 -0
- numdaplot/statistics/sum.py +27 -0
- numdaplot/tables/__init__.py +5 -0
- numdaplot/tables/aggregation/__init__.py +5 -0
- numdaplot/tables/aggregation/aggregated_frame.py +189 -0
- numdaplot/tables/aggregation/aggregation.py +97 -0
- numdaplot/tables/aggregation/calculation.py +123 -0
- numdaplot/tables/aggregation/result_column.py +108 -0
- numdaplot/tables/aggregation/row_groups.py +96 -0
- numdaplot/tables/aggregation/statistic_name.py +122 -0
- numdaplot/tables/columns/__init__.py +5 -0
- numdaplot/tables/columns/added_column.py +89 -0
- numdaplot/tables/columns/boolean_conversion.py +144 -0
- numdaplot/tables/columns/boolean_rule.py +59 -0
- numdaplot/tables/columns/bracket_end.py +50 -0
- numdaplot/tables/columns/bracket_names.py +346 -0
- numdaplot/tables/columns/bracketed_column.py +179 -0
- numdaplot/tables/columns/brackets.py +234 -0
- numdaplot/tables/columns/chosen_columns.py +55 -0
- numdaplot/tables/columns/column_choice.py +84 -0
- numdaplot/tables/columns/column_mode.py +64 -0
- numdaplot/tables/columns/column_names.py +186 -0
- numdaplot/tables/columns/conversion.py +103 -0
- numdaplot/tables/columns/converted_column.py +669 -0
- numdaplot/tables/columns/date_conversion.py +526 -0
- numdaplot/tables/columns/date_range.py +135 -0
- numdaplot/tables/columns/name_change.py +67 -0
- numdaplot/tables/columns/new_column.py +79 -0
- numdaplot/tables/columns/number_conversion.py +281 -0
- numdaplot/tables/columns/renamed_columns.py +60 -0
- numdaplot/tables/columns/renaming.py +81 -0
- numdaplot/tables/columns/text_conversion.py +70 -0
- numdaplot/tables/columns/time_conversion.py +313 -0
- numdaplot/tables/columns/time_zone_conversion.py +128 -0
- numdaplot/tables/conflict.py +68 -0
- numdaplot/tables/description/__init__.py +5 -0
- numdaplot/tables/description/described_frame.py +335 -0
- numdaplot/tables/description/description.py +155 -0
- numdaplot/tables/duplicates/__init__.py +5 -0
- numdaplot/tables/duplicates/deduplicated_frame.py +66 -0
- numdaplot/tables/duplicates/deduplication.py +88 -0
- numdaplot/tables/duplicates/keep.py +81 -0
- numdaplot/tables/files/__init__.py +5 -0
- numdaplot/tables/files/column_names.py +60 -0
- numdaplot/tables/files/csv_file.py +265 -0
- numdaplot/tables/files/csv_read_options.py +89 -0
- numdaplot/tables/files/csv_separator.py +41 -0
- numdaplot/tables/files/csv_write_options.py +79 -0
- numdaplot/tables/files/decimal_count.py +42 -0
- numdaplot/tables/files/encoding.py +82 -0
- numdaplot/tables/files/excel_file.py +171 -0
- numdaplot/tables/files/excel_read_options.py +79 -0
- numdaplot/tables/files/excel_sheet.py +50 -0
- numdaplot/tables/files/excel_time_cells.py +146 -0
- numdaplot/tables/files/excel_write_options.py +63 -0
- numdaplot/tables/files/file_access.py +152 -0
- numdaplot/tables/files/file_paths.py +106 -0
- numdaplot/tables/files/json_decimals.py +387 -0
- numdaplot/tables/files/json_file.py +203 -0
- numdaplot/tables/files/json_layout.py +63 -0
- numdaplot/tables/files/json_read_options.py +64 -0
- numdaplot/tables/files/json_write_options.py +71 -0
- numdaplot/tables/files/missing_texts.py +63 -0
- numdaplot/tables/files/optional_package.py +42 -0
- numdaplot/tables/files/pandas_backend.py +11 -0
- numdaplot/tables/files/parquet_file.py +91 -0
- numdaplot/tables/files/parquet_read_options.py +56 -0
- numdaplot/tables/files/sas_file.py +94 -0
- numdaplot/tables/files/sas_read_options.py +67 -0
- numdaplot/tables/files/stata_file.py +83 -0
- numdaplot/tables/files/stata_read_options.py +56 -0
- numdaplot/tables/files/xpt_read_options.py +65 -0
- numdaplot/tables/filtering/__init__.py +5 -0
- numdaplot/tables/filtering/checked_frame.py +60 -0
- numdaplot/tables/filtering/column_mask.py +71 -0
- numdaplot/tables/filtering/column_match.py +62 -0
- numdaplot/tables/filtering/condition.py +94 -0
- numdaplot/tables/filtering/filter.py +74 -0
- numdaplot/tables/filtering/filter_mode.py +67 -0
- numdaplot/tables/filtering/row_mask.py +152 -0
- numdaplot/tables/filtering/rule_moments.py +164 -0
- numdaplot/tables/frames/__init__.py +5 -0
- numdaplot/tables/frames/array_frame.py +95 -0
- numdaplot/tables/frames/cleaned_names.py +132 -0
- numdaplot/tables/frames/column.py +15 -0
- numdaplot/tables/frames/column_values.py +273 -0
- numdaplot/tables/frames/frame_equality.py +130 -0
- numdaplot/tables/frames/frame_normalization.py +459 -0
- numdaplot/tables/frames/named_column_errors.py +85 -0
- numdaplot/tables/frames/pandas_decimals.py +113 -0
- numdaplot/tables/frames/region_positions.py +113 -0
- numdaplot/tables/frames/table_text.py +222 -0
- numdaplot/tables/frames/time_columns.py +345 -0
- numdaplot/tables/frames/time_range_errors.py +117 -0
- numdaplot/tables/frames/time_zones.py +271 -0
- numdaplot/tables/joining/__init__.py +5 -0
- numdaplot/tables/joining/join.py +110 -0
- numdaplot/tables/joining/join_keys.py +367 -0
- numdaplot/tables/joining/join_mode.py +93 -0
- numdaplot/tables/joining/join_relation.py +149 -0
- numdaplot/tables/joining/join_suffixes.py +71 -0
- numdaplot/tables/joining/joined_frame.py +166 -0
- numdaplot/tables/joining/joined_names.py +107 -0
- numdaplot/tables/joining/joined_rows.py +235 -0
- numdaplot/tables/joining/key_types.py +57 -0
- numdaplot/tables/joining/relation.py +78 -0
- numdaplot/tables/missing/__init__.py +5 -0
- numdaplot/tables/missing/missing_count.py +59 -0
- numdaplot/tables/missing/missing_counts.py +214 -0
- numdaplot/tables/missing/missing_drop.py +98 -0
- numdaplot/tables/missing/missing_mode.py +63 -0
- numdaplot/tables/missing/missing_ratio.py +71 -0
- numdaplot/tables/missing/missing_removal.py +257 -0
- numdaplot/tables/missing/missing_summary.py +174 -0
- numdaplot/tables/missing/ratio_comparison.py +70 -0
- numdaplot/tables/pivot/__init__.py +5 -0
- numdaplot/tables/pivot/pivot_table.py +104 -0
- numdaplot/tables/pivot/pivoted_frame.py +244 -0
- numdaplot/tables/preview/__init__.py +5 -0
- numdaplot/tables/preview/notebook_display.py +238 -0
- numdaplot/tables/preview/preview.py +100 -0
- numdaplot/tables/preview/preview_rows.py +55 -0
- numdaplot/tables/preview/shown_columns.py +62 -0
- numdaplot/tables/preview/side.py +82 -0
- numdaplot/tables/sorting/__init__.py +5 -0
- numdaplot/tables/sorting/sort_key.py +71 -0
- numdaplot/tables/sorting/sorted_frame.py +81 -0
- numdaplot/tables/sorting/sorting.py +82 -0
- numdaplot/tables/table.py +71 -0
- numdaplot/tables/table_calculation.py +172 -0
- numdaplot/tables/table_columns.py +214 -0
- numdaplot/tables/table_conversion.py +351 -0
- numdaplot/tables/table_data.py +321 -0
- numdaplot/tables/table_display.py +56 -0
- numdaplot/tables/table_joining.py +80 -0
- numdaplot/tables/table_layout.py +105 -0
- numdaplot/tables/table_missing.py +146 -0
- numdaplot/tables/table_reading.py +451 -0
- numdaplot/tables/table_refusals.py +295 -0
- numdaplot/tables/table_selection.py +163 -0
- numdaplot/tables/table_writing.py +269 -0
- numdaplot-0.1.0.dist-info/METADATA +176 -0
- numdaplot-0.1.0.dist-info/RECORD +474 -0
- numdaplot-0.1.0.dist-info/WHEEL +4 -0
- numdaplot-0.1.0.dist-info/licenses/LICENSE +28 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bounds of an integer result, found from the lowest and the highest values of its operands.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import math
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import numpy
|
|
11
|
+
from numpy.typing import NDArray
|
|
12
|
+
|
|
13
|
+
# A power above this number of bits fits no integer type, and is not worth computing exactly.
|
|
14
|
+
LARGEST_COMPUTED_BITS = 65
|
|
15
|
+
BEYOND_EVERY_INTEGER = 2**LARGEST_COMPUTED_BITS
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def find_value_bounds(values: NDArray[Any]) -> tuple[int, int]:
|
|
19
|
+
"""
|
|
20
|
+
Return the lowest and the highest values of integers or booleans, as Python integers.
|
|
21
|
+
|
|
22
|
+
.. versionadded:: 0.1.0
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
values
|
|
27
|
+
At least one integer or boolean.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
tuple[int, int]
|
|
32
|
+
The lowest and the highest values.
|
|
33
|
+
|
|
34
|
+
Examples
|
|
35
|
+
--------
|
|
36
|
+
>>> import numpy
|
|
37
|
+
>>> from numdaplot.arrays.operations.integer_bounds import find_value_bounds
|
|
38
|
+
>>> find_value_bounds(numpy.array([3, -1, 2]))
|
|
39
|
+
(-1, 3)
|
|
40
|
+
"""
|
|
41
|
+
lowest_value = values.min()
|
|
42
|
+
highest_value = values.max()
|
|
43
|
+
low_bound = int(lowest_value)
|
|
44
|
+
high_bound = int(highest_value)
|
|
45
|
+
|
|
46
|
+
return low_bound, high_bound
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def find_result_bounds(left: tuple[int, int], right: tuple[int, int], function: numpy.ufunc) -> tuple[int, int]:
|
|
50
|
+
"""
|
|
51
|
+
Return bounds that every result of an integer function stays within.
|
|
52
|
+
|
|
53
|
+
.. versionadded:: 0.1.0
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
left
|
|
58
|
+
The bounds of the left operand.
|
|
59
|
+
right
|
|
60
|
+
The bounds of the right operand. No divisor is 0 and no power is negative.
|
|
61
|
+
function
|
|
62
|
+
``numpy.add``, ``numpy.subtract``, ``numpy.multiply``, ``numpy.floor_divide`` or ``numpy.power``.
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
tuple[int, int]
|
|
67
|
+
The low and the high bounds.
|
|
68
|
+
|
|
69
|
+
Examples
|
|
70
|
+
--------
|
|
71
|
+
>>> import numpy
|
|
72
|
+
>>> from numdaplot.arrays.operations.integer_bounds import find_result_bounds
|
|
73
|
+
>>> find_result_bounds((-2, 3), (4, 5), numpy.multiply)
|
|
74
|
+
(-10, 15)
|
|
75
|
+
"""
|
|
76
|
+
left_low, left_high = left
|
|
77
|
+
right_low, right_high = right
|
|
78
|
+
if function == numpy.add:
|
|
79
|
+
sum_bounds = (left_low + right_low, left_high + right_high)
|
|
80
|
+
return sum_bounds
|
|
81
|
+
|
|
82
|
+
if function == numpy.subtract:
|
|
83
|
+
difference_bounds = (left_low - right_high, left_high - right_low)
|
|
84
|
+
return difference_bounds
|
|
85
|
+
|
|
86
|
+
if function == numpy.multiply:
|
|
87
|
+
products = [left_low * right_low, left_low * right_high, left_high * right_low, left_high * right_high]
|
|
88
|
+
lowest_product = min(products)
|
|
89
|
+
highest_product = max(products)
|
|
90
|
+
return lowest_product, highest_product
|
|
91
|
+
|
|
92
|
+
left_magnitude = max(abs(left_low), abs(left_high))
|
|
93
|
+
if function == numpy.floor_divide:
|
|
94
|
+
has_negative = left_low < 0 or right_low < 0
|
|
95
|
+
lowest_quotient = -left_magnitude if has_negative else 0
|
|
96
|
+
return lowest_quotient, left_magnitude
|
|
97
|
+
|
|
98
|
+
highest_power = find_power_bound(left_magnitude, right_high)
|
|
99
|
+
lowest_power = -highest_power if left_low < 0 else 0
|
|
100
|
+
|
|
101
|
+
return lowest_power, highest_power
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def find_power_bound(magnitude: int, power: int) -> int:
|
|
105
|
+
"""
|
|
106
|
+
Return a bound of the absolute value of integers raised to a power.
|
|
107
|
+
|
|
108
|
+
.. versionadded:: 0.1.0
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
magnitude
|
|
113
|
+
The highest absolute value of the integers.
|
|
114
|
+
power
|
|
115
|
+
The highest power, 0 or more.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
int
|
|
120
|
+
The bound, or a number beyond every integer type when the exact bound would be huge.
|
|
121
|
+
|
|
122
|
+
Examples
|
|
123
|
+
--------
|
|
124
|
+
>>> from numdaplot.arrays.operations.integer_bounds import find_power_bound
|
|
125
|
+
>>> find_power_bound(2, 10)
|
|
126
|
+
1024
|
|
127
|
+
>>> find_power_bound(3, 10**18) > 2**64
|
|
128
|
+
True
|
|
129
|
+
"""
|
|
130
|
+
if magnitude <= 1:
|
|
131
|
+
return 1
|
|
132
|
+
|
|
133
|
+
magnitude_bits = math.log2(magnitude)
|
|
134
|
+
power_bits = power * magnitude_bits
|
|
135
|
+
if power_bits > LARGEST_COMPUTED_BITS:
|
|
136
|
+
return BEYOND_EVERY_INTEGER
|
|
137
|
+
|
|
138
|
+
power_bound = magnitude**power
|
|
139
|
+
|
|
140
|
+
return power_bound
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def find_sum_bounds(values: NDArray[Any], axis: int | None) -> tuple[int, int]:
|
|
144
|
+
"""
|
|
145
|
+
Return bounds that every sum of integers or booleans stays within.
|
|
146
|
+
|
|
147
|
+
.. versionadded:: 0.1.0
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
values
|
|
152
|
+
At least one integer or boolean.
|
|
153
|
+
axis
|
|
154
|
+
The numpy axis reduced, or ``None`` for the whole Array.
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
tuple[int, int]
|
|
159
|
+
The low and the high bounds.
|
|
160
|
+
|
|
161
|
+
Examples
|
|
162
|
+
--------
|
|
163
|
+
>>> import numpy
|
|
164
|
+
>>> from numdaplot.arrays.operations.integer_bounds import find_sum_bounds
|
|
165
|
+
>>> find_sum_bounds(numpy.array([[1, 2], [-3, 4]]), None)
|
|
166
|
+
(-12, 16)
|
|
167
|
+
>>> find_sum_bounds(numpy.array([[1, 2], [-3, 4]]), 1)
|
|
168
|
+
(-6, 8)
|
|
169
|
+
"""
|
|
170
|
+
value_count = values.size if axis is None else values.shape[axis]
|
|
171
|
+
low_value, high_value = find_value_bounds(values)
|
|
172
|
+
low_bound = min(low_value, 0) * value_count
|
|
173
|
+
high_bound = max(high_value, 0) * value_count
|
|
174
|
+
|
|
175
|
+
return low_bound, high_bound
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Refusal of integer calculations whose result numpy would silently write as a wrong number.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import numpy
|
|
10
|
+
from numpy.typing import NDArray
|
|
11
|
+
|
|
12
|
+
from numdaplot.arrays.operations.integer_bounds import find_result_bounds, find_sum_bounds, find_value_bounds
|
|
13
|
+
from numdaplot.arrays.operations.operand import Operand
|
|
14
|
+
from numdaplot.data_types.numpy_mapping import from_numpy_dtype
|
|
15
|
+
from numdaplot.errors.integer_overflow_error import IntegerOverflowError
|
|
16
|
+
from numdaplot.errors.out_of_domain_error import OutOfDomainError
|
|
17
|
+
|
|
18
|
+
SIGNED_KIND = "i"
|
|
19
|
+
UNSIGNED_KIND = "u"
|
|
20
|
+
INTEGER_KINDS = frozenset({SIGNED_KIND, UNSIGNED_KIND})
|
|
21
|
+
INTEGER_OR_BOOL_KINDS = frozenset({SIGNED_KIND, UNSIGNED_KIND, "b"})
|
|
22
|
+
POWER_NAME = "Power"
|
|
23
|
+
ZERO_DIVISION_NAMES = dict[numpy.ufunc, str](
|
|
24
|
+
{
|
|
25
|
+
numpy.floor_divide: "Floor division",
|
|
26
|
+
numpy.remainder: "Remainder",
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
OVERFLOWING_FUNCTIONS = frozenset({numpy.add, numpy.subtract, numpy.multiply, numpy.power, numpy.floor_divide})
|
|
30
|
+
PYTHON_OBJECT_DTYPE = numpy.dtype(object)
|
|
31
|
+
ESTIMATE_DTYPE = numpy.dtype(numpy.float64)
|
|
32
|
+
IGNORE_MODE = "ignore"
|
|
33
|
+
# A decimal estimate below half the limit cannot hide a result above it, and one above twice the limit cannot hide a
|
|
34
|
+
# result below it. Exact integers are computed only between both, which also avoids computing huge powers.
|
|
35
|
+
SAFE_ESTIMATE_RATIO = 0.5
|
|
36
|
+
CERTAIN_ESTIMATE_RATIO = 2
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def require_defined_integers(left: Operand, right: Operand, function: numpy.ufunc) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Check that an operation between integers has a result an integer can hold.
|
|
42
|
+
|
|
43
|
+
.. versionadded:: 0.1.0
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
left
|
|
48
|
+
The values of an Array, or a single value.
|
|
49
|
+
right
|
|
50
|
+
The values of an Array, or a single value.
|
|
51
|
+
function
|
|
52
|
+
The numpy function about to be applied.
|
|
53
|
+
|
|
54
|
+
Raises
|
|
55
|
+
------
|
|
56
|
+
OutOfDomainError
|
|
57
|
+
When integers are divided by 0 with ``//`` or ``%``, or raised to a negative power.
|
|
58
|
+
|
|
59
|
+
Examples
|
|
60
|
+
--------
|
|
61
|
+
>>> import numpy
|
|
62
|
+
>>> import numdaplot as ndp
|
|
63
|
+
>>> from numdaplot.arrays.operations.integer_rules import require_defined_integers
|
|
64
|
+
>>> try:
|
|
65
|
+
... require_defined_integers(numpy.array([1, 2]), 0, numpy.floor_divide)
|
|
66
|
+
... except ndp.OutOfDomainError as error:
|
|
67
|
+
... print(error)
|
|
68
|
+
Floor division is not defined for 0 between integers. Convert the values to FLOAT64 first.
|
|
69
|
+
"""
|
|
70
|
+
left_values = numpy.asarray(left)
|
|
71
|
+
right_values = numpy.asarray(right)
|
|
72
|
+
has_integers = left_values.dtype.kind in INTEGER_OR_BOOL_KINDS and right_values.dtype.kind in INTEGER_OR_BOOL_KINDS
|
|
73
|
+
if not has_integers:
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
if function in ZERO_DIVISION_NAMES:
|
|
77
|
+
zeros = right_values == 0
|
|
78
|
+
has_zero = bool(zeros.any())
|
|
79
|
+
if has_zero:
|
|
80
|
+
raise OutOfDomainError(ZERO_DIVISION_NAMES[function], 0, True)
|
|
81
|
+
|
|
82
|
+
if function == numpy.power:
|
|
83
|
+
negatives = right_values < 0
|
|
84
|
+
has_negative = bool(negatives.any())
|
|
85
|
+
if has_negative:
|
|
86
|
+
negative_values = right_values[negatives]
|
|
87
|
+
first_negative = negative_values[0].item()
|
|
88
|
+
raise OutOfDomainError(POWER_NAME, first_negative, True)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def require_combination_fits(operands: list[Operand], function: numpy.ufunc, result: NDArray[Any], symbol: str) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Check that the integers of a result were not wrapped around by numpy.
|
|
94
|
+
|
|
95
|
+
.. versionadded:: 0.1.0
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
operands
|
|
100
|
+
The left and the right operands, each the values of an Array or a single value.
|
|
101
|
+
function
|
|
102
|
+
The numpy function that was applied.
|
|
103
|
+
result
|
|
104
|
+
Its result.
|
|
105
|
+
symbol
|
|
106
|
+
The operator shown in the error message.
|
|
107
|
+
|
|
108
|
+
Raises
|
|
109
|
+
------
|
|
110
|
+
IntegerOverflowError
|
|
111
|
+
When a result does not fit the integer type of ``result``.
|
|
112
|
+
|
|
113
|
+
Examples
|
|
114
|
+
--------
|
|
115
|
+
>>> import numpy
|
|
116
|
+
>>> from numdaplot.arrays.operations.integer_rules import require_combination_fits
|
|
117
|
+
>>> require_combination_fits([numpy.array([1]), 2], numpy.add, numpy.array([3]), "+")
|
|
118
|
+
"""
|
|
119
|
+
if result.dtype.kind not in INTEGER_KINDS:
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
if function not in OVERFLOWING_FUNCTIONS:
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
left_operand, right_operand = operands
|
|
126
|
+
left_array = numpy.asarray(left_operand)
|
|
127
|
+
right_array = numpy.asarray(right_operand)
|
|
128
|
+
if left_array.size == 0 or right_array.size == 0:
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
left_bounds = find_value_bounds(left_array)
|
|
132
|
+
right_bounds = find_value_bounds(right_array)
|
|
133
|
+
result_bounds = find_result_bounds(left_bounds, right_bounds, function)
|
|
134
|
+
bounds_fit = do_bounds_fit(result_bounds, result)
|
|
135
|
+
if bounds_fit:
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
left_values, right_values = numpy.broadcast_arrays(left_array, right_array)
|
|
139
|
+
left_estimates = left_values.astype(ESTIMATE_DTYPE)
|
|
140
|
+
right_estimates = right_values.astype(ESTIMATE_DTYPE)
|
|
141
|
+
with numpy.errstate(all=IGNORE_MODE):
|
|
142
|
+
estimates = function(left_estimates, right_estimates)
|
|
143
|
+
|
|
144
|
+
doubtful = find_doubtful_estimates(estimates, result, symbol)
|
|
145
|
+
has_doubt = bool(doubtful.any())
|
|
146
|
+
if not has_doubt:
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
exact_left = left_values[doubtful].astype(PYTHON_OBJECT_DTYPE)
|
|
150
|
+
exact_right = right_values[doubtful].astype(PYTHON_OBJECT_DTYPE)
|
|
151
|
+
exact_values = function(exact_left, exact_right)
|
|
152
|
+
require_exact_values_fit(exact_values, result, symbol)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def require_sum_fits(values: NDArray[Any], axis: int | None, result: NDArray[Any], statistic_name: str) -> None:
|
|
156
|
+
"""
|
|
157
|
+
Check that the integers of a sum were not wrapped around by numpy.
|
|
158
|
+
|
|
159
|
+
.. versionadded:: 0.1.0
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
values
|
|
164
|
+
The summed values.
|
|
165
|
+
axis
|
|
166
|
+
The numpy axis reduced, or ``None`` for the whole Array.
|
|
167
|
+
result
|
|
168
|
+
The sum given by numpy.
|
|
169
|
+
statistic_name
|
|
170
|
+
Name of the statistic, shown in the error message.
|
|
171
|
+
|
|
172
|
+
Raises
|
|
173
|
+
------
|
|
174
|
+
IntegerOverflowError
|
|
175
|
+
When a sum does not fit the integer type of ``result``.
|
|
176
|
+
|
|
177
|
+
Examples
|
|
178
|
+
--------
|
|
179
|
+
>>> import numpy
|
|
180
|
+
>>> import numdaplot as ndp
|
|
181
|
+
>>> from numdaplot.arrays.operations.integer_rules import require_sum_fits
|
|
182
|
+
>>> values = numpy.array([2**62, 2**62])
|
|
183
|
+
>>> try:
|
|
184
|
+
... require_sum_fits(values, None, numpy.array([0]), "Sum")
|
|
185
|
+
... except ndp.IntegerOverflowError as error:
|
|
186
|
+
... print(error)
|
|
187
|
+
The operation Sum gives values too large for INT64. Convert the values to FLOAT64 first.
|
|
188
|
+
"""
|
|
189
|
+
if result.dtype.kind not in INTEGER_KINDS:
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
if values.size == 0:
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
sum_bounds = find_sum_bounds(values, axis)
|
|
196
|
+
bounds_fit = do_bounds_fit(sum_bounds, result)
|
|
197
|
+
if bounds_fit:
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
decimal_values = values.astype(ESTIMATE_DTYPE)
|
|
201
|
+
estimates = numpy.sum(decimal_values, axis=axis)
|
|
202
|
+
estimate_values = numpy.asarray(estimates)
|
|
203
|
+
doubtful = find_doubtful_estimates(estimate_values, result, statistic_name)
|
|
204
|
+
has_doubt = bool(doubtful.any())
|
|
205
|
+
if not has_doubt:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
exact_integers = values.astype(PYTHON_OBJECT_DTYPE)
|
|
209
|
+
exact_values = numpy.sum(exact_integers, axis=axis)
|
|
210
|
+
exact_array = numpy.asarray(exact_values, dtype=PYTHON_OBJECT_DTYPE)
|
|
211
|
+
require_exact_values_fit(exact_array, result, statistic_name)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def do_bounds_fit(bounds: tuple[int, int], result: NDArray[Any]) -> bool:
|
|
215
|
+
"""
|
|
216
|
+
Return whether bounds of a result stay within the limits of its integer type.
|
|
217
|
+
|
|
218
|
+
.. versionadded:: 0.1.0
|
|
219
|
+
|
|
220
|
+
Parameters
|
|
221
|
+
----------
|
|
222
|
+
bounds
|
|
223
|
+
The low and the high bounds of the result.
|
|
224
|
+
result
|
|
225
|
+
The result computed with integers, giving the integer type.
|
|
226
|
+
|
|
227
|
+
Returns
|
|
228
|
+
-------
|
|
229
|
+
bool
|
|
230
|
+
True when no value can have been wrapped around.
|
|
231
|
+
|
|
232
|
+
Examples
|
|
233
|
+
--------
|
|
234
|
+
>>> import numpy
|
|
235
|
+
>>> from numdaplot.arrays.operations.integer_rules import do_bounds_fit
|
|
236
|
+
>>> do_bounds_fit((0, 127), numpy.array([0], dtype="int8"))
|
|
237
|
+
True
|
|
238
|
+
>>> do_bounds_fit((0, 128), numpy.array([0], dtype="int8"))
|
|
239
|
+
False
|
|
240
|
+
"""
|
|
241
|
+
limits = numpy.iinfo(result.dtype)
|
|
242
|
+
low_bound, high_bound = bounds
|
|
243
|
+
bounds_fit = limits.min <= low_bound and high_bound <= limits.max
|
|
244
|
+
|
|
245
|
+
return bounds_fit
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def require_absolute_fits(values: NDArray[Any], operation_name: str) -> None:
|
|
249
|
+
"""
|
|
250
|
+
Check that signed integers have an absolute value of their type: the lowest integer has none.
|
|
251
|
+
|
|
252
|
+
.. versionadded:: 0.1.0
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
values
|
|
257
|
+
The values of a number Array.
|
|
258
|
+
operation_name
|
|
259
|
+
The operator or the function, shown in the error message.
|
|
260
|
+
|
|
261
|
+
Raises
|
|
262
|
+
------
|
|
263
|
+
IntegerOverflowError
|
|
264
|
+
When a value is the lowest integer of its type.
|
|
265
|
+
|
|
266
|
+
Examples
|
|
267
|
+
--------
|
|
268
|
+
>>> import numpy
|
|
269
|
+
>>> from numdaplot.arrays.operations.integer_rules import require_absolute_fits
|
|
270
|
+
>>> require_absolute_fits(numpy.array([-1, 2]), "Absolute")
|
|
271
|
+
"""
|
|
272
|
+
if values.dtype.kind != SIGNED_KIND:
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
limits = numpy.iinfo(values.dtype)
|
|
276
|
+
is_lowest = values == limits.min
|
|
277
|
+
has_lowest = bool(is_lowest.any())
|
|
278
|
+
if has_lowest:
|
|
279
|
+
values_type = from_numpy_dtype(values.dtype)
|
|
280
|
+
raise IntegerOverflowError(operation_name, values_type.name)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def require_opposite_fits(values: NDArray[Any], operation_name: str) -> None:
|
|
284
|
+
"""
|
|
285
|
+
Check that integers have an opposite of their type: unsigned integers only have the opposite of 0.
|
|
286
|
+
|
|
287
|
+
.. versionadded:: 0.1.0
|
|
288
|
+
|
|
289
|
+
Parameters
|
|
290
|
+
----------
|
|
291
|
+
values
|
|
292
|
+
The values of a number Array.
|
|
293
|
+
operation_name
|
|
294
|
+
The operator, shown in the error message.
|
|
295
|
+
|
|
296
|
+
Raises
|
|
297
|
+
------
|
|
298
|
+
IntegerOverflowError
|
|
299
|
+
When a value has no opposite in its type.
|
|
300
|
+
|
|
301
|
+
Examples
|
|
302
|
+
--------
|
|
303
|
+
>>> import numpy
|
|
304
|
+
>>> from numdaplot.arrays.operations.integer_rules import require_opposite_fits
|
|
305
|
+
>>> require_opposite_fits(numpy.array([0], dtype="uint8"), "-")
|
|
306
|
+
"""
|
|
307
|
+
require_absolute_fits(values, operation_name)
|
|
308
|
+
if values.dtype.kind != UNSIGNED_KIND:
|
|
309
|
+
return
|
|
310
|
+
|
|
311
|
+
has_value_above_zero = bool(values.any())
|
|
312
|
+
if has_value_above_zero:
|
|
313
|
+
values_type = from_numpy_dtype(values.dtype)
|
|
314
|
+
raise IntegerOverflowError(operation_name, values_type.name)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def find_doubtful_estimates(estimates: NDArray[Any], result: NDArray[Any], operation_name: str) -> NDArray[numpy.bool_]:
|
|
318
|
+
"""
|
|
319
|
+
Return which decimal estimates of integers need an exact calculation.
|
|
320
|
+
|
|
321
|
+
.. versionadded:: 0.1.0
|
|
322
|
+
|
|
323
|
+
Parameters
|
|
324
|
+
----------
|
|
325
|
+
estimates
|
|
326
|
+
The result computed with decimals.
|
|
327
|
+
result
|
|
328
|
+
The result computed with integers, giving the integer type.
|
|
329
|
+
operation_name
|
|
330
|
+
The operator or the statistic, shown in the error message.
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
NDArray[numpy.bool_]
|
|
335
|
+
True at each estimate too close to the limits of the type to conclude.
|
|
336
|
+
|
|
337
|
+
Raises
|
|
338
|
+
------
|
|
339
|
+
IntegerOverflowError
|
|
340
|
+
When an estimate is far above the limits of the type.
|
|
341
|
+
|
|
342
|
+
Examples
|
|
343
|
+
--------
|
|
344
|
+
>>> import numpy
|
|
345
|
+
>>> from numdaplot.arrays.operations.integer_rules import find_doubtful_estimates
|
|
346
|
+
>>> find_doubtful_estimates(numpy.array([1.0, 100.0]), numpy.array([1, 100], dtype="int8"), "+")
|
|
347
|
+
array([False, True])
|
|
348
|
+
"""
|
|
349
|
+
limits = numpy.iinfo(result.dtype)
|
|
350
|
+
magnitudes = numpy.abs(estimates)
|
|
351
|
+
is_certain = magnitudes >= limits.max * CERTAIN_ESTIMATE_RATIO
|
|
352
|
+
has_certain_overflow = bool(numpy.any(is_certain))
|
|
353
|
+
if has_certain_overflow:
|
|
354
|
+
result_type = from_numpy_dtype(result.dtype)
|
|
355
|
+
raise IntegerOverflowError(operation_name, result_type.name)
|
|
356
|
+
|
|
357
|
+
is_near_limit = magnitudes >= limits.max * SAFE_ESTIMATE_RATIO
|
|
358
|
+
is_below_lowest = estimates < limits.min
|
|
359
|
+
doubtful = is_near_limit | is_below_lowest
|
|
360
|
+
|
|
361
|
+
return doubtful
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def require_exact_values_fit(exact_values: NDArray[Any], result: NDArray[Any], operation_name: str) -> None:
|
|
365
|
+
"""
|
|
366
|
+
Check that exact Python integers fit an integer type.
|
|
367
|
+
|
|
368
|
+
.. versionadded:: 0.1.0
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
exact_values
|
|
373
|
+
Python integers, in a numpy array of objects.
|
|
374
|
+
result
|
|
375
|
+
The result computed with integers, giving the integer type.
|
|
376
|
+
operation_name
|
|
377
|
+
The operator or the statistic, shown in the error message.
|
|
378
|
+
|
|
379
|
+
Raises
|
|
380
|
+
------
|
|
381
|
+
IntegerOverflowError
|
|
382
|
+
When a value is outside the limits of the type.
|
|
383
|
+
|
|
384
|
+
Examples
|
|
385
|
+
--------
|
|
386
|
+
>>> import numpy
|
|
387
|
+
>>> from numdaplot.arrays.operations.integer_rules import require_exact_values_fit
|
|
388
|
+
>>> require_exact_values_fit(numpy.array([100], dtype=object), numpy.array([100], dtype="int8"), "+")
|
|
389
|
+
"""
|
|
390
|
+
limits = numpy.iinfo(result.dtype)
|
|
391
|
+
is_above = exact_values > limits.max
|
|
392
|
+
is_below = exact_values < limits.min
|
|
393
|
+
is_outside = is_above | is_below
|
|
394
|
+
has_outside_value = bool(numpy.any(is_outside))
|
|
395
|
+
if has_outside_value:
|
|
396
|
+
result_type = from_numpy_dtype(result.dtype)
|
|
397
|
+
raise IntegerOverflowError(operation_name, result_type.name)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Values an Array can be combined with.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import date, time, timedelta
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import numpy
|
|
11
|
+
from numpy.typing import NDArray
|
|
12
|
+
|
|
13
|
+
from numdaplot.data_types.numpy_mapping import from_numpy_dtype
|
|
14
|
+
from numdaplot.data_types.time_of_day import to_time_since_midnight
|
|
15
|
+
from numdaplot.data_types.type import Type
|
|
16
|
+
from numdaplot.data_types.value_type import find_value_type
|
|
17
|
+
from numdaplot.rules.rule_values import ScalarValue
|
|
18
|
+
|
|
19
|
+
MICROSECONDS_IN_COUNT = 2**63 - 1
|
|
20
|
+
LONGEST_MICROSECOND_DURATION = timedelta(microseconds=MICROSECONDS_IN_COUNT)
|
|
21
|
+
ONE_SECOND = timedelta(seconds=1)
|
|
22
|
+
SECOND_CODE = "s"
|
|
23
|
+
TIME_CODE = "us"
|
|
24
|
+
|
|
25
|
+
type Operand = NDArray[Any] | ScalarValue
|
|
26
|
+
"""The values of an Array, or a single value, on one side of an operation.
|
|
27
|
+
|
|
28
|
+
.. versionadded:: 0.1.0
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def find_operand_type(operand: Operand) -> Type:
|
|
33
|
+
"""
|
|
34
|
+
Return the numdaplot type of the values on one side of an operation.
|
|
35
|
+
|
|
36
|
+
.. versionadded:: 0.1.0
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
operand
|
|
41
|
+
The values of an Array, or a single value.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
Type
|
|
46
|
+
The type of the values.
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
>>> import numpy
|
|
51
|
+
>>> from numdaplot.arrays.operations.operand import find_operand_type
|
|
52
|
+
>>> find_operand_type(numpy.array([1.5]))
|
|
53
|
+
<Type.FLOAT64: 10>
|
|
54
|
+
"""
|
|
55
|
+
if isinstance(operand, numpy.ndarray):
|
|
56
|
+
array_type = from_numpy_dtype(operand.dtype)
|
|
57
|
+
return array_type
|
|
58
|
+
|
|
59
|
+
value_type = find_value_type(operand)
|
|
60
|
+
|
|
61
|
+
return value_type
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def find_operand_type_names(operands: list[Operand]) -> list[str]:
|
|
65
|
+
"""
|
|
66
|
+
Return the names of the numdaplot types of several operands, as shown in error messages.
|
|
67
|
+
|
|
68
|
+
.. versionadded:: 0.1.0
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
operands
|
|
73
|
+
The values of Arrays, or single values.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
list[str]
|
|
78
|
+
The name of the type of each operand, in order.
|
|
79
|
+
|
|
80
|
+
Examples
|
|
81
|
+
--------
|
|
82
|
+
>>> import numpy
|
|
83
|
+
>>> from numdaplot.arrays.operations.operand import find_operand_type_names
|
|
84
|
+
>>> find_operand_type_names([numpy.array([1]), "euros"])
|
|
85
|
+
['INT64', 'TEXT']
|
|
86
|
+
"""
|
|
87
|
+
operand_types = [find_operand_type(operand) for operand in operands]
|
|
88
|
+
type_names = [operand_type.name for operand_type in operand_types]
|
|
89
|
+
|
|
90
|
+
return type_names
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def convert_time_value(value: ScalarValue) -> Any:
|
|
94
|
+
"""
|
|
95
|
+
Return a single value in the form numpy compares with Array values.
|
|
96
|
+
|
|
97
|
+
numpy compares a Python date with its own dates through Python objects, which fails on a missing date.
|
|
98
|
+
|
|
99
|
+
.. versionadded:: 0.1.0
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
value
|
|
104
|
+
A single value.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
Any
|
|
109
|
+
A ``numpy.datetime64`` for a date or a datetime, a ``numpy.timedelta64`` for a duration, in seconds when
|
|
110
|
+
microseconds cannot count it, the time since midnight in microseconds for a time of day, the value itself
|
|
111
|
+
otherwise.
|
|
112
|
+
|
|
113
|
+
Examples
|
|
114
|
+
--------
|
|
115
|
+
>>> from datetime import date
|
|
116
|
+
>>> from numdaplot.arrays.operations.operand import convert_time_value
|
|
117
|
+
>>> convert_time_value(date(2026, 1, 31))
|
|
118
|
+
np.datetime64('2026-01-31')
|
|
119
|
+
"""
|
|
120
|
+
if isinstance(value, date):
|
|
121
|
+
moment = numpy.datetime64(value)
|
|
122
|
+
return moment
|
|
123
|
+
|
|
124
|
+
if isinstance(value, time):
|
|
125
|
+
since_midnight = to_time_since_midnight(value)
|
|
126
|
+
time_of_day = numpy.timedelta64(since_midnight, TIME_CODE)
|
|
127
|
+
return time_of_day
|
|
128
|
+
|
|
129
|
+
if isinstance(value, timedelta):
|
|
130
|
+
is_too_long_for_microseconds = abs(value) > LONGEST_MICROSECOND_DURATION
|
|
131
|
+
if is_too_long_for_microseconds:
|
|
132
|
+
whole_seconds = value // ONE_SECOND
|
|
133
|
+
second_duration = numpy.timedelta64(whole_seconds, SECOND_CODE)
|
|
134
|
+
return second_duration
|
|
135
|
+
|
|
136
|
+
duration = numpy.timedelta64(value)
|
|
137
|
+
return duration
|
|
138
|
+
|
|
139
|
+
return value
|