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,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Text encodings of the files a Table reads and writes.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Encoding(Enum):
|
|
11
|
+
r"""
|
|
12
|
+
Text encoding of a file, used by the CSV, SAS and SAS transport options.
|
|
13
|
+
|
|
14
|
+
``CsvReadOptions``, ``CsvWriteOptions``, ``SasReadOptions`` and ``XptReadOptions`` take it.
|
|
15
|
+
|
|
16
|
+
The value of each member is the name Python gives to the encoding.
|
|
17
|
+
|
|
18
|
+
.. versionadded:: 0.1.0
|
|
19
|
+
|
|
20
|
+
Examples
|
|
21
|
+
--------
|
|
22
|
+
>>> import tempfile
|
|
23
|
+
>>> from pathlib import Path
|
|
24
|
+
>>> import numdaplot as ndp
|
|
25
|
+
>>> folder = Path(tempfile.mkdtemp())
|
|
26
|
+
>>> path = folder / "cities.csv"
|
|
27
|
+
>>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="latin-1")
|
|
28
|
+
>>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.LATIN_1))
|
|
29
|
+
>>> cities.column("city").to_list() == ["B\u00e9ziers"]
|
|
30
|
+
True
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
UTF_8 = "utf-8"
|
|
34
|
+
r"""
|
|
35
|
+
UTF-8, the most common encoding. Default value.
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
>>> import tempfile
|
|
40
|
+
>>> from pathlib import Path
|
|
41
|
+
>>> import numdaplot as ndp
|
|
42
|
+
>>> folder = Path(tempfile.mkdtemp())
|
|
43
|
+
>>> path = folder / "cities.csv"
|
|
44
|
+
>>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="utf-8")
|
|
45
|
+
>>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.UTF_8))
|
|
46
|
+
>>> cities.column("city").to_list() == ["B\u00e9ziers"]
|
|
47
|
+
True
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
UTF_8_BOM = "utf-8-sig"
|
|
51
|
+
r"""
|
|
52
|
+
UTF-8 starting with a byte order mark, as written by Excel when it saves a CSV file.
|
|
53
|
+
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
>>> import tempfile
|
|
57
|
+
>>> from pathlib import Path
|
|
58
|
+
>>> import numdaplot as ndp
|
|
59
|
+
>>> folder = Path(tempfile.mkdtemp())
|
|
60
|
+
>>> path = folder / "cities.csv"
|
|
61
|
+
>>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="utf-8-sig")
|
|
62
|
+
>>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.UTF_8_BOM))
|
|
63
|
+
>>> cities.column("city").to_list() == ["B\u00e9ziers"]
|
|
64
|
+
True
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
LATIN_1 = "latin-1"
|
|
68
|
+
r"""
|
|
69
|
+
Latin-1 (ISO 8859-1), used by older software in Western Europe.
|
|
70
|
+
|
|
71
|
+
Examples
|
|
72
|
+
--------
|
|
73
|
+
>>> import tempfile
|
|
74
|
+
>>> from pathlib import Path
|
|
75
|
+
>>> import numdaplot as ndp
|
|
76
|
+
>>> folder = Path(tempfile.mkdtemp())
|
|
77
|
+
>>> path = folder / "cities.csv"
|
|
78
|
+
>>> _ = path.write_text("city\nB\u00e9ziers\n", encoding="latin-1")
|
|
79
|
+
>>> cities = ndp.Table.from_csv(path, ndp.CsvReadOptions(encoding=ndp.Encoding.LATIN_1))
|
|
80
|
+
>>> cities.column("city").to_list() == ["B\u00e9ziers"]
|
|
81
|
+
True
|
|
82
|
+
"""
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Reading and writing Excel files.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, cast
|
|
9
|
+
|
|
10
|
+
import pandas
|
|
11
|
+
|
|
12
|
+
from numdaplot.tables.columns.column_names import require_column_names
|
|
13
|
+
from numdaplot.tables.files.excel_read_options import ExcelReadOptions
|
|
14
|
+
from numdaplot.tables.files.excel_time_cells import restore_time_columns
|
|
15
|
+
from numdaplot.tables.files.excel_write_options import ExcelWriteOptions
|
|
16
|
+
from numdaplot.tables.files.missing_texts import find_missing_settings
|
|
17
|
+
from numdaplot.tables.files.optional_package import require_package
|
|
18
|
+
from numdaplot.tables.files.pandas_backend import NULLABLE_DTYPE_BACKEND
|
|
19
|
+
from numdaplot.tables.frames.time_zones import require_no_time_zone
|
|
20
|
+
|
|
21
|
+
EXCEL_PACKAGE = "openpyxl"
|
|
22
|
+
EXCEL_EXTRA = "excel"
|
|
23
|
+
FIRST_SHEET = 0
|
|
24
|
+
DEFAULT_SHEET_NAME = "Sheet1"
|
|
25
|
+
HEADER_ROW_COUNT = 1
|
|
26
|
+
NO_MISSING_TEXTS = list[str]()
|
|
27
|
+
EXCEL_OPERATION = "An Excel file"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def read_excel_file(path: Path, options: ExcelReadOptions) -> pandas.DataFrame:
|
|
31
|
+
"""
|
|
32
|
+
Return the columns of a sheet of an Excel file whose first row holds the column names.
|
|
33
|
+
|
|
34
|
+
.. versionadded:: 0.1.0
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
path
|
|
39
|
+
The path of an existing Excel file.
|
|
40
|
+
options
|
|
41
|
+
The sheet to read, the first one when omitted, and the texts read as missing.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
pandas.DataFrame
|
|
46
|
+
The columns as pandas reads them, empty for an empty sheet. A column of time cells only, or of duration cells
|
|
47
|
+
only, holds Python times or durations.
|
|
48
|
+
|
|
49
|
+
Raises
|
|
50
|
+
------
|
|
51
|
+
MissingDependencyError
|
|
52
|
+
When ``openpyxl`` is not installed.
|
|
53
|
+
TimeZoneMismatchError
|
|
54
|
+
When a column holds datetimes with a time zone, which Excel files cannot store.
|
|
55
|
+
InvalidColumnNameError
|
|
56
|
+
When a cell of the first row is empty or is not a text.
|
|
57
|
+
DuplicateColumnError
|
|
58
|
+
When a column name appears twice.
|
|
59
|
+
|
|
60
|
+
Examples
|
|
61
|
+
--------
|
|
62
|
+
>>> import tempfile
|
|
63
|
+
>>> from pathlib import Path
|
|
64
|
+
>>> import pandas
|
|
65
|
+
>>> import numdaplot as ndp
|
|
66
|
+
>>> from numdaplot.tables.files.excel_file import read_excel_file
|
|
67
|
+
>>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
|
|
68
|
+
>>> pandas.DataFrame({"price": [1.5]}).to_excel(path, index=False)
|
|
69
|
+
>>> read_excel_file(path, ndp.ExcelReadOptions())
|
|
70
|
+
price
|
|
71
|
+
0 1.5
|
|
72
|
+
"""
|
|
73
|
+
require_package(EXCEL_PACKAGE, EXCEL_EXTRA)
|
|
74
|
+
sheet = find_read_sheet(options)
|
|
75
|
+
# The pandas stubs leave the types of the Excel engines unknown.
|
|
76
|
+
excel_pandas = cast(Any, pandas)
|
|
77
|
+
# A column name is never a missing value, so the first row is read without any missing text.
|
|
78
|
+
header_settings = find_missing_settings(NO_MISSING_TEXTS)
|
|
79
|
+
raw_header_frame = excel_pandas.read_excel(
|
|
80
|
+
path, sheet_name=sheet, header=None, nrows=HEADER_ROW_COUNT, **header_settings
|
|
81
|
+
)
|
|
82
|
+
header_frame = cast(pandas.DataFrame, raw_header_frame)
|
|
83
|
+
if header_frame.empty:
|
|
84
|
+
empty_frame = pandas.DataFrame()
|
|
85
|
+
return empty_frame
|
|
86
|
+
|
|
87
|
+
header_row = header_frame.iloc[0]
|
|
88
|
+
header = header_row.tolist()
|
|
89
|
+
require_column_names(header)
|
|
90
|
+
missing_settings = find_missing_settings(options.missing_texts)
|
|
91
|
+
raw_frame = excel_pandas.read_excel(
|
|
92
|
+
path, sheet_name=sheet, dtype_backend=NULLABLE_DTYPE_BACKEND, **missing_settings
|
|
93
|
+
)
|
|
94
|
+
read_frame = cast(pandas.DataFrame, raw_frame)
|
|
95
|
+
frame = restore_time_columns(read_frame, path, sheet, missing_settings)
|
|
96
|
+
|
|
97
|
+
return frame
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def find_read_sheet(options: ExcelReadOptions) -> str | int:
|
|
101
|
+
"""
|
|
102
|
+
Return the sheet pandas reads: its name, or the position of the first sheet.
|
|
103
|
+
|
|
104
|
+
.. versionadded:: 0.1.0
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
options
|
|
109
|
+
The settings of the Excel file.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
str or int
|
|
114
|
+
The name of the sheet, or 0 when no sheet is named.
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
>>> import numdaplot as ndp
|
|
119
|
+
>>> from numdaplot.tables.files.excel_file import find_read_sheet
|
|
120
|
+
>>> find_read_sheet(ndp.ExcelReadOptions())
|
|
121
|
+
0
|
|
122
|
+
"""
|
|
123
|
+
if options.sheet is None:
|
|
124
|
+
return FIRST_SHEET
|
|
125
|
+
|
|
126
|
+
return options.sheet
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def write_excel_file(frame: pandas.DataFrame, path: Path, options: ExcelWriteOptions) -> None:
|
|
130
|
+
"""
|
|
131
|
+
Write the columns of a Table in a sheet of an Excel file, column names on the first row.
|
|
132
|
+
|
|
133
|
+
.. versionadded:: 0.1.0
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
frame
|
|
138
|
+
The columns of a Table.
|
|
139
|
+
path
|
|
140
|
+
The path of the file, replaced when it exists.
|
|
141
|
+
options
|
|
142
|
+
The name of the sheet, ``"Sheet1"`` when omitted.
|
|
143
|
+
|
|
144
|
+
Raises
|
|
145
|
+
------
|
|
146
|
+
MissingDependencyError
|
|
147
|
+
When ``openpyxl`` is not installed.
|
|
148
|
+
TimeZoneMismatchError
|
|
149
|
+
When a column holds datetimes with a time zone, which Excel files cannot store.
|
|
150
|
+
|
|
151
|
+
Examples
|
|
152
|
+
--------
|
|
153
|
+
>>> import tempfile
|
|
154
|
+
>>> from pathlib import Path
|
|
155
|
+
>>> import pandas
|
|
156
|
+
>>> import numdaplot as ndp
|
|
157
|
+
>>> from numdaplot.tables.files.excel_file import write_excel_file
|
|
158
|
+
>>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
|
|
159
|
+
>>> write_excel_file(pandas.DataFrame({"price": [1.5]}), path, ndp.ExcelWriteOptions(sheet="Sales"))
|
|
160
|
+
>>> pandas.ExcelFile(path).sheet_names
|
|
161
|
+
['Sales']
|
|
162
|
+
"""
|
|
163
|
+
require_no_time_zone(frame, EXCEL_OPERATION)
|
|
164
|
+
require_package(EXCEL_PACKAGE, EXCEL_EXTRA)
|
|
165
|
+
sheet_name = DEFAULT_SHEET_NAME
|
|
166
|
+
if options.sheet is not None:
|
|
167
|
+
sheet_name = options.sheet
|
|
168
|
+
|
|
169
|
+
# The pandas stubs leave the types of the Excel engines unknown.
|
|
170
|
+
excel_frame = cast(Any, frame)
|
|
171
|
+
excel_frame.to_excel(path, sheet_name=sheet_name, index=False)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Settings of the Excel files a Table reads.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from numdaplot.settings.field_types import require_field_types
|
|
10
|
+
from numdaplot.tables.files.column_names import ColumnNames
|
|
11
|
+
from numdaplot.tables.files.excel_sheet import require_sheet_name
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class ExcelReadOptions:
|
|
16
|
+
r"""
|
|
17
|
+
Settings of an Excel file read by ``Table.from_excel``.
|
|
18
|
+
|
|
19
|
+
.. versionadded:: 0.1.0
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
sheet
|
|
24
|
+
The name of the sheet read, the first sheet when omitted.
|
|
25
|
+
column_names
|
|
26
|
+
Whether the column names are cleaned, ``ColumnNames.CLEANED`` by default: the spaces, tabs and line breaks at
|
|
27
|
+
the start and the end of each name are removed. ``ColumnNames.KEPT`` keeps the names as written.
|
|
28
|
+
missing_texts
|
|
29
|
+
The texts read as missing values, compared with the whole value of each cell. When omitted, the texts pandas
|
|
30
|
+
reads as missing: ``""``, ``"#N/A"``, ``"#N/A N/A"``, ``"#NA"``, ``"-1.#IND"``, ``"-1.#QNAN"``, ``"-NaN"``,
|
|
31
|
+
``"-nan"``, ``"1.#IND"``, ``"1.#QNAN"``, ``"<NA>"``, ``"N/A"``, ``"NA"``, ``"NULL"``, ``"NaN"``, ``"None"``,
|
|
32
|
+
``"n/a"``, ``"nan"`` and ``"null"``. A given list replaces them: ``[]`` reads no value as missing, not even
|
|
33
|
+
an empty one: an empty cell is then read as an empty text.
|
|
34
|
+
|
|
35
|
+
Raises
|
|
36
|
+
------
|
|
37
|
+
InvalidTypeError
|
|
38
|
+
When a setting is not of the type its annotation names.
|
|
39
|
+
InvalidSheetNameError
|
|
40
|
+
When the name is empty, longer than 31 characters, or holds ``[ ] : * ? / \``, which Excel refuses.
|
|
41
|
+
|
|
42
|
+
Examples
|
|
43
|
+
--------
|
|
44
|
+
>>> import tempfile
|
|
45
|
+
>>> from pathlib import Path
|
|
46
|
+
>>> import numdaplot as ndp
|
|
47
|
+
>>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
|
|
48
|
+
>>> prices = ndp.Table.from_arrays({"price": ndp.Array.from_list([1.5])})
|
|
49
|
+
>>> prices.to_excel(path, ndp.ExcelWriteOptions(sheet="Sales"))
|
|
50
|
+
>>> ndp.Table.from_excel(path, ndp.ExcelReadOptions(sheet="Sales"))
|
|
51
|
+
price
|
|
52
|
+
FLOAT64
|
|
53
|
+
0 1.5
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
sheet: str | None = None
|
|
57
|
+
column_names: ColumnNames = ColumnNames.CLEANED
|
|
58
|
+
missing_texts: list[str] | None = None
|
|
59
|
+
|
|
60
|
+
def __post_init__(self) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Check the type of every setting, and that Excel accepts the sheet name.
|
|
63
|
+
|
|
64
|
+
.. versionadded:: 0.1.0
|
|
65
|
+
|
|
66
|
+
Raises
|
|
67
|
+
------
|
|
68
|
+
InvalidTypeError
|
|
69
|
+
When a setting is not of the type its annotation names.
|
|
70
|
+
InvalidSheetNameError
|
|
71
|
+
When the name is empty, longer than 31 characters, or holds a character Excel refuses.
|
|
72
|
+
"""
|
|
73
|
+
require_field_types(self)
|
|
74
|
+
|
|
75
|
+
require_sheet_name(self.sheet)
|
|
76
|
+
|
|
77
|
+
if self.missing_texts is not None:
|
|
78
|
+
missing_texts_copy = list(self.missing_texts)
|
|
79
|
+
object.__setattr__(self, "missing_texts", missing_texts_copy)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Check of the name of an Excel sheet.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from numdaplot.errors.invalid_sheet_name_error import InvalidSheetNameError
|
|
8
|
+
|
|
9
|
+
MAXIMUM_SHEET_LENGTH = 31
|
|
10
|
+
FORBIDDEN_SHEET_CHARACTERS = frozenset("[]:*?/\\")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def require_sheet_name(sheet: str | None) -> None:
|
|
14
|
+
r"""
|
|
15
|
+
Check that Excel accepts a sheet name, when it is given.
|
|
16
|
+
|
|
17
|
+
.. versionadded:: 0.1.0
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
sheet
|
|
22
|
+
The name of the sheet, or None for the default sheet.
|
|
23
|
+
|
|
24
|
+
Raises
|
|
25
|
+
------
|
|
26
|
+
InvalidSheetNameError
|
|
27
|
+
When the name is empty, longer than 31 characters, or holds ``[ ] : * ? / \``, which Excel refuses.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> import numdaplot as ndp
|
|
32
|
+
>>> from numdaplot.tables.files.excel_sheet import require_sheet_name
|
|
33
|
+
>>> try:
|
|
34
|
+
... require_sheet_name("Sales/2026")
|
|
35
|
+
... except ndp.InvalidSheetNameError as error:
|
|
36
|
+
... print(error)
|
|
37
|
+
Expected a sheet name of 1 to 31 characters without [ ] : * ? / \, got 'Sales/2026'.
|
|
38
|
+
"""
|
|
39
|
+
if sheet is None:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
sheet_length = len(sheet)
|
|
43
|
+
has_valid_length = 0 < sheet_length <= MAXIMUM_SHEET_LENGTH
|
|
44
|
+
sheet_characters = set(sheet)
|
|
45
|
+
forbidden_characters = sheet_characters & FORBIDDEN_SHEET_CHARACTERS
|
|
46
|
+
forbidden_count = len(forbidden_characters)
|
|
47
|
+
has_forbidden_character = forbidden_count > 0
|
|
48
|
+
is_valid = has_valid_length and not has_forbidden_character
|
|
49
|
+
if not is_valid:
|
|
50
|
+
raise InvalidSheetNameError(sheet)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Time and duration cells of an Excel file, which pandas reads as texts.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, cast
|
|
9
|
+
|
|
10
|
+
import pandas
|
|
11
|
+
from pandas.api.types import infer_dtype
|
|
12
|
+
|
|
13
|
+
PYTHON_OBJECT_DTYPE = object
|
|
14
|
+
TIME_KINDS = frozenset({"time", "timedelta"})
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def restore_time_columns(
|
|
18
|
+
frame: pandas.DataFrame, path: Path, sheet: str | int, missing_settings: dict[str, Any]
|
|
19
|
+
) -> pandas.DataFrame:
|
|
20
|
+
"""
|
|
21
|
+
Return the columns of a sheet with the columns of time or duration cells read again as Python values.
|
|
22
|
+
|
|
23
|
+
The types of pandas that accept missing values write a time or a duration cell as a text. Only the text columns
|
|
24
|
+
are read again, as Python values: a column of times of day only, or of durations only, keeps them, and becomes a
|
|
25
|
+
``TIME`` or a ``DURATION`` column. The other columns are kept as read.
|
|
26
|
+
|
|
27
|
+
.. versionadded:: 0.1.0
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
frame
|
|
32
|
+
The columns of the sheet, read with the types of pandas that accept missing values.
|
|
33
|
+
path
|
|
34
|
+
The path of the Excel file.
|
|
35
|
+
sheet
|
|
36
|
+
The name or the position of the sheet.
|
|
37
|
+
missing_settings
|
|
38
|
+
The settings of pandas reading the missing values, the same as for ``frame``.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
pandas.DataFrame
|
|
43
|
+
The same columns, a column of times or durations holding Python values.
|
|
44
|
+
|
|
45
|
+
Examples
|
|
46
|
+
--------
|
|
47
|
+
>>> import tempfile
|
|
48
|
+
>>> from datetime import time
|
|
49
|
+
>>> from pathlib import Path
|
|
50
|
+
>>> import openpyxl
|
|
51
|
+
>>> import pandas
|
|
52
|
+
>>> from numdaplot.tables.files.excel_time_cells import restore_time_columns
|
|
53
|
+
>>> path = Path(tempfile.mkdtemp()) / "hours.xlsx"
|
|
54
|
+
>>> book = openpyxl.Workbook()
|
|
55
|
+
>>> book.active.append(["hrmn"])
|
|
56
|
+
>>> book.active.append([time(15, 35)])
|
|
57
|
+
>>> book.save(path)
|
|
58
|
+
>>> frame = pandas.read_excel(path, dtype_backend="numpy_nullable")
|
|
59
|
+
>>> restore_time_columns(frame, path, 0, {})["hrmn"].tolist()
|
|
60
|
+
[datetime.time(15, 35)]
|
|
61
|
+
"""
|
|
62
|
+
text_names = find_text_columns(frame)
|
|
63
|
+
if text_names == []:
|
|
64
|
+
return frame
|
|
65
|
+
|
|
66
|
+
# The pandas stubs leave the types of the Excel engines unknown.
|
|
67
|
+
excel_pandas = cast(Any, pandas)
|
|
68
|
+
raw_object_frame = excel_pandas.read_excel(
|
|
69
|
+
path, sheet_name=sheet, dtype=PYTHON_OBJECT_DTYPE, usecols=text_names, **missing_settings
|
|
70
|
+
)
|
|
71
|
+
object_frame = cast(pandas.DataFrame, raw_object_frame)
|
|
72
|
+
restored_frame = frame.copy()
|
|
73
|
+
|
|
74
|
+
for text_name in text_names:
|
|
75
|
+
object_column = object_frame[text_name]
|
|
76
|
+
holds_time_cells = holds_only_time_cells(object_column)
|
|
77
|
+
if holds_time_cells:
|
|
78
|
+
restored_frame[text_name] = object_column
|
|
79
|
+
|
|
80
|
+
return restored_frame
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def find_text_columns(frame: pandas.DataFrame) -> list[str]:
|
|
84
|
+
"""
|
|
85
|
+
Return the names of the text columns of a sheet read with the types of pandas that accept missing values.
|
|
86
|
+
|
|
87
|
+
.. versionadded:: 0.1.0
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
frame
|
|
92
|
+
The columns of a sheet.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
list[str]
|
|
97
|
+
The names of the columns of texts, in their order.
|
|
98
|
+
|
|
99
|
+
Examples
|
|
100
|
+
--------
|
|
101
|
+
>>> import pandas
|
|
102
|
+
>>> from numdaplot.tables.files.excel_time_cells import find_text_columns
|
|
103
|
+
>>> frame = pandas.DataFrame({"city": pandas.Series(["Pau"], dtype="string"), "count": [1]})
|
|
104
|
+
>>> find_text_columns(frame)
|
|
105
|
+
['city']
|
|
106
|
+
"""
|
|
107
|
+
text_names = list[str]()
|
|
108
|
+
|
|
109
|
+
for column_name, column in frame.items():
|
|
110
|
+
if isinstance(column.dtype, pandas.StringDtype):
|
|
111
|
+
text_names.append(str(column_name))
|
|
112
|
+
|
|
113
|
+
return text_names
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def holds_only_time_cells(column: pandas.Series) -> bool:
|
|
117
|
+
"""
|
|
118
|
+
Return whether a column of Python values holds times of day only, or durations only, besides missing values.
|
|
119
|
+
|
|
120
|
+
.. versionadded:: 0.1.0
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
column
|
|
125
|
+
A column read as Python values.
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
bool
|
|
130
|
+
True for ``datetime.time`` values only or ``datetime.timedelta`` values only, False for a mix with texts or
|
|
131
|
+
an empty column.
|
|
132
|
+
|
|
133
|
+
Examples
|
|
134
|
+
--------
|
|
135
|
+
>>> from datetime import time
|
|
136
|
+
>>> import pandas
|
|
137
|
+
>>> from numdaplot.tables.files.excel_time_cells import holds_only_time_cells
|
|
138
|
+
>>> holds_only_time_cells(pandas.Series([time(8), None], dtype=object))
|
|
139
|
+
True
|
|
140
|
+
>>> holds_only_time_cells(pandas.Series([time(8), "unknown"], dtype=object))
|
|
141
|
+
False
|
|
142
|
+
"""
|
|
143
|
+
inferred_kind = infer_dtype(column, skipna=True)
|
|
144
|
+
is_time_kind = inferred_kind in TIME_KINDS
|
|
145
|
+
|
|
146
|
+
return is_time_kind
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Settings of the Excel files a Table writes.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from numdaplot.settings.field_types import require_field_types
|
|
10
|
+
from numdaplot.tables.files.excel_sheet import require_sheet_name
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class ExcelWriteOptions:
|
|
15
|
+
r"""
|
|
16
|
+
Settings of an Excel file written by ``Table.to_excel``.
|
|
17
|
+
|
|
18
|
+
.. versionadded:: 0.1.0
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
sheet
|
|
23
|
+
The name of the written sheet, ``"Sheet1"`` when omitted.
|
|
24
|
+
|
|
25
|
+
Raises
|
|
26
|
+
------
|
|
27
|
+
InvalidTypeError
|
|
28
|
+
When a setting is not of the type its annotation names.
|
|
29
|
+
InvalidSheetNameError
|
|
30
|
+
When the name is empty, longer than 31 characters, or holds ``[ ] : * ? / \``, which Excel refuses.
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
--------
|
|
34
|
+
>>> import tempfile
|
|
35
|
+
>>> from pathlib import Path
|
|
36
|
+
>>> import numdaplot as ndp
|
|
37
|
+
>>> path = Path(tempfile.mkdtemp()) / "sales.xlsx"
|
|
38
|
+
>>> prices = ndp.Table.from_arrays({"price": ndp.Array.from_list([1.5])})
|
|
39
|
+
>>> prices.to_excel(path, ndp.ExcelWriteOptions(sheet="Sales"))
|
|
40
|
+
>>> ndp.Table.from_excel(path, ndp.ExcelReadOptions(sheet="Sales"))
|
|
41
|
+
price
|
|
42
|
+
FLOAT64
|
|
43
|
+
0 1.5
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
sheet: str | None = None
|
|
47
|
+
|
|
48
|
+
def __post_init__(self) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Check the type of every setting, and that Excel accepts the sheet name.
|
|
51
|
+
|
|
52
|
+
.. versionadded:: 0.1.0
|
|
53
|
+
|
|
54
|
+
Raises
|
|
55
|
+
------
|
|
56
|
+
InvalidTypeError
|
|
57
|
+
When a setting is not of the type its annotation names.
|
|
58
|
+
InvalidSheetNameError
|
|
59
|
+
When the name is empty, longer than 31 characters, or holds a character Excel refuses.
|
|
60
|
+
"""
|
|
61
|
+
require_field_types(self)
|
|
62
|
+
|
|
63
|
+
require_sheet_name(self.sheet)
|