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,360 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Drawing of the missing values of a Table: bars per column and a map of every value.
|
|
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
|
+
from typing import cast
|
|
11
|
+
|
|
12
|
+
import numpy
|
|
13
|
+
from matplotlib.axes import Axes
|
|
14
|
+
from matplotlib.colors import ListedColormap
|
|
15
|
+
from matplotlib.container import BarContainer
|
|
16
|
+
from matplotlib.patches import Rectangle
|
|
17
|
+
|
|
18
|
+
from numdaplot.plots.chart_layer import ChartLayer
|
|
19
|
+
from numdaplot.plots.charts.bar_chart import BarChart
|
|
20
|
+
from numdaplot.plots.charts.missing_chart import MissingChart
|
|
21
|
+
from numdaplot.plots.data.chart_values import ChartValues
|
|
22
|
+
from numdaplot.plots.data.missing_cells import MissingCounts
|
|
23
|
+
from numdaplot.plots.drawing.bar_drawing import draw_bar_chart
|
|
24
|
+
from numdaplot.plots.drawing.cell_merging import find_cell_limits, fit_cells_to_axes, merge_cells
|
|
25
|
+
from numdaplot.plots.drawing.default_labels import COLUMN_LABEL, ROW_LABEL
|
|
26
|
+
from numdaplot.plots.drawing.drawn_chart import DrawnChart
|
|
27
|
+
from numdaplot.plots.drawing.grid_axes import GridAxes
|
|
28
|
+
from numdaplot.plots.drawing.heatmap_drawing import (
|
|
29
|
+
CELL_ASPECT,
|
|
30
|
+
CELL_INTERPOLATION,
|
|
31
|
+
hide_frame,
|
|
32
|
+
place_column_names,
|
|
33
|
+
stack_columns,
|
|
34
|
+
)
|
|
35
|
+
from numdaplot.plots.drawing.plot_theme import GRID_COLOR
|
|
36
|
+
from numdaplot.plots.drawing.whole_numbers import place_whole_ticks
|
|
37
|
+
from numdaplot.ratios.measure import Measure
|
|
38
|
+
|
|
39
|
+
MISSING_COLOR = "#33415c"
|
|
40
|
+
PRESENT_COLOR = GRID_COLOR
|
|
41
|
+
MISSING_TOTAL_LABEL = "Missing ({missing_total})"
|
|
42
|
+
PRESENT_LABEL = "Present"
|
|
43
|
+
MAP_TITLE = "Map of missing values"
|
|
44
|
+
LOWEST_RATIO = 0.0
|
|
45
|
+
HIGHEST_RATIO = 1.0
|
|
46
|
+
RATIO_TICK_COUNT = 6
|
|
47
|
+
# A patch placed nowhere draws nothing, yet the legend shows its colors.
|
|
48
|
+
LEGEND_SWATCH_CORNER = (numpy.nan, numpy.nan)
|
|
49
|
+
LEGEND_SWATCH_SIZE = 0.0
|
|
50
|
+
LEGEND_SWATCH_EDGE_WIDTH = 0.5
|
|
51
|
+
PERCENT_FACTOR = 100.0
|
|
52
|
+
STACKED_BAR_LABEL = "{count}\n{percent:.1f} %"
|
|
53
|
+
ONE_LINE_BAR_LABEL = "{count} ({percent:.1f} %)"
|
|
54
|
+
BAR_LABEL_FONT_SIZE = 9
|
|
55
|
+
BAR_LABEL_PADDING = 3
|
|
56
|
+
STACKED_LABEL_MINIMUM_WIDTH = 34.0
|
|
57
|
+
ONE_LINE_LABEL_MINIMUM_WIDTH = 13.0
|
|
58
|
+
# Heights in pixels, kept high enough for the layout narrowing the axes afterwards.
|
|
59
|
+
STACKED_LABEL_HEIGHT = 40.0
|
|
60
|
+
ONE_LINE_LABEL_HEIGHT = 90.0
|
|
61
|
+
UPWARD_ROTATION = 90
|
|
62
|
+
HIGHEST_HEADROOM_SHARE = 0.5
|
|
63
|
+
EMPTY_BAR_TOP = 1.0
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def draw_missing_chart(axes: Axes, layer: ChartLayer) -> DrawnChart:
|
|
67
|
+
"""
|
|
68
|
+
Draw one bar per column of a Table, as high as its missing values.
|
|
69
|
+
|
|
70
|
+
Ratios have ticks from 0 to 1, and counts have ticks on whole numbers. Each bar is labeled with its number of
|
|
71
|
+
missing values and their share of the rows, when the bars leave room for it.
|
|
72
|
+
|
|
73
|
+
.. versionadded:: 0.1.0
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
axes
|
|
78
|
+
The matplotlib axes drawn on.
|
|
79
|
+
layer
|
|
80
|
+
A MissingChart and the missing values of each column.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
DrawnChart
|
|
85
|
+
``"Missing count"`` or ``"Missing ratio"`` as label of the values, and grid lines across their axis only.
|
|
86
|
+
|
|
87
|
+
Examples
|
|
88
|
+
--------
|
|
89
|
+
>>> import numdaplot as ndp
|
|
90
|
+
>>> from matplotlib.figure import Figure
|
|
91
|
+
>>> from numdaplot.plots.chart_layer import ChartLayer
|
|
92
|
+
>>> from numdaplot.plots.data.missing_cells import read_missing_counts
|
|
93
|
+
>>> from numdaplot.plots.drawing.missing_drawing import draw_missing_chart
|
|
94
|
+
>>> prices = ndp.Array.from_list([12.0, None])
|
|
95
|
+
>>> flats = ndp.Table.from_arrays({"price": prices})
|
|
96
|
+
>>> axes = Figure().add_subplot()
|
|
97
|
+
>>> chart = ndp.MissingChart(measure=ndp.Measure.RATIO)
|
|
98
|
+
>>> drawn_chart = draw_missing_chart(axes, ChartLayer(chart, read_missing_counts(flats, chart.measure)))
|
|
99
|
+
>>> [float(tick) for tick in axes.get_yticks()][-1]
|
|
100
|
+
1.0
|
|
101
|
+
"""
|
|
102
|
+
chart = cast(MissingChart, layer.chart)
|
|
103
|
+
values = cast(MissingCounts, layer.values)
|
|
104
|
+
bar_layer = ChartLayer(BarChart(), values)
|
|
105
|
+
drawn_chart = draw_bar_chart(axes, bar_layer)
|
|
106
|
+
label_height = write_bar_labels(axes, values)
|
|
107
|
+
shown_values = values.series[0].values
|
|
108
|
+
highest_bar = float(numpy.max(shown_values, initial=0.0))
|
|
109
|
+
if chart.measure == Measure.RATIO:
|
|
110
|
+
highest_bar = HIGHEST_RATIO
|
|
111
|
+
|
|
112
|
+
bar_top = highest_bar
|
|
113
|
+
if bar_top == 0:
|
|
114
|
+
bar_top = EMPTY_BAR_TOP
|
|
115
|
+
|
|
116
|
+
axis_top = find_axis_top(bar_top, label_height, axes.bbox.height)
|
|
117
|
+
axes.set_ylim(LOWEST_RATIO, axis_top)
|
|
118
|
+
if chart.measure == Measure.RATIO:
|
|
119
|
+
ratio_ticks = numpy.linspace(LOWEST_RATIO, HIGHEST_RATIO, RATIO_TICK_COUNT)
|
|
120
|
+
axes.set_yticks(ratio_ticks)
|
|
121
|
+
return drawn_chart
|
|
122
|
+
|
|
123
|
+
place_whole_ticks(axes.yaxis, shown_values)
|
|
124
|
+
|
|
125
|
+
return drawn_chart
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def write_bar_labels(axes: Axes, values: MissingCounts) -> float:
|
|
129
|
+
"""
|
|
130
|
+
Write the number of missing values and their share of the rows above each bar, with the room the bars leave.
|
|
131
|
+
|
|
132
|
+
.. versionadded:: 0.1.0
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
axes
|
|
137
|
+
The matplotlib axes holding the bars.
|
|
138
|
+
values
|
|
139
|
+
The counts of each column and the number of rows.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
float
|
|
144
|
+
The height in pixels the labels need above the bars, 0 when the bars are too narrow for them.
|
|
145
|
+
|
|
146
|
+
Examples
|
|
147
|
+
--------
|
|
148
|
+
>>> import numdaplot as ndp
|
|
149
|
+
>>> from matplotlib.figure import Figure
|
|
150
|
+
>>> from numdaplot.plots.chart_layer import ChartLayer
|
|
151
|
+
>>> from numdaplot.plots.data.missing_cells import read_missing_counts
|
|
152
|
+
>>> from numdaplot.plots.drawing.bar_drawing import draw_bar_chart
|
|
153
|
+
>>> from numdaplot.plots.drawing.missing_drawing import write_bar_labels
|
|
154
|
+
>>> flats = ndp.Table.from_arrays({"price": ndp.Array.from_list([12.0, None])})
|
|
155
|
+
>>> values = read_missing_counts(flats, ndp.Measure.COUNT)
|
|
156
|
+
>>> axes = Figure().add_subplot()
|
|
157
|
+
>>> drawn_chart = draw_bar_chart(axes, ChartLayer(ndp.BarChart(), values))
|
|
158
|
+
>>> write_bar_labels(axes, values)
|
|
159
|
+
40.0
|
|
160
|
+
>>> axes.texts[0].get_text().splitlines()
|
|
161
|
+
['1', '50.0 %']
|
|
162
|
+
"""
|
|
163
|
+
column_count = len(values.counts)
|
|
164
|
+
if column_count == 0:
|
|
165
|
+
return 0.0
|
|
166
|
+
|
|
167
|
+
column_width = axes.bbox.width / column_count
|
|
168
|
+
if column_width < ONE_LINE_LABEL_MINIMUM_WIDTH:
|
|
169
|
+
return 0.0
|
|
170
|
+
|
|
171
|
+
is_stacked = column_width >= STACKED_LABEL_MINIMUM_WIDTH
|
|
172
|
+
label_format = ONE_LINE_BAR_LABEL
|
|
173
|
+
rotation = UPWARD_ROTATION
|
|
174
|
+
label_height = ONE_LINE_LABEL_HEIGHT
|
|
175
|
+
if is_stacked:
|
|
176
|
+
label_format = STACKED_BAR_LABEL
|
|
177
|
+
rotation = 0
|
|
178
|
+
label_height = STACKED_LABEL_HEIGHT
|
|
179
|
+
|
|
180
|
+
labels = format_bar_labels(values, label_format)
|
|
181
|
+
bars = cast(BarContainer, axes.containers[0])
|
|
182
|
+
axes.bar_label(
|
|
183
|
+
bars,
|
|
184
|
+
labels=labels,
|
|
185
|
+
padding=BAR_LABEL_PADDING,
|
|
186
|
+
fontsize=BAR_LABEL_FONT_SIZE,
|
|
187
|
+
rotation=rotation,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return label_height
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def format_bar_labels(values: MissingCounts, label_format: str) -> list[str]:
|
|
194
|
+
"""
|
|
195
|
+
Return the label of each bar, with its number of missing values and their percentage of the rows.
|
|
196
|
+
|
|
197
|
+
.. versionadded:: 0.1.0
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
values
|
|
202
|
+
The counts of each column and the number of rows.
|
|
203
|
+
label_format
|
|
204
|
+
The text of a label, with the fields ``count`` and ``percent``.
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
list[str]
|
|
209
|
+
One label per bar. The percentages of a Table without rows are 0.
|
|
210
|
+
|
|
211
|
+
Examples
|
|
212
|
+
--------
|
|
213
|
+
>>> import numdaplot as ndp
|
|
214
|
+
>>> from numdaplot.plots.data.missing_cells import read_missing_counts
|
|
215
|
+
>>> from numdaplot.plots.drawing.missing_drawing import ONE_LINE_BAR_LABEL, format_bar_labels
|
|
216
|
+
>>> flats = ndp.Table.from_arrays({"price": ndp.Array.from_list([12.0, None])})
|
|
217
|
+
>>> format_bar_labels(read_missing_counts(flats, ndp.Measure.COUNT), ONE_LINE_BAR_LABEL)
|
|
218
|
+
['1 (50.0 %)']
|
|
219
|
+
"""
|
|
220
|
+
row_count = max(values.row_count, 1)
|
|
221
|
+
labels = list[str]()
|
|
222
|
+
|
|
223
|
+
for count in values.counts:
|
|
224
|
+
whole_count = int(count)
|
|
225
|
+
percent = whole_count * PERCENT_FACTOR / row_count
|
|
226
|
+
label = label_format.format(count=whole_count, percent=percent)
|
|
227
|
+
labels.append(label)
|
|
228
|
+
|
|
229
|
+
return labels
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def find_axis_top(bar_top: float, label_height: float, axes_height: float) -> float:
|
|
233
|
+
"""
|
|
234
|
+
Return the top of the axis of the values, high enough to leave the labels room above the highest bar.
|
|
235
|
+
|
|
236
|
+
.. versionadded:: 0.1.0
|
|
237
|
+
|
|
238
|
+
Parameters
|
|
239
|
+
----------
|
|
240
|
+
bar_top
|
|
241
|
+
The highest value the axis must show, above 0.
|
|
242
|
+
label_height
|
|
243
|
+
The height in pixels the labels need.
|
|
244
|
+
axes_height
|
|
245
|
+
The height of the axes in pixels.
|
|
246
|
+
|
|
247
|
+
Returns
|
|
248
|
+
-------
|
|
249
|
+
float
|
|
250
|
+
The top of the axis, at most twice the highest value.
|
|
251
|
+
|
|
252
|
+
Examples
|
|
253
|
+
--------
|
|
254
|
+
>>> from numdaplot.plots.drawing.missing_drawing import find_axis_top
|
|
255
|
+
>>> find_axis_top(30.0, 40.0, 400.0)
|
|
256
|
+
33.333333333333336
|
|
257
|
+
"""
|
|
258
|
+
headroom_share = min(label_height / axes_height, HIGHEST_HEADROOM_SHARE)
|
|
259
|
+
axis_top = bar_top / (1 - headroom_share)
|
|
260
|
+
|
|
261
|
+
return axis_top
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def draw_missing_map(axes: Axes, layer: ChartLayer) -> DrawnChart:
|
|
265
|
+
"""
|
|
266
|
+
Draw each value of a Table as a cell, light gray when present and dark when missing.
|
|
267
|
+
|
|
268
|
+
The columns are side by side and the rows go down from the first one. When the axes have too few pixels for the
|
|
269
|
+
cells, a dark band marks at least one missing value among the cells it covers. A legend names the two colors and
|
|
270
|
+
gives the total of missing values, past the axes with ``LegendPosition.BEST``.
|
|
271
|
+
|
|
272
|
+
.. versionadded:: 0.1.0
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
axes
|
|
277
|
+
The matplotlib axes drawn on.
|
|
278
|
+
layer
|
|
279
|
+
The chart of the map and where each value is missing.
|
|
280
|
+
|
|
281
|
+
Returns
|
|
282
|
+
-------
|
|
283
|
+
DrawnChart
|
|
284
|
+
``Column`` and ``Row`` as labels, the title of the map, no grid lines, and the legend past the axes.
|
|
285
|
+
|
|
286
|
+
Examples
|
|
287
|
+
--------
|
|
288
|
+
>>> import numdaplot as ndp
|
|
289
|
+
>>> from matplotlib.figure import Figure
|
|
290
|
+
>>> from numdaplot.plots.chart_layer import ChartLayer
|
|
291
|
+
>>> from numdaplot.plots.charts.missing_map_chart import MissingMapChart
|
|
292
|
+
>>> from numdaplot.plots.data.missing_cells import read_missing_cells
|
|
293
|
+
>>> from numdaplot.plots.drawing.missing_drawing import draw_missing_map
|
|
294
|
+
>>> prices = ndp.Array.from_list([12.0, None])
|
|
295
|
+
>>> flats = ndp.Table.from_arrays({"price": prices})
|
|
296
|
+
>>> axes = Figure().add_subplot()
|
|
297
|
+
>>> drawn_chart = draw_missing_map(axes, ChartLayer(MissingMapChart(), read_missing_cells(flats)))
|
|
298
|
+
>>> axes.images[0].get_array().tolist()
|
|
299
|
+
[[0.0], [1.0]]
|
|
300
|
+
"""
|
|
301
|
+
values = cast(ChartValues, layer.values)
|
|
302
|
+
grid = stack_columns(values.series)
|
|
303
|
+
shown_cells = fit_cells_to_axes(grid, axes, merge_cells)
|
|
304
|
+
cell_colors = ListedColormap([PRESENT_COLOR, MISSING_COLOR])
|
|
305
|
+
cell_limits = find_cell_limits(grid)
|
|
306
|
+
axes.imshow(
|
|
307
|
+
shown_cells,
|
|
308
|
+
cmap=cell_colors,
|
|
309
|
+
vmin=LOWEST_RATIO,
|
|
310
|
+
vmax=HIGHEST_RATIO,
|
|
311
|
+
aspect=CELL_ASPECT,
|
|
312
|
+
interpolation=CELL_INTERPOLATION,
|
|
313
|
+
extent=cell_limits,
|
|
314
|
+
)
|
|
315
|
+
place_column_names(axes, values.series)
|
|
316
|
+
place_whole_ticks(axes.yaxis, values.positions.values)
|
|
317
|
+
hide_frame(axes)
|
|
318
|
+
missing_total = int(grid.sum())
|
|
319
|
+
missing_label = MISSING_TOTAL_LABEL.format(missing_total=missing_total)
|
|
320
|
+
add_legend_swatch(axes, MISSING_COLOR, missing_label)
|
|
321
|
+
add_legend_swatch(axes, PRESENT_COLOR, PRESENT_LABEL)
|
|
322
|
+
drawn_chart = DrawnChart(COLUMN_LABEL, ROW_LABEL, False, GridAxes.NONE, None, title=MAP_TITLE, legend_outside=True)
|
|
323
|
+
|
|
324
|
+
return drawn_chart
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def add_legend_swatch(axes: Axes, color_code: str, label: str) -> None:
|
|
328
|
+
"""
|
|
329
|
+
Add an invisible patch of a color, which the legend shows with a thin border and its label.
|
|
330
|
+
|
|
331
|
+
.. versionadded:: 0.1.0
|
|
332
|
+
|
|
333
|
+
Parameters
|
|
334
|
+
----------
|
|
335
|
+
axes
|
|
336
|
+
The matplotlib axes drawn on.
|
|
337
|
+
color_code
|
|
338
|
+
The ``#rrggbb`` code shown in the legend.
|
|
339
|
+
label
|
|
340
|
+
The name of the color in the legend.
|
|
341
|
+
|
|
342
|
+
Examples
|
|
343
|
+
--------
|
|
344
|
+
>>> from matplotlib.figure import Figure
|
|
345
|
+
>>> from numdaplot.plots.drawing.missing_drawing import add_legend_swatch
|
|
346
|
+
>>> axes = Figure().add_subplot()
|
|
347
|
+
>>> add_legend_swatch(axes, "#33415c", "Missing (3)")
|
|
348
|
+
>>> axes.get_legend_handles_labels()[1]
|
|
349
|
+
['Missing (3)']
|
|
350
|
+
"""
|
|
351
|
+
swatch = Rectangle(
|
|
352
|
+
LEGEND_SWATCH_CORNER,
|
|
353
|
+
LEGEND_SWATCH_SIZE,
|
|
354
|
+
LEGEND_SWATCH_SIZE,
|
|
355
|
+
facecolor=color_code,
|
|
356
|
+
edgecolor=MISSING_COLOR,
|
|
357
|
+
linewidth=LEGEND_SWATCH_EDGE_WIDTH,
|
|
358
|
+
label=label,
|
|
359
|
+
)
|
|
360
|
+
axes.add_patch(swatch)
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Labels of a time axis, with a corner label giving the period of the drawn values.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# The matplotlib stubs leave the arguments of the date functions and of the shared axes untyped.
|
|
8
|
+
# pyright: reportUnknownMemberType=false, reportUnknownVariableType=false
|
|
9
|
+
|
|
10
|
+
from typing import cast
|
|
11
|
+
|
|
12
|
+
from matplotlib.axes import Axes
|
|
13
|
+
from matplotlib.dates import AutoDateLocator, ConciseDateFormatter, num2date
|
|
14
|
+
|
|
15
|
+
# strftime turns each %% into %, so the corner label matplotlib writes is the format to read the period with.
|
|
16
|
+
PERIOD_FORMATS = ["", "%%Y", "%%Y-%%b", "%%Y-%%b-%%d", "%%Y-%%b-%%d", "%%Y-%%b-%%d %%H:%%M"]
|
|
17
|
+
PERIOD_TEXT = "{start} to {stop}"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MomentPeriodFormatter(ConciseDateFormatter):
|
|
21
|
+
"""
|
|
22
|
+
The concise labels of matplotlib, with a corner label giving the period of the visible values.
|
|
23
|
+
|
|
24
|
+
matplotlib writes the date of the last tick in that corner, which can be a month without any value.
|
|
25
|
+
|
|
26
|
+
.. versionadded:: 0.1.0
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
locator
|
|
31
|
+
The locator choosing the ticks of the axis.
|
|
32
|
+
axes
|
|
33
|
+
The matplotlib axes drawn on.
|
|
34
|
+
on_vertical_axis
|
|
35
|
+
True when the moments are on the vertical axis.
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
>>> import numpy
|
|
40
|
+
>>> from matplotlib.dates import AutoDateLocator
|
|
41
|
+
>>> from matplotlib.figure import Figure
|
|
42
|
+
>>> from numdaplot.plots.drawing.moment_period_formatter import MomentPeriodFormatter
|
|
43
|
+
>>> figure = Figure()
|
|
44
|
+
>>> axes = figure.add_subplot()
|
|
45
|
+
>>> days = numpy.array(["2019-03-01", "2019-03-31"], dtype="datetime64[ns]")
|
|
46
|
+
>>> _ = axes.plot(days, [1.0, 2.0])
|
|
47
|
+
>>> locator = AutoDateLocator()
|
|
48
|
+
>>> axes.xaxis.set_major_locator(locator)
|
|
49
|
+
>>> axes.xaxis.set_major_formatter(MomentPeriodFormatter(locator, axes, False))
|
|
50
|
+
>>> figure.draw_without_rendering()
|
|
51
|
+
>>> axes.xaxis.get_offset_text().get_text()
|
|
52
|
+
'2019-Mar'
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, locator: AutoDateLocator, axes: Axes, on_vertical_axis: bool) -> None:
|
|
56
|
+
super().__init__(locator, offset_formats=PERIOD_FORMATS)
|
|
57
|
+
self.drawn_axes = axes
|
|
58
|
+
self.on_vertical_axis = on_vertical_axis
|
|
59
|
+
|
|
60
|
+
def get_offset(self) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Return the text of the corner label.
|
|
63
|
+
|
|
64
|
+
.. versionadded:: 0.1.0
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
str
|
|
69
|
+
The period of the visible values, as one value or as two values separated by ``to``,
|
|
70
|
+
and an empty text when the ticks already give it.
|
|
71
|
+
|
|
72
|
+
Examples
|
|
73
|
+
--------
|
|
74
|
+
>>> import numpy
|
|
75
|
+
>>> from matplotlib.dates import AutoDateLocator
|
|
76
|
+
>>> from matplotlib.figure import Figure
|
|
77
|
+
>>> from numdaplot.plots.drawing.moment_period_formatter import MomentPeriodFormatter
|
|
78
|
+
>>> figure = Figure()
|
|
79
|
+
>>> axes = figure.add_subplot()
|
|
80
|
+
>>> days = numpy.array(["2019-03-15", "2019-05-15"], dtype="datetime64[ns]")
|
|
81
|
+
>>> _ = axes.plot(days, [1.0, 2.0])
|
|
82
|
+
>>> locator = AutoDateLocator()
|
|
83
|
+
>>> axes.xaxis.set_major_locator(locator)
|
|
84
|
+
>>> formatter = MomentPeriodFormatter(locator, axes, False)
|
|
85
|
+
>>> axes.xaxis.set_major_formatter(formatter)
|
|
86
|
+
>>> figure.draw_without_rendering()
|
|
87
|
+
>>> formatter.get_offset()
|
|
88
|
+
'2019-Mar to 2019-May'
|
|
89
|
+
"""
|
|
90
|
+
period_format = super().get_offset()
|
|
91
|
+
if period_format == "":
|
|
92
|
+
return ""
|
|
93
|
+
|
|
94
|
+
start, stop = find_visible_period(self.drawn_axes, self.on_vertical_axis)
|
|
95
|
+
period_text = write_period(start, stop, period_format)
|
|
96
|
+
|
|
97
|
+
return period_text
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def find_visible_period(axes: Axes, on_vertical_axis: bool) -> tuple[float, float]:
|
|
101
|
+
"""
|
|
102
|
+
Return the first and the last visible coordinates holding values.
|
|
103
|
+
|
|
104
|
+
.. versionadded:: 0.1.0
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
axes
|
|
109
|
+
The matplotlib axes drawn on.
|
|
110
|
+
on_vertical_axis
|
|
111
|
+
True when the moments are on the vertical axis.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
tuple[float, float]
|
|
116
|
+
The start and the stop of the visible values, or of the visible axis when it shows no value.
|
|
117
|
+
|
|
118
|
+
Examples
|
|
119
|
+
--------
|
|
120
|
+
>>> from matplotlib.figure import Figure
|
|
121
|
+
>>> from numdaplot.plots.drawing.moment_period_formatter import find_visible_period
|
|
122
|
+
>>> axes = Figure().add_subplot()
|
|
123
|
+
>>> _ = axes.plot([10.0, 20.0], [1.0, 2.0])
|
|
124
|
+
>>> find_visible_period(axes, False)
|
|
125
|
+
(10.0, 20.0)
|
|
126
|
+
"""
|
|
127
|
+
view_start, view_stop = find_view_bounds(axes, on_vertical_axis)
|
|
128
|
+
data_start, data_stop = find_data_bounds(axes, on_vertical_axis)
|
|
129
|
+
visible_start = max(view_start, data_start)
|
|
130
|
+
visible_stop = min(view_stop, data_stop)
|
|
131
|
+
if visible_start > visible_stop:
|
|
132
|
+
return view_start, view_stop
|
|
133
|
+
|
|
134
|
+
return visible_start, visible_stop
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def find_data_bounds(axes: Axes, on_vertical_axis: bool) -> tuple[float, float]:
|
|
138
|
+
"""
|
|
139
|
+
Return the lowest and the highest coordinates of the values of axes and of the axes sharing their axis.
|
|
140
|
+
|
|
141
|
+
.. versionadded:: 0.1.0
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
axes
|
|
146
|
+
The matplotlib axes drawn on.
|
|
147
|
+
on_vertical_axis
|
|
148
|
+
True when the moments are on the vertical axis.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
tuple[float, float]
|
|
153
|
+
The two bounds. The low bound is above the high bound without any value.
|
|
154
|
+
|
|
155
|
+
Examples
|
|
156
|
+
--------
|
|
157
|
+
>>> from matplotlib.figure import Figure
|
|
158
|
+
>>> from numdaplot.plots.drawing.moment_period_formatter import find_data_bounds
|
|
159
|
+
>>> axes = Figure().add_subplot()
|
|
160
|
+
>>> right_axes = axes.twinx()
|
|
161
|
+
>>> _ = axes.plot([10.0, 20.0], [1.0, 2.0])
|
|
162
|
+
>>> _ = right_axes.plot([15.0, 30.0], [1.0, 2.0])
|
|
163
|
+
>>> find_data_bounds(axes, False)
|
|
164
|
+
(10.0, 30.0)
|
|
165
|
+
"""
|
|
166
|
+
shared_axes = axes.get_shared_y_axes() if on_vertical_axis else axes.get_shared_x_axes()
|
|
167
|
+
sibling_axes = cast(list[Axes], shared_axes.get_siblings(axes))
|
|
168
|
+
data_limits = [sibling.dataLim for sibling in sibling_axes]
|
|
169
|
+
low_bounds = [limits.y0 if on_vertical_axis else limits.x0 for limits in data_limits]
|
|
170
|
+
high_bounds = [limits.y1 if on_vertical_axis else limits.x1 for limits in data_limits]
|
|
171
|
+
lowest_bound = min(low_bounds)
|
|
172
|
+
highest_bound = max(high_bounds)
|
|
173
|
+
low_bound = float(lowest_bound)
|
|
174
|
+
high_bound = float(highest_bound)
|
|
175
|
+
|
|
176
|
+
return low_bound, high_bound
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def find_view_bounds(axes: Axes, on_vertical_axis: bool) -> tuple[float, float]:
|
|
180
|
+
"""
|
|
181
|
+
Return the lowest and the highest visible coordinates of an axis, even when it is inverted.
|
|
182
|
+
|
|
183
|
+
.. versionadded:: 0.1.0
|
|
184
|
+
|
|
185
|
+
Parameters
|
|
186
|
+
----------
|
|
187
|
+
axes
|
|
188
|
+
The matplotlib axes drawn on.
|
|
189
|
+
on_vertical_axis
|
|
190
|
+
True for the vertical axis.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
tuple[float, float]
|
|
195
|
+
The two bounds.
|
|
196
|
+
|
|
197
|
+
Examples
|
|
198
|
+
--------
|
|
199
|
+
>>> from matplotlib.figure import Figure
|
|
200
|
+
>>> from numdaplot.plots.drawing.moment_period_formatter import find_view_bounds
|
|
201
|
+
>>> axes = Figure().add_subplot()
|
|
202
|
+
>>> axes.set_xlim(20.0, 10.0)
|
|
203
|
+
(20.0, 10.0)
|
|
204
|
+
>>> find_view_bounds(axes, False)
|
|
205
|
+
(10.0, 20.0)
|
|
206
|
+
"""
|
|
207
|
+
first_bound, second_bound = axes.get_ybound() if on_vertical_axis else axes.get_xbound()
|
|
208
|
+
low_bound = float(first_bound)
|
|
209
|
+
high_bound = float(second_bound)
|
|
210
|
+
|
|
211
|
+
return low_bound, high_bound
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def write_period(start: float, stop: float, period_format: str) -> str:
|
|
215
|
+
"""
|
|
216
|
+
Return the text of a period, as one value when both ends read the same.
|
|
217
|
+
|
|
218
|
+
.. versionadded:: 0.1.0
|
|
219
|
+
|
|
220
|
+
Parameters
|
|
221
|
+
----------
|
|
222
|
+
start
|
|
223
|
+
The matplotlib date number of the start.
|
|
224
|
+
stop
|
|
225
|
+
The matplotlib date number of the stop.
|
|
226
|
+
period_format
|
|
227
|
+
The strftime format of each end.
|
|
228
|
+
|
|
229
|
+
Returns
|
|
230
|
+
-------
|
|
231
|
+
str
|
|
232
|
+
The text of the period.
|
|
233
|
+
|
|
234
|
+
Examples
|
|
235
|
+
--------
|
|
236
|
+
>>> from datetime import date
|
|
237
|
+
>>> from matplotlib.dates import date2num
|
|
238
|
+
>>> from numdaplot.plots.drawing.moment_period_formatter import write_period
|
|
239
|
+
>>> write_period(date2num(date(2019, 3, 1)), date2num(date(2019, 3, 31)), "%Y-%b")
|
|
240
|
+
'2019-Mar'
|
|
241
|
+
>>> write_period(date2num(date(2019, 11, 1)), date2num(date(2020, 2, 15)), "%Y-%b")
|
|
242
|
+
'2019-Nov to 2020-Feb'
|
|
243
|
+
"""
|
|
244
|
+
start_date = num2date(start)
|
|
245
|
+
stop_date = num2date(stop)
|
|
246
|
+
start_text = start_date.strftime(period_format)
|
|
247
|
+
stop_text = stop_date.strftime(period_format)
|
|
248
|
+
if start_text == stop_text:
|
|
249
|
+
return start_text
|
|
250
|
+
|
|
251
|
+
period_text = PERIOD_TEXT.format(start=start_text, stop=stop_text)
|
|
252
|
+
|
|
253
|
+
return period_text
|