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,313 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Drawing of a HeatmapChart.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# The matplotlib stubs leave the keyword arguments of most drawing methods untyped.
|
|
8
|
+
# pyright: reportUnknownMemberType=false
|
|
9
|
+
|
|
10
|
+
import warnings
|
|
11
|
+
from typing import cast
|
|
12
|
+
|
|
13
|
+
import matplotlib
|
|
14
|
+
import numpy
|
|
15
|
+
from matplotlib.axes import Axes
|
|
16
|
+
from matplotlib.image import AxesImage
|
|
17
|
+
from numpy.typing import NDArray
|
|
18
|
+
|
|
19
|
+
from numdaplot.arrays.operations.float_errors import INTERNAL_FILES
|
|
20
|
+
from numdaplot.errors.readability_warning import ReadabilityWarning
|
|
21
|
+
from numdaplot.plots.chart_layer import ChartLayer
|
|
22
|
+
from numdaplot.plots.charts.cell_values import CellValues
|
|
23
|
+
from numdaplot.plots.charts.heatmap_chart import HeatmapChart
|
|
24
|
+
from numdaplot.plots.data.chart_values import ChartValues, Series
|
|
25
|
+
from numdaplot.plots.drawing.cell_merging import average_cells, find_cell_limits, fit_cells_to_axes
|
|
26
|
+
from numdaplot.plots.drawing.color_bar import add_color_bar
|
|
27
|
+
from numdaplot.plots.drawing.color_scale_values import SCALE_NAMES, find_scale_limits
|
|
28
|
+
from numdaplot.plots.drawing.default_labels import COLUMN_LABEL, find_position_label
|
|
29
|
+
from numdaplot.plots.drawing.drawn_chart import DrawnChart
|
|
30
|
+
from numdaplot.plots.drawing.grid_axes import GridAxes
|
|
31
|
+
from numdaplot.plots.drawing.plot_theme import GRID_COLOR
|
|
32
|
+
from numdaplot.plots.drawing.position_axis import TRIMMED_ZEROS, place_categories, set_fixed_labels
|
|
33
|
+
from numdaplot.plots.drawing.text_contrast import choose_text_color
|
|
34
|
+
|
|
35
|
+
CELL_DECIMALS = 2
|
|
36
|
+
CELL_ASPECT = "auto"
|
|
37
|
+
CELL_INTERPOLATION = "nearest"
|
|
38
|
+
CENTERED = "center"
|
|
39
|
+
MERGED_CELLS_MESSAGE = (
|
|
40
|
+
"A HeatmapChart with {row_count} rows and {column_count} columns does not fit in the image, so each band shows the "
|
|
41
|
+
"mean of its cells. Give a larger ndp.Size, or group the values with Table.aggregate first."
|
|
42
|
+
)
|
|
43
|
+
UNWRITTEN_VALUES_MESSAGE = " The values of the cells are not written."
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def draw_heatmap_chart(axes: Axes, layer: ChartLayer) -> DrawnChart:
|
|
47
|
+
"""
|
|
48
|
+
Draw each value as a cell colored along a color scale, the columns side by side and the first row on top.
|
|
49
|
+
|
|
50
|
+
When the axes have too few pixels for the cells, each band shows the mean of its cells, missing values left out,
|
|
51
|
+
the color scale follows these means, and the values of the cells are not written.
|
|
52
|
+
|
|
53
|
+
.. versionadded:: 0.1.0
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
axes
|
|
58
|
+
The matplotlib axes drawn on.
|
|
59
|
+
layer
|
|
60
|
+
A HeatmapChart, its row labels and its columns.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
DrawnChart
|
|
65
|
+
The ``labels`` column as default label of the vertical axis, and no grid lines.
|
|
66
|
+
|
|
67
|
+
Warns
|
|
68
|
+
-----
|
|
69
|
+
ReadabilityWarning
|
|
70
|
+
When the cells are merged into bands.
|
|
71
|
+
|
|
72
|
+
Examples
|
|
73
|
+
--------
|
|
74
|
+
>>> import numdaplot as ndp
|
|
75
|
+
>>> from matplotlib.figure import Figure
|
|
76
|
+
>>> from numdaplot.plots.chart_layer import ChartLayer
|
|
77
|
+
>>> from numdaplot.plots.data.array_values import read_array_values
|
|
78
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import draw_heatmap_chart
|
|
79
|
+
>>> grid = ndp.Array.from_list([[1.0, 2.0], [3.0, None]])
|
|
80
|
+
>>> axes = Figure().add_subplot()
|
|
81
|
+
>>> drawn_chart = draw_heatmap_chart(axes, ChartLayer(ndp.HeatmapChart(), read_array_values(grid, "HeatmapChart")))
|
|
82
|
+
>>> axes.images[0].get_array().mask.tolist()
|
|
83
|
+
[[False, False], [False, True]]
|
|
84
|
+
"""
|
|
85
|
+
chart = cast(HeatmapChart, layer.chart)
|
|
86
|
+
values = cast(ChartValues, layer.values)
|
|
87
|
+
grid = stack_columns(values.series)
|
|
88
|
+
shown_cells = fit_cells_to_axes(grid, axes, average_cells)
|
|
89
|
+
cells_are_merged = shown_cells is not grid
|
|
90
|
+
scale_name = SCALE_NAMES[chart.scale]
|
|
91
|
+
base_scale = matplotlib.colormaps[scale_name]
|
|
92
|
+
color_scale = base_scale.with_extremes(bad=GRID_COLOR)
|
|
93
|
+
lowest_color, highest_color = find_scale_limits(shown_cells, chart.scale)
|
|
94
|
+
cell_limits = find_cell_limits(grid)
|
|
95
|
+
# matplotlib paints the NaN cells with the color for missing values of the scale.
|
|
96
|
+
image = axes.imshow(
|
|
97
|
+
shown_cells,
|
|
98
|
+
cmap=color_scale,
|
|
99
|
+
vmin=lowest_color,
|
|
100
|
+
vmax=highest_color,
|
|
101
|
+
aspect=CELL_ASPECT,
|
|
102
|
+
interpolation=CELL_INTERPOLATION,
|
|
103
|
+
extent=cell_limits,
|
|
104
|
+
)
|
|
105
|
+
place_column_names(axes, values.series)
|
|
106
|
+
place_categories(axes, values.positions, True)
|
|
107
|
+
hide_frame(axes)
|
|
108
|
+
scale_label = ""
|
|
109
|
+
if values.value_name is not None:
|
|
110
|
+
scale_label = values.value_name
|
|
111
|
+
|
|
112
|
+
add_color_bar(axes, image, scale_label, shown_cells)
|
|
113
|
+
values_are_asked = chart.values == CellValues.SHOWN
|
|
114
|
+
if cells_are_merged:
|
|
115
|
+
warn_merged_cells(grid, values_are_asked)
|
|
116
|
+
elif values_are_asked:
|
|
117
|
+
write_cell_values(axes, image, grid)
|
|
118
|
+
|
|
119
|
+
y_label = find_position_label(values.positions)
|
|
120
|
+
drawn_chart = DrawnChart(COLUMN_LABEL, y_label, False, GridAxes.NONE, None)
|
|
121
|
+
|
|
122
|
+
return drawn_chart
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def warn_merged_cells(grid: NDArray[numpy.float64], values_are_asked: bool) -> None:
|
|
126
|
+
"""
|
|
127
|
+
Warn that a heatmap shows the mean of its cells, and that their values are not written when they were asked for.
|
|
128
|
+
|
|
129
|
+
.. versionadded:: 0.1.0
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
grid
|
|
134
|
+
The cells before they are merged.
|
|
135
|
+
values_are_asked
|
|
136
|
+
True when the chart asks for the values of the cells to be written.
|
|
137
|
+
|
|
138
|
+
Warns
|
|
139
|
+
-----
|
|
140
|
+
ReadabilityWarning
|
|
141
|
+
Always.
|
|
142
|
+
|
|
143
|
+
Examples
|
|
144
|
+
--------
|
|
145
|
+
>>> import numpy
|
|
146
|
+
>>> import warnings
|
|
147
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import warn_merged_cells
|
|
148
|
+
>>> with warnings.catch_warnings(record=True) as caught_warnings:
|
|
149
|
+
... warnings.simplefilter("always")
|
|
150
|
+
... warn_merged_cells(numpy.zeros((3000, 2)), False)
|
|
151
|
+
>>> str(caught_warnings[0].message).startswith("A HeatmapChart with 3000 rows and 2 columns")
|
|
152
|
+
True
|
|
153
|
+
"""
|
|
154
|
+
row_count, column_count = grid.shape
|
|
155
|
+
message = MERGED_CELLS_MESSAGE.format(row_count=row_count, column_count=column_count)
|
|
156
|
+
if values_are_asked:
|
|
157
|
+
message = message + UNWRITTEN_VALUES_MESSAGE
|
|
158
|
+
|
|
159
|
+
warnings.warn(message, ReadabilityWarning, skip_file_prefixes=INTERNAL_FILES)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def stack_columns(series_list: list[Series]) -> NDArray[numpy.float64]:
|
|
163
|
+
"""
|
|
164
|
+
Return the columns of a chart side by side, as a grid of one row per row and one column per column.
|
|
165
|
+
|
|
166
|
+
.. versionadded:: 0.1.0
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
series_list
|
|
171
|
+
The columns, each with one number per row.
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
NDArray[numpy.float64]
|
|
176
|
+
The grid of numbers, NaN where a value is missing.
|
|
177
|
+
|
|
178
|
+
Examples
|
|
179
|
+
--------
|
|
180
|
+
>>> import numpy
|
|
181
|
+
>>> from numdaplot.plots.data.chart_values import Series
|
|
182
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import stack_columns
|
|
183
|
+
>>> stack_columns([Series("jan", numpy.array([1.0, 2.0])), Series("feb", numpy.array([3.0, 4.0]))]).tolist()
|
|
184
|
+
[[1.0, 3.0], [2.0, 4.0]]
|
|
185
|
+
"""
|
|
186
|
+
columns = [series.values for series in series_list]
|
|
187
|
+
grid = numpy.column_stack(columns)
|
|
188
|
+
|
|
189
|
+
return grid
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def place_column_names(axes: Axes, series_list: list[Series]) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Label each column of cells with its name along the horizontal axis.
|
|
195
|
+
|
|
196
|
+
.. versionadded:: 0.1.0
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
axes
|
|
201
|
+
The matplotlib axes drawn on.
|
|
202
|
+
series_list
|
|
203
|
+
The columns, in the order of the cells.
|
|
204
|
+
|
|
205
|
+
Examples
|
|
206
|
+
--------
|
|
207
|
+
>>> import numpy
|
|
208
|
+
>>> from matplotlib.figure import Figure
|
|
209
|
+
>>> from numdaplot.plots.data.chart_values import Series
|
|
210
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import place_column_names
|
|
211
|
+
>>> axes = Figure().add_subplot()
|
|
212
|
+
>>> place_column_names(axes, [Series("jan", numpy.array([1.0])), Series("feb", numpy.array([2.0]))])
|
|
213
|
+
>>> [label.get_text() for label in axes.get_xticklabels()]
|
|
214
|
+
['jan', 'feb']
|
|
215
|
+
"""
|
|
216
|
+
column_names = [series.name for series in series_list]
|
|
217
|
+
column_count = len(column_names)
|
|
218
|
+
coordinates = numpy.arange(column_count, dtype=numpy.float64)
|
|
219
|
+
set_fixed_labels(axes.xaxis, coordinates, column_names)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def hide_frame(axes: Axes) -> None:
|
|
223
|
+
"""
|
|
224
|
+
Hide the lines framing the axes and their tick marks, the cells drawing their own edges.
|
|
225
|
+
|
|
226
|
+
.. versionadded:: 0.1.0
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
axes
|
|
231
|
+
The matplotlib axes drawn on.
|
|
232
|
+
|
|
233
|
+
Examples
|
|
234
|
+
--------
|
|
235
|
+
>>> from matplotlib.figure import Figure
|
|
236
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import hide_frame
|
|
237
|
+
>>> axes = Figure().add_subplot()
|
|
238
|
+
>>> hide_frame(axes)
|
|
239
|
+
>>> axes.spines["left"].get_visible()
|
|
240
|
+
False
|
|
241
|
+
"""
|
|
242
|
+
for spine in axes.spines.values():
|
|
243
|
+
spine.set_visible(False)
|
|
244
|
+
|
|
245
|
+
axes.tick_params(length=0)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def write_cell_values(axes: Axes, image: AxesImage, grid: NDArray[numpy.float64]) -> None:
|
|
249
|
+
"""
|
|
250
|
+
Write the value of each cell inside it, in black or white to stay readable over its color.
|
|
251
|
+
|
|
252
|
+
A missing value writes nothing.
|
|
253
|
+
|
|
254
|
+
.. versionadded:: 0.1.0
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
axes
|
|
259
|
+
The matplotlib axes drawn on.
|
|
260
|
+
image
|
|
261
|
+
The colored cells.
|
|
262
|
+
grid
|
|
263
|
+
The numbers of the cells, NaN where a value is missing.
|
|
264
|
+
|
|
265
|
+
Examples
|
|
266
|
+
--------
|
|
267
|
+
>>> import numpy
|
|
268
|
+
>>> from matplotlib.figure import Figure
|
|
269
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import write_cell_values
|
|
270
|
+
>>> axes = Figure().add_subplot()
|
|
271
|
+
>>> grid = numpy.array([[1.25, numpy.nan, 3.0]])
|
|
272
|
+
>>> write_cell_values(axes, axes.imshow(grid), grid)
|
|
273
|
+
>>> [text.get_text() for text in axes.texts]
|
|
274
|
+
['1.25', '3']
|
|
275
|
+
"""
|
|
276
|
+
# Some versions of the matplotlib stubs leave the colors given by to_rgba untyped.
|
|
277
|
+
cell_colors = cast(NDArray[numpy.float64], image.to_rgba(grid))
|
|
278
|
+
|
|
279
|
+
for (row, column), number in numpy.ndenumerate(grid):
|
|
280
|
+
if numpy.isnan(number):
|
|
281
|
+
continue
|
|
282
|
+
|
|
283
|
+
cell_color = cell_colors[row, column].tolist()
|
|
284
|
+
text_color = choose_text_color(cell_color)
|
|
285
|
+
cell_text = format_cell_value(number)
|
|
286
|
+
axes.text(column, row, cell_text, color=text_color, horizontalalignment=CENTERED, verticalalignment=CENTERED)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def format_cell_value(number: float) -> str:
|
|
290
|
+
"""
|
|
291
|
+
Return the text of a cell value, with at most two decimals and no trailing zero.
|
|
292
|
+
|
|
293
|
+
.. versionadded:: 0.1.0
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
number
|
|
298
|
+
The value of the cell.
|
|
299
|
+
|
|
300
|
+
Returns
|
|
301
|
+
-------
|
|
302
|
+
str
|
|
303
|
+
The value rounded to two decimals.
|
|
304
|
+
|
|
305
|
+
Examples
|
|
306
|
+
--------
|
|
307
|
+
>>> from numdaplot.plots.drawing.heatmap_drawing import format_cell_value
|
|
308
|
+
>>> format_cell_value(12.3456), format_cell_value(4.0)
|
|
309
|
+
('12.35', '4')
|
|
310
|
+
"""
|
|
311
|
+
cell_text = numpy.format_float_positional(number, precision=CELL_DECIMALS, trim=TRIMMED_ZEROS)
|
|
312
|
+
|
|
313
|
+
return cell_text
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Drawing of a HistogramChart.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# The matplotlib stubs leave the keyword arguments of most drawing methods untyped.
|
|
8
|
+
# pyright: reportUnknownMemberType=false
|
|
9
|
+
|
|
10
|
+
import math
|
|
11
|
+
from datetime import timedelta
|
|
12
|
+
from typing import cast
|
|
13
|
+
|
|
14
|
+
import numpy
|
|
15
|
+
from matplotlib.axes import Axes
|
|
16
|
+
from numpy.typing import NDArray
|
|
17
|
+
|
|
18
|
+
from numdaplot.data_types.type import Type
|
|
19
|
+
from numdaplot.errors.incompatible_types_error import IncompatibleTypesError
|
|
20
|
+
from numdaplot.plots.chart_layer import ChartLayer
|
|
21
|
+
from numdaplot.plots.charts.bin_count import BinCount
|
|
22
|
+
from numdaplot.plots.charts.bin_width import BinWidth
|
|
23
|
+
from numdaplot.plots.charts.histogram_chart import HistogramChart
|
|
24
|
+
from numdaplot.plots.data.sample_values import SampleValues, drop_missing_numbers
|
|
25
|
+
from numdaplot.plots.drawing.drawn_chart import DrawnChart
|
|
26
|
+
from numdaplot.plots.drawing.grid_axes import GridAxes
|
|
27
|
+
from numdaplot.plots.drawing.plot_theme import BACKGROUND_COLOR
|
|
28
|
+
from numdaplot.plots.drawing.series_colors import choose_series_colors
|
|
29
|
+
from numdaplot.plots.drawing.time_axis import measures_times, place_hour_ticks
|
|
30
|
+
from numdaplot.plots.drawing.whole_numbers import place_whole_ticks
|
|
31
|
+
from numdaplot.ratios.measure import Measure
|
|
32
|
+
|
|
33
|
+
MEASURE_LABELS = {
|
|
34
|
+
Measure.COUNT: "Count",
|
|
35
|
+
Measure.RATIO: "Ratio",
|
|
36
|
+
}
|
|
37
|
+
SINGLE_OPACITY = 1.0
|
|
38
|
+
OVERLAID_OPACITY = 0.5
|
|
39
|
+
BIN_EDGE_WIDTH = 0.8
|
|
40
|
+
# Each bar starts at the left edge of its bin.
|
|
41
|
+
BIN_ALIGNMENT = "edge"
|
|
42
|
+
DEFAULT_BIN_COUNT = 10
|
|
43
|
+
HOURS_PER_DAY = 24
|
|
44
|
+
DAY_EDGE_COUNT = HOURS_PER_DAY + 1
|
|
45
|
+
ONE_HOUR = timedelta(hours=1)
|
|
46
|
+
NUMBER_WIDTH_TYPE = Type.FLOAT64
|
|
47
|
+
DURATION_WIDTH_TYPE = Type.DURATION
|
|
48
|
+
WIDTH_OPERATION = "BinWidth"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def draw_histogram_chart(axes: Axes, layer: ChartLayer) -> DrawnChart:
|
|
52
|
+
"""
|
|
53
|
+
Draw how many values of each column fall in each bin, the columns sharing the same bins.
|
|
54
|
+
|
|
55
|
+
Several columns are drawn over each other, half transparent. Missing values are left out.
|
|
56
|
+
|
|
57
|
+
.. versionadded:: 0.1.0
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
axes
|
|
62
|
+
The matplotlib axes drawn on.
|
|
63
|
+
layer
|
|
64
|
+
A HistogramChart and its columns.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
DrawnChart
|
|
69
|
+
The single column as default label of the values, ``"Count"`` or ``"Ratio"`` as label of the other axis,
|
|
70
|
+
and grid lines across that axis only.
|
|
71
|
+
|
|
72
|
+
Raises
|
|
73
|
+
------
|
|
74
|
+
InvalidColorCountError
|
|
75
|
+
When the colors of the chart are not one per column.
|
|
76
|
+
|
|
77
|
+
Examples
|
|
78
|
+
--------
|
|
79
|
+
>>> import numdaplot as ndp
|
|
80
|
+
>>> from matplotlib.figure import Figure
|
|
81
|
+
>>> from numdaplot.plots.chart_layer import ChartLayer
|
|
82
|
+
>>> from numdaplot.plots.data.sample_values import read_sample_values
|
|
83
|
+
>>> from numdaplot.plots.drawing.histogram_drawing import draw_histogram_chart
|
|
84
|
+
>>> prices = ndp.Array.from_list([12.0, 13.0, 17.0, None])
|
|
85
|
+
>>> axes = Figure().add_subplot()
|
|
86
|
+
>>> samples = read_sample_values(prices, None, None, "HistogramChart")
|
|
87
|
+
>>> layer = ChartLayer(ndp.HistogramChart(bins=ndp.BinWidth(5.0)), samples)
|
|
88
|
+
>>> drawn_chart = draw_histogram_chart(axes, layer)
|
|
89
|
+
>>> [float(bar.get_height()) for bar in axes.patches]
|
|
90
|
+
[2.0, 1.0]
|
|
91
|
+
"""
|
|
92
|
+
chart = cast(HistogramChart, layer.chart)
|
|
93
|
+
values = cast(SampleValues, layer.values)
|
|
94
|
+
series_count = len(values.series)
|
|
95
|
+
color_codes = choose_series_colors(chart.colors, series_count)
|
|
96
|
+
samples = [drop_missing_numbers(series.values) for series in values.series]
|
|
97
|
+
all_numbers = numpy.concatenate(samples)
|
|
98
|
+
bin_edges = find_bin_edges(all_numbers, chart.bins, values.value_type)
|
|
99
|
+
bin_starts = bin_edges[:-1]
|
|
100
|
+
bin_widths = numpy.diff(bin_edges)
|
|
101
|
+
opacity = SINGLE_OPACITY
|
|
102
|
+
if series_count > 1:
|
|
103
|
+
opacity = OVERLAID_OPACITY
|
|
104
|
+
|
|
105
|
+
bin_counts = list[NDArray[numpy.float64]]()
|
|
106
|
+
|
|
107
|
+
for i, series in enumerate(values.series):
|
|
108
|
+
weights = find_bin_weights(samples[i], chart.measure)
|
|
109
|
+
counts, _ = numpy.histogram(samples[i], bins=bin_edges, weights=weights)
|
|
110
|
+
series_counts = numpy.asarray(counts, dtype=numpy.float64)
|
|
111
|
+
axes.bar(
|
|
112
|
+
bin_starts,
|
|
113
|
+
series_counts,
|
|
114
|
+
width=bin_widths,
|
|
115
|
+
align=BIN_ALIGNMENT,
|
|
116
|
+
color=color_codes[i],
|
|
117
|
+
alpha=opacity,
|
|
118
|
+
label=series.name,
|
|
119
|
+
edgecolor=BACKGROUND_COLOR,
|
|
120
|
+
linewidth=BIN_EDGE_WIDTH,
|
|
121
|
+
)
|
|
122
|
+
bin_counts.append(series_counts)
|
|
123
|
+
|
|
124
|
+
all_counts = numpy.concatenate(bin_counts)
|
|
125
|
+
place_whole_ticks(axes.yaxis, all_counts)
|
|
126
|
+
|
|
127
|
+
is_time = measures_times(values.value_type)
|
|
128
|
+
if is_time:
|
|
129
|
+
place_hour_ticks(axes.xaxis, bin_edges)
|
|
130
|
+
|
|
131
|
+
measure_label = MEASURE_LABELS[chart.measure]
|
|
132
|
+
drawn_chart = DrawnChart(values.value_name, measure_label, False, GridAxes.VALUES, None)
|
|
133
|
+
|
|
134
|
+
return drawn_chart
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def require_bins_on_values(bins: BinCount | BinWidth | None, value_type: Type) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Check that the width of the bins of a histogram is a number for numbers and a duration for times of day.
|
|
140
|
+
|
|
141
|
+
.. versionadded:: 0.1.0
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
bins
|
|
146
|
+
The bins of the HistogramChart, None for the default ones.
|
|
147
|
+
value_type
|
|
148
|
+
The type of the values drawn.
|
|
149
|
+
|
|
150
|
+
Raises
|
|
151
|
+
------
|
|
152
|
+
IncompatibleTypesError
|
|
153
|
+
When a number gives the width of bins of times of day, or a duration the width of bins of numbers.
|
|
154
|
+
|
|
155
|
+
Examples
|
|
156
|
+
--------
|
|
157
|
+
>>> from datetime import timedelta
|
|
158
|
+
>>> import numdaplot as ndp
|
|
159
|
+
>>> from numdaplot.plots.drawing.histogram_drawing import require_bins_on_values
|
|
160
|
+
>>> try:
|
|
161
|
+
... require_bins_on_values(ndp.BinWidth(timedelta(hours=1)), ndp.Type.FLOAT64)
|
|
162
|
+
... except ndp.IncompatibleTypesError as error:
|
|
163
|
+
... print(error)
|
|
164
|
+
Cannot apply BinWidth to DURATION and FLOAT64.
|
|
165
|
+
"""
|
|
166
|
+
if not isinstance(bins, BinWidth):
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
is_time = measures_times(value_type)
|
|
170
|
+
is_duration = isinstance(bins.width, timedelta)
|
|
171
|
+
if is_duration == is_time:
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
width_type = NUMBER_WIDTH_TYPE
|
|
175
|
+
if is_duration:
|
|
176
|
+
width_type = DURATION_WIDTH_TYPE
|
|
177
|
+
|
|
178
|
+
raise IncompatibleTypesError(WIDTH_OPERATION, [width_type.name, value_type.name])
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def find_bin_edges(
|
|
182
|
+
numbers: NDArray[numpy.float64], bins: BinCount | BinWidth | None, value_type: Type
|
|
183
|
+
) -> NDArray[numpy.float64]:
|
|
184
|
+
"""
|
|
185
|
+
Return the edges of the bins of a histogram.
|
|
186
|
+
|
|
187
|
+
.. versionadded:: 0.1.0
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
numbers
|
|
192
|
+
Every number drawn, of every column, none missing, a time of day being its hours since midnight.
|
|
193
|
+
bins
|
|
194
|
+
The number of bins, spread from the smallest to the largest number, or their width, checked against the
|
|
195
|
+
values. None gives 10 bins for numbers and one bin per hour from 00:00 to 24:00 for times of day.
|
|
196
|
+
value_type
|
|
197
|
+
The type of the values drawn.
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
NDArray[numpy.float64]
|
|
202
|
+
One edge more than there are bins, in hours for times of day.
|
|
203
|
+
|
|
204
|
+
Examples
|
|
205
|
+
--------
|
|
206
|
+
>>> import numdaplot as ndp
|
|
207
|
+
>>> import numpy
|
|
208
|
+
>>> from numdaplot.plots.drawing.histogram_drawing import find_bin_edges
|
|
209
|
+
>>> find_bin_edges(numpy.array([12.0, 20.0]), ndp.BinCount(4), ndp.Type.FLOAT64)
|
|
210
|
+
array([12., 14., 16., 18., 20.])
|
|
211
|
+
>>> len(find_bin_edges(numpy.array([8.5]), None, ndp.Type.TIME))
|
|
212
|
+
25
|
|
213
|
+
"""
|
|
214
|
+
is_time = measures_times(value_type)
|
|
215
|
+
uses_day_edges = bins is None and is_time
|
|
216
|
+
if uses_day_edges:
|
|
217
|
+
day_edges = numpy.arange(DAY_EDGE_COUNT, dtype=numpy.float64)
|
|
218
|
+
return day_edges
|
|
219
|
+
|
|
220
|
+
if bins is None:
|
|
221
|
+
bins = BinCount(DEFAULT_BIN_COUNT)
|
|
222
|
+
|
|
223
|
+
if isinstance(bins, BinWidth):
|
|
224
|
+
width = read_width_hours(bins)
|
|
225
|
+
width_edges = find_width_edges(numbers, width)
|
|
226
|
+
return width_edges
|
|
227
|
+
|
|
228
|
+
count_edges = numpy.histogram_bin_edges(numbers, bins=bins.count)
|
|
229
|
+
|
|
230
|
+
return count_edges
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def read_width_hours(bins: BinWidth) -> float:
|
|
234
|
+
"""
|
|
235
|
+
Return the width of bins as a number, a duration being counted in hours.
|
|
236
|
+
|
|
237
|
+
.. versionadded:: 0.1.0
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
bins
|
|
242
|
+
The width of the bins.
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
float
|
|
247
|
+
The width of bins of numbers, or the hours of a duration.
|
|
248
|
+
|
|
249
|
+
Examples
|
|
250
|
+
--------
|
|
251
|
+
>>> from datetime import timedelta
|
|
252
|
+
>>> import numdaplot as ndp
|
|
253
|
+
>>> from numdaplot.plots.drawing.histogram_drawing import read_width_hours
|
|
254
|
+
>>> read_width_hours(ndp.BinWidth(timedelta(minutes=30))), read_width_hours(ndp.BinWidth(2.5))
|
|
255
|
+
(0.5, 2.5)
|
|
256
|
+
"""
|
|
257
|
+
if isinstance(bins.width, timedelta):
|
|
258
|
+
width_hours = bins.width / ONE_HOUR
|
|
259
|
+
return width_hours
|
|
260
|
+
|
|
261
|
+
return bins.width
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def find_width_edges(numbers: NDArray[numpy.float64], width: float) -> NDArray[numpy.float64]:
|
|
265
|
+
"""
|
|
266
|
+
Return the edges of bins of a given width, each edge being a multiple of the width.
|
|
267
|
+
|
|
268
|
+
The first edge is the largest multiple not above the smallest number, and the bins go on until the largest
|
|
269
|
+
number. Without numbers, a single bin starts at 0.
|
|
270
|
+
|
|
271
|
+
.. versionadded:: 0.1.0
|
|
272
|
+
|
|
273
|
+
Parameters
|
|
274
|
+
----------
|
|
275
|
+
numbers
|
|
276
|
+
Every number drawn, none missing.
|
|
277
|
+
width
|
|
278
|
+
The width of each bin, above 0.
|
|
279
|
+
|
|
280
|
+
Returns
|
|
281
|
+
-------
|
|
282
|
+
NDArray[numpy.float64]
|
|
283
|
+
The edges, at least two.
|
|
284
|
+
|
|
285
|
+
Examples
|
|
286
|
+
--------
|
|
287
|
+
>>> import numpy
|
|
288
|
+
>>> from numdaplot.plots.drawing.histogram_drawing import find_width_edges
|
|
289
|
+
>>> find_width_edges(numpy.array([12.0, 21.0]), 5.0)
|
|
290
|
+
array([10., 15., 20., 25.])
|
|
291
|
+
"""
|
|
292
|
+
smallest_number = 0.0
|
|
293
|
+
largest_number = 0.0
|
|
294
|
+
number_count = len(numbers)
|
|
295
|
+
if number_count > 0:
|
|
296
|
+
smallest_number = float(numbers.min())
|
|
297
|
+
largest_number = float(numbers.max())
|
|
298
|
+
|
|
299
|
+
first_width_count = math.floor(smallest_number / width)
|
|
300
|
+
first_edge = first_width_count * width
|
|
301
|
+
covered_widths = (largest_number - first_edge) / width
|
|
302
|
+
bin_count = math.ceil(covered_widths)
|
|
303
|
+
bin_count = max(bin_count, 1)
|
|
304
|
+
edge_count = bin_count + 1
|
|
305
|
+
edge_numbers = numpy.arange(edge_count, dtype=numpy.float64)
|
|
306
|
+
edge_offsets = edge_numbers * width
|
|
307
|
+
shifted_offsets = first_edge + edge_offsets
|
|
308
|
+
# Some versions of the numpy stubs widen the sum of float64 values to any floating type.
|
|
309
|
+
edges = numpy.asarray(shifted_offsets, dtype=numpy.float64)
|
|
310
|
+
|
|
311
|
+
return edges
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def find_bin_weights(numbers: NDArray[numpy.float64], measure: Measure) -> NDArray[numpy.float64] | None:
|
|
315
|
+
"""
|
|
316
|
+
Return how much each number weighs in its bin.
|
|
317
|
+
|
|
318
|
+
.. versionadded:: 0.1.0
|
|
319
|
+
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
numbers
|
|
323
|
+
The numbers of one column, none missing.
|
|
324
|
+
measure
|
|
325
|
+
``Measure.COUNT`` to count the numbers, ``Measure.RATIO`` for their share of the column.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
NDArray[numpy.float64] or None
|
|
330
|
+
None to count each number once, or one share per number, the shares adding up to 1.
|
|
331
|
+
|
|
332
|
+
Examples
|
|
333
|
+
--------
|
|
334
|
+
>>> import numdaplot as ndp
|
|
335
|
+
>>> import numpy
|
|
336
|
+
>>> from numdaplot.plots.drawing.histogram_drawing import find_bin_weights
|
|
337
|
+
>>> find_bin_weights(numpy.array([3.0, 5.0, 8.0, 9.0]), ndp.Measure.RATIO)
|
|
338
|
+
array([0.25, 0.25, 0.25, 0.25])
|
|
339
|
+
"""
|
|
340
|
+
number_count = len(numbers)
|
|
341
|
+
is_counted = measure == Measure.COUNT
|
|
342
|
+
has_no_numbers = number_count == 0
|
|
343
|
+
weighs_one = is_counted or has_no_numbers
|
|
344
|
+
if weighs_one:
|
|
345
|
+
return None
|
|
346
|
+
|
|
347
|
+
share = 1 / number_count
|
|
348
|
+
weights = numpy.full(number_count, share)
|
|
349
|
+
|
|
350
|
+
return weights
|