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,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Errors of the file system while reading or writing a file.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from types import TracebackType
|
|
9
|
+
|
|
10
|
+
from numdaplot.errors.file_access_error import FileAccessError
|
|
11
|
+
from numdaplot.errors.numdaplot_error import NumdaplotError
|
|
12
|
+
|
|
13
|
+
READ_OPERATION = "read"
|
|
14
|
+
WRITE_OPERATION = "write to"
|
|
15
|
+
PERMISSION_REASON = "permission denied"
|
|
16
|
+
MISSING_FOLDER_REASON = "the folder {folder} does not exist"
|
|
17
|
+
FOLDER_IS_FILE_REASON = "the folder {folder} is a file"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FileAccessErrors:
|
|
21
|
+
"""
|
|
22
|
+
Context turning an error of the file system during a block into a ``FileAccessError``.
|
|
23
|
+
|
|
24
|
+
.. versionadded:: 0.1.0
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
operation
|
|
29
|
+
What the block does: ``READ_OPERATION`` or ``WRITE_OPERATION``.
|
|
30
|
+
path
|
|
31
|
+
The path of the file.
|
|
32
|
+
|
|
33
|
+
Examples
|
|
34
|
+
--------
|
|
35
|
+
>>> from pathlib import Path
|
|
36
|
+
>>> import numdaplot as ndp
|
|
37
|
+
>>> from numdaplot.tables.files.file_access import FileAccessErrors, WRITE_OPERATION
|
|
38
|
+
>>> path = Path("missing_folder/sales.csv")
|
|
39
|
+
>>> try:
|
|
40
|
+
... with FileAccessErrors(WRITE_OPERATION, path):
|
|
41
|
+
... path.write_text("sales")
|
|
42
|
+
... except ndp.FileAccessError as error:
|
|
43
|
+
... print(error)
|
|
44
|
+
Cannot write to missing_folder/sales.csv: the folder missing_folder does not exist.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, operation: str, path: Path) -> None:
|
|
48
|
+
"""
|
|
49
|
+
Keep the operation and the path of the block.
|
|
50
|
+
|
|
51
|
+
.. versionadded:: 0.1.0
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
operation
|
|
56
|
+
What the block does: ``READ_OPERATION`` or ``WRITE_OPERATION``.
|
|
57
|
+
path
|
|
58
|
+
The path of the file.
|
|
59
|
+
"""
|
|
60
|
+
self.operation = operation
|
|
61
|
+
self.path = path
|
|
62
|
+
|
|
63
|
+
def __enter__(self) -> None:
|
|
64
|
+
"""
|
|
65
|
+
Start the block.
|
|
66
|
+
|
|
67
|
+
.. versionadded:: 0.1.0
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __exit__(
|
|
71
|
+
self,
|
|
72
|
+
error_type: type[BaseException] | None,
|
|
73
|
+
error: BaseException | None,
|
|
74
|
+
traceback: TracebackType | None,
|
|
75
|
+
) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Raise a ``FileAccessError`` for an error of the file system. Any other error goes on unchanged.
|
|
78
|
+
|
|
79
|
+
.. versionadded:: 0.1.0
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
error_type
|
|
84
|
+
The type of the error raised by the block, or None.
|
|
85
|
+
error
|
|
86
|
+
The error raised by the block, or None.
|
|
87
|
+
traceback
|
|
88
|
+
Its traceback, or None.
|
|
89
|
+
|
|
90
|
+
Raises
|
|
91
|
+
------
|
|
92
|
+
FileAccessError
|
|
93
|
+
When the block raised an ``OSError`` that is not already an error of numdaplot.
|
|
94
|
+
"""
|
|
95
|
+
if not isinstance(error, OSError):
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
if isinstance(error, NumdaplotError):
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
reason = find_access_reason(self.path, error)
|
|
102
|
+
path_text = str(self.path)
|
|
103
|
+
raise FileAccessError(self.operation, path_text, reason) from error
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def find_access_reason(path: Path, error: OSError) -> str:
|
|
107
|
+
"""
|
|
108
|
+
Return why the file system refused a file.
|
|
109
|
+
|
|
110
|
+
.. versionadded:: 0.1.0
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
path
|
|
115
|
+
The path of the file.
|
|
116
|
+
error
|
|
117
|
+
The error of the file system.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
str
|
|
122
|
+
A missing permission or a wrong folder in words, else what the system says.
|
|
123
|
+
|
|
124
|
+
Examples
|
|
125
|
+
--------
|
|
126
|
+
>>> from pathlib import Path
|
|
127
|
+
>>> from numdaplot.tables.files.file_access import find_access_reason
|
|
128
|
+
>>> find_access_reason(Path("missing_folder/sales.csv"), OSError("Disk is full"))
|
|
129
|
+
'the folder missing_folder does not exist'
|
|
130
|
+
>>> find_access_reason(Path("sales.csv"), OSError(28, "No space left on device"))
|
|
131
|
+
'No space left on device'
|
|
132
|
+
"""
|
|
133
|
+
if isinstance(error, PermissionError):
|
|
134
|
+
return PERMISSION_REASON
|
|
135
|
+
|
|
136
|
+
folder = path.parent
|
|
137
|
+
folder_exists = folder.exists()
|
|
138
|
+
if not folder_exists:
|
|
139
|
+
missing_folder_reason = MISSING_FOLDER_REASON.format(folder=folder)
|
|
140
|
+
return missing_folder_reason
|
|
141
|
+
|
|
142
|
+
folder_is_folder = folder.is_dir()
|
|
143
|
+
if not folder_is_folder:
|
|
144
|
+
folder_is_file_reason = FOLDER_IS_FILE_REASON.format(folder=folder)
|
|
145
|
+
return folder_is_file_reason
|
|
146
|
+
|
|
147
|
+
if error.strerror is not None:
|
|
148
|
+
return error.strerror
|
|
149
|
+
|
|
150
|
+
system_reason = str(error)
|
|
151
|
+
|
|
152
|
+
return system_reason
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Paths of the files a Table reads and writes.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from numdaplot.errors.file_exists_error import FileExistsError
|
|
10
|
+
from numdaplot.errors.file_not_found_error import FileNotFoundError
|
|
11
|
+
from numdaplot.tables.conflict import Conflict
|
|
12
|
+
|
|
13
|
+
type FilePath = str | Path
|
|
14
|
+
"""
|
|
15
|
+
The path of a file, as a text or a ``pathlib.Path``.
|
|
16
|
+
|
|
17
|
+
It is a name used by the documentation and the annotations, not an object to create: pass the value itself,
|
|
18
|
+
such as ``"sales.csv"`` or ``Path("data/sales.csv")``.
|
|
19
|
+
|
|
20
|
+
.. versionadded:: 0.1.0
|
|
21
|
+
|
|
22
|
+
Examples
|
|
23
|
+
--------
|
|
24
|
+
>>> from pathlib import Path
|
|
25
|
+
>>> from tempfile import TemporaryDirectory
|
|
26
|
+
>>> import numdaplot as ndp
|
|
27
|
+
>>> cities = ndp.Array.from_list(["Paris", "Lyon"])
|
|
28
|
+
>>> sales = ndp.Table.from_arrays({"city": cities})
|
|
29
|
+
>>> with TemporaryDirectory() as folder:
|
|
30
|
+
... sales.to_csv(Path(folder) / "sales.csv")
|
|
31
|
+
... ndp.Table.from_csv(Path(folder) / "sales.csv").column("city").to_list()
|
|
32
|
+
['Paris', 'Lyon']
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def require_existing_file(path: Path) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Check that a file exists at a path.
|
|
39
|
+
|
|
40
|
+
.. versionadded:: 0.1.0
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
path
|
|
45
|
+
The path of the file to read.
|
|
46
|
+
|
|
47
|
+
Raises
|
|
48
|
+
------
|
|
49
|
+
FileNotFoundError
|
|
50
|
+
When there is no file at the path, the numdaplot error that is also the Python one.
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
>>> import numdaplot as ndp
|
|
55
|
+
>>> from pathlib import Path
|
|
56
|
+
>>> from numdaplot.tables.files.file_paths import require_existing_file
|
|
57
|
+
>>> try:
|
|
58
|
+
... require_existing_file(Path("missing.csv"))
|
|
59
|
+
... except ndp.FileNotFoundError as error:
|
|
60
|
+
... print(error)
|
|
61
|
+
No file found at missing.csv.
|
|
62
|
+
"""
|
|
63
|
+
is_file = path.is_file()
|
|
64
|
+
if not is_file:
|
|
65
|
+
path_text = str(path)
|
|
66
|
+
raise FileNotFoundError(path_text)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def require_free_path(path: Path, on_conflict: Conflict) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Check that a file can be written at a path.
|
|
72
|
+
|
|
73
|
+
.. versionadded:: 0.1.0
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
path
|
|
78
|
+
The path of the file to write.
|
|
79
|
+
on_conflict
|
|
80
|
+
``ERROR`` refuses to overwrite an existing file, ``REPLACE`` allows it.
|
|
81
|
+
|
|
82
|
+
Raises
|
|
83
|
+
------
|
|
84
|
+
FileExistsError
|
|
85
|
+
When a file exists at the path and ``on_conflict`` is ``ERROR``.
|
|
86
|
+
|
|
87
|
+
Examples
|
|
88
|
+
--------
|
|
89
|
+
>>> import tempfile
|
|
90
|
+
>>> from pathlib import Path
|
|
91
|
+
>>> import numdaplot as ndp
|
|
92
|
+
>>> from numdaplot.tables.files.file_paths import require_free_path
|
|
93
|
+
>>> with tempfile.NamedTemporaryFile(suffix=".csv") as file:
|
|
94
|
+
... path = Path(file.name)
|
|
95
|
+
... require_free_path(path, ndp.Conflict.REPLACE)
|
|
96
|
+
... try:
|
|
97
|
+
... require_free_path(path, ndp.Conflict.ERROR)
|
|
98
|
+
... except ndp.FileExistsError:
|
|
99
|
+
... print("refused")
|
|
100
|
+
refused
|
|
101
|
+
"""
|
|
102
|
+
file_exists = path.exists()
|
|
103
|
+
refuses_existing_file = file_exists and on_conflict == Conflict.ERROR
|
|
104
|
+
if refuses_existing_file:
|
|
105
|
+
path_text = str(path)
|
|
106
|
+
raise FileExistsError(path_text)
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exact writing of the decimal columns of a Table in a JSON file.
|
|
3
|
+
|
|
4
|
+
pandas writes decimals with 10 digits after the point at most, which changes values such as ``1 / 3``.
|
|
5
|
+
|
|
6
|
+
.. versionadded:: 0.1.0
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from typing import Any, cast
|
|
11
|
+
|
|
12
|
+
import numpy
|
|
13
|
+
import pandas
|
|
14
|
+
from numpy.typing import NDArray
|
|
15
|
+
|
|
16
|
+
from numdaplot.data_types.numpy_mapping import from_numpy_dtype
|
|
17
|
+
from numdaplot.errors.value_conversion_error import ValueConversionError
|
|
18
|
+
from numdaplot.tables.frames.column import Column
|
|
19
|
+
from numdaplot.tables.frames.named_column_errors import NamedColumnErrors
|
|
20
|
+
|
|
21
|
+
DECIMAL_KIND = "f"
|
|
22
|
+
DOUBLE_DTYPE = numpy.dtype(numpy.float64)
|
|
23
|
+
JSON_FORMAT_NAME = "JSON"
|
|
24
|
+
JSON_NULL = "null"
|
|
25
|
+
NAN_TEXT = "nan"
|
|
26
|
+
DECIMAL_FORMAT = "%.{decimals}f"
|
|
27
|
+
CELL_SEPARATOR = ":"
|
|
28
|
+
CELL_JOINER = ","
|
|
29
|
+
OBJECT_START = "{"
|
|
30
|
+
OBJECT_END = "}"
|
|
31
|
+
LINE_END = "\n"
|
|
32
|
+
RECORDS_ORIENTATION = "records"
|
|
33
|
+
ISO_DATE_FORMAT = "iso"
|
|
34
|
+
FIRST_CHARACTER_AFTER_BRACE = 1
|
|
35
|
+
LAST_CHARACTER_BEFORE_BRACE = -1
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def is_decimal_column(column: Column) -> bool:
|
|
39
|
+
"""
|
|
40
|
+
Return whether a column holds decimals, stored by pandas with or without missing values.
|
|
41
|
+
|
|
42
|
+
.. versionadded:: 0.1.0
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
column
|
|
47
|
+
A column.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
bool
|
|
52
|
+
True for a column of 32 or 64 bit decimals.
|
|
53
|
+
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
>>> import pandas
|
|
57
|
+
>>> from numdaplot.tables.files.json_decimals import is_decimal_column
|
|
58
|
+
>>> is_decimal_column(pandas.Series([1.5], dtype="Float64")), is_decimal_column(pandas.Series([1]))
|
|
59
|
+
(True, False)
|
|
60
|
+
"""
|
|
61
|
+
is_decimal = column.dtype.kind == DECIMAL_KIND
|
|
62
|
+
|
|
63
|
+
return is_decimal
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def read_decimals(column: Column) -> NDArray[Any]:
|
|
67
|
+
"""
|
|
68
|
+
Return the decimals of a column, in their number of bits, NaN for a missing value.
|
|
69
|
+
|
|
70
|
+
.. versionadded:: 0.1.0
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
column
|
|
75
|
+
A decimal column.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
NDArray
|
|
80
|
+
The values.
|
|
81
|
+
|
|
82
|
+
Examples
|
|
83
|
+
--------
|
|
84
|
+
>>> import pandas
|
|
85
|
+
>>> from numdaplot.tables.files.json_decimals import read_decimals
|
|
86
|
+
>>> read_decimals(pandas.Series([1.5, None], dtype="Float32"))
|
|
87
|
+
array([1.5, nan], dtype=float32)
|
|
88
|
+
"""
|
|
89
|
+
dtype_name = str(column.dtype)
|
|
90
|
+
numpy_dtype = numpy.dtype(dtype_name.lower())
|
|
91
|
+
values = column.to_numpy(dtype=numpy_dtype, na_value=numpy.nan)
|
|
92
|
+
|
|
93
|
+
return values
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def has_decimal_column(frame: pandas.DataFrame) -> bool:
|
|
97
|
+
"""
|
|
98
|
+
Return whether a frame holds a column of decimals.
|
|
99
|
+
|
|
100
|
+
.. versionadded:: 0.1.0
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
frame
|
|
105
|
+
The columns of a Table.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
bool
|
|
110
|
+
True when at least one column holds decimals.
|
|
111
|
+
|
|
112
|
+
Examples
|
|
113
|
+
--------
|
|
114
|
+
>>> import pandas
|
|
115
|
+
>>> from numdaplot.tables.files.json_decimals import has_decimal_column
|
|
116
|
+
>>> has_decimal_column(pandas.DataFrame({"count": [1], "price": [1.5]}))
|
|
117
|
+
True
|
|
118
|
+
"""
|
|
119
|
+
column_names = list[str](frame.columns)
|
|
120
|
+
|
|
121
|
+
for column_name in column_names:
|
|
122
|
+
column = frame[column_name]
|
|
123
|
+
is_decimal = is_decimal_column(column)
|
|
124
|
+
if is_decimal:
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def require_finite_values(values: NDArray[Any]) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Check that decimals hold no infinite value, which JSON cannot write.
|
|
133
|
+
|
|
134
|
+
.. versionadded:: 0.1.0
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
values
|
|
139
|
+
The decimals, NaN for a missing value.
|
|
140
|
+
|
|
141
|
+
Raises
|
|
142
|
+
------
|
|
143
|
+
ValueConversionError
|
|
144
|
+
At the first infinite value.
|
|
145
|
+
|
|
146
|
+
Examples
|
|
147
|
+
--------
|
|
148
|
+
>>> import numpy
|
|
149
|
+
>>> import numdaplot as ndp
|
|
150
|
+
>>> from numdaplot.tables.files.json_decimals import require_finite_values
|
|
151
|
+
>>> try:
|
|
152
|
+
... require_finite_values(numpy.array([1.5, numpy.inf]))
|
|
153
|
+
... except ndp.ValueConversionError as error:
|
|
154
|
+
... print(error)
|
|
155
|
+
Cannot store the FLOAT64 value inf as JSON without losing information.
|
|
156
|
+
"""
|
|
157
|
+
is_infinite = numpy.isinf(values)
|
|
158
|
+
has_infinite = bool(is_infinite.any())
|
|
159
|
+
if not has_infinite:
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
infinite_values = values[is_infinite]
|
|
163
|
+
first_infinite = float(infinite_values[0])
|
|
164
|
+
column_type = from_numpy_dtype(values.dtype)
|
|
165
|
+
raise ValueConversionError(column_type.name, JSON_FORMAT_NAME, first_infinite)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def write_shortest_texts(values: NDArray[Any]) -> list[str]:
|
|
169
|
+
"""
|
|
170
|
+
Return decimals as the shortest texts giving the same values in their number of bits.
|
|
171
|
+
|
|
172
|
+
.. versionadded:: 0.1.0
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
values
|
|
177
|
+
The finite decimals, NaN for a missing value.
|
|
178
|
+
|
|
179
|
+
Returns
|
|
180
|
+
-------
|
|
181
|
+
list[str]
|
|
182
|
+
One JSON number per value, ``null`` for a missing value.
|
|
183
|
+
|
|
184
|
+
Examples
|
|
185
|
+
--------
|
|
186
|
+
>>> import numpy
|
|
187
|
+
>>> from numdaplot.tables.files.json_decimals import write_shortest_texts
|
|
188
|
+
>>> write_shortest_texts(numpy.array([1 / 3, numpy.nan]))
|
|
189
|
+
['0.3333333333333333', 'null']
|
|
190
|
+
>>> write_shortest_texts(numpy.array([0.1], dtype="float32"))
|
|
191
|
+
['0.1']
|
|
192
|
+
"""
|
|
193
|
+
if values.dtype == DOUBLE_DTYPE:
|
|
194
|
+
python_values = cast(list[float], values.tolist())
|
|
195
|
+
texts = list(map(repr, python_values))
|
|
196
|
+
else:
|
|
197
|
+
# A Python float would write the value of a 32 bit decimal widened to 64 bits, such as 0.10000000149011612.
|
|
198
|
+
numpy_texts = values.astype(str)
|
|
199
|
+
texts = cast(list[str], numpy_texts.tolist())
|
|
200
|
+
|
|
201
|
+
missing_positions = numpy.flatnonzero(numpy.isnan(values))
|
|
202
|
+
for position in missing_positions:
|
|
203
|
+
missing_position = int(position)
|
|
204
|
+
texts[missing_position] = JSON_NULL
|
|
205
|
+
|
|
206
|
+
return texts
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def write_rounded_texts(values: NDArray[Any], decimals: int) -> list[str]:
|
|
210
|
+
"""
|
|
211
|
+
Return decimals rounded to a number of decimals, keeping their zeros as in a CSV file.
|
|
212
|
+
|
|
213
|
+
.. versionadded:: 0.1.0
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
values
|
|
218
|
+
The finite decimals, NaN for a missing value.
|
|
219
|
+
decimals
|
|
220
|
+
The number of decimals.
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
list[str]
|
|
225
|
+
One JSON number per value, ``null`` for a missing value.
|
|
226
|
+
|
|
227
|
+
Examples
|
|
228
|
+
--------
|
|
229
|
+
>>> import numpy
|
|
230
|
+
>>> from numdaplot.tables.files.json_decimals import write_rounded_texts
|
|
231
|
+
>>> write_rounded_texts(numpy.array([1.5, numpy.nan]), 2)
|
|
232
|
+
['1.50', 'null']
|
|
233
|
+
"""
|
|
234
|
+
decimal_format = DECIMAL_FORMAT.format(decimals=decimals)
|
|
235
|
+
python_values = cast(list[float], values.tolist())
|
|
236
|
+
rounded_texts = [JSON_NULL if value != value else decimal_format % value for value in python_values]
|
|
237
|
+
|
|
238
|
+
return rounded_texts
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def write_decimal_cells(column: Column, column_name: str, decimals: int | None) -> list[str]:
|
|
242
|
+
"""
|
|
243
|
+
Return the name and the value of a decimal column, as they appear in each object of a JSON file.
|
|
244
|
+
|
|
245
|
+
.. versionadded:: 0.1.0
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
column
|
|
250
|
+
A decimal column.
|
|
251
|
+
column_name
|
|
252
|
+
The name of the column.
|
|
253
|
+
decimals
|
|
254
|
+
The number of decimals written, every digit of each value when ``None``.
|
|
255
|
+
|
|
256
|
+
Returns
|
|
257
|
+
-------
|
|
258
|
+
list[str]
|
|
259
|
+
One text per row.
|
|
260
|
+
|
|
261
|
+
Raises
|
|
262
|
+
------
|
|
263
|
+
ValueConversionError
|
|
264
|
+
At the first infinite value.
|
|
265
|
+
|
|
266
|
+
Examples
|
|
267
|
+
--------
|
|
268
|
+
>>> import pandas
|
|
269
|
+
>>> from numdaplot.tables.files.json_decimals import write_decimal_cells
|
|
270
|
+
>>> write_decimal_cells(pandas.Series([0.1 + 0.2]), "price", None)
|
|
271
|
+
['"price":0.30000000000000004']
|
|
272
|
+
"""
|
|
273
|
+
values = read_decimals(column)
|
|
274
|
+
with NamedColumnErrors(column):
|
|
275
|
+
require_finite_values(values)
|
|
276
|
+
|
|
277
|
+
if decimals is None:
|
|
278
|
+
value_texts = write_shortest_texts(values)
|
|
279
|
+
else:
|
|
280
|
+
value_texts = write_rounded_texts(values, decimals)
|
|
281
|
+
|
|
282
|
+
name_text = json.dumps(column_name, ensure_ascii=False)
|
|
283
|
+
cell_start = name_text + CELL_SEPARATOR
|
|
284
|
+
cells = [cell_start + value_text for value_text in value_texts]
|
|
285
|
+
|
|
286
|
+
return cells
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def write_other_cells(frame: pandas.DataFrame) -> list[str]:
|
|
290
|
+
"""
|
|
291
|
+
Return the names and the values of columns without decimals, as they appear in each object of a JSON file.
|
|
292
|
+
|
|
293
|
+
.. versionadded:: 0.1.0
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
frame
|
|
298
|
+
Columns without decimals.
|
|
299
|
+
|
|
300
|
+
Returns
|
|
301
|
+
-------
|
|
302
|
+
list[str]
|
|
303
|
+
One text per row, written by pandas: ``null``, ISO 8601 dates and durations.
|
|
304
|
+
|
|
305
|
+
Examples
|
|
306
|
+
--------
|
|
307
|
+
>>> import pandas
|
|
308
|
+
>>> from numdaplot.tables.files.json_decimals import write_other_cells
|
|
309
|
+
>>> write_other_cells(pandas.DataFrame({"city": ["Paris", None], "count": [1, 2]}))
|
|
310
|
+
['"city":"Paris","count":1', '"city":null,"count":2']
|
|
311
|
+
"""
|
|
312
|
+
# Some versions of the pandas stubs leave the parameter types of to_json unknown.
|
|
313
|
+
json_frame = cast(Any, frame)
|
|
314
|
+
lines_text = cast(
|
|
315
|
+
str,
|
|
316
|
+
json_frame.to_json(orient=RECORDS_ORIENTATION, lines=True, force_ascii=False, date_format=ISO_DATE_FORMAT),
|
|
317
|
+
)
|
|
318
|
+
stripped_text = lines_text.removesuffix(LINE_END)
|
|
319
|
+
# JSON writes a line break inside a text as an escape, so each line is one object.
|
|
320
|
+
lines = stripped_text.split(LINE_END)
|
|
321
|
+
cells = [line[FIRST_CHARACTER_AFTER_BRACE:LAST_CHARACTER_BEFORE_BRACE] for line in lines]
|
|
322
|
+
|
|
323
|
+
return cells
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def write_exact_objects(frame: pandas.DataFrame, decimals: int | None) -> list[str]:
|
|
327
|
+
"""
|
|
328
|
+
Return one JSON object per row, the columns staying in their order.
|
|
329
|
+
|
|
330
|
+
Neighbor columns without decimals are written together by pandas, which is much faster than one by one.
|
|
331
|
+
|
|
332
|
+
.. versionadded:: 0.1.0
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
----------
|
|
336
|
+
frame
|
|
337
|
+
The columns of a Table, at least one holding decimals.
|
|
338
|
+
decimals
|
|
339
|
+
The number of decimals written, every digit of each value when ``None``.
|
|
340
|
+
|
|
341
|
+
Returns
|
|
342
|
+
-------
|
|
343
|
+
list[str]
|
|
344
|
+
One object per row.
|
|
345
|
+
|
|
346
|
+
Raises
|
|
347
|
+
------
|
|
348
|
+
ValueConversionError
|
|
349
|
+
At the first infinite value.
|
|
350
|
+
|
|
351
|
+
Examples
|
|
352
|
+
--------
|
|
353
|
+
>>> import pandas
|
|
354
|
+
>>> from numdaplot.tables.files.json_decimals import write_exact_objects
|
|
355
|
+
>>> write_exact_objects(pandas.DataFrame({"city": ["Paris"], "price": [1 / 3]}), None)
|
|
356
|
+
['{"city":"Paris","price":0.3333333333333333}']
|
|
357
|
+
"""
|
|
358
|
+
if frame.empty:
|
|
359
|
+
return []
|
|
360
|
+
|
|
361
|
+
cell_groups = list[list[str]]()
|
|
362
|
+
other_names = list[str]()
|
|
363
|
+
|
|
364
|
+
for column_name in list[str](frame.columns):
|
|
365
|
+
column = frame[column_name]
|
|
366
|
+
is_decimal = is_decimal_column(column)
|
|
367
|
+
if not is_decimal:
|
|
368
|
+
other_names.append(column_name)
|
|
369
|
+
continue
|
|
370
|
+
|
|
371
|
+
if other_names != []:
|
|
372
|
+
other_cells = write_other_cells(frame[other_names])
|
|
373
|
+
cell_groups.append(other_cells)
|
|
374
|
+
other_names = list[str]()
|
|
375
|
+
|
|
376
|
+
decimal_cells = write_decimal_cells(column, column_name, decimals)
|
|
377
|
+
cell_groups.append(decimal_cells)
|
|
378
|
+
|
|
379
|
+
if other_names != []:
|
|
380
|
+
last_cells = write_other_cells(frame[other_names])
|
|
381
|
+
cell_groups.append(last_cells)
|
|
382
|
+
|
|
383
|
+
row_cells = zip(*cell_groups, strict=True)
|
|
384
|
+
rows = map(CELL_JOINER.join, row_cells)
|
|
385
|
+
objects = [OBJECT_START + row + OBJECT_END for row in rows]
|
|
386
|
+
|
|
387
|
+
return objects
|