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,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Checks and alignment of the key columns of a join.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import numpy
|
|
8
|
+
import pandas
|
|
9
|
+
|
|
10
|
+
from numdaplot.data_types.numpy_mapping import from_numpy_dtype, to_numpy_dtype
|
|
11
|
+
from numdaplot.data_types.pandas_mapping import to_pandas_dtype
|
|
12
|
+
from numdaplot.data_types.type import Type
|
|
13
|
+
from numdaplot.data_types.value_family import ValueFamily, find_family
|
|
14
|
+
from numdaplot.errors.column_not_found_error import ColumnNotFoundError
|
|
15
|
+
from numdaplot.errors.incompatible_types_error import IncompatibleTypesError
|
|
16
|
+
from numdaplot.errors.time_zone_mismatch_error import TimeZoneMismatchError
|
|
17
|
+
from numdaplot.tables.columns.column_names import require_known_columns
|
|
18
|
+
from numdaplot.tables.frames.column import Column
|
|
19
|
+
from numdaplot.tables.frames.column_values import find_column_type
|
|
20
|
+
from numdaplot.tables.frames.named_column_errors import NamedColumnErrors
|
|
21
|
+
from numdaplot.tables.frames.time_zones import find_column_time_zone
|
|
22
|
+
from numdaplot.tables.joining.key_types import KeyTypes
|
|
23
|
+
|
|
24
|
+
OTHER_TABLE_NAME = "the other Table"
|
|
25
|
+
JOIN_OPERATION = "Join"
|
|
26
|
+
KEY_OPERATION = "Joining on {key_name!r}"
|
|
27
|
+
FLOAT_DTYPE = numpy.dtype(numpy.float64)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def align_key_frames(
|
|
31
|
+
frame: pandas.DataFrame, other_frame: pandas.DataFrame, keys: list[str], key_types: KeyTypes
|
|
32
|
+
) -> tuple[pandas.DataFrame, pandas.DataFrame]:
|
|
33
|
+
"""
|
|
34
|
+
Return the key columns of both Tables of a join, each key converted to one type on both sides.
|
|
35
|
+
|
|
36
|
+
.. versionadded:: 0.1.0
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
frame
|
|
41
|
+
The columns of the joined Table.
|
|
42
|
+
other_frame
|
|
43
|
+
The columns of the other Table.
|
|
44
|
+
keys
|
|
45
|
+
The names of the key columns.
|
|
46
|
+
key_types
|
|
47
|
+
How close the types of each key must be.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
tuple[pandas.DataFrame, pandas.DataFrame]
|
|
52
|
+
The key columns of the joined Table and of the other Table, of the same types.
|
|
53
|
+
|
|
54
|
+
Raises
|
|
55
|
+
------
|
|
56
|
+
ColumnNotFoundError
|
|
57
|
+
When a key is missing from one of the Tables.
|
|
58
|
+
IncompatibleTypesError
|
|
59
|
+
When the two columns of a key are of different families, of different types with ``KeyTypes.SAME_TYPE``, or
|
|
60
|
+
a date and a datetime.
|
|
61
|
+
TimeZoneMismatchError
|
|
62
|
+
When the two columns of a key hold datetimes of different time zones, or with and without one.
|
|
63
|
+
|
|
64
|
+
Examples
|
|
65
|
+
--------
|
|
66
|
+
>>> import pandas
|
|
67
|
+
>>> import numdaplot as ndp
|
|
68
|
+
>>> from numdaplot.tables.joining.join_keys import align_key_frames
|
|
69
|
+
>>> frame = pandas.DataFrame({"id": pandas.array([1, 2], dtype="Int64")})
|
|
70
|
+
>>> other_frame = pandas.DataFrame({"id": [1.0, 2.5]})
|
|
71
|
+
>>> key_frame, other_key_frame = align_key_frames(frame, other_frame, ["id"], ndp.KeyTypes.SAME_FAMILY)
|
|
72
|
+
>>> key_frame["id"].tolist()
|
|
73
|
+
[1.0, 2.0]
|
|
74
|
+
"""
|
|
75
|
+
column_names = frame.columns.tolist()
|
|
76
|
+
other_names = other_frame.columns.tolist()
|
|
77
|
+
require_known_columns(keys, column_names)
|
|
78
|
+
require_other_keys(keys, other_names)
|
|
79
|
+
key_columns = dict[str, Column]()
|
|
80
|
+
other_key_columns = dict[str, Column]()
|
|
81
|
+
|
|
82
|
+
for key_name in keys:
|
|
83
|
+
column = frame[key_name]
|
|
84
|
+
other_column = other_frame[key_name]
|
|
85
|
+
key_type = find_key_type(column, other_column, key_types)
|
|
86
|
+
key_column = convert_key_column(column, key_type)
|
|
87
|
+
other_key_column = convert_key_column(other_column, key_type)
|
|
88
|
+
key_columns[key_name] = key_column
|
|
89
|
+
other_key_columns[key_name] = other_key_column
|
|
90
|
+
|
|
91
|
+
key_frame = pandas.DataFrame(key_columns)
|
|
92
|
+
other_key_frame = pandas.DataFrame(other_key_columns)
|
|
93
|
+
|
|
94
|
+
return key_frame, other_key_frame
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def require_other_keys(keys: list[str], other_names: list[str]) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Check that the other Table of a join has every key column.
|
|
100
|
+
|
|
101
|
+
.. versionadded:: 0.1.0
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
keys
|
|
106
|
+
The names of the key columns.
|
|
107
|
+
other_names
|
|
108
|
+
The column names of the other Table.
|
|
109
|
+
|
|
110
|
+
Raises
|
|
111
|
+
------
|
|
112
|
+
ColumnNotFoundError
|
|
113
|
+
At the first key the other Table does not have, naming it.
|
|
114
|
+
|
|
115
|
+
Examples
|
|
116
|
+
--------
|
|
117
|
+
>>> import numdaplot as ndp
|
|
118
|
+
>>> from numdaplot.tables.joining.join_keys import require_other_keys
|
|
119
|
+
>>> try:
|
|
120
|
+
... require_other_keys(["Num_Acc"], ["num_acc"])
|
|
121
|
+
... except ndp.ColumnNotFoundError as error:
|
|
122
|
+
... print(error)
|
|
123
|
+
No column of the other Table is named 'Num_Acc'.
|
|
124
|
+
"""
|
|
125
|
+
known_names = set(other_names)
|
|
126
|
+
|
|
127
|
+
for key_name in keys:
|
|
128
|
+
if key_name not in known_names:
|
|
129
|
+
raise ColumnNotFoundError(key_name, OTHER_TABLE_NAME)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def find_key_type(column: Column, other_column: Column, key_types: KeyTypes) -> Type:
|
|
133
|
+
"""
|
|
134
|
+
Return the type both columns of a key take for the join.
|
|
135
|
+
|
|
136
|
+
.. versionadded:: 0.1.0
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
column
|
|
141
|
+
The key column of the joined Table.
|
|
142
|
+
other_column
|
|
143
|
+
The key column of the other Table.
|
|
144
|
+
key_types
|
|
145
|
+
How close their types must be.
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
Type
|
|
150
|
+
Their type when they share it, except categories of different categories, which give ``TEXT``. Otherwise
|
|
151
|
+
the number type holding both, or ``TEXT`` for a text and a category.
|
|
152
|
+
|
|
153
|
+
Raises
|
|
154
|
+
------
|
|
155
|
+
IncompatibleTypesError
|
|
156
|
+
When the columns are of different families, of different types with ``KeyTypes.SAME_TYPE``, or a date and
|
|
157
|
+
a datetime.
|
|
158
|
+
TimeZoneMismatchError
|
|
159
|
+
When the columns hold datetimes of different time zones, or with and without one.
|
|
160
|
+
|
|
161
|
+
Examples
|
|
162
|
+
--------
|
|
163
|
+
>>> import pandas
|
|
164
|
+
>>> import numdaplot as ndp
|
|
165
|
+
>>> from numdaplot.tables.joining.join_keys import find_key_type
|
|
166
|
+
>>> integers = pandas.Series([1], dtype="Int32")
|
|
167
|
+
>>> find_key_type(integers, pandas.Series([1], dtype="Int64"), ndp.KeyTypes.SAME_FAMILY)
|
|
168
|
+
<Type.INT64: 4>
|
|
169
|
+
"""
|
|
170
|
+
column_type = find_column_type(column)
|
|
171
|
+
other_type = find_column_type(other_column)
|
|
172
|
+
require_key_types(column, column_type, other_type, key_types)
|
|
173
|
+
require_same_time_zone(column, other_column)
|
|
174
|
+
if column_type == other_type:
|
|
175
|
+
shared_type = find_shared_key_type(column, other_column, column_type)
|
|
176
|
+
return shared_type
|
|
177
|
+
|
|
178
|
+
family = find_family(column_type)
|
|
179
|
+
if family == ValueFamily.TEXT:
|
|
180
|
+
return Type.TEXT
|
|
181
|
+
|
|
182
|
+
numpy_dtype = to_numpy_dtype(column_type)
|
|
183
|
+
other_numpy_dtype = to_numpy_dtype(other_type)
|
|
184
|
+
common_numpy_dtype = numpy.result_type(numpy_dtype, other_numpy_dtype)
|
|
185
|
+
common_type = from_numpy_dtype(common_numpy_dtype)
|
|
186
|
+
|
|
187
|
+
return common_type
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def require_key_types(column: Column, column_type: Type, other_type: Type, key_types: KeyTypes) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Check that the two columns of a key can match.
|
|
193
|
+
|
|
194
|
+
.. versionadded:: 0.1.0
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
column
|
|
199
|
+
The key column of the joined Table, named in the error message.
|
|
200
|
+
column_type
|
|
201
|
+
Its type.
|
|
202
|
+
other_type
|
|
203
|
+
The type of the key column of the other Table.
|
|
204
|
+
key_types
|
|
205
|
+
How close the types must be.
|
|
206
|
+
|
|
207
|
+
Raises
|
|
208
|
+
------
|
|
209
|
+
IncompatibleTypesError
|
|
210
|
+
When the types are of different families, different with ``KeyTypes.SAME_TYPE``, or a date and a datetime,
|
|
211
|
+
whose family is the same.
|
|
212
|
+
|
|
213
|
+
Examples
|
|
214
|
+
--------
|
|
215
|
+
>>> import pandas
|
|
216
|
+
>>> import numdaplot as ndp
|
|
217
|
+
>>> from numdaplot.tables.joining.join_keys import require_key_types
|
|
218
|
+
>>> days = pandas.Series(pandas.to_datetime(["2026-01-01"]), name="day").astype("datetime64[s]")
|
|
219
|
+
>>> try:
|
|
220
|
+
... require_key_types(days, ndp.Type.DATE, ndp.Type.DATETIME, ndp.KeyTypes.SAME_FAMILY)
|
|
221
|
+
... except ndp.IncompatibleTypesError as error:
|
|
222
|
+
... print(error)
|
|
223
|
+
Cannot apply Join to the DATE column 'day' and DATETIME.
|
|
224
|
+
"""
|
|
225
|
+
if column_type == other_type:
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
family = find_family(column_type)
|
|
229
|
+
other_family = find_family(other_type)
|
|
230
|
+
is_same_family = family == other_family
|
|
231
|
+
is_moment = family == ValueFamily.MOMENT
|
|
232
|
+
needs_same_type = key_types == KeyTypes.SAME_TYPE
|
|
233
|
+
can_match = is_same_family and not is_moment and not needs_same_type
|
|
234
|
+
if can_match:
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
with NamedColumnErrors(column):
|
|
238
|
+
raise IncompatibleTypesError(JOIN_OPERATION, [column_type.name, other_type.name])
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def require_same_time_zone(column: Column, other_column: Column) -> None:
|
|
242
|
+
"""
|
|
243
|
+
Check that the two columns of a key hold datetimes of the same time zone, or both without one.
|
|
244
|
+
|
|
245
|
+
.. versionadded:: 0.1.0
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
column
|
|
250
|
+
The key column of the joined Table, named in the error message.
|
|
251
|
+
other_column
|
|
252
|
+
The key column of the other Table.
|
|
253
|
+
|
|
254
|
+
Raises
|
|
255
|
+
------
|
|
256
|
+
TimeZoneMismatchError
|
|
257
|
+
When only one has a time zone, naming the state the other column needs, or their time zones differ: change
|
|
258
|
+
them first with ``TimeZoneChange``.
|
|
259
|
+
|
|
260
|
+
Examples
|
|
261
|
+
--------
|
|
262
|
+
>>> import pandas
|
|
263
|
+
>>> import numdaplot as ndp
|
|
264
|
+
>>> from numdaplot.tables.joining.join_keys import require_same_time_zone
|
|
265
|
+
>>> utc_times = pandas.Series(pandas.to_datetime(["2026-07-01 10:30"]), name="time").dt.tz_localize("UTC")
|
|
266
|
+
>>> try:
|
|
267
|
+
... require_same_time_zone(utc_times, utc_times.dt.tz_convert("Europe/Paris"))
|
|
268
|
+
... except ndp.TimeZoneMismatchError as error:
|
|
269
|
+
... print(error)
|
|
270
|
+
Joining on 'time' needs datetimes in one time zone, got UTC and Europe/Paris.
|
|
271
|
+
"""
|
|
272
|
+
time_zone = find_column_time_zone(column)
|
|
273
|
+
other_time_zone = find_column_time_zone(other_column)
|
|
274
|
+
if time_zone == other_time_zone:
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
operation = KEY_OPERATION.format(key_name=column.name)
|
|
278
|
+
if time_zone is None:
|
|
279
|
+
raise TimeZoneMismatchError(operation, False)
|
|
280
|
+
|
|
281
|
+
if other_time_zone is None:
|
|
282
|
+
raise TimeZoneMismatchError(operation, True)
|
|
283
|
+
|
|
284
|
+
zone_names = [time_zone.name, other_time_zone.name]
|
|
285
|
+
raise TimeZoneMismatchError(operation, True, zone_names)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def find_shared_key_type(column: Column, other_column: Column, key_type: Type) -> Type:
|
|
289
|
+
"""
|
|
290
|
+
Return the type of a key whose two columns have the same type.
|
|
291
|
+
|
|
292
|
+
.. versionadded:: 0.1.0
|
|
293
|
+
|
|
294
|
+
Parameters
|
|
295
|
+
----------
|
|
296
|
+
column
|
|
297
|
+
The key column of the joined Table.
|
|
298
|
+
other_column
|
|
299
|
+
The key column of the other Table.
|
|
300
|
+
key_type
|
|
301
|
+
Their type.
|
|
302
|
+
|
|
303
|
+
Returns
|
|
304
|
+
-------
|
|
305
|
+
Type
|
|
306
|
+
The type itself, or ``TEXT`` for two categories that do not have the same categories.
|
|
307
|
+
|
|
308
|
+
Examples
|
|
309
|
+
--------
|
|
310
|
+
>>> import pandas
|
|
311
|
+
>>> import numdaplot as ndp
|
|
312
|
+
>>> from numdaplot.tables.joining.join_keys import find_shared_key_type
|
|
313
|
+
>>> paris = pandas.Series(["Paris"], dtype="category")
|
|
314
|
+
>>> find_shared_key_type(paris, pandas.Series(["Lyon"], dtype="category"), ndp.Type.CATEGORY)
|
|
315
|
+
<Type.TEXT: 12>
|
|
316
|
+
"""
|
|
317
|
+
if key_type != Type.CATEGORY:
|
|
318
|
+
return key_type
|
|
319
|
+
|
|
320
|
+
categories = column.cat.categories
|
|
321
|
+
other_categories = other_column.cat.categories
|
|
322
|
+
has_same_categories = categories.equals(other_categories)
|
|
323
|
+
if has_same_categories:
|
|
324
|
+
return key_type
|
|
325
|
+
|
|
326
|
+
return Type.TEXT
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def convert_key_column(column: Column, key_type: Type) -> Column:
|
|
330
|
+
"""
|
|
331
|
+
Return a key column converted to the type both sides of the key take.
|
|
332
|
+
|
|
333
|
+
.. versionadded:: 0.1.0
|
|
334
|
+
|
|
335
|
+
Parameters
|
|
336
|
+
----------
|
|
337
|
+
column
|
|
338
|
+
A key column.
|
|
339
|
+
key_type
|
|
340
|
+
The type of the key for the join.
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
Column
|
|
345
|
+
The column itself when it has that type, otherwise a converted copy, missing values staying missing.
|
|
346
|
+
|
|
347
|
+
Examples
|
|
348
|
+
--------
|
|
349
|
+
>>> import pandas
|
|
350
|
+
>>> import numdaplot as ndp
|
|
351
|
+
>>> from numdaplot.tables.joining.join_keys import convert_key_column
|
|
352
|
+
>>> convert_key_column(pandas.Series([1, None], dtype="Int64"), ndp.Type.FLOAT64).tolist()
|
|
353
|
+
[1.0, nan]
|
|
354
|
+
"""
|
|
355
|
+
column_type = find_column_type(column)
|
|
356
|
+
if column_type == key_type:
|
|
357
|
+
return column
|
|
358
|
+
|
|
359
|
+
if key_type == Type.FLOAT64:
|
|
360
|
+
numbers = column.to_numpy(dtype=FLOAT_DTYPE, na_value=numpy.nan)
|
|
361
|
+
number_column = pandas.Series(numbers, name=column.name)
|
|
362
|
+
return number_column
|
|
363
|
+
|
|
364
|
+
key_dtype = to_pandas_dtype(key_type)
|
|
365
|
+
converted_column = column.astype(key_dtype)
|
|
366
|
+
|
|
367
|
+
return converted_column
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Which rows a join of two Tables keeps.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum, auto
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class JoinMode(Enum):
|
|
11
|
+
"""
|
|
12
|
+
Which rows a join keeps, used by ``Join``: the rows of both Tables whose keys match, and the rows left alone.
|
|
13
|
+
|
|
14
|
+
A row whose keys match several rows of the other Table appears once per match. A missing key never matches.
|
|
15
|
+
|
|
16
|
+
.. versionadded:: 0.1.0
|
|
17
|
+
|
|
18
|
+
Examples
|
|
19
|
+
--------
|
|
20
|
+
>>> import numdaplot as ndp
|
|
21
|
+
>>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
|
|
22
|
+
>>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
|
|
23
|
+
>>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.OUTER))
|
|
24
|
+
id dep age
|
|
25
|
+
INT64 TEXT INT64
|
|
26
|
+
0 1 75 34
|
|
27
|
+
1 2 69 <NA>
|
|
28
|
+
2 3 <NA> 51
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
INNER = auto()
|
|
32
|
+
"""
|
|
33
|
+
Only the rows whose keys match a row of the other Table. Default value.
|
|
34
|
+
|
|
35
|
+
Examples
|
|
36
|
+
--------
|
|
37
|
+
>>> import numdaplot as ndp
|
|
38
|
+
>>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
|
|
39
|
+
>>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
|
|
40
|
+
>>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.INNER))
|
|
41
|
+
id dep age
|
|
42
|
+
INT64 TEXT INT64
|
|
43
|
+
0 1 75 34
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
LEFT = auto()
|
|
47
|
+
"""
|
|
48
|
+
Every row of the joined Table, with missing values where the other Table has no match.
|
|
49
|
+
|
|
50
|
+
Examples
|
|
51
|
+
--------
|
|
52
|
+
>>> import numdaplot as ndp
|
|
53
|
+
>>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
|
|
54
|
+
>>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
|
|
55
|
+
>>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.LEFT))
|
|
56
|
+
id dep age
|
|
57
|
+
INT64 TEXT INT64
|
|
58
|
+
0 1 75 34
|
|
59
|
+
1 2 69 <NA>
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
RIGHT = auto()
|
|
63
|
+
"""
|
|
64
|
+
Every row of the other Table, with missing values where the joined Table has no match.
|
|
65
|
+
|
|
66
|
+
Examples
|
|
67
|
+
--------
|
|
68
|
+
>>> import numdaplot as ndp
|
|
69
|
+
>>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
|
|
70
|
+
>>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
|
|
71
|
+
>>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.RIGHT))
|
|
72
|
+
id dep age
|
|
73
|
+
INT64 TEXT INT64
|
|
74
|
+
0 1 75 34
|
|
75
|
+
1 3 <NA> 51
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
OUTER = auto()
|
|
79
|
+
"""
|
|
80
|
+
Every row of both Tables, with missing values where one has no match.
|
|
81
|
+
|
|
82
|
+
Examples
|
|
83
|
+
--------
|
|
84
|
+
>>> import numdaplot as ndp
|
|
85
|
+
>>> accidents = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 2]), "dep": ndp.Array.from_list(["75", "69"])})
|
|
86
|
+
>>> users = ndp.Table.from_arrays({"id": ndp.Array.from_list([1, 3]), "age": ndp.Array.from_list([34, 51])})
|
|
87
|
+
>>> accidents.join(ndp.Join(other=users, keys=["id"], mode=ndp.JoinMode.OUTER))
|
|
88
|
+
id dep age
|
|
89
|
+
INT64 TEXT INT64
|
|
90
|
+
0 1 75 34
|
|
91
|
+
1 2 69 <NA>
|
|
92
|
+
2 3 <NA> 51
|
|
93
|
+
"""
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check of the number of times each key appears in the Tables of a join.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import pandas
|
|
10
|
+
|
|
11
|
+
from numdaplot.arrays.conversion.python_values import to_python_list
|
|
12
|
+
from numdaplot.errors.join_relation_error import JoinRelationError
|
|
13
|
+
from numdaplot.errors.repeated_key import RepeatedKey
|
|
14
|
+
from numdaplot.tables.frames.column_values import convert_column_values
|
|
15
|
+
from numdaplot.tables.joining.relation import Relation
|
|
16
|
+
|
|
17
|
+
UNIQUE_LEFT_RELATIONS = frozenset({Relation.ONE_TO_ONE, Relation.ONE_TO_MANY})
|
|
18
|
+
UNIQUE_RIGHT_RELATIONS = frozenset({Relation.ONE_TO_ONE, Relation.MANY_TO_ONE})
|
|
19
|
+
LEFT_TABLE_NAME = "the left Table"
|
|
20
|
+
RIGHT_TABLE_NAME = "the right Table"
|
|
21
|
+
RELATION_NAME = "Relation.{member_name}"
|
|
22
|
+
ROWS_AXIS = 1
|
|
23
|
+
EVERY_REPEAT = False
|
|
24
|
+
FIRST_ROW_COUNT = 1
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def require_relation(key_frame: pandas.DataFrame, other_key_frame: pandas.DataFrame, relation: Relation) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Check that each key appears at most once in the Tables where the relation of a join expects it once.
|
|
30
|
+
|
|
31
|
+
The left Table is checked first, then the right Table.
|
|
32
|
+
|
|
33
|
+
.. versionadded:: 0.1.0
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
key_frame
|
|
38
|
+
The key columns of the left Table, the one joined.
|
|
39
|
+
other_key_frame
|
|
40
|
+
The key columns of the right Table, the other one.
|
|
41
|
+
relation
|
|
42
|
+
How many times each key may appear on each side.
|
|
43
|
+
|
|
44
|
+
Raises
|
|
45
|
+
------
|
|
46
|
+
JoinRelationError
|
|
47
|
+
At the first key repeated in a Table where the relation expects it once.
|
|
48
|
+
|
|
49
|
+
Examples
|
|
50
|
+
--------
|
|
51
|
+
>>> import pandas
|
|
52
|
+
>>> import numdaplot as ndp
|
|
53
|
+
>>> from numdaplot.tables.joining.join_relation import require_relation
|
|
54
|
+
>>> key_frame = pandas.DataFrame({"id": pandas.Series([1], dtype="Int64")})
|
|
55
|
+
>>> other_key_frame = pandas.DataFrame({"id": pandas.Series([1, 1], dtype="Int64")})
|
|
56
|
+
>>> try:
|
|
57
|
+
... require_relation(key_frame, other_key_frame, ndp.Relation.ONE_TO_ONE)
|
|
58
|
+
... except ndp.JoinRelationError as error:
|
|
59
|
+
... print(error)
|
|
60
|
+
Expected each key of the right Table to appear once for Relation.ONE_TO_ONE, but 'id' 1 appears 2 times.
|
|
61
|
+
"""
|
|
62
|
+
if relation in UNIQUE_LEFT_RELATIONS:
|
|
63
|
+
require_unique_keys(key_frame, relation, LEFT_TABLE_NAME)
|
|
64
|
+
|
|
65
|
+
if relation in UNIQUE_RIGHT_RELATIONS:
|
|
66
|
+
require_unique_keys(other_key_frame, relation, RIGHT_TABLE_NAME)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def require_unique_keys(key_frame: pandas.DataFrame, relation: Relation, table_name: str) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Check that each key, or combination of keys, appears at most once in a Table, missing keys aside.
|
|
72
|
+
|
|
73
|
+
.. versionadded:: 0.1.0
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
key_frame
|
|
78
|
+
The key columns of a Table.
|
|
79
|
+
relation
|
|
80
|
+
The relation checked, named in the error message.
|
|
81
|
+
table_name
|
|
82
|
+
The Table checked, named in the error message.
|
|
83
|
+
|
|
84
|
+
Raises
|
|
85
|
+
------
|
|
86
|
+
JoinRelationError
|
|
87
|
+
At the first repeated key, in the order of the rows, with its number of rows.
|
|
88
|
+
|
|
89
|
+
Examples
|
|
90
|
+
--------
|
|
91
|
+
>>> import pandas
|
|
92
|
+
>>> import numdaplot as ndp
|
|
93
|
+
>>> from numdaplot.tables.joining.join_relation import require_unique_keys
|
|
94
|
+
>>> key_frame = pandas.DataFrame({"id": pandas.Series([1, None, None], dtype="Int64")})
|
|
95
|
+
>>> require_unique_keys(key_frame, ndp.Relation.ONE_TO_ONE, "the left Table")
|
|
96
|
+
"""
|
|
97
|
+
missing_keys = key_frame.isna()
|
|
98
|
+
has_missing_key = missing_keys.any(axis=ROWS_AXIS)
|
|
99
|
+
present_frame = key_frame[~has_missing_key]
|
|
100
|
+
repeated_rows = present_frame.duplicated(keep=EVERY_REPEAT)
|
|
101
|
+
has_repeat = bool(repeated_rows.any())
|
|
102
|
+
if not has_repeat:
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
repeated_frame = present_frame[repeated_rows]
|
|
106
|
+
first_repeat_frame = repeated_frame.iloc[:FIRST_ROW_COUNT]
|
|
107
|
+
first_repeat = first_repeat_frame.iloc[0]
|
|
108
|
+
matching_cells = present_frame == first_repeat
|
|
109
|
+
matching_rows = matching_cells.all(axis=ROWS_AXIS)
|
|
110
|
+
repeat_count = int(matching_rows.sum())
|
|
111
|
+
key_names = key_frame.columns.tolist()
|
|
112
|
+
key_values = read_key_values(first_repeat_frame)
|
|
113
|
+
repeated_key = RepeatedKey(key_names, key_values, repeat_count)
|
|
114
|
+
relation_name = RELATION_NAME.format(member_name=relation.name)
|
|
115
|
+
raise JoinRelationError(relation_name, table_name, repeated_key)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def read_key_values(key_row_frame: pandas.DataFrame) -> list[Any]:
|
|
119
|
+
"""
|
|
120
|
+
Return the values of the single row of key columns as Python values.
|
|
121
|
+
|
|
122
|
+
.. versionadded:: 0.1.0
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
key_row_frame
|
|
127
|
+
One row of the key columns of a Table.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
list[Any]
|
|
132
|
+
The value of each key column, such as ``202500000001`` or ``datetime.date(2026, 1, 1)``.
|
|
133
|
+
|
|
134
|
+
Examples
|
|
135
|
+
--------
|
|
136
|
+
>>> import pandas
|
|
137
|
+
>>> from numdaplot.tables.joining.join_relation import read_key_values
|
|
138
|
+
>>> seat = pandas.Series(["A"], dtype="string")
|
|
139
|
+
>>> read_key_values(pandas.DataFrame({"id": pandas.Series([7], dtype="Int64"), "seat": seat}))
|
|
140
|
+
[7, 'A']
|
|
141
|
+
"""
|
|
142
|
+
key_values = list[Any]()
|
|
143
|
+
|
|
144
|
+
for _, column in key_row_frame.items():
|
|
145
|
+
column_values = convert_column_values(column)
|
|
146
|
+
python_values = to_python_list(column_values)
|
|
147
|
+
key_values.append(python_values[0])
|
|
148
|
+
|
|
149
|
+
return key_values
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Suffixes telling apart the columns that two joined Tables both have.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from numdaplot.errors.invalid_suffixes_error import InvalidSuffixesError
|
|
10
|
+
from numdaplot.settings.field_types import require_field_types
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class JoinSuffixes:
|
|
15
|
+
"""
|
|
16
|
+
Suffixes added to the names of the columns both Tables of a join have, besides the keys, used by ``Join``.
|
|
17
|
+
|
|
18
|
+
Only those columns get a suffix, as in pandas. A suffixed name that another column already has raises
|
|
19
|
+
``DuplicateColumnError`` at the join.
|
|
20
|
+
|
|
21
|
+
.. versionadded:: 0.1.0
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
left
|
|
26
|
+
The suffix of the columns of the joined Table, such as ``"_2024"``.
|
|
27
|
+
right
|
|
28
|
+
The suffix of the columns of the other Table, such as ``"_2025"``.
|
|
29
|
+
|
|
30
|
+
Raises
|
|
31
|
+
------
|
|
32
|
+
InvalidTypeError
|
|
33
|
+
When a setting is not of the type its annotation names.
|
|
34
|
+
InvalidSuffixesError
|
|
35
|
+
When a suffix is empty, or both suffixes are the same.
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
>>> import numdaplot as ndp
|
|
40
|
+
>>> before = ndp.Table.from_arrays({"dep": ndp.Array.from_list(["75"]), "deaths": ndp.Array.from_list([40])})
|
|
41
|
+
>>> after = ndp.Table.from_arrays({"dep": ndp.Array.from_list(["75"]), "deaths": ndp.Array.from_list([35])})
|
|
42
|
+
>>> years = ndp.JoinSuffixes(left="_2024", right="_2025")
|
|
43
|
+
>>> before.join(ndp.Join(other=after, keys=["dep"], suffixes=years))
|
|
44
|
+
dep deaths_2024 deaths_2025
|
|
45
|
+
TEXT INT64 INT64
|
|
46
|
+
0 75 40 35
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
left: str
|
|
50
|
+
right: str
|
|
51
|
+
|
|
52
|
+
def __post_init__(self) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Check that the suffixes are not empty and differ.
|
|
55
|
+
|
|
56
|
+
.. versionadded:: 0.1.0
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
InvalidTypeError
|
|
61
|
+
When a setting is not of the type its annotation names.
|
|
62
|
+
InvalidSuffixesError
|
|
63
|
+
When a suffix is empty, or both suffixes are the same.
|
|
64
|
+
"""
|
|
65
|
+
require_field_types(self)
|
|
66
|
+
|
|
67
|
+
has_empty_suffix = self.left == "" or self.right == ""
|
|
68
|
+
are_same = self.left == self.right
|
|
69
|
+
is_invalid = has_empty_suffix or are_same
|
|
70
|
+
if is_invalid:
|
|
71
|
+
raise InvalidSuffixesError(self.left, self.right)
|