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,354 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Rotation of the labels of the ``x`` and ``y`` values of a Plot.
|
|
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 Literal
|
|
11
|
+
|
|
12
|
+
from matplotlib.axes import Axes
|
|
13
|
+
from matplotlib.axis import Axis
|
|
14
|
+
from matplotlib.dates import ConciseDateFormatter
|
|
15
|
+
from matplotlib.ticker import ScalarFormatter
|
|
16
|
+
|
|
17
|
+
from numdaplot.plots.drawing.drawn_chart import DrawnChart
|
|
18
|
+
from numdaplot.plots.drawing.label_room import (
|
|
19
|
+
LABEL_GAP_RATIO,
|
|
20
|
+
find_current_length,
|
|
21
|
+
find_font_pixels,
|
|
22
|
+
find_tick_locations,
|
|
23
|
+
find_tick_room,
|
|
24
|
+
find_widest_label,
|
|
25
|
+
read_label_texts,
|
|
26
|
+
)
|
|
27
|
+
from numdaplot.plots.drawing.label_thinning import MINIMUM_TICKS, thin_labels
|
|
28
|
+
from numdaplot.plots.drawing.position_axis import find_axis
|
|
29
|
+
|
|
30
|
+
TEXT_ROTATION = 45.0
|
|
31
|
+
NO_ROTATION = 0.0
|
|
32
|
+
ANCHOR_ROTATION_MODE = "anchor"
|
|
33
|
+
MINUS_SIGN = "\N{MINUS SIGN}"
|
|
34
|
+
HYPHEN_MINUS = "-"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def rotate_x_labels(axes: Axes, drawn_chart: DrawnChart, rotation: float | None) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Rotate the labels of the ``x`` values, wherever the chart places them, keeping those that stay readable.
|
|
40
|
+
|
|
41
|
+
.. versionadded:: 0.1.0
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
axes
|
|
46
|
+
The matplotlib axes of the Plot.
|
|
47
|
+
drawn_chart
|
|
48
|
+
Which axis holds the ``x`` values.
|
|
49
|
+
rotation
|
|
50
|
+
The angle in degrees. When None, 45 degrees for texts, moments and numbers without enough room, and no
|
|
51
|
+
rotation for other numbers and for labels on the vertical axis.
|
|
52
|
+
|
|
53
|
+
Warns
|
|
54
|
+
-----
|
|
55
|
+
ReadabilityWarning
|
|
56
|
+
When labels left out may be texts.
|
|
57
|
+
|
|
58
|
+
Examples
|
|
59
|
+
--------
|
|
60
|
+
>>> from matplotlib.figure import Figure
|
|
61
|
+
>>> from numdaplot.plots.drawing.drawn_chart import DrawnChart
|
|
62
|
+
>>> from numdaplot.plots.drawing.grid_axes import GridAxes
|
|
63
|
+
>>> from numdaplot.plots.drawing.tick_rotation import rotate_x_labels
|
|
64
|
+
>>> axes = Figure().add_subplot()
|
|
65
|
+
>>> axes.xaxis.set_ticks([0.0, 1.0], ["Paris", "Lyon"]) # doctest: +ELLIPSIS
|
|
66
|
+
[...]
|
|
67
|
+
>>> rotate_x_labels(axes, DrawnChart(None, None, False, GridAxes.NONE, None), None)
|
|
68
|
+
>>> axes.get_xticklabels()[0].get_rotation()
|
|
69
|
+
45.0
|
|
70
|
+
"""
|
|
71
|
+
if drawn_chart.x_on_vertical_axis:
|
|
72
|
+
vertical_rotation = NO_ROTATION if rotation is None else rotation
|
|
73
|
+
thin_labels(axes.yaxis, True, vertical_rotation)
|
|
74
|
+
apply_rotation(axes, True, vertical_rotation)
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
horizontal_rotation = choose_rotation(axes.xaxis, rotation)
|
|
78
|
+
thin_labels(axes.xaxis, False, horizontal_rotation)
|
|
79
|
+
apply_rotation(axes, False, horizontal_rotation)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def rotate_y_labels(axes: Axes, drawn_chart: DrawnChart, rotation: float | None) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Rotate the labels of the ``y`` values, wherever the chart places them, keeping those that stay readable.
|
|
85
|
+
|
|
86
|
+
.. versionadded:: 0.1.0
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
axes
|
|
91
|
+
The matplotlib axes of the Plot.
|
|
92
|
+
drawn_chart
|
|
93
|
+
Which axis holds the ``x`` values: the ``y`` values are on the other one.
|
|
94
|
+
rotation
|
|
95
|
+
The angle in degrees. When None, the labels stay horizontal.
|
|
96
|
+
|
|
97
|
+
Warns
|
|
98
|
+
-----
|
|
99
|
+
ReadabilityWarning
|
|
100
|
+
When labels left out may be texts.
|
|
101
|
+
|
|
102
|
+
Examples
|
|
103
|
+
--------
|
|
104
|
+
>>> from matplotlib.figure import Figure
|
|
105
|
+
>>> from numdaplot.plots.drawing.drawn_chart import DrawnChart
|
|
106
|
+
>>> from numdaplot.plots.drawing.grid_axes import GridAxes
|
|
107
|
+
>>> from numdaplot.plots.drawing.tick_rotation import rotate_y_labels
|
|
108
|
+
>>> axes = Figure().add_subplot()
|
|
109
|
+
>>> rotate_y_labels(axes, DrawnChart(None, None, False, GridAxes.NONE, None), 30.0)
|
|
110
|
+
>>> axes.get_yticklabels()[0].get_rotation()
|
|
111
|
+
30.0
|
|
112
|
+
"""
|
|
113
|
+
y_on_vertical_axis = not drawn_chart.x_on_vertical_axis
|
|
114
|
+
y_axis = find_axis(axes, y_on_vertical_axis)
|
|
115
|
+
thinning_rotation = NO_ROTATION if rotation is None else rotation
|
|
116
|
+
thin_labels(y_axis, y_on_vertical_axis, thinning_rotation)
|
|
117
|
+
if rotation is None:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
apply_rotation(axes, y_on_vertical_axis, rotation)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def apply_rotation(axes: Axes, on_vertical_axis: bool, rotation: float) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Rotate the labels of an axis around their end closest to the axis.
|
|
126
|
+
|
|
127
|
+
.. versionadded:: 0.1.0
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
axes
|
|
132
|
+
The matplotlib axes of the Plot.
|
|
133
|
+
on_vertical_axis
|
|
134
|
+
True for the vertical axis, whose labels already end at their tick.
|
|
135
|
+
rotation
|
|
136
|
+
The angle in degrees.
|
|
137
|
+
|
|
138
|
+
Examples
|
|
139
|
+
--------
|
|
140
|
+
>>> from matplotlib.figure import Figure
|
|
141
|
+
>>> from numdaplot.plots.drawing.tick_rotation import apply_rotation
|
|
142
|
+
>>> axes = Figure().add_subplot()
|
|
143
|
+
>>> apply_rotation(axes, False, 45.0)
|
|
144
|
+
>>> axes.get_xticklabels()[0].get_horizontalalignment()
|
|
145
|
+
'right'
|
|
146
|
+
"""
|
|
147
|
+
axis = find_axis(axes, on_vertical_axis)
|
|
148
|
+
axis.set_tick_params(labelrotation=rotation)
|
|
149
|
+
alignment = choose_alignment(rotation)
|
|
150
|
+
|
|
151
|
+
for label in axis.get_ticklabels():
|
|
152
|
+
label.set_rotation_mode(ANCHOR_ROTATION_MODE)
|
|
153
|
+
if not on_vertical_axis:
|
|
154
|
+
label.set_horizontalalignment(alignment)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def choose_rotation(axis: Axis, rotation: float | None) -> float:
|
|
158
|
+
"""
|
|
159
|
+
Return the angle of the labels of a horizontal axis.
|
|
160
|
+
|
|
161
|
+
.. versionadded:: 0.1.0
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
axis
|
|
166
|
+
The horizontal axis, with its ticks.
|
|
167
|
+
rotation
|
|
168
|
+
The angle chosen in degrees, or None.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
float
|
|
173
|
+
The angle chosen, else 45 degrees for texts, moments and numbers without enough room, and no rotation for
|
|
174
|
+
other numbers.
|
|
175
|
+
|
|
176
|
+
Examples
|
|
177
|
+
--------
|
|
178
|
+
>>> from matplotlib.figure import Figure
|
|
179
|
+
>>> from numdaplot.plots.drawing.tick_rotation import choose_rotation
|
|
180
|
+
>>> axes = Figure().add_subplot()
|
|
181
|
+
>>> choose_rotation(axes.xaxis, None), choose_rotation(axes.xaxis, 30.0)
|
|
182
|
+
(0.0, 30.0)
|
|
183
|
+
"""
|
|
184
|
+
if rotation is not None:
|
|
185
|
+
return rotation
|
|
186
|
+
|
|
187
|
+
has_text = has_text_labels(axis)
|
|
188
|
+
if has_text:
|
|
189
|
+
return TEXT_ROTATION
|
|
190
|
+
|
|
191
|
+
labels_touch = do_labels_touch(axis)
|
|
192
|
+
if labels_touch:
|
|
193
|
+
return TEXT_ROTATION
|
|
194
|
+
|
|
195
|
+
return NO_ROTATION
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def do_labels_touch(axis: Axis) -> bool:
|
|
199
|
+
"""
|
|
200
|
+
Return whether horizontal labels fixed on each tick of a horizontal axis leave too little room between them.
|
|
201
|
+
|
|
202
|
+
The axes do not have their final width yet. Their current width is a little lower, which makes the answer prudent.
|
|
203
|
+
|
|
204
|
+
.. versionadded:: 0.1.0
|
|
205
|
+
|
|
206
|
+
Parameters
|
|
207
|
+
----------
|
|
208
|
+
axis
|
|
209
|
+
The horizontal axis, with its ticks.
|
|
210
|
+
|
|
211
|
+
Returns
|
|
212
|
+
-------
|
|
213
|
+
bool
|
|
214
|
+
True when the widest label and a gap of half its font size exceed the room between the closest ticks. Labels
|
|
215
|
+
chosen by matplotlib according to the room, such as those of a line chart, never touch.
|
|
216
|
+
|
|
217
|
+
Examples
|
|
218
|
+
--------
|
|
219
|
+
>>> from matplotlib.figure import Figure
|
|
220
|
+
>>> from numdaplot.plots.drawing.tick_rotation import do_labels_touch
|
|
221
|
+
>>> axes = Figure().add_subplot()
|
|
222
|
+
>>> years = [float(year) for year in range(24)]
|
|
223
|
+
>>> axes.xaxis.set_ticks(years, [str(2000 + year) for year in range(24)]) # doctest: +ELLIPSIS
|
|
224
|
+
[...]
|
|
225
|
+
>>> do_labels_touch(axes.xaxis)
|
|
226
|
+
True
|
|
227
|
+
"""
|
|
228
|
+
formatter = axis.get_major_formatter()
|
|
229
|
+
if isinstance(formatter, ScalarFormatter):
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
tick_locations = find_tick_locations(axis)
|
|
233
|
+
tick_count = len(tick_locations)
|
|
234
|
+
if tick_count < MINIMUM_TICKS:
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
current_length = find_current_length(axis, False)
|
|
238
|
+
room = find_tick_room(axis, False, current_length)
|
|
239
|
+
widest_label = find_widest_label(axis)
|
|
240
|
+
font_pixels = find_font_pixels(axis)
|
|
241
|
+
needed_room = widest_label + font_pixels * LABEL_GAP_RATIO
|
|
242
|
+
labels_touch = bool(needed_room > room)
|
|
243
|
+
|
|
244
|
+
return labels_touch
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def has_text_labels(axis: Axis) -> bool:
|
|
248
|
+
"""
|
|
249
|
+
Return whether the labels of an axis are moments, or texts that are not all numbers.
|
|
250
|
+
|
|
251
|
+
Numbers can be written as texts, such as the years or the row numbers below bars: they stay numbers.
|
|
252
|
+
|
|
253
|
+
.. versionadded:: 0.1.0
|
|
254
|
+
|
|
255
|
+
Parameters
|
|
256
|
+
----------
|
|
257
|
+
axis
|
|
258
|
+
An axis, with its ticks.
|
|
259
|
+
|
|
260
|
+
Returns
|
|
261
|
+
-------
|
|
262
|
+
bool
|
|
263
|
+
True when at least one label is not a number. An axis without label holds no text.
|
|
264
|
+
|
|
265
|
+
Examples
|
|
266
|
+
--------
|
|
267
|
+
>>> from matplotlib.figure import Figure
|
|
268
|
+
>>> from numdaplot.plots.drawing.tick_rotation import has_text_labels
|
|
269
|
+
>>> axes = Figure().add_subplot()
|
|
270
|
+
>>> axes.xaxis.set_ticks([0.0, 1.0], ["2025", "2026"]) # doctest: +ELLIPSIS
|
|
271
|
+
[...]
|
|
272
|
+
>>> has_text_labels(axes.xaxis)
|
|
273
|
+
False
|
|
274
|
+
"""
|
|
275
|
+
formatter = axis.get_major_formatter()
|
|
276
|
+
if isinstance(formatter, ScalarFormatter):
|
|
277
|
+
return False
|
|
278
|
+
|
|
279
|
+
if isinstance(formatter, ConciseDateFormatter):
|
|
280
|
+
return True
|
|
281
|
+
|
|
282
|
+
label_texts = read_label_texts(axis)
|
|
283
|
+
|
|
284
|
+
for label_text in label_texts:
|
|
285
|
+
is_number = is_number_text(label_text)
|
|
286
|
+
if not is_number:
|
|
287
|
+
return True
|
|
288
|
+
|
|
289
|
+
return False
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def is_number_text(text: str) -> bool:
|
|
293
|
+
"""
|
|
294
|
+
Return whether a label is a number, as matplotlib or numdaplot writes it.
|
|
295
|
+
|
|
296
|
+
.. versionadded:: 0.1.0
|
|
297
|
+
|
|
298
|
+
Parameters
|
|
299
|
+
----------
|
|
300
|
+
text
|
|
301
|
+
The text of a label.
|
|
302
|
+
|
|
303
|
+
Returns
|
|
304
|
+
-------
|
|
305
|
+
bool
|
|
306
|
+
True for a number, with the minus sign matplotlib writes, or for an empty label.
|
|
307
|
+
|
|
308
|
+
Examples
|
|
309
|
+
--------
|
|
310
|
+
>>> from numdaplot.plots.drawing.tick_rotation import is_number_text
|
|
311
|
+
>>> is_number_text("2025"), is_number_text("-1.5"), is_number_text("Paris")
|
|
312
|
+
(True, True, False)
|
|
313
|
+
"""
|
|
314
|
+
if text == "":
|
|
315
|
+
return True
|
|
316
|
+
|
|
317
|
+
python_text = text.replace(MINUS_SIGN, HYPHEN_MINUS)
|
|
318
|
+
try:
|
|
319
|
+
float(python_text)
|
|
320
|
+
except ValueError:
|
|
321
|
+
return False
|
|
322
|
+
|
|
323
|
+
return True
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def choose_alignment(rotation: float) -> Literal["left", "center", "right"]:
|
|
327
|
+
"""
|
|
328
|
+
Return the side of a rotated label that stays under its tick.
|
|
329
|
+
|
|
330
|
+
.. versionadded:: 0.1.0
|
|
331
|
+
|
|
332
|
+
Parameters
|
|
333
|
+
----------
|
|
334
|
+
rotation
|
|
335
|
+
The angle of the label in degrees.
|
|
336
|
+
|
|
337
|
+
Returns
|
|
338
|
+
-------
|
|
339
|
+
Literal["left", "center", "right"]
|
|
340
|
+
The end of the text for a positive angle, its start for a negative one, its middle without rotation.
|
|
341
|
+
|
|
342
|
+
Examples
|
|
343
|
+
--------
|
|
344
|
+
>>> from numdaplot.plots.drawing.tick_rotation import choose_alignment
|
|
345
|
+
>>> choose_alignment(45.0), choose_alignment(-45.0), choose_alignment(0.0)
|
|
346
|
+
('right', 'left', 'center')
|
|
347
|
+
"""
|
|
348
|
+
if rotation > NO_ROTATION:
|
|
349
|
+
return "right"
|
|
350
|
+
|
|
351
|
+
if rotation < NO_ROTATION:
|
|
352
|
+
return "left"
|
|
353
|
+
|
|
354
|
+
return "center"
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Axes of times of day, counted in hours since midnight and labeled ``HH:MM``.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import numpy
|
|
10
|
+
from matplotlib.axes import Axes
|
|
11
|
+
from matplotlib.axis import Axis
|
|
12
|
+
from matplotlib.ticker import FuncFormatter, MultipleLocator
|
|
13
|
+
from numpy.typing import NDArray
|
|
14
|
+
|
|
15
|
+
from numdaplot.data_types.type import Type
|
|
16
|
+
from numdaplot.data_types.value_family import ValueFamily, find_family
|
|
17
|
+
from numdaplot.plots.chart_layer import ChartLayer
|
|
18
|
+
from numdaplot.plots.data.chart_values import ChartValues
|
|
19
|
+
|
|
20
|
+
MINUTES_PER_HOUR = 60
|
|
21
|
+
MINUTES_PER_DAY = 1440
|
|
22
|
+
OUTSIDE_DAY_LABEL = ""
|
|
23
|
+
HOUR_LABEL = "{hour:02d}:{minute:02d}"
|
|
24
|
+
# The step between two labels, in hours, for the widest span of times it fits, in hours.
|
|
25
|
+
HOUR_STEPS = ((1.0, 0.25), (3.0, 0.5), (6.0, 1.0), (12.0, 2.0))
|
|
26
|
+
LONGEST_HOUR_STEP = 3.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def format_hour(hours: float, _position: object = None) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Return a number of hours since midnight as ``HH:MM``, rounded to the minute.
|
|
32
|
+
|
|
33
|
+
The ticks that the margins of an axis place before 00:00 or after 24:00 are left without label.
|
|
34
|
+
|
|
35
|
+
.. versionadded:: 0.1.0
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
hours
|
|
40
|
+
The hours since midnight, such as 15.5.
|
|
41
|
+
_position
|
|
42
|
+
The position of the label, given by matplotlib and not used.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
str
|
|
47
|
+
The time, such as ``15:30``, or an empty text outside 00:00 to 24:00.
|
|
48
|
+
|
|
49
|
+
Examples
|
|
50
|
+
--------
|
|
51
|
+
>>> from numdaplot.plots.drawing.time_axis import format_hour
|
|
52
|
+
>>> format_hour(15.5), format_hour(0.0), format_hour(24.0), format_hour(-3.0)
|
|
53
|
+
('15:30', '00:00', '24:00', '')
|
|
54
|
+
"""
|
|
55
|
+
minutes = hours * MINUTES_PER_HOUR
|
|
56
|
+
whole_minutes = round(minutes)
|
|
57
|
+
is_outside_day = whole_minutes < 0 or whole_minutes > MINUTES_PER_DAY
|
|
58
|
+
if is_outside_day:
|
|
59
|
+
return OUTSIDE_DAY_LABEL
|
|
60
|
+
|
|
61
|
+
hour, minute = divmod(whole_minutes, MINUTES_PER_HOUR)
|
|
62
|
+
hour_label = HOUR_LABEL.format(hour=hour, minute=minute)
|
|
63
|
+
|
|
64
|
+
return hour_label
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def choose_hour_step(hours: NDArray[numpy.float64]) -> float:
|
|
68
|
+
"""
|
|
69
|
+
Return the step between two labels of an axis of times, from the span of the times.
|
|
70
|
+
|
|
71
|
+
.. versionadded:: 0.1.0
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
hours
|
|
76
|
+
The hours since midnight shown on the axis, NaN where missing.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
float
|
|
81
|
+
A quarter of an hour for an hour or less, then half an hour, one, two or three hours.
|
|
82
|
+
|
|
83
|
+
Examples
|
|
84
|
+
--------
|
|
85
|
+
>>> import numpy
|
|
86
|
+
>>> from numdaplot.plots.drawing.time_axis import choose_hour_step
|
|
87
|
+
>>> choose_hour_step(numpy.array([8.0, 23.0])), choose_hour_step(numpy.array([8.0, 8.5]))
|
|
88
|
+
(3.0, 0.25)
|
|
89
|
+
"""
|
|
90
|
+
present_hours = hours[~numpy.isnan(hours)]
|
|
91
|
+
if present_hours.size == 0:
|
|
92
|
+
return LONGEST_HOUR_STEP
|
|
93
|
+
|
|
94
|
+
earliest_hour = present_hours.min()
|
|
95
|
+
latest_hour = present_hours.max()
|
|
96
|
+
span = float(latest_hour - earliest_hour)
|
|
97
|
+
for widest_span, step in HOUR_STEPS:
|
|
98
|
+
if span <= widest_span:
|
|
99
|
+
return step
|
|
100
|
+
|
|
101
|
+
return LONGEST_HOUR_STEP
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def place_hour_ticks(axis: Axis, hours: NDArray[Any]) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Place labels ``HH:MM`` on an axis counted in hours since midnight, at a regular step.
|
|
107
|
+
|
|
108
|
+
.. versionadded:: 0.1.0
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
axis
|
|
113
|
+
A matplotlib axis.
|
|
114
|
+
hours
|
|
115
|
+
The hours since midnight shown on the axis.
|
|
116
|
+
|
|
117
|
+
Examples
|
|
118
|
+
--------
|
|
119
|
+
>>> import numpy
|
|
120
|
+
>>> from matplotlib.figure import Figure
|
|
121
|
+
>>> from numdaplot.plots.drawing.time_axis import place_hour_ticks
|
|
122
|
+
>>> axes = Figure().add_subplot()
|
|
123
|
+
>>> _ = axes.plot([8.0, 14.0], [1.0, 2.0])
|
|
124
|
+
>>> place_hour_ticks(axes.xaxis, numpy.array([8.0, 14.0]))
|
|
125
|
+
>>> axes.figure.canvas.draw()
|
|
126
|
+
>>> [label.get_text() for label in axes.get_xticklabels()][1:4]
|
|
127
|
+
['08:00', '09:00', '10:00']
|
|
128
|
+
"""
|
|
129
|
+
step = choose_hour_step(hours)
|
|
130
|
+
locator = MultipleLocator(step)
|
|
131
|
+
formatter = FuncFormatter(format_hour)
|
|
132
|
+
axis.set_major_locator(locator)
|
|
133
|
+
axis.set_major_formatter(formatter)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def measures_times(value_type: Type) -> bool:
|
|
137
|
+
"""
|
|
138
|
+
Return whether the values of a chart are times of day, drawn on an axis labeled ``HH:MM``.
|
|
139
|
+
|
|
140
|
+
.. versionadded:: 0.1.0
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
value_type
|
|
145
|
+
The type of the values of the chart.
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
bool
|
|
150
|
+
True for ``TIME``.
|
|
151
|
+
|
|
152
|
+
Examples
|
|
153
|
+
--------
|
|
154
|
+
>>> import numdaplot as ndp
|
|
155
|
+
>>> from numdaplot.plots.drawing.time_axis import measures_times
|
|
156
|
+
>>> measures_times(ndp.Type.TIME), measures_times(ndp.Type.FLOAT64)
|
|
157
|
+
(True, False)
|
|
158
|
+
"""
|
|
159
|
+
value_family = find_family(value_type)
|
|
160
|
+
is_time = value_family == ValueFamily.TIME
|
|
161
|
+
|
|
162
|
+
return is_time
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def place_value_hours(axes: Axes, layers: list[ChartLayer]) -> None:
|
|
166
|
+
"""
|
|
167
|
+
Label ``HH:MM`` the vertical axis of the lines and points measuring times of day, from all their values.
|
|
168
|
+
|
|
169
|
+
Histograms and boxes, which are drawn alone, label their own axis of values.
|
|
170
|
+
|
|
171
|
+
.. versionadded:: 0.1.0
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
axes
|
|
176
|
+
The matplotlib axes the charts are drawn on.
|
|
177
|
+
layers
|
|
178
|
+
The charts drawn on these axes and their values.
|
|
179
|
+
|
|
180
|
+
Examples
|
|
181
|
+
--------
|
|
182
|
+
>>> from datetime import time
|
|
183
|
+
>>> from matplotlib.figure import Figure
|
|
184
|
+
>>> import numdaplot as ndp
|
|
185
|
+
>>> from numdaplot.plots.chart_layer import ChartLayer
|
|
186
|
+
>>> from numdaplot.plots.data.array_values import read_array_values
|
|
187
|
+
>>> from numdaplot.plots.drawing.time_axis import place_value_hours
|
|
188
|
+
>>> hours = ndp.Array.from_list([time(8), time(14)])
|
|
189
|
+
>>> axes = Figure().add_subplot()
|
|
190
|
+
>>> place_value_hours(axes, [ChartLayer(ndp.LineChart(), read_array_values(hours, "LineChart"))])
|
|
191
|
+
>>> axes.yaxis.get_major_formatter()(8.5)
|
|
192
|
+
'08:30'
|
|
193
|
+
"""
|
|
194
|
+
hour_series = list[NDArray[numpy.float64]]()
|
|
195
|
+
|
|
196
|
+
for layer in layers:
|
|
197
|
+
values = layer.values
|
|
198
|
+
if not isinstance(values, ChartValues):
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
is_time = measures_times(values.value_type)
|
|
202
|
+
if not is_time:
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
for series in values.series:
|
|
206
|
+
hour_series.append(series.values)
|
|
207
|
+
|
|
208
|
+
if hour_series == []:
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
hours = numpy.concatenate(hour_series)
|
|
212
|
+
place_hour_ticks(axes.yaxis, hours)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ticks of an axis holding whole numbers only.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import numpy
|
|
8
|
+
from matplotlib.axis import Axis
|
|
9
|
+
from matplotlib.ticker import MaxNLocator
|
|
10
|
+
from numpy.typing import NDArray
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def has_only_whole_numbers(numbers: NDArray[numpy.float64]) -> bool:
|
|
14
|
+
"""
|
|
15
|
+
Return whether every present number is a whole number.
|
|
16
|
+
|
|
17
|
+
.. versionadded:: 0.1.0
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
numbers
|
|
22
|
+
float64 numbers, NaN where a value is missing.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
bool
|
|
27
|
+
True when no present number has a fraction, such as days or counts.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> import numpy
|
|
32
|
+
>>> from numdaplot.plots.drawing.whole_numbers import has_only_whole_numbers
|
|
33
|
+
>>> has_only_whole_numbers(numpy.array([1.0, numpy.nan, 3.0]))
|
|
34
|
+
True
|
|
35
|
+
"""
|
|
36
|
+
present = ~numpy.isnan(numbers)
|
|
37
|
+
present_numbers = numbers[present]
|
|
38
|
+
rounded_numbers = numpy.round(present_numbers)
|
|
39
|
+
is_whole = rounded_numbers == present_numbers
|
|
40
|
+
all_whole = bool(numpy.all(is_whole))
|
|
41
|
+
|
|
42
|
+
return all_whole
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def place_whole_ticks(axis: Axis, numbers: NDArray[numpy.float64]) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Place the ticks of an axis on whole numbers only, when every number it shows is whole.
|
|
48
|
+
|
|
49
|
+
.. versionadded:: 0.1.0
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
axis
|
|
54
|
+
A matplotlib axis.
|
|
55
|
+
numbers
|
|
56
|
+
The numbers shown along the axis.
|
|
57
|
+
|
|
58
|
+
Examples
|
|
59
|
+
--------
|
|
60
|
+
>>> import numpy
|
|
61
|
+
>>> from matplotlib.figure import Figure
|
|
62
|
+
>>> from numdaplot.plots.drawing.whole_numbers import place_whole_ticks
|
|
63
|
+
>>> axes = Figure().add_subplot()
|
|
64
|
+
>>> lines = axes.plot([1.0, 2.0], [5.0, 6.0])
|
|
65
|
+
>>> place_whole_ticks(axes.xaxis, numpy.array([1.0, 2.0]))
|
|
66
|
+
>>> all(float(tick).is_integer() for tick in axes.get_xticks())
|
|
67
|
+
True
|
|
68
|
+
"""
|
|
69
|
+
all_whole = has_only_whole_numbers(numbers)
|
|
70
|
+
if all_whole:
|
|
71
|
+
whole_locator = MaxNLocator(integer=True)
|
|
72
|
+
axis.set_major_locator(whole_locator)
|