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,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A Plot placed in the grid of a Figure, and the checks of its place.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from numdaplot.errors.cell_out_of_range_error import CellOutOfRangeError
|
|
10
|
+
from numdaplot.errors.occupied_cell_error import OccupiedCellError
|
|
11
|
+
from numdaplot.plots.figure.cell import Cell
|
|
12
|
+
from numdaplot.plots.figure.layout import Layout
|
|
13
|
+
from numdaplot.plots.plot import Plot
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True, eq=False)
|
|
17
|
+
class Placement:
|
|
18
|
+
"""
|
|
19
|
+
A Plot and the cells it covers in a Figure.
|
|
20
|
+
|
|
21
|
+
.. versionadded:: 0.1.0
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
plot
|
|
26
|
+
The Plot placed.
|
|
27
|
+
cell
|
|
28
|
+
Its first cell and the number of cells it spans.
|
|
29
|
+
|
|
30
|
+
Examples
|
|
31
|
+
--------
|
|
32
|
+
>>> import numdaplot as ndp
|
|
33
|
+
>>> from numdaplot.plots.figure.placement import Placement
|
|
34
|
+
>>> plot = ndp.Plot.line(ndp.Array.from_list([12.0, 15.5]))
|
|
35
|
+
>>> Placement(plot, ndp.Cell(row=0, column=1)).cell.column
|
|
36
|
+
1
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
plot: Plot
|
|
40
|
+
cell: Cell
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def require_cell_inside(cell: Cell, layout: Layout) -> None:
|
|
44
|
+
"""
|
|
45
|
+
Check that every cell a Plot covers is inside the grid of a Figure.
|
|
46
|
+
|
|
47
|
+
.. versionadded:: 0.1.0
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
cell
|
|
52
|
+
The first cell and the spans of the Plot.
|
|
53
|
+
layout
|
|
54
|
+
The grid of the Figure.
|
|
55
|
+
|
|
56
|
+
Raises
|
|
57
|
+
------
|
|
58
|
+
CellOutOfRangeError
|
|
59
|
+
When a cell it spans is after the last row or column. ``Cell`` already refuses a negative row or column.
|
|
60
|
+
|
|
61
|
+
Examples
|
|
62
|
+
--------
|
|
63
|
+
>>> import numdaplot as ndp
|
|
64
|
+
>>> from numdaplot.plots.figure.placement import require_cell_inside
|
|
65
|
+
>>> try:
|
|
66
|
+
... require_cell_inside(ndp.Cell(row=1, column=0, column_span=3), ndp.Layout(rows=2, columns=2))
|
|
67
|
+
... except ndp.CellOutOfRangeError as error:
|
|
68
|
+
... print(error)
|
|
69
|
+
Cell (1, 0) is outside a Layout of 2 rows and 2 columns.
|
|
70
|
+
"""
|
|
71
|
+
row_end = cell.row + cell.row_span
|
|
72
|
+
column_end = cell.column + cell.column_span
|
|
73
|
+
is_outside = row_end > layout.rows or column_end > layout.columns
|
|
74
|
+
if is_outside:
|
|
75
|
+
raise CellOutOfRangeError(cell.row, cell.column, layout.rows, layout.columns)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def require_free_cells(cell: Cell, placements: list[Placement]) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Check that no cell a Plot covers already holds another Plot.
|
|
81
|
+
|
|
82
|
+
.. versionadded:: 0.1.0
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
cell
|
|
87
|
+
The first cell and the spans of the Plot placed.
|
|
88
|
+
placements
|
|
89
|
+
The Plots already in the Figure.
|
|
90
|
+
|
|
91
|
+
Raises
|
|
92
|
+
------
|
|
93
|
+
OccupiedCellError
|
|
94
|
+
At the first cell, row by row, already covered by another Plot.
|
|
95
|
+
|
|
96
|
+
Examples
|
|
97
|
+
--------
|
|
98
|
+
>>> import numdaplot as ndp
|
|
99
|
+
>>> from numdaplot.plots.figure.placement import Placement, require_free_cells
|
|
100
|
+
>>> plot = ndp.Plot.line(ndp.Array.from_list([12.0, 15.5]))
|
|
101
|
+
>>> wide_placement = Placement(plot, ndp.Cell(row=0, column=0, column_span=2))
|
|
102
|
+
>>> try:
|
|
103
|
+
... require_free_cells(ndp.Cell(row=0, column=1), [wide_placement])
|
|
104
|
+
... except ndp.OccupiedCellError as error:
|
|
105
|
+
... print(error)
|
|
106
|
+
Cell (0, 1) already holds a Plot.
|
|
107
|
+
"""
|
|
108
|
+
covered_cells = set[tuple[int, int]]()
|
|
109
|
+
|
|
110
|
+
for placement in placements:
|
|
111
|
+
placement_cells = list_covered_cells(placement.cell)
|
|
112
|
+
covered_cells.update(placement_cells)
|
|
113
|
+
|
|
114
|
+
new_cells = list_covered_cells(cell)
|
|
115
|
+
|
|
116
|
+
for row, column in new_cells:
|
|
117
|
+
if (row, column) in covered_cells:
|
|
118
|
+
raise OccupiedCellError(row, column)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def list_covered_cells(cell: Cell) -> list[tuple[int, int]]:
|
|
122
|
+
"""
|
|
123
|
+
Return the row and the column of every cell a Plot covers, row by row.
|
|
124
|
+
|
|
125
|
+
.. versionadded:: 0.1.0
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
cell
|
|
130
|
+
The first cell and the spans of the Plot.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
list[tuple[int, int]]
|
|
135
|
+
The covered cells.
|
|
136
|
+
|
|
137
|
+
Examples
|
|
138
|
+
--------
|
|
139
|
+
>>> import numdaplot as ndp
|
|
140
|
+
>>> from numdaplot.plots.figure.placement import list_covered_cells
|
|
141
|
+
>>> list_covered_cells(ndp.Cell(row=1, column=0, column_span=2))
|
|
142
|
+
[(1, 0), (1, 1)]
|
|
143
|
+
"""
|
|
144
|
+
row_end = cell.row + cell.row_span
|
|
145
|
+
column_end = cell.column + cell.column_span
|
|
146
|
+
rows = range(cell.row, row_end)
|
|
147
|
+
columns = range(cell.column, column_end)
|
|
148
|
+
covered_cells = [(row, column) for row in rows for column in columns]
|
|
149
|
+
|
|
150
|
+
return covered_cells
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Reading of the charts a Plot draws on its axes: lines, bars and points.
|
|
3
|
+
|
|
4
|
+
``Plot.line``, ``Plot.bar`` and ``Plot.scatter`` read their first chart with these functions, and
|
|
5
|
+
``Plot.add_line``, ``Plot.add_bar`` and ``Plot.add_scatter`` the charts they add.
|
|
6
|
+
|
|
7
|
+
.. versionadded:: 0.1.0
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from numdaplot.arrays.array import Array
|
|
11
|
+
from numdaplot.plots.chart_layer import ChartLayer
|
|
12
|
+
from numdaplot.plots.charts.bar_chart import BarChart
|
|
13
|
+
from numdaplot.plots.charts.line_chart import LineChart
|
|
14
|
+
from numdaplot.plots.charts.scatter_chart import ScatterChart
|
|
15
|
+
from numdaplot.plots.data.array_values import read_array_values
|
|
16
|
+
from numdaplot.plots.data.chart_data import read_chart_values, require_column_setting, require_no_column_settings
|
|
17
|
+
from numdaplot.plots.data.point_values import hide_missing_points, read_point_values, require_scale_on_numbers
|
|
18
|
+
from numdaplot.plots.data.table_values import read_table_values
|
|
19
|
+
from numdaplot.plots.drawing.series_colors import require_color_count
|
|
20
|
+
from numdaplot.tables.table import Table
|
|
21
|
+
|
|
22
|
+
LINE_NAME = "LineChart"
|
|
23
|
+
BAR_NAME = "BarChart"
|
|
24
|
+
SCATTER_NAME = "ScatterChart"
|
|
25
|
+
X_SETTING = "x"
|
|
26
|
+
Y_SETTING = "y"
|
|
27
|
+
COLOR_BY_SETTING = "color_by"
|
|
28
|
+
SIZE_BY_SETTING = "size_by"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def read_line_layer(data: Table | Array, chart: LineChart) -> ChartLayer:
|
|
32
|
+
"""
|
|
33
|
+
Return a LineChart with the values it draws from a Table or an Array.
|
|
34
|
+
|
|
35
|
+
.. versionadded:: 0.1.0
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
data
|
|
40
|
+
The Table or the Array drawn.
|
|
41
|
+
chart
|
|
42
|
+
The columns drawn and the look of the lines.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
ChartLayer
|
|
47
|
+
The chart and its values.
|
|
48
|
+
|
|
49
|
+
Raises
|
|
50
|
+
------
|
|
51
|
+
InvalidChartDataError
|
|
52
|
+
When a Table has no ``y`` columns, or an Array has ``x`` or ``y`` columns.
|
|
53
|
+
InvalidColorCountError
|
|
54
|
+
When the colors of the chart are not one per line.
|
|
55
|
+
|
|
56
|
+
Examples
|
|
57
|
+
--------
|
|
58
|
+
>>> import numdaplot as ndp
|
|
59
|
+
>>> from numdaplot.plots.layer_reading import read_line_layer
|
|
60
|
+
>>> grid = ndp.Array.from_list([[1.0, 2.0], [3.0, 4.0]])
|
|
61
|
+
>>> len(read_line_layer(grid, ndp.LineChart()).values.series)
|
|
62
|
+
2
|
|
63
|
+
"""
|
|
64
|
+
values = read_chart_values(data, chart.x, chart.y, LINE_NAME)
|
|
65
|
+
series_count = len(values.series)
|
|
66
|
+
require_color_count(chart.colors, series_count)
|
|
67
|
+
layer = ChartLayer(chart, values)
|
|
68
|
+
|
|
69
|
+
return layer
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def read_bar_layer(data: Table | Array, chart: BarChart) -> ChartLayer:
|
|
73
|
+
"""
|
|
74
|
+
Return a BarChart with the values it draws from a Table or an Array.
|
|
75
|
+
|
|
76
|
+
.. versionadded:: 0.1.0
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
data
|
|
81
|
+
The Table or the Array drawn.
|
|
82
|
+
chart
|
|
83
|
+
The columns drawn and the look of the bars.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
ChartLayer
|
|
88
|
+
The chart and its values.
|
|
89
|
+
|
|
90
|
+
Raises
|
|
91
|
+
------
|
|
92
|
+
InvalidChartDataError
|
|
93
|
+
When a Table has no ``y`` columns, or an Array has ``x`` or ``y`` columns.
|
|
94
|
+
InvalidColorCountError
|
|
95
|
+
When the colors of the chart are not one per series.
|
|
96
|
+
|
|
97
|
+
Examples
|
|
98
|
+
--------
|
|
99
|
+
>>> import numdaplot as ndp
|
|
100
|
+
>>> from numdaplot.plots.layer_reading import read_bar_layer
|
|
101
|
+
>>> prices = ndp.Array.from_list([12.0, 15.5])
|
|
102
|
+
>>> read_bar_layer(prices, ndp.BarChart()).values.series[0].values
|
|
103
|
+
array([12. , 15.5])
|
|
104
|
+
"""
|
|
105
|
+
values = read_chart_values(data, chart.x, chart.y, BAR_NAME)
|
|
106
|
+
series_count = len(values.series)
|
|
107
|
+
require_color_count(chart.colors, series_count)
|
|
108
|
+
layer = ChartLayer(chart, values)
|
|
109
|
+
|
|
110
|
+
return layer
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def read_scatter_layer(data: Table | Array, chart: ScatterChart) -> ChartLayer:
|
|
114
|
+
"""
|
|
115
|
+
Return a ScatterChart with the values it draws from a Table or an Array.
|
|
116
|
+
|
|
117
|
+
.. versionadded:: 0.1.0
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
data
|
|
122
|
+
The Table or the Array drawn.
|
|
123
|
+
chart
|
|
124
|
+
The columns drawn and the look of the points.
|
|
125
|
+
|
|
126
|
+
Returns
|
|
127
|
+
-------
|
|
128
|
+
ChartLayer
|
|
129
|
+
The chart, its values, and for a Table the values coloring and sizing its points.
|
|
130
|
+
|
|
131
|
+
Raises
|
|
132
|
+
------
|
|
133
|
+
InvalidChartDataError
|
|
134
|
+
When a Table has no ``y`` column, or an Array has a column setting.
|
|
135
|
+
InvalidColorCountError
|
|
136
|
+
When ``color`` is given for an Array of several columns.
|
|
137
|
+
|
|
138
|
+
Examples
|
|
139
|
+
--------
|
|
140
|
+
>>> import numdaplot as ndp
|
|
141
|
+
>>> from numdaplot.plots.layer_reading import read_scatter_layer
|
|
142
|
+
>>> grid = ndp.Array.from_list([[1.0, 2.0], [3.0, 4.0]])
|
|
143
|
+
>>> len(read_scatter_layer(grid, ndp.ScatterChart()).values.series)
|
|
144
|
+
2
|
|
145
|
+
"""
|
|
146
|
+
if isinstance(data, Array):
|
|
147
|
+
column_settings = dict[str, object](
|
|
148
|
+
{X_SETTING: chart.x, Y_SETTING: chart.y, COLOR_BY_SETTING: chart.color_by, SIZE_BY_SETTING: chart.size_by}
|
|
149
|
+
)
|
|
150
|
+
require_no_column_settings(SCATTER_NAME, column_settings)
|
|
151
|
+
array_values = read_array_values(data, SCATTER_NAME)
|
|
152
|
+
series_count = len(array_values.series)
|
|
153
|
+
if chart.color is not None:
|
|
154
|
+
require_color_count([chart.color], series_count)
|
|
155
|
+
|
|
156
|
+
array_layer = ChartLayer(chart, array_values)
|
|
157
|
+
return array_layer
|
|
158
|
+
|
|
159
|
+
y_name = require_column_setting(SCATTER_NAME, Y_SETTING, chart.y)
|
|
160
|
+
table_values = read_table_values(data, chart.x, [y_name], SCATTER_NAME)
|
|
161
|
+
point_values = read_point_values(data, chart.color_by, chart.size_by, table_values.rows)
|
|
162
|
+
require_scale_on_numbers(chart.scale, point_values.colors)
|
|
163
|
+
shown_values = hide_missing_points(table_values, point_values)
|
|
164
|
+
table_layer = ChartLayer(chart, shown_values, point_values)
|
|
165
|
+
|
|
166
|
+
return table_layer
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Image files 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 pathlib import Path
|
|
11
|
+
|
|
12
|
+
from matplotlib.figure import Figure
|
|
13
|
+
|
|
14
|
+
from numdaplot.errors.refused_setting_error import RefusedSettingError
|
|
15
|
+
from numdaplot.errors.unsupported_image_format_error import UnsupportedImageFormatError
|
|
16
|
+
from numdaplot.plots.drawing.plot_drawing import FigureDrawing, build_figure
|
|
17
|
+
from numdaplot.plots.style.image_options import DEFAULT_DPI, ImageOptions
|
|
18
|
+
from numdaplot.tables.conflict import Conflict
|
|
19
|
+
from numdaplot.tables.files.file_access import WRITE_OPERATION, FileAccessErrors
|
|
20
|
+
from numdaplot.tables.files.file_paths import FilePath, require_free_path
|
|
21
|
+
|
|
22
|
+
IMAGE_FORMATS = {".png": "png", ".svg": "svg", ".pdf": "pdf"}
|
|
23
|
+
RESOLUTION_EXTENSION = ".png"
|
|
24
|
+
OPTIONS_NAME = "ImageOptions"
|
|
25
|
+
IMAGE_OWNER = "A {extension} image"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def find_image_format(path: Path) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Return the image format named by the extension of a path.
|
|
31
|
+
|
|
32
|
+
.. versionadded:: 0.1.0
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
path
|
|
37
|
+
The path of the image, ending with ``.png``, ``.svg`` or ``.pdf`` in lowercase or uppercase.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
str
|
|
42
|
+
The matplotlib name of the format: ``png``, ``svg`` or ``pdf``.
|
|
43
|
+
|
|
44
|
+
Raises
|
|
45
|
+
------
|
|
46
|
+
UnsupportedImageFormatError
|
|
47
|
+
When the path has another extension or none.
|
|
48
|
+
|
|
49
|
+
Examples
|
|
50
|
+
--------
|
|
51
|
+
>>> from pathlib import Path
|
|
52
|
+
>>> from numdaplot.plots.output.image_saving import find_image_format
|
|
53
|
+
>>> find_image_format(Path("sales.SVG"))
|
|
54
|
+
'svg'
|
|
55
|
+
"""
|
|
56
|
+
extension = path.suffix.lower()
|
|
57
|
+
if extension not in IMAGE_FORMATS:
|
|
58
|
+
raise UnsupportedImageFormatError(path.suffix)
|
|
59
|
+
|
|
60
|
+
image_format = IMAGE_FORMATS[extension]
|
|
61
|
+
|
|
62
|
+
return image_format
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def choose_resolution(path: Path, options: ImageOptions | None) -> int:
|
|
66
|
+
"""
|
|
67
|
+
Return the number of dots per inch an image is saved with.
|
|
68
|
+
|
|
69
|
+
.. versionadded:: 0.1.0
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
path
|
|
74
|
+
The path of the image, with a supported extension.
|
|
75
|
+
options
|
|
76
|
+
The settings of a PNG image, or None.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
int
|
|
81
|
+
The resolution of the options, 100 without them.
|
|
82
|
+
|
|
83
|
+
Raises
|
|
84
|
+
------
|
|
85
|
+
RefusedSettingError
|
|
86
|
+
When options are given for an SVG or PDF image, which has no resolution.
|
|
87
|
+
|
|
88
|
+
Examples
|
|
89
|
+
--------
|
|
90
|
+
>>> from pathlib import Path
|
|
91
|
+
>>> import numdaplot as ndp
|
|
92
|
+
>>> from numdaplot.plots.output.image_saving import choose_resolution
|
|
93
|
+
>>> try:
|
|
94
|
+
... choose_resolution(Path("sales.svg"), ndp.ImageOptions(dpi=200))
|
|
95
|
+
... except ndp.RefusedSettingError as error:
|
|
96
|
+
... print(error)
|
|
97
|
+
A .svg image does not accept ImageOptions.
|
|
98
|
+
"""
|
|
99
|
+
if options is None:
|
|
100
|
+
return DEFAULT_DPI
|
|
101
|
+
|
|
102
|
+
extension = path.suffix.lower()
|
|
103
|
+
if extension != RESOLUTION_EXTENSION:
|
|
104
|
+
image_name = IMAGE_OWNER.format(extension=extension)
|
|
105
|
+
raise RefusedSettingError(OPTIONS_NAME, image_name)
|
|
106
|
+
|
|
107
|
+
return options.dpi
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def save_figure(figure: Figure, path: Path, image_format: str, resolution: int) -> None:
|
|
111
|
+
"""
|
|
112
|
+
Save a matplotlib figure as an image.
|
|
113
|
+
|
|
114
|
+
.. versionadded:: 0.1.0
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
figure
|
|
119
|
+
The figure to save.
|
|
120
|
+
path
|
|
121
|
+
The path of the image.
|
|
122
|
+
image_format
|
|
123
|
+
The matplotlib name of the format, as ``find_image_format`` gives it.
|
|
124
|
+
resolution
|
|
125
|
+
The number of dots per inch, as ``choose_resolution`` gives it.
|
|
126
|
+
|
|
127
|
+
Examples
|
|
128
|
+
--------
|
|
129
|
+
>>> import tempfile
|
|
130
|
+
>>> from pathlib import Path
|
|
131
|
+
>>> from matplotlib.figure import Figure
|
|
132
|
+
>>> from numdaplot.plots.output.image_saving import save_figure
|
|
133
|
+
>>> path = Path(tempfile.mkdtemp()) / "empty.pdf"
|
|
134
|
+
>>> save_figure(Figure(), path, "pdf", 100)
|
|
135
|
+
>>> path.read_bytes()[:4]
|
|
136
|
+
b'%PDF'
|
|
137
|
+
"""
|
|
138
|
+
with FileAccessErrors(WRITE_OPERATION, path):
|
|
139
|
+
figure.savefig(path, format=image_format, dpi=resolution)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def write_image(drawing: FigureDrawing, path: FilePath, options: ImageOptions | None, on_conflict: Conflict) -> None:
|
|
143
|
+
"""
|
|
144
|
+
Save what a Plot or a Figure draws as an image, in the format named by the extension of the path.
|
|
145
|
+
|
|
146
|
+
.. versionadded:: 0.1.0
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
drawing
|
|
151
|
+
What is drawn, and the size of the image.
|
|
152
|
+
path
|
|
153
|
+
The path of the image, ending with ``.png``, ``.svg`` or ``.pdf``.
|
|
154
|
+
options
|
|
155
|
+
The resolution of a PNG image, 100 dots per inch when omitted. SVG and PDF images take none.
|
|
156
|
+
on_conflict
|
|
157
|
+
``ERROR`` refuses to overwrite an existing file, ``REPLACE`` overwrites it.
|
|
158
|
+
|
|
159
|
+
Raises
|
|
160
|
+
------
|
|
161
|
+
UnsupportedImageFormatError
|
|
162
|
+
When the path does not end with ``.png``, ``.svg`` or ``.pdf``.
|
|
163
|
+
RefusedSettingError
|
|
164
|
+
When options are given for an SVG or PDF image.
|
|
165
|
+
FileExistsError
|
|
166
|
+
When a file exists at the path and ``on_conflict`` is ``ERROR``.
|
|
167
|
+
FileAccessError
|
|
168
|
+
When the file system refuses the file: missing folder, missing permission and so on.
|
|
169
|
+
|
|
170
|
+
Examples
|
|
171
|
+
--------
|
|
172
|
+
>>> import tempfile
|
|
173
|
+
>>> from pathlib import Path
|
|
174
|
+
>>> import numdaplot as ndp
|
|
175
|
+
>>> from numdaplot.plots.drawing.plot_drawing import FigureDrawing
|
|
176
|
+
>>> from numdaplot.plots.output.image_saving import write_image
|
|
177
|
+
>>> path = Path(tempfile.mkdtemp()) / "title.svg"
|
|
178
|
+
>>> write_image(FigureDrawing(lambda target: target.suptitle("Sales"), (3.0, 2.0)), path, None, ndp.Conflict.ERROR)
|
|
179
|
+
>>> path.read_text().startswith("<?xml")
|
|
180
|
+
True
|
|
181
|
+
"""
|
|
182
|
+
file_path = Path(path)
|
|
183
|
+
image_format = find_image_format(file_path)
|
|
184
|
+
resolution = choose_resolution(file_path, options)
|
|
185
|
+
require_free_path(file_path, on_conflict)
|
|
186
|
+
figure = build_figure(drawing)
|
|
187
|
+
save_figure(figure, file_path, image_format, resolution)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Display of a Plot or a Figure in a Jupyter notebook or in a matplotlib window.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 0.1.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# The matplotlib stubs leave the keyword arguments of most drawing methods untyped.
|
|
8
|
+
# pyright: reportUnknownMemberType=false
|
|
9
|
+
|
|
10
|
+
import warnings
|
|
11
|
+
from importlib import import_module
|
|
12
|
+
from io import BytesIO
|
|
13
|
+
|
|
14
|
+
from matplotlib.backends.registry import BackendFilter, backend_registry
|
|
15
|
+
from matplotlib.figure import Figure
|
|
16
|
+
|
|
17
|
+
from numdaplot.arrays.operations.float_errors import INTERNAL_FILES
|
|
18
|
+
from numdaplot.errors.display_warning import DisplayWarning
|
|
19
|
+
from numdaplot.plots.drawing.plot_drawing import FIGURE_LAYOUT, FigureDrawing, build_figure
|
|
20
|
+
from numdaplot.plots.output.shown_object import ShownObject
|
|
21
|
+
from numdaplot.plots.style.image_options import DEFAULT_DPI
|
|
22
|
+
from numdaplot.tables.preview.notebook_display import is_notebook
|
|
23
|
+
|
|
24
|
+
IPYTHON_DISPLAY_MODULE = "IPython.display"
|
|
25
|
+
PNG_FORMAT = "png"
|
|
26
|
+
NO_WINDOW_MESSAGE = (
|
|
27
|
+
"No window can be opened, matplotlib has no graphical backend here. Install tkinter (python3-tk on Debian and "
|
|
28
|
+
"Ubuntu) to see the {object_name}, or save it with {class_name}.save."
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def show_drawing(drawing: FigureDrawing, shown_object: ShownObject) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Show what a Plot or a Figure draws: as an image in a Jupyter notebook, in a matplotlib window anywhere else.
|
|
35
|
+
|
|
36
|
+
.. versionadded:: 0.1.0
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
drawing
|
|
41
|
+
What is drawn, and the size of the figure.
|
|
42
|
+
shown_object
|
|
43
|
+
Whether a Plot or a Figure is shown, named by the warning emitted when no window can be opened.
|
|
44
|
+
|
|
45
|
+
Examples
|
|
46
|
+
--------
|
|
47
|
+
>>> from numdaplot.plots.drawing.plot_drawing import FigureDrawing
|
|
48
|
+
>>> from numdaplot.plots.output.plot_display import show_drawing
|
|
49
|
+
>>> from numdaplot.plots.output.shown_object import ShownObject
|
|
50
|
+
>>> show_drawing(FigureDrawing(lambda target: target.suptitle("Sales"), (3.0, 2.0)), ShownObject.PLOT)
|
|
51
|
+
"""
|
|
52
|
+
runs_in_notebook = is_notebook()
|
|
53
|
+
if not runs_in_notebook:
|
|
54
|
+
show_drawing_in_window(drawing, shown_object)
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
figure = build_figure(drawing)
|
|
58
|
+
show_figure_in_notebook(figure)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def show_figure_in_notebook(figure: Figure) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Show a matplotlib figure as a PNG image in the output of a Jupyter notebook cell.
|
|
64
|
+
|
|
65
|
+
.. versionadded:: 0.1.0
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
figure
|
|
70
|
+
The figure to show.
|
|
71
|
+
"""
|
|
72
|
+
image_buffer = BytesIO()
|
|
73
|
+
figure.savefig(image_buffer, format=PNG_FORMAT, dpi=DEFAULT_DPI)
|
|
74
|
+
image_bytes = image_buffer.getvalue()
|
|
75
|
+
display_module = import_module(IPYTHON_DISPLAY_MODULE)
|
|
76
|
+
image = display_module.Image(data=image_bytes)
|
|
77
|
+
display_module.display(image)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def show_drawing_in_window(drawing: FigureDrawing, shown_object: ShownObject) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Show what a Plot or a Figure draws in a matplotlib window.
|
|
83
|
+
|
|
84
|
+
The call waits until the window is closed, unless matplotlib runs interactively. With a matplotlib backend
|
|
85
|
+
that opens no window, such as the one of a server, nothing is drawn and a ``DisplayWarning`` is emitted.
|
|
86
|
+
|
|
87
|
+
.. versionadded:: 0.1.0
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
drawing
|
|
92
|
+
What is drawn, and the size of the figure.
|
|
93
|
+
shown_object
|
|
94
|
+
Whether a Plot or a Figure is shown, named by the warning emitted when no window can be opened.
|
|
95
|
+
|
|
96
|
+
Examples
|
|
97
|
+
--------
|
|
98
|
+
>>> from numdaplot.plots.drawing.plot_drawing import FigureDrawing
|
|
99
|
+
>>> from numdaplot.plots.output.plot_display import show_drawing_in_window
|
|
100
|
+
>>> from numdaplot.plots.output.shown_object import ShownObject
|
|
101
|
+
>>> drawing = FigureDrawing(lambda target: target.suptitle("Sales"), (3.0, 2.0))
|
|
102
|
+
>>> show_drawing_in_window(drawing, ShownObject.FIGURE)
|
|
103
|
+
"""
|
|
104
|
+
# pyplot chooses a matplotlib backend when imported, so it is only imported to open a window.
|
|
105
|
+
from matplotlib import pyplot
|
|
106
|
+
|
|
107
|
+
backend_name = pyplot.get_backend()
|
|
108
|
+
can_open_window = is_window_backend(backend_name)
|
|
109
|
+
if not can_open_window:
|
|
110
|
+
warn_without_window(shown_object)
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
figure = pyplot.figure(figsize=drawing.size_inches, dpi=DEFAULT_DPI, layout=FIGURE_LAYOUT)
|
|
114
|
+
drawing.draw_on(figure)
|
|
115
|
+
pyplot.show()
|
|
116
|
+
is_interactive = pyplot.isinteractive()
|
|
117
|
+
if not is_interactive:
|
|
118
|
+
pyplot.close(figure)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def is_window_backend(backend_name: str) -> bool:
|
|
122
|
+
"""
|
|
123
|
+
Return whether a matplotlib backend opens windows.
|
|
124
|
+
|
|
125
|
+
Only the backends matplotlib lists as non-interactive, such as ``agg`` chosen when no window can be opened,
|
|
126
|
+
are refused: a backend added by another package is trusted.
|
|
127
|
+
|
|
128
|
+
.. versionadded:: 0.1.0
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
backend_name
|
|
133
|
+
The name matplotlib gives to its backend, such as ``tkagg`` or ``agg``, in any case.
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
bool
|
|
138
|
+
False for a matplotlib backend without window, True otherwise.
|
|
139
|
+
|
|
140
|
+
Examples
|
|
141
|
+
--------
|
|
142
|
+
>>> from numdaplot.plots.output.plot_display import is_window_backend
|
|
143
|
+
>>> is_window_backend("Agg")
|
|
144
|
+
False
|
|
145
|
+
>>> is_window_backend("TkAgg")
|
|
146
|
+
True
|
|
147
|
+
"""
|
|
148
|
+
lowered_name = backend_name.lower()
|
|
149
|
+
non_interactive_names = backend_registry.list_builtin(BackendFilter.NON_INTERACTIVE)
|
|
150
|
+
is_window = lowered_name not in non_interactive_names
|
|
151
|
+
|
|
152
|
+
return is_window
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def warn_without_window(shown_object: ShownObject) -> None:
|
|
156
|
+
"""
|
|
157
|
+
Emit a ``DisplayWarning`` pointing at the line of the calling code that asked to show a Plot or a Figure.
|
|
158
|
+
|
|
159
|
+
.. versionadded:: 0.1.0
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
shown_object
|
|
164
|
+
Whether a Plot or a Figure could not be shown.
|
|
165
|
+
|
|
166
|
+
Examples
|
|
167
|
+
--------
|
|
168
|
+
>>> import warnings
|
|
169
|
+
>>> from numdaplot.plots.output.plot_display import warn_without_window
|
|
170
|
+
>>> from numdaplot.plots.output.shown_object import ShownObject
|
|
171
|
+
>>> with warnings.catch_warnings(record=True) as caught_warnings:
|
|
172
|
+
... warnings.simplefilter("always")
|
|
173
|
+
... warn_without_window(ShownObject.FIGURE)
|
|
174
|
+
>>> print(caught_warnings[0].message)
|
|
175
|
+
No window can be opened, matplotlib has no graphical backend here. Install tkinter (python3-tk on Debian and
|
|
176
|
+
Ubuntu) to see the figure, or save it with Figure.save.
|
|
177
|
+
"""
|
|
178
|
+
class_name = shown_object.value
|
|
179
|
+
object_name = class_name.lower()
|
|
180
|
+
message = NO_WINDOW_MESSAGE.format(object_name=object_name, class_name=class_name)
|
|
181
|
+
warnings.warn(message, DisplayWarning, skip_file_prefixes=INTERNAL_FILES)
|