ultraplot 0.99.3__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.
- ultraplot/__init__.py +115 -0
- ultraplot/__init__.py.rej +58 -0
- ultraplot/axes/__init__.py +42 -0
- ultraplot/axes/base.py +3240 -0
- ultraplot/axes/cartesian.py +1425 -0
- ultraplot/axes/geo.py +1675 -0
- ultraplot/axes/plot.py +4569 -0
- ultraplot/axes/polar.py +381 -0
- ultraplot/axes/shared.py +186 -0
- ultraplot/axes/three.py +34 -0
- ultraplot/cmaps/Algae.rgb +256 -0
- ultraplot/cmaps/Amp.rgb +256 -0
- ultraplot/cmaps/BR.rgb +256 -0
- ultraplot/cmaps/Balance.rgb +256 -0
- ultraplot/cmaps/Blues1_r.xml +17 -0
- ultraplot/cmaps/Blues2.xml +16 -0
- ultraplot/cmaps/Blues3.xml +25 -0
- ultraplot/cmaps/Blues4_r.xml +17 -0
- ultraplot/cmaps/Blues5.xml +16 -0
- ultraplot/cmaps/Blues6.xml +25 -0
- ultraplot/cmaps/Blues7.xml +16 -0
- ultraplot/cmaps/Blues8.xml +17 -0
- ultraplot/cmaps/Blues9.xml +1 -0
- ultraplot/cmaps/Boreal.json +53 -0
- ultraplot/cmaps/Browns1.xml +16 -0
- ultraplot/cmaps/Browns2.xml +26 -0
- ultraplot/cmaps/Browns3.xml +17 -0
- ultraplot/cmaps/Browns4.xml +17 -0
- ultraplot/cmaps/Browns5.xml +26 -0
- ultraplot/cmaps/Browns6.xml +17 -0
- ultraplot/cmaps/Browns7.xml +19 -0
- ultraplot/cmaps/Browns8.xml +11 -0
- ultraplot/cmaps/Browns9.xml +1 -0
- ultraplot/cmaps/ColdHot.rgb +229 -0
- ultraplot/cmaps/Crest.rgb +256 -0
- ultraplot/cmaps/Curl.rgb +512 -0
- ultraplot/cmaps/Deep.rgb +256 -0
- ultraplot/cmaps/Delta.rgb +512 -0
- ultraplot/cmaps/Dense.rgb +256 -0
- ultraplot/cmaps/Div.json +71 -0
- ultraplot/cmaps/DryWet.json +73 -0
- ultraplot/cmaps/Dusk.json +53 -0
- ultraplot/cmaps/Fire.json +53 -0
- ultraplot/cmaps/Flare.rgb +256 -0
- ultraplot/cmaps/Glacial.json +53 -0
- ultraplot/cmaps/Greens1_r.xml +26 -0
- ultraplot/cmaps/Greens2.xml +28 -0
- ultraplot/cmaps/Greens3_r.xml +28 -0
- ultraplot/cmaps/Greens4.xml +17 -0
- ultraplot/cmaps/Greens5.xml +16 -0
- ultraplot/cmaps/Greens6_r.xml +16 -0
- ultraplot/cmaps/Greens7.xml +16 -0
- ultraplot/cmaps/Greens8.xml +26 -0
- ultraplot/cmaps/Haline.rgb +256 -0
- ultraplot/cmaps/Ice.rgb +256 -0
- ultraplot/cmaps/IceFire.rgb +256 -0
- ultraplot/cmaps/Mako.rgb +256 -0
- ultraplot/cmaps/Marine.json +53 -0
- ultraplot/cmaps/Matter.rgb +256 -0
- ultraplot/cmaps/Mono.txt +256 -0
- ultraplot/cmaps/MonoCycle.txt +256 -0
- ultraplot/cmaps/NegPos.json +71 -0
- ultraplot/cmaps/Oranges1.xml +27 -0
- ultraplot/cmaps/Oranges2.xml +26 -0
- ultraplot/cmaps/Oranges3.xml +15 -0
- ultraplot/cmaps/Oranges4.xml +23 -0
- ultraplot/cmaps/Oxy.rgb +256 -0
- ultraplot/cmaps/Phase.rgb +256 -0
- ultraplot/cmaps/Purples1_r.xml +16 -0
- ultraplot/cmaps/Purples2.xml +17 -0
- ultraplot/cmaps/Purples3.xml +18 -0
- ultraplot/cmaps/Reds1.xml +26 -0
- ultraplot/cmaps/Reds2.xml +22 -0
- ultraplot/cmaps/Reds3.xml +23 -0
- ultraplot/cmaps/Reds4.xml +26 -0
- ultraplot/cmaps/Reds5.xml +17 -0
- ultraplot/cmaps/Rocket.rgb +256 -0
- ultraplot/cmaps/Solar.rgb +256 -0
- ultraplot/cmaps/Speed.rgb +256 -0
- ultraplot/cmaps/Stellar.json +53 -0
- ultraplot/cmaps/Sunrise.json +53 -0
- ultraplot/cmaps/Sunset.json +53 -0
- ultraplot/cmaps/Tempo.rgb +256 -0
- ultraplot/cmaps/Thermal.rgb +256 -0
- ultraplot/cmaps/Turbid.rgb +256 -0
- ultraplot/cmaps/Vivid.xml +11 -0
- ultraplot/cmaps/Vlag.rgb +256 -0
- ultraplot/cmaps/Yellows1.xml +17 -0
- ultraplot/cmaps/Yellows2.xml +17 -0
- ultraplot/cmaps/Yellows3.xml +17 -0
- ultraplot/cmaps/Yellows4.xml +17 -0
- ultraplot/cmaps/acton.txt +256 -0
- ultraplot/cmaps/bam.txt +256 -0
- ultraplot/cmaps/bamO.txt +256 -0
- ultraplot/cmaps/bamako.txt +256 -0
- ultraplot/cmaps/batlow.txt +256 -0
- ultraplot/cmaps/batlowK.txt +256 -0
- ultraplot/cmaps/batlowW.txt +256 -0
- ultraplot/cmaps/berlin.txt +256 -0
- ultraplot/cmaps/bilbao.txt +256 -0
- ultraplot/cmaps/broc.txt +256 -0
- ultraplot/cmaps/brocO.txt +256 -0
- ultraplot/cmaps/buda.txt +256 -0
- ultraplot/cmaps/bukavu.txt +256 -0
- ultraplot/cmaps/cork.txt +256 -0
- ultraplot/cmaps/corkO.txt +256 -0
- ultraplot/cmaps/davos.txt +256 -0
- ultraplot/cmaps/devon.txt +256 -0
- ultraplot/cmaps/fes.txt +256 -0
- ultraplot/cmaps/hawaii.txt +256 -0
- ultraplot/cmaps/imola.txt +256 -0
- ultraplot/cmaps/lajolla.txt +256 -0
- ultraplot/cmaps/lapaz.txt +256 -0
- ultraplot/cmaps/lisbon.txt +256 -0
- ultraplot/cmaps/nuuk.txt +256 -0
- ultraplot/cmaps/oleron.txt +256 -0
- ultraplot/cmaps/oslo.txt +256 -0
- ultraplot/cmaps/roma.txt +256 -0
- ultraplot/cmaps/romaO.txt +256 -0
- ultraplot/cmaps/tofino.txt +256 -0
- ultraplot/cmaps/tokyo.txt +256 -0
- ultraplot/cmaps/turku.txt +256 -0
- ultraplot/cmaps/vanimo.txt +256 -0
- ultraplot/cmaps/vik.txt +256 -0
- ultraplot/cmaps/vikO.txt +256 -0
- ultraplot/colors/opencolor.txt +132 -0
- ultraplot/colors/xkcd.txt +951 -0
- ultraplot/colors.py +3241 -0
- ultraplot/colors.py.rej +243 -0
- ultraplot/config.py +1809 -0
- ultraplot/constructor.py +1633 -0
- ultraplot/cycles/538.hex +2 -0
- ultraplot/cycles/FlatUI.hex +1 -0
- ultraplot/cycles/Qual1.rgb +7 -0
- ultraplot/cycles/Qual2.rgb +13 -0
- ultraplot/cycles/bmh.hex +2 -0
- ultraplot/cycles/classic.hex +2 -0
- ultraplot/cycles/colorblind.hex +2 -0
- ultraplot/cycles/colorblind10.hex +2 -0
- ultraplot/cycles/default.hex +2 -0
- ultraplot/cycles/ggplot.hex +1 -0
- ultraplot/cycles/seaborn.hex +2 -0
- ultraplot/cycles/tableau.hex +2 -0
- ultraplot/demos.py +1201 -0
- ultraplot/externals/__init__.py +5 -0
- ultraplot/externals/hsluv.py +330 -0
- ultraplot/figure.py +2102 -0
- ultraplot/fonts/FiraMath-Bold.ttf +0 -0
- ultraplot/fonts/FiraMath-ExtraLight.ttf +0 -0
- ultraplot/fonts/FiraMath-Heavy.ttf +0 -0
- ultraplot/fonts/FiraMath-Light.ttf +0 -0
- ultraplot/fonts/FiraMath-Medium.ttf +0 -0
- ultraplot/fonts/FiraMath-Regular.ttf +0 -0
- ultraplot/fonts/FiraMath-SemiBold.ttf +0 -0
- ultraplot/fonts/FiraMath-UltraLight.ttf +0 -0
- ultraplot/fonts/FiraSans-Black.ttf +0 -0
- ultraplot/fonts/FiraSans-BlackItalic.ttf +0 -0
- ultraplot/fonts/FiraSans-Bold.ttf +0 -0
- ultraplot/fonts/FiraSans-BoldItalic.ttf +0 -0
- ultraplot/fonts/FiraSans-ExtraBold.ttf +0 -0
- ultraplot/fonts/FiraSans-ExtraBoldItalic.ttf +0 -0
- ultraplot/fonts/FiraSans-ExtraLight.ttf +0 -0
- ultraplot/fonts/FiraSans-ExtraLightItalic.ttf +0 -0
- ultraplot/fonts/FiraSans-Italic.ttf +0 -0
- ultraplot/fonts/FiraSans-Light.ttf +0 -0
- ultraplot/fonts/FiraSans-LightItalic.ttf +0 -0
- ultraplot/fonts/FiraSans-Medium.ttf +0 -0
- ultraplot/fonts/FiraSans-MediumItalic.ttf +0 -0
- ultraplot/fonts/FiraSans-Regular.ttf +0 -0
- ultraplot/fonts/FiraSans-SemiBold.ttf +0 -0
- ultraplot/fonts/FiraSans-SemiBoldItalic.ttf +0 -0
- ultraplot/fonts/LICENSE_FIRAMATH.txt +92 -0
- ultraplot/fonts/LICENSE_FIRASANS.txt +97 -0
- ultraplot/fonts/LICENSE_NOTOSANS.txt +202 -0
- ultraplot/fonts/LICENSE_NOTOSERIF.txt +93 -0
- ultraplot/fonts/LICENSE_OPENSANS.txt +202 -0
- ultraplot/fonts/LICENSE_ROBOTO.txt +202 -0
- ultraplot/fonts/LICENSE_SOURCESANS.txt +93 -0
- ultraplot/fonts/LICENSE_SOURCESERIF.txt +93 -0
- ultraplot/fonts/LICENSE_TEXGYRE.txt +29 -0
- ultraplot/fonts/LICENSE_UBUNTU.txt +96 -0
- ultraplot/fonts/NotoSans-Bold.ttf +0 -0
- ultraplot/fonts/NotoSans-BoldItalic.ttf +0 -0
- ultraplot/fonts/NotoSans-Italic.ttf +0 -0
- ultraplot/fonts/NotoSans-Regular.ttf +0 -0
- ultraplot/fonts/NotoSerif-Bold.ttf +0 -0
- ultraplot/fonts/NotoSerif-BoldItalic.ttf +0 -0
- ultraplot/fonts/NotoSerif-Italic.ttf +0 -0
- ultraplot/fonts/NotoSerif-Regular.ttf +0 -0
- ultraplot/fonts/OpenSans-Bold.ttf +0 -0
- ultraplot/fonts/OpenSans-BoldItalic.ttf +0 -0
- ultraplot/fonts/OpenSans-Italic.ttf +0 -0
- ultraplot/fonts/OpenSans-Regular.ttf +0 -0
- ultraplot/fonts/OpenSans-Semibold.ttf +0 -0
- ultraplot/fonts/OpenSans-SemiboldItalic.ttf +0 -0
- ultraplot/fonts/Roboto-Black.ttf +0 -0
- ultraplot/fonts/Roboto-BlackItalic.ttf +0 -0
- ultraplot/fonts/Roboto-Bold.ttf +0 -0
- ultraplot/fonts/Roboto-BoldItalic.ttf +0 -0
- ultraplot/fonts/Roboto-Italic.ttf +0 -0
- ultraplot/fonts/Roboto-Light.ttf +0 -0
- ultraplot/fonts/Roboto-LightItalic.ttf +0 -0
- ultraplot/fonts/Roboto-Medium.ttf +0 -0
- ultraplot/fonts/Roboto-MediumItalic.ttf +0 -0
- ultraplot/fonts/Roboto-Regular.ttf +0 -0
- ultraplot/fonts/SourceSansPro-Black.ttf +0 -0
- ultraplot/fonts/SourceSansPro-BlackItalic.ttf +0 -0
- ultraplot/fonts/SourceSansPro-Bold.ttf +0 -0
- ultraplot/fonts/SourceSansPro-BoldItalic.ttf +0 -0
- ultraplot/fonts/SourceSansPro-ExtraLight.ttf +0 -0
- ultraplot/fonts/SourceSansPro-ExtraLightItalic.ttf +0 -0
- ultraplot/fonts/SourceSansPro-Italic.ttf +0 -0
- ultraplot/fonts/SourceSansPro-Light.ttf +0 -0
- ultraplot/fonts/SourceSansPro-LightItalic.ttf +0 -0
- ultraplot/fonts/SourceSansPro-Regular.ttf +0 -0
- ultraplot/fonts/SourceSansPro-SemiBold.ttf +0 -0
- ultraplot/fonts/SourceSansPro-SemiBoldItalic.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-Black.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-BlackItalic.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-Bold.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-BoldItalic.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-ExtraLight.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-ExtraLightItalic.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-Italic.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-Light.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-LightItalic.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-Regular.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-SemiBold.ttf +0 -0
- ultraplot/fonts/SourceSerifPro-SemiBoldItalic.ttf +0 -0
- ultraplot/fonts/Ubuntu-Bold.ttf +0 -0
- ultraplot/fonts/Ubuntu-BoldItalic.ttf +0 -0
- ultraplot/fonts/Ubuntu-Italic.ttf +0 -0
- ultraplot/fonts/Ubuntu-Light.ttf +0 -0
- ultraplot/fonts/Ubuntu-LightItalic.ttf +0 -0
- ultraplot/fonts/Ubuntu-Medium.ttf +0 -0
- ultraplot/fonts/Ubuntu-MediumItalic.ttf +0 -0
- ultraplot/fonts/Ubuntu-Regular.ttf +0 -0
- ultraplot/fonts/texgyreadventor-bold.ttf +0 -0
- ultraplot/fonts/texgyreadventor-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyreadventor-italic.ttf +0 -0
- ultraplot/fonts/texgyreadventor-regular.ttf +0 -0
- ultraplot/fonts/texgyrebonum-bold.ttf +0 -0
- ultraplot/fonts/texgyrebonum-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyrebonum-italic.ttf +0 -0
- ultraplot/fonts/texgyrebonum-regular.ttf +0 -0
- ultraplot/fonts/texgyrechorus-mediumitalic.ttf +0 -0
- ultraplot/fonts/texgyrecursor-bold.ttf +0 -0
- ultraplot/fonts/texgyrecursor-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyrecursor-italic.ttf +0 -0
- ultraplot/fonts/texgyrecursor-regular.ttf +0 -0
- ultraplot/fonts/texgyreheros-bold.ttf +0 -0
- ultraplot/fonts/texgyreheros-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyreheros-italic.ttf +0 -0
- ultraplot/fonts/texgyreheros-regular.ttf +0 -0
- ultraplot/fonts/texgyrepagella-bold.ttf +0 -0
- ultraplot/fonts/texgyrepagella-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyrepagella-italic.ttf +0 -0
- ultraplot/fonts/texgyrepagella-regular.ttf +0 -0
- ultraplot/fonts/texgyreschola-bold.ttf +0 -0
- ultraplot/fonts/texgyreschola-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyreschola-italic.ttf +0 -0
- ultraplot/fonts/texgyreschola-regular.ttf +0 -0
- ultraplot/fonts/texgyretermes-bold.ttf +0 -0
- ultraplot/fonts/texgyretermes-bolditalic.ttf +0 -0
- ultraplot/fonts/texgyretermes-italic.ttf +0 -0
- ultraplot/fonts/texgyretermes-regular.ttf +0 -0
- ultraplot/gridspec.py +1698 -0
- ultraplot/internals/__init__.py +529 -0
- ultraplot/internals/benchmarks.py +26 -0
- ultraplot/internals/context.py +44 -0
- ultraplot/internals/docstring.py +139 -0
- ultraplot/internals/fonts.py +75 -0
- ultraplot/internals/guides.py +167 -0
- ultraplot/internals/inputs.py +862 -0
- ultraplot/internals/labels.py +85 -0
- ultraplot/internals/rcsetup.py +1933 -0
- ultraplot/internals/versions.py +61 -0
- ultraplot/internals/warnings.py +122 -0
- ultraplot/proj.py +325 -0
- ultraplot/scale.py +966 -0
- ultraplot/tests/__init__.py +28 -0
- ultraplot/tests/baseline/test_align_labels.png +0 -0
- ultraplot/tests/baseline/test_aligned_outer_guides.png +0 -0
- ultraplot/tests/baseline/test_aspect_ratios.png +0 -0
- ultraplot/tests/baseline/test_auto_diverging1.png +0 -0
- ultraplot/tests/baseline/test_auto_legend.png +0 -0
- ultraplot/tests/baseline/test_auto_reverse.png +0 -0
- ultraplot/tests/baseline/test_autodiverging3.png +0 -0
- ultraplot/tests/baseline/test_autodiverging4.png +0 -0
- ultraplot/tests/baseline/test_autodiverging5.png +0 -0
- ultraplot/tests/baseline/test_axes_colors.png +0 -0
- ultraplot/tests/baseline/test_bar_vectors.png +0 -0
- ultraplot/tests/baseline/test_bar_width.png +0 -0
- ultraplot/tests/baseline/test_both_ticklabels.png +0 -0
- ultraplot/tests/baseline/test_bounds_ticks.png +0 -0
- ultraplot/tests/baseline/test_boxplot_colors.png +0 -0
- ultraplot/tests/baseline/test_boxplot_vectors.png +0 -0
- ultraplot/tests/baseline/test_cartopy_contours.png +0 -0
- ultraplot/tests/baseline/test_cartopy_labels.png +0 -0
- ultraplot/tests/baseline/test_cartopy_manual.png +0 -0
- ultraplot/tests/baseline/test_centered_legends.png +0 -0
- ultraplot/tests/baseline/test_cmap_cycles.png +0 -0
- ultraplot/tests/baseline/test_colorbar.png +0 -0
- ultraplot/tests/baseline/test_colorbar_ticks.png +0 -0
- ultraplot/tests/baseline/test_colormap_mode.png +0 -0
- ultraplot/tests/baseline/test_column_iteration.png +0 -0
- ultraplot/tests/baseline/test_complex_ticks.png +0 -0
- ultraplot/tests/baseline/test_contour_labels.png +0 -0
- ultraplot/tests/baseline/test_contour_legend_with_label.png +0 -0
- ultraplot/tests/baseline/test_contour_legend_without_label.png +0 -0
- ultraplot/tests/baseline/test_contour_negative.png +0 -0
- ultraplot/tests/baseline/test_contour_single.png +0 -0
- ultraplot/tests/baseline/test_cutoff_ticks.png +0 -0
- ultraplot/tests/baseline/test_data_keyword.png +0 -0
- ultraplot/tests/baseline/test_discrete_ticks.png +0 -0
- ultraplot/tests/baseline/test_discrete_vs_fixed.png +0 -0
- ultraplot/tests/baseline/test_drawing_in_projection_with_globe.png +0 -0
- ultraplot/tests/baseline/test_drawing_in_projection_without_globe.png +0 -0
- ultraplot/tests/baseline/test_edge_fix.png +0 -0
- ultraplot/tests/baseline/test_flow_functions.png +0 -0
- ultraplot/tests/baseline/test_font_adjustments.png +0 -0
- ultraplot/tests/baseline/test_geographic_multiple_projections.png +0 -0
- ultraplot/tests/baseline/test_geographic_single_projection.png +0 -0
- ultraplot/tests/baseline/test_gray_adjustment.png +0 -0
- ultraplot/tests/baseline/test_histogram_legend.png +0 -0
- ultraplot/tests/baseline/test_histogram_types.png +0 -0
- ultraplot/tests/baseline/test_ignore_message.png +0 -0
- ultraplot/tests/baseline/test_inbounds_data.png +0 -0
- ultraplot/tests/baseline/test_init_format.png +0 -0
- ultraplot/tests/baseline/test_inner_title_zorder.png +0 -0
- ultraplot/tests/baseline/test_inset_basic.png +0 -0
- ultraplot/tests/baseline/test_inset_colorbars.png +0 -0
- ultraplot/tests/baseline/test_inset_colors_1.png +0 -0
- ultraplot/tests/baseline/test_inset_colors_2.png +0 -0
- ultraplot/tests/baseline/test_inset_zoom_update.png +0 -0
- ultraplot/tests/baseline/test_invalid_dist.png +0 -0
- ultraplot/tests/baseline/test_invalid_plot.png +0 -0
- ultraplot/tests/baseline/test_keep_guide_labels.png +0 -0
- ultraplot/tests/baseline/test_label_settings.png +0 -0
- ultraplot/tests/baseline/test_level_restriction.png +0 -0
- ultraplot/tests/baseline/test_levels_with_vmin_vmax.png +0 -0
- ultraplot/tests/baseline/test_locale_formatting.png +0 -0
- ultraplot/tests/baseline/test_locale_formatting_en_US.UTF-8.png +0 -0
- ultraplot/tests/baseline/test_manual_labels.png +0 -0
- ultraplot/tests/baseline/test_multi_formatting.png +0 -0
- ultraplot/tests/baseline/test_multiple_calls.png +0 -0
- ultraplot/tests/baseline/test_on_the_fly_mappable.png +0 -0
- ultraplot/tests/baseline/test_outer_align.png +0 -0
- ultraplot/tests/baseline/test_panel_dist.png +0 -0
- ultraplot/tests/baseline/test_panels_suplabels_three_hor_panels.png +0 -0
- ultraplot/tests/baseline/test_panels_with_sharing.png +0 -0
- ultraplot/tests/baseline/test_panels_without_sharing_1.png +0 -0
- ultraplot/tests/baseline/test_panels_without_sharing_2.png +0 -0
- ultraplot/tests/baseline/test_parametric_colors.png +0 -0
- ultraplot/tests/baseline/test_parametric_labels.png +0 -0
- ultraplot/tests/baseline/test_patch_format.png +0 -0
- ultraplot/tests/baseline/test_pie_charts.png +0 -0
- ultraplot/tests/baseline/test_pint_quantities.png +0 -0
- ultraplot/tests/baseline/test_polar_projections.png +0 -0
- ultraplot/tests/baseline/test_projection_dicts.png +0 -0
- ultraplot/tests/baseline/test_qualitative_colormaps_1.png +0 -0
- ultraplot/tests/baseline/test_qualitative_colormaps_2.png +0 -0
- ultraplot/tests/baseline/test_reversed_levels.png +0 -0
- ultraplot/tests/baseline/test_scatter_alpha.png +0 -0
- ultraplot/tests/baseline/test_scatter_args.png +0 -0
- ultraplot/tests/baseline/test_scatter_cycle.png +0 -0
- ultraplot/tests/baseline/test_scatter_inbounds.png +0 -0
- ultraplot/tests/baseline/test_scatter_sizes.png +0 -0
- ultraplot/tests/baseline/test_seaborn_heatmap.png +0 -0
- ultraplot/tests/baseline/test_seaborn_hist.png +0 -0
- ultraplot/tests/baseline/test_seaborn_relational.png +0 -0
- ultraplot/tests/baseline/test_seaborn_swarmplot.png +0 -0
- ultraplot/tests/baseline/test_segmented_norm.png +0 -0
- ultraplot/tests/baseline/test_segmented_norm_ticks.png +0 -0
- ultraplot/tests/baseline/test_share_all_basic.png +0 -0
- ultraplot/tests/baseline/test_singleton_legend.png +0 -0
- ultraplot/tests/baseline/test_span_labels.png +0 -0
- ultraplot/tests/baseline/test_spine_offset.png +0 -0
- ultraplot/tests/baseline/test_spine_side.png +0 -0
- ultraplot/tests/baseline/test_standardized_input.png +0 -0
- ultraplot/tests/baseline/test_statistical_boxplot.png +0 -0
- ultraplot/tests/baseline/test_three_axes.png +0 -0
- ultraplot/tests/baseline/test_tick_direction.png +0 -0
- ultraplot/tests/baseline/test_tick_labels.png +0 -0
- ultraplot/tests/baseline/test_tick_length.png +0 -0
- ultraplot/tests/baseline/test_tick_width.png +0 -0
- ultraplot/tests/baseline/test_title_deflection.png +0 -0
- ultraplot/tests/baseline/test_triangular_functions.png +0 -0
- ultraplot/tests/baseline/test_tuple_handles.png +0 -0
- ultraplot/tests/baseline/test_twin_axes_1.png +0 -0
- ultraplot/tests/baseline/test_twin_axes_2.png +0 -0
- ultraplot/tests/baseline/test_twin_axes_3.png +0 -0
- ultraplot/tests/baseline/test_uneven_levels.png +0 -0
- ultraplot/tests/test_1dplots.py +373 -0
- ultraplot/tests/test_2dplots.py +354 -0
- ultraplot/tests/test_axes.py +179 -0
- ultraplot/tests/test_colorbar.py +253 -0
- ultraplot/tests/test_docs.py +78 -0
- ultraplot/tests/test_format.py +340 -0
- ultraplot/tests/test_geographic.py +116 -0
- ultraplot/tests/test_imshow.py +110 -0
- ultraplot/tests/test_inset.py +28 -0
- ultraplot/tests/test_integration.py +149 -0
- ultraplot/tests/test_legend.py +181 -0
- ultraplot/tests/test_projections.py +138 -0
- ultraplot/tests/test_statistical_plotting.py +77 -0
- ultraplot/tests/test_subplots.py +174 -0
- ultraplot/ticker.py +879 -0
- ultraplot/ui.py +233 -0
- ultraplot/utils.py +912 -0
- ultraplot-0.99.3.dist-info/LICENSE.txt +427 -0
- ultraplot-0.99.3.dist-info/METADATA +88 -0
- ultraplot-0.99.3.dist-info/RECORD +416 -0
- ultraplot-0.99.3.dist-info/WHEEL +5 -0
- ultraplot-0.99.3.dist-info/entry_points.txt +2 -0
- ultraplot-0.99.3.dist-info/top_level.txt +1 -0
ultraplot/ticker.py
ADDED
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Various `~matplotlib.ticker.Locator` and `~matplotlib.ticker.Formatter` classes.
|
|
4
|
+
"""
|
|
5
|
+
import locale
|
|
6
|
+
import re
|
|
7
|
+
from fractions import Fraction
|
|
8
|
+
|
|
9
|
+
import matplotlib.axis as maxis
|
|
10
|
+
import matplotlib.ticker as mticker
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from .config import rc
|
|
14
|
+
from .internals import ic # noqa: F401
|
|
15
|
+
from .internals import _not_none, context, docstring
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import cartopy.crs as ccrs
|
|
19
|
+
from cartopy.mpl.ticker import (
|
|
20
|
+
LatitudeFormatter,
|
|
21
|
+
LongitudeFormatter,
|
|
22
|
+
_PlateCarreeFormatter,
|
|
23
|
+
)
|
|
24
|
+
except ModuleNotFoundError:
|
|
25
|
+
ccrs = None
|
|
26
|
+
LatitudeFormatter = LongitudeFormatter = _PlateCarreeFormatter = object
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"IndexLocator",
|
|
30
|
+
"DiscreteLocator",
|
|
31
|
+
"DegreeLocator",
|
|
32
|
+
"LongitudeLocator",
|
|
33
|
+
"LatitudeLocator",
|
|
34
|
+
"AutoFormatter",
|
|
35
|
+
"SimpleFormatter",
|
|
36
|
+
"IndexFormatter",
|
|
37
|
+
"SciFormatter",
|
|
38
|
+
"SigFigFormatter",
|
|
39
|
+
"FracFormatter",
|
|
40
|
+
"DegreeFormatter",
|
|
41
|
+
"LongitudeFormatter",
|
|
42
|
+
"LatitudeFormatter",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
REGEX_ZERO = re.compile("\\A[-\N{MINUS SIGN}]?0(.0*)?\\Z")
|
|
46
|
+
REGEX_MINUS = re.compile("\\A[-\N{MINUS SIGN}]\\Z")
|
|
47
|
+
REGEX_MINUS_ZERO = re.compile("\\A[-\N{MINUS SIGN}]0(.0*)?\\Z")
|
|
48
|
+
|
|
49
|
+
_precision_docstring = """
|
|
50
|
+
precision : int, default: {6, 2}
|
|
51
|
+
The maximum number of digits after the decimal point. Default is ``6``
|
|
52
|
+
when `zerotrim` is ``True`` and ``2`` otherwise.
|
|
53
|
+
"""
|
|
54
|
+
_zerotrim_docstring = """
|
|
55
|
+
zerotrim : bool, default: :rc:`format.zerotrim`
|
|
56
|
+
Whether to trim trailing decimal zeros.
|
|
57
|
+
"""
|
|
58
|
+
_auto_docstring = """
|
|
59
|
+
tickrange : 2-tuple of float, optional
|
|
60
|
+
Range within which major tick marks are labeled.
|
|
61
|
+
All ticks are labeled by default.
|
|
62
|
+
wraprange : 2-tuple of float, optional
|
|
63
|
+
Range outside of which tick values are wrapped. For example,
|
|
64
|
+
``(-180, 180)`` will format a value of ``200`` as ``-160``.
|
|
65
|
+
prefix, suffix : str, optional
|
|
66
|
+
Prefix and suffix for all tick strings. The suffix is added before
|
|
67
|
+
the optional `negpos` suffix.
|
|
68
|
+
negpos : str, optional
|
|
69
|
+
Length-2 string indicating the suffix for "negative" and "positive"
|
|
70
|
+
numbers, meant to replace the minus sign.
|
|
71
|
+
"""
|
|
72
|
+
_formatter_call = """
|
|
73
|
+
Convert number to a string.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
x : float
|
|
78
|
+
The value.
|
|
79
|
+
pos : float, optional
|
|
80
|
+
The position.
|
|
81
|
+
"""
|
|
82
|
+
docstring._snippet_manager["ticker.precision"] = _precision_docstring
|
|
83
|
+
docstring._snippet_manager["ticker.zerotrim"] = _zerotrim_docstring
|
|
84
|
+
docstring._snippet_manager["ticker.auto"] = _auto_docstring
|
|
85
|
+
docstring._snippet_manager["ticker.call"] = _formatter_call
|
|
86
|
+
|
|
87
|
+
_dms_docstring = """
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
dms : bool, default: False
|
|
91
|
+
Locate the ticks on clean degree-minute-second intervals and format the
|
|
92
|
+
ticks with minutes and seconds instead of decimals.
|
|
93
|
+
"""
|
|
94
|
+
docstring._snippet_manager["ticker.dms"] = _dms_docstring
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _default_precision_zerotrim(precision=None, zerotrim=None):
|
|
98
|
+
"""
|
|
99
|
+
Return the default zerotrim and precision. Shared by several formatters.
|
|
100
|
+
"""
|
|
101
|
+
zerotrim = _not_none(zerotrim, rc["formatter.zerotrim"])
|
|
102
|
+
if precision is None:
|
|
103
|
+
precision = 6 if zerotrim else 2
|
|
104
|
+
return precision, zerotrim
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class IndexLocator(mticker.Locator):
|
|
108
|
+
"""
|
|
109
|
+
Format numbers by assigning fixed strings to non-negative indices. The ticks
|
|
110
|
+
are restricted to the extent of plotted content when content is present.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
def __init__(self, base=1, offset=0):
|
|
114
|
+
self._base = base
|
|
115
|
+
self._offset = offset
|
|
116
|
+
|
|
117
|
+
def set_params(self, base=None, offset=None):
|
|
118
|
+
if base is not None:
|
|
119
|
+
self._base = base
|
|
120
|
+
if offset is not None:
|
|
121
|
+
self._offset = offset
|
|
122
|
+
|
|
123
|
+
def __call__(self):
|
|
124
|
+
# NOTE: We adapt matplotlib IndexLocator to support case where
|
|
125
|
+
# the data interval is empty. Only restrict after data is plotted.
|
|
126
|
+
dmin, dmax = self.axis.get_data_interval()
|
|
127
|
+
vmin, vmax = self.axis.get_view_interval()
|
|
128
|
+
min_ = max(dmin, vmin)
|
|
129
|
+
max_ = min(dmax, vmax)
|
|
130
|
+
return self.tick_values(min_, max_)
|
|
131
|
+
|
|
132
|
+
def tick_values(self, vmin, vmax):
|
|
133
|
+
base, offset = self._base, self._offset
|
|
134
|
+
vmin = max(base * np.ceil(vmin / base), offset)
|
|
135
|
+
vmax = max(base * np.floor(vmax / base), offset)
|
|
136
|
+
locs = np.arange(vmin, vmax + 0.5 * base, base)
|
|
137
|
+
return self.raise_if_exceeds(locs)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class DiscreteLocator(mticker.Locator):
|
|
141
|
+
"""
|
|
142
|
+
A tick locator suitable for discretized colorbars. Adds ticks to some
|
|
143
|
+
subset of the location list depending on the available space determined from
|
|
144
|
+
`~matplotlib.axis.Axis.get_tick_space`. Zero will be used if it appears in the
|
|
145
|
+
location list, and step sizes along the location list are restricted to "nice"
|
|
146
|
+
intervals by default.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
default_params = {
|
|
150
|
+
"nbins": None,
|
|
151
|
+
"minor": False,
|
|
152
|
+
"steps": np.array([1, 2, 3, 4, 5, 6, 8, 10]),
|
|
153
|
+
"min_n_ticks": 2,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
@docstring._snippet_manager
|
|
157
|
+
def __init__(self, locs, **kwargs):
|
|
158
|
+
"""
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
locs : array-like
|
|
162
|
+
The tick location list.
|
|
163
|
+
nbins : int, optional
|
|
164
|
+
Maximum number of ticks to select. By default this is automatically
|
|
165
|
+
determined based on the the axis length and tick label font size.
|
|
166
|
+
minor : bool, default: False
|
|
167
|
+
Whether this is for "minor" ticks. Setting to ``True`` will select more
|
|
168
|
+
ticks with an index step that divides the index step used for "major" ticks.
|
|
169
|
+
steps : array-like of int, default: ``[1 2 3 4 5 6 8]``
|
|
170
|
+
Valid integer index steps when selecting from the tick list. Must fall
|
|
171
|
+
between 1 and 9. Powers of 10 of these step sizes will also be permitted.
|
|
172
|
+
min_n_ticks : int, default: 1
|
|
173
|
+
The minimum number of ticks to select. See also `nbins`.
|
|
174
|
+
"""
|
|
175
|
+
self.locs = np.array(locs)
|
|
176
|
+
self._nbins = None # otherwise unset
|
|
177
|
+
self.set_params(**{**self.default_params, **kwargs})
|
|
178
|
+
|
|
179
|
+
def __call__(self):
|
|
180
|
+
"""
|
|
181
|
+
Return the locations of the ticks.
|
|
182
|
+
"""
|
|
183
|
+
return self.tick_values(None, None)
|
|
184
|
+
|
|
185
|
+
def set_params(self, steps=None, nbins=None, minor=None, min_n_ticks=None):
|
|
186
|
+
"""
|
|
187
|
+
Set the parameters for this locator. See `DiscreteLocator` for details.
|
|
188
|
+
"""
|
|
189
|
+
if steps is not None:
|
|
190
|
+
steps = np.unique(np.array(steps, dtype=int)) # also sorts, makes 1D
|
|
191
|
+
if np.any(steps < 1) or np.any(steps > 10):
|
|
192
|
+
raise ValueError("Steps must fall between one and ten (inclusive).")
|
|
193
|
+
if steps[0] != 1:
|
|
194
|
+
steps = np.concatenate([[1], steps])
|
|
195
|
+
if steps[-1] != 10:
|
|
196
|
+
steps = np.concatenate([steps, [10]])
|
|
197
|
+
self._steps = steps
|
|
198
|
+
if nbins is not None:
|
|
199
|
+
self._nbins = nbins
|
|
200
|
+
if minor is not None:
|
|
201
|
+
self._minor = bool(minor) # needed to scale tick space
|
|
202
|
+
if min_n_ticks is not None:
|
|
203
|
+
self._min_n_ticks = int(min_n_ticks) # compare to MaxNLocator
|
|
204
|
+
|
|
205
|
+
def tick_values(self, vmin, vmax): # noqa: U100
|
|
206
|
+
"""
|
|
207
|
+
Return the locations of the ticks.
|
|
208
|
+
"""
|
|
209
|
+
# NOTE: Critical that minor tick interval evenly divides major tick
|
|
210
|
+
# interval. Otherwise get misaligned major and minor tick steps.
|
|
211
|
+
# NOTE: This tries to select ticks that are integer steps away from zero (like
|
|
212
|
+
# AutoLocator). The list minimum is used if this fails (like FixedLocator)
|
|
213
|
+
# NOTE: This avoids awkward steps like '7' or '13' that produce awkward
|
|
214
|
+
# jumps and have no integer divisors (and therefore eliminate minor ticks)
|
|
215
|
+
# NOTE: We virtually always want to subsample the level list rather than
|
|
216
|
+
# using continuous minor locators (e.g. LogLocator or SymLogLocator) because
|
|
217
|
+
# _parse_autolev interpolates evenly in the norm-space (e.g. 1, 3.16, 10, 31.6
|
|
218
|
+
# for a LogNorm) rather than in linear-space (e.g. 1, 5, 10, 15, 20).
|
|
219
|
+
locs = self.locs
|
|
220
|
+
axis = self.axis
|
|
221
|
+
if axis is None:
|
|
222
|
+
return locs
|
|
223
|
+
nbins = self._nbins
|
|
224
|
+
steps = self._steps
|
|
225
|
+
if nbins is None:
|
|
226
|
+
nbins = axis.get_tick_space()
|
|
227
|
+
nbins = max((1, self._min_n_ticks - 1, nbins))
|
|
228
|
+
step = max(1, int(np.ceil(locs.size / nbins)))
|
|
229
|
+
fact = 10 ** max(0, -AutoFormatter._decimal_place(step)) # e.g. 2 for 100
|
|
230
|
+
idx = min(len(steps) - 1, np.searchsorted(steps, step / fact))
|
|
231
|
+
step = int(np.round(steps[idx] * fact))
|
|
232
|
+
if self._minor: # tick every half font size
|
|
233
|
+
if isinstance(axis, maxis.XAxis):
|
|
234
|
+
fact = 6 # unscale heuristic scaling of 3 em-widths
|
|
235
|
+
elif isinstance(axis, maxis.YAxis):
|
|
236
|
+
fact = 4 # unscale standard scaling of 2 em-widths
|
|
237
|
+
else:
|
|
238
|
+
fact = 2 # fall back to just one em-width
|
|
239
|
+
for i in range(fact, 0, -1):
|
|
240
|
+
if step % i == 0:
|
|
241
|
+
step = step // i
|
|
242
|
+
break
|
|
243
|
+
diff = np.abs(np.diff(locs[: step + 1 : step]))
|
|
244
|
+
(offset,) = np.where(np.isclose(locs % diff if diff.size else 0.0, 0.0))
|
|
245
|
+
offset = offset[0] if offset.size else np.argmin(np.abs(locs))
|
|
246
|
+
return locs[offset % step :: step] # even multiples from zero or zero-close
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class DegreeLocator(mticker.MaxNLocator):
|
|
250
|
+
"""
|
|
251
|
+
Locate geographic gridlines with degree-minute-second support.
|
|
252
|
+
Adapted from cartopy.
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
# NOTE: This is identical to cartopy except they only define LongitutdeLocator
|
|
256
|
+
# for common methods whereas we use DegreeLocator. More intuitive this way in
|
|
257
|
+
# case users need degree-minute-seconds for non-specific degree axis.
|
|
258
|
+
# NOTE: Locator implementation is weird AF. __init__ just calls set_params with all
|
|
259
|
+
# keyword args and fills in missing params with default_params class attribute.
|
|
260
|
+
# Unknown params result in warning instead of error.
|
|
261
|
+
default_params = mticker.MaxNLocator.default_params.copy()
|
|
262
|
+
default_params.update(nbins=8, dms=False)
|
|
263
|
+
|
|
264
|
+
@docstring._snippet_manager
|
|
265
|
+
def __init__(self, *args, **kwargs):
|
|
266
|
+
"""
|
|
267
|
+
%(ticker.dms)s
|
|
268
|
+
"""
|
|
269
|
+
super().__init__(*args, **kwargs)
|
|
270
|
+
|
|
271
|
+
def set_params(self, **kwargs):
|
|
272
|
+
if "dms" in kwargs:
|
|
273
|
+
self._dms = kwargs.pop("dms")
|
|
274
|
+
super().set_params(**kwargs)
|
|
275
|
+
|
|
276
|
+
def _guess_steps(self, vmin, vmax):
|
|
277
|
+
dv = abs(vmax - vmin)
|
|
278
|
+
if dv > 180:
|
|
279
|
+
dv -= 180
|
|
280
|
+
if dv > 50:
|
|
281
|
+
steps = np.array([1, 2, 3, 6, 10])
|
|
282
|
+
elif not self._dms or dv > 3.0:
|
|
283
|
+
steps = np.array([1, 1.5, 2, 2.5, 3, 5, 10])
|
|
284
|
+
else:
|
|
285
|
+
steps = np.array([1, 10 / 6.0, 15 / 6.0, 20 / 6.0, 30 / 6.0, 10])
|
|
286
|
+
self.set_params(steps=np.array(steps))
|
|
287
|
+
|
|
288
|
+
def _raw_ticks(self, vmin, vmax):
|
|
289
|
+
self._guess_steps(vmin, vmax)
|
|
290
|
+
return super()._raw_ticks(vmin, vmax)
|
|
291
|
+
|
|
292
|
+
def bin_boundaries(self, vmin, vmax): # matplotlib < 2.2.0
|
|
293
|
+
return self._raw_ticks(vmin, vmax) # may call Latitude/Longitude Locator copies
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class LongitudeLocator(DegreeLocator):
|
|
297
|
+
"""
|
|
298
|
+
Locate longitude gridlines with degree-minute-second support.
|
|
299
|
+
Adapted from cartopy.
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
@docstring._snippet_manager
|
|
303
|
+
def __init__(self, *args, **kwargs):
|
|
304
|
+
"""
|
|
305
|
+
%(ticker.dms)s
|
|
306
|
+
"""
|
|
307
|
+
super().__init__(*args, **kwargs)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class LatitudeLocator(DegreeLocator):
|
|
311
|
+
"""
|
|
312
|
+
Locate latitude gridlines with degree-minute-second support.
|
|
313
|
+
Adapted from cartopy.
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
@docstring._snippet_manager
|
|
317
|
+
def __init__(self, *args, **kwargs):
|
|
318
|
+
"""
|
|
319
|
+
%(ticker.dms)s
|
|
320
|
+
"""
|
|
321
|
+
super().__init__(*args, **kwargs)
|
|
322
|
+
|
|
323
|
+
def tick_values(self, vmin, vmax):
|
|
324
|
+
vmin = max(vmin, -90)
|
|
325
|
+
vmax = min(vmax, 90)
|
|
326
|
+
return super().tick_values(vmin, vmax)
|
|
327
|
+
|
|
328
|
+
def _guess_steps(self, vmin, vmax):
|
|
329
|
+
vmin = max(vmin, -90)
|
|
330
|
+
vmax = min(vmax, 90)
|
|
331
|
+
super()._guess_steps(vmin, vmax)
|
|
332
|
+
|
|
333
|
+
def _raw_ticks(self, vmin, vmax):
|
|
334
|
+
ticks = super()._raw_ticks(vmin, vmax)
|
|
335
|
+
return [t for t in ticks if -90 <= t <= 90]
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class AutoFormatter(mticker.ScalarFormatter):
|
|
339
|
+
"""
|
|
340
|
+
The default formatter used for ultraplot tick labels.
|
|
341
|
+
Replaces `~matplotlib.ticker.ScalarFormatter`.
|
|
342
|
+
"""
|
|
343
|
+
|
|
344
|
+
@docstring._snippet_manager
|
|
345
|
+
def __init__(
|
|
346
|
+
self,
|
|
347
|
+
zerotrim=None,
|
|
348
|
+
tickrange=None,
|
|
349
|
+
wraprange=None,
|
|
350
|
+
prefix=None,
|
|
351
|
+
suffix=None,
|
|
352
|
+
negpos=None,
|
|
353
|
+
**kwargs,
|
|
354
|
+
):
|
|
355
|
+
"""
|
|
356
|
+
Parameters
|
|
357
|
+
----------
|
|
358
|
+
%(ticker.zerotrim)s
|
|
359
|
+
%(ticker.auto)s
|
|
360
|
+
|
|
361
|
+
Other parameters
|
|
362
|
+
----------------
|
|
363
|
+
**kwargs
|
|
364
|
+
Passed to `matplotlib.ticker.ScalarFormatter`.
|
|
365
|
+
|
|
366
|
+
See also
|
|
367
|
+
--------
|
|
368
|
+
ultraplot.constructor.Formatter
|
|
369
|
+
ultraplot.ticker.SimpleFormatter
|
|
370
|
+
|
|
371
|
+
Note
|
|
372
|
+
----
|
|
373
|
+
`matplotlib.ticker.ScalarFormatter` determines the number of
|
|
374
|
+
significant digits based on the axis limits, and therefore may
|
|
375
|
+
truncate digits while formatting ticks on highly non-linear axis
|
|
376
|
+
scales like `~ultraplot.scale.LogScale`. `AutoFormatter` corrects
|
|
377
|
+
this behavior, making it suitable for arbitrary axis scales. We
|
|
378
|
+
therefore use `AutoFormatter` with every axis scale by default.
|
|
379
|
+
"""
|
|
380
|
+
tickrange = tickrange or (-np.inf, np.inf)
|
|
381
|
+
super().__init__(**kwargs)
|
|
382
|
+
zerotrim = _not_none(zerotrim, rc["formatter.zerotrim"])
|
|
383
|
+
self._zerotrim = zerotrim
|
|
384
|
+
self._tickrange = tickrange
|
|
385
|
+
self._wraprange = wraprange
|
|
386
|
+
self._prefix = prefix or ""
|
|
387
|
+
self._suffix = suffix or ""
|
|
388
|
+
self._negpos = negpos or ""
|
|
389
|
+
|
|
390
|
+
@docstring._snippet_manager
|
|
391
|
+
def __call__(self, x, pos=None):
|
|
392
|
+
"""
|
|
393
|
+
%(ticker.call)s
|
|
394
|
+
"""
|
|
395
|
+
# Tick range limitation
|
|
396
|
+
x = self._wrap_tick_range(x, self._wraprange)
|
|
397
|
+
if self._outside_tick_range(x, self._tickrange):
|
|
398
|
+
return ""
|
|
399
|
+
|
|
400
|
+
# Negative positive handling
|
|
401
|
+
x, tail = self._neg_pos_format(x, self._negpos, wraprange=self._wraprange)
|
|
402
|
+
|
|
403
|
+
# Default string formatting
|
|
404
|
+
string = super().__call__(x, pos)
|
|
405
|
+
|
|
406
|
+
# Fix issue where non-zero string is formatted as zero
|
|
407
|
+
string = self._fix_small_number(x, string)
|
|
408
|
+
|
|
409
|
+
# Custom string formatting
|
|
410
|
+
string = self._minus_format(string)
|
|
411
|
+
if self._zerotrim:
|
|
412
|
+
string = self._trim_trailing_zeros(string, self._get_decimal_point())
|
|
413
|
+
|
|
414
|
+
# Prefix and suffix
|
|
415
|
+
string = self._add_prefix_suffix(string, self._prefix, self._suffix)
|
|
416
|
+
string = string + tail # add negative-positive indicator
|
|
417
|
+
return string
|
|
418
|
+
|
|
419
|
+
def get_offset(self):
|
|
420
|
+
"""
|
|
421
|
+
Get the offset but *always* use math text.
|
|
422
|
+
"""
|
|
423
|
+
with context._state_context(self, _useMathText=True):
|
|
424
|
+
return super().get_offset()
|
|
425
|
+
|
|
426
|
+
@staticmethod
|
|
427
|
+
def _add_prefix_suffix(string, prefix=None, suffix=None):
|
|
428
|
+
"""
|
|
429
|
+
Add prefix and suffix to string.
|
|
430
|
+
"""
|
|
431
|
+
sign = ""
|
|
432
|
+
prefix = prefix or ""
|
|
433
|
+
suffix = suffix or ""
|
|
434
|
+
if string and REGEX_MINUS.match(string[0]):
|
|
435
|
+
sign, string = string[0], string[1:]
|
|
436
|
+
return sign + prefix + string + suffix
|
|
437
|
+
|
|
438
|
+
def _fix_small_number(self, x, string, precision_offset=2):
|
|
439
|
+
"""
|
|
440
|
+
Fix formatting for non-zero formatted as zero. The `offset` controls the offset
|
|
441
|
+
from true floating point precision at which we want to limit string precision.
|
|
442
|
+
"""
|
|
443
|
+
# Add just enough precision for small numbers. Default formatter is
|
|
444
|
+
# only meant to be used for linear scales and cannot handle the wide
|
|
445
|
+
# range of magnitudes in e.g. log scales. To correct this, we only
|
|
446
|
+
# truncate if value is within `offset` order of magnitude of the float
|
|
447
|
+
# precision. Common issue is e.g. levels=pplt.arange(-1, 1, 0.1).
|
|
448
|
+
# This choice satisfies even 1000 additions of 0.1 to -100.
|
|
449
|
+
m = REGEX_ZERO.match(string)
|
|
450
|
+
decimal_point = self._get_decimal_point()
|
|
451
|
+
|
|
452
|
+
if m and x != 0:
|
|
453
|
+
# Get initial precision spit out by algorithm
|
|
454
|
+
(decimals,) = m.groups()
|
|
455
|
+
precision_init = len(decimals.lstrip(decimal_point)) if decimals else 0
|
|
456
|
+
|
|
457
|
+
# Format with precision below floating point error
|
|
458
|
+
x -= getattr(self, "offset", 0) # guard against API change
|
|
459
|
+
x /= 10 ** getattr(self, "orderOfMagnitude", 0) # guard against API change
|
|
460
|
+
precision_true = max(0, self._decimal_place(x))
|
|
461
|
+
precision_max = max(0, np.finfo(type(x)).precision - precision_offset)
|
|
462
|
+
precision = min(precision_true, precision_max)
|
|
463
|
+
string = ("{:.%df}" % precision).format(x)
|
|
464
|
+
|
|
465
|
+
# If zero ignoring floating point error then match original precision
|
|
466
|
+
if REGEX_ZERO.match(string):
|
|
467
|
+
string = ("{:.%df}" % precision_init).format(0)
|
|
468
|
+
|
|
469
|
+
# Fix decimal point
|
|
470
|
+
string = string.replace(".", decimal_point)
|
|
471
|
+
|
|
472
|
+
return string
|
|
473
|
+
|
|
474
|
+
def _get_decimal_point(self, use_locale=None):
|
|
475
|
+
"""
|
|
476
|
+
Get decimal point symbol for current locale (e.g. in Europe will be comma).
|
|
477
|
+
"""
|
|
478
|
+
use_locale = _not_none(use_locale, self.get_useLocale())
|
|
479
|
+
return self._get_default_decimal_point(use_locale)
|
|
480
|
+
|
|
481
|
+
@staticmethod
|
|
482
|
+
def _get_default_decimal_point(use_locale=None):
|
|
483
|
+
"""
|
|
484
|
+
Get decimal point symbol for current locale. Called externally.
|
|
485
|
+
"""
|
|
486
|
+
use_locale = _not_none(use_locale, rc["formatter.use_locale"])
|
|
487
|
+
return locale.localeconv()["decimal_point"] if use_locale else "."
|
|
488
|
+
|
|
489
|
+
@staticmethod
|
|
490
|
+
def _decimal_place(x):
|
|
491
|
+
"""
|
|
492
|
+
Return the decimal place of the number (e.g., 100 is -2 and 0.01 is 2).
|
|
493
|
+
"""
|
|
494
|
+
if x == 0:
|
|
495
|
+
digits = 0
|
|
496
|
+
else:
|
|
497
|
+
digits = -int(np.log10(abs(x)) // 1)
|
|
498
|
+
return digits
|
|
499
|
+
|
|
500
|
+
@staticmethod
|
|
501
|
+
def _minus_format(string):
|
|
502
|
+
"""
|
|
503
|
+
Format the minus sign and avoid "negative zero," e.g. ``-0.000``.
|
|
504
|
+
"""
|
|
505
|
+
if rc["axes.unicode_minus"] and not rc["text.usetex"]:
|
|
506
|
+
string = string.replace("-", "\N{MINUS SIGN}")
|
|
507
|
+
if REGEX_MINUS_ZERO.match(string):
|
|
508
|
+
string = string[1:]
|
|
509
|
+
return string
|
|
510
|
+
|
|
511
|
+
@staticmethod
|
|
512
|
+
def _neg_pos_format(x, negpos, wraprange=None):
|
|
513
|
+
"""
|
|
514
|
+
Permit suffixes indicators for "negative" and "positive" numbers.
|
|
515
|
+
"""
|
|
516
|
+
# NOTE: If input is a symmetric wraprange, the value conceptually has
|
|
517
|
+
# no "sign", so trim tail and format as absolute value.
|
|
518
|
+
if not negpos or x == 0:
|
|
519
|
+
tail = ""
|
|
520
|
+
elif (
|
|
521
|
+
wraprange is not None
|
|
522
|
+
and np.isclose(-wraprange[0], wraprange[1])
|
|
523
|
+
and np.any(np.isclose(x, wraprange))
|
|
524
|
+
):
|
|
525
|
+
x = abs(x)
|
|
526
|
+
tail = ""
|
|
527
|
+
elif x > 0:
|
|
528
|
+
tail = negpos[1]
|
|
529
|
+
else:
|
|
530
|
+
x *= -1
|
|
531
|
+
tail = negpos[0]
|
|
532
|
+
return x, tail
|
|
533
|
+
|
|
534
|
+
@staticmethod
|
|
535
|
+
def _outside_tick_range(x, tickrange):
|
|
536
|
+
"""
|
|
537
|
+
Return whether point is outside tick range up to some precision.
|
|
538
|
+
"""
|
|
539
|
+
eps = abs(x) / 1000
|
|
540
|
+
return (x + eps) < tickrange[0] or (x - eps) > tickrange[1]
|
|
541
|
+
|
|
542
|
+
@staticmethod
|
|
543
|
+
def _trim_trailing_zeros(string, decimal_point="."):
|
|
544
|
+
"""
|
|
545
|
+
Sanitize tick label strings.
|
|
546
|
+
"""
|
|
547
|
+
if decimal_point in string:
|
|
548
|
+
string = string.rstrip("0").rstrip(decimal_point)
|
|
549
|
+
return string
|
|
550
|
+
|
|
551
|
+
@staticmethod
|
|
552
|
+
def _wrap_tick_range(x, wraprange):
|
|
553
|
+
"""
|
|
554
|
+
Wrap the tick range to within these values.
|
|
555
|
+
"""
|
|
556
|
+
if wraprange is None:
|
|
557
|
+
return x
|
|
558
|
+
base = wraprange[0]
|
|
559
|
+
modulus = wraprange[1] - wraprange[0]
|
|
560
|
+
return (x - base) % modulus + base
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
class SimpleFormatter(mticker.Formatter):
|
|
564
|
+
"""
|
|
565
|
+
A general purpose number formatter. This is similar to `AutoFormatter`
|
|
566
|
+
but suitable for arbitrary formatting not necessarily associated with
|
|
567
|
+
an `~matplotlib.axis.Axis` instance.
|
|
568
|
+
"""
|
|
569
|
+
|
|
570
|
+
@docstring._snippet_manager
|
|
571
|
+
def __init__(
|
|
572
|
+
self,
|
|
573
|
+
precision=None,
|
|
574
|
+
zerotrim=None,
|
|
575
|
+
tickrange=None,
|
|
576
|
+
wraprange=None,
|
|
577
|
+
prefix=None,
|
|
578
|
+
suffix=None,
|
|
579
|
+
negpos=None,
|
|
580
|
+
):
|
|
581
|
+
"""
|
|
582
|
+
Parameters
|
|
583
|
+
----------
|
|
584
|
+
%(ticker.precision)s
|
|
585
|
+
%(ticker.zerotrim)s
|
|
586
|
+
%(ticker.auto)s
|
|
587
|
+
|
|
588
|
+
See also
|
|
589
|
+
--------
|
|
590
|
+
ultraplot.constructor.Formatter
|
|
591
|
+
ultraplot.ticker.AutoFormatter
|
|
592
|
+
"""
|
|
593
|
+
precision, zerotrim = _default_precision_zerotrim(precision, zerotrim)
|
|
594
|
+
self._precision = precision
|
|
595
|
+
self._prefix = prefix or ""
|
|
596
|
+
self._suffix = suffix or ""
|
|
597
|
+
self._negpos = negpos or ""
|
|
598
|
+
self._tickrange = tickrange or (-np.inf, np.inf)
|
|
599
|
+
self._wraprange = wraprange
|
|
600
|
+
self._zerotrim = zerotrim
|
|
601
|
+
|
|
602
|
+
@docstring._snippet_manager
|
|
603
|
+
def __call__(self, x, pos=None): # noqa: U100
|
|
604
|
+
"""
|
|
605
|
+
%(ticker.call)s
|
|
606
|
+
"""
|
|
607
|
+
# Tick range limitation
|
|
608
|
+
x = AutoFormatter._wrap_tick_range(x, self._wraprange)
|
|
609
|
+
if AutoFormatter._outside_tick_range(x, self._tickrange):
|
|
610
|
+
return ""
|
|
611
|
+
|
|
612
|
+
# Negative positive handling
|
|
613
|
+
x, tail = AutoFormatter._neg_pos_format(
|
|
614
|
+
x, self._negpos, wraprange=self._wraprange
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
# Default string formatting
|
|
618
|
+
decimal_point = AutoFormatter._get_default_decimal_point()
|
|
619
|
+
string = ("{:.%df}" % self._precision).format(x)
|
|
620
|
+
string = string.replace(".", decimal_point)
|
|
621
|
+
|
|
622
|
+
# Custom string formatting
|
|
623
|
+
string = AutoFormatter._minus_format(string)
|
|
624
|
+
if self._zerotrim:
|
|
625
|
+
string = AutoFormatter._trim_trailing_zeros(string, decimal_point)
|
|
626
|
+
|
|
627
|
+
# Prefix and suffix
|
|
628
|
+
string = AutoFormatter._add_prefix_suffix(string, self._prefix, self._suffix)
|
|
629
|
+
string = string + tail # add negative-positive indicator
|
|
630
|
+
return string
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
class IndexFormatter(mticker.Formatter):
|
|
634
|
+
"""
|
|
635
|
+
Format numbers by assigning fixed strings to non-negative indices. Generally
|
|
636
|
+
paired with `IndexLocator` or `~matplotlib.ticker.FixedLocator`.
|
|
637
|
+
"""
|
|
638
|
+
|
|
639
|
+
# NOTE: This was deprecated in matplotlib 3.3. For details check out
|
|
640
|
+
# https://github.com/matplotlib/matplotlib/issues/16631 and bring some popcorn.
|
|
641
|
+
def __init__(self, labels):
|
|
642
|
+
self.labels = labels
|
|
643
|
+
self.n = len(labels)
|
|
644
|
+
|
|
645
|
+
def __call__(self, x, pos=None): # noqa: U100
|
|
646
|
+
i = int(round(x))
|
|
647
|
+
if i < 0 or i >= self.n:
|
|
648
|
+
return ""
|
|
649
|
+
else:
|
|
650
|
+
return self.labels[i]
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
class SciFormatter(mticker.Formatter):
|
|
654
|
+
"""
|
|
655
|
+
Format numbers with scientific notation.
|
|
656
|
+
"""
|
|
657
|
+
|
|
658
|
+
@docstring._snippet_manager
|
|
659
|
+
def __init__(self, precision=None, zerotrim=None):
|
|
660
|
+
"""
|
|
661
|
+
Parameters
|
|
662
|
+
----------
|
|
663
|
+
%(ticker.precision)s
|
|
664
|
+
%(ticker.zerotrim)s
|
|
665
|
+
|
|
666
|
+
See also
|
|
667
|
+
--------
|
|
668
|
+
ultraplot.constructor.Formatter
|
|
669
|
+
ultraplot.ticker.AutoFormatter
|
|
670
|
+
"""
|
|
671
|
+
precision, zerotrim = _default_precision_zerotrim(precision, zerotrim)
|
|
672
|
+
self._precision = precision
|
|
673
|
+
self._zerotrim = zerotrim
|
|
674
|
+
|
|
675
|
+
@docstring._snippet_manager
|
|
676
|
+
def __call__(self, x, pos=None): # noqa: U100
|
|
677
|
+
"""
|
|
678
|
+
%(ticker.call)s
|
|
679
|
+
"""
|
|
680
|
+
# Get string
|
|
681
|
+
decimal_point = AutoFormatter._get_default_decimal_point()
|
|
682
|
+
string = ("{:.%de}" % self._precision).format(x)
|
|
683
|
+
parts = string.split("e")
|
|
684
|
+
|
|
685
|
+
# Trim trailing zeros
|
|
686
|
+
significand = parts[0].rstrip(decimal_point)
|
|
687
|
+
if self._zerotrim:
|
|
688
|
+
significand = AutoFormatter._trim_trailing_zeros(significand, decimal_point)
|
|
689
|
+
|
|
690
|
+
# Get sign and exponent
|
|
691
|
+
sign = parts[1][0].replace("+", "")
|
|
692
|
+
exponent = parts[1][1:].lstrip("0")
|
|
693
|
+
if exponent:
|
|
694
|
+
exponent = f"10^{{{sign}{exponent}}}"
|
|
695
|
+
if significand and exponent:
|
|
696
|
+
string = rf"{significand}{{\times}}{exponent}"
|
|
697
|
+
else:
|
|
698
|
+
string = rf"{significand}{exponent}"
|
|
699
|
+
|
|
700
|
+
# Ensure unicode minus sign
|
|
701
|
+
string = AutoFormatter._minus_format(string)
|
|
702
|
+
|
|
703
|
+
# Return TeX string
|
|
704
|
+
return f"${string}$"
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
class SigFigFormatter(mticker.Formatter):
|
|
708
|
+
"""
|
|
709
|
+
Format numbers by retaining the specified number of significant digits.
|
|
710
|
+
"""
|
|
711
|
+
|
|
712
|
+
@docstring._snippet_manager
|
|
713
|
+
def __init__(self, sigfig=None, zerotrim=None, base=None):
|
|
714
|
+
"""
|
|
715
|
+
Parameters
|
|
716
|
+
----------
|
|
717
|
+
sigfig : float, default: 3
|
|
718
|
+
The number of significant digits.
|
|
719
|
+
%(ticker.zerotrim)s
|
|
720
|
+
base : float, default: 1
|
|
721
|
+
The base unit for rounding. For example ``SigFigFormatter(2, base=5)``
|
|
722
|
+
rounds to the nearest 5 with up to 2 digits (e.g., 87 --> 85, 8.7 --> 8.5).
|
|
723
|
+
|
|
724
|
+
See also
|
|
725
|
+
--------
|
|
726
|
+
ultraplot.constructor.Formatter
|
|
727
|
+
ultraplot.ticker.AutoFormatter
|
|
728
|
+
"""
|
|
729
|
+
self._sigfig = _not_none(sigfig, 3)
|
|
730
|
+
self._zerotrim = _not_none(zerotrim, rc["formatter.zerotrim"])
|
|
731
|
+
self._base = _not_none(base, 1)
|
|
732
|
+
|
|
733
|
+
@docstring._snippet_manager
|
|
734
|
+
def __call__(self, x, pos=None): # noqa: U100
|
|
735
|
+
"""
|
|
736
|
+
%(ticker.call)s
|
|
737
|
+
"""
|
|
738
|
+
# Limit to significant figures
|
|
739
|
+
digits = AutoFormatter._decimal_place(x) + self._sigfig - 1
|
|
740
|
+
scale = self._base * 10**-digits
|
|
741
|
+
x = scale * round(x / scale)
|
|
742
|
+
|
|
743
|
+
# Create the string
|
|
744
|
+
decimal_point = AutoFormatter._get_default_decimal_point()
|
|
745
|
+
precision = max(0, digits) + max(0, AutoFormatter._decimal_place(self._base))
|
|
746
|
+
string = ("{:.%df}" % precision).format(x)
|
|
747
|
+
string = string.replace(".", decimal_point)
|
|
748
|
+
|
|
749
|
+
# Custom string formatting
|
|
750
|
+
string = AutoFormatter._minus_format(string)
|
|
751
|
+
if self._zerotrim:
|
|
752
|
+
string = AutoFormatter._trim_trailing_zeros(string, decimal_point)
|
|
753
|
+
return string
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
class FracFormatter(mticker.Formatter):
|
|
757
|
+
r"""
|
|
758
|
+
Format numbers as integers or integer fractions. Optionally express the
|
|
759
|
+
values relative to some constant like `numpy.pi`.
|
|
760
|
+
"""
|
|
761
|
+
|
|
762
|
+
def __init__(self, symbol="", number=1):
|
|
763
|
+
r"""
|
|
764
|
+
Parameters
|
|
765
|
+
----------
|
|
766
|
+
symbol : str, default: ''
|
|
767
|
+
The constant symbol, e.g. ``r'$\pi$'``.
|
|
768
|
+
number : float, default: 1
|
|
769
|
+
The constant value, e.g. `numpy.pi`.
|
|
770
|
+
|
|
771
|
+
Note
|
|
772
|
+
----
|
|
773
|
+
The fractions shown by this formatter are resolved using the builtin
|
|
774
|
+
`fractions.Fraction` class and `fractions.Fraction.limit_denominator`.
|
|
775
|
+
|
|
776
|
+
See also
|
|
777
|
+
--------
|
|
778
|
+
ultraplot.constructor.Formatter
|
|
779
|
+
ultraplot.ticker.AutoFormatter
|
|
780
|
+
"""
|
|
781
|
+
self._symbol = symbol
|
|
782
|
+
self._number = number
|
|
783
|
+
super().__init__()
|
|
784
|
+
|
|
785
|
+
@docstring._snippet_manager
|
|
786
|
+
def __call__(self, x, pos=None): # noqa: U100
|
|
787
|
+
"""
|
|
788
|
+
%(ticker.call)s
|
|
789
|
+
"""
|
|
790
|
+
frac = Fraction(x / self._number).limit_denominator()
|
|
791
|
+
symbol = self._symbol
|
|
792
|
+
if x == 0:
|
|
793
|
+
string = "0"
|
|
794
|
+
elif frac.denominator == 1: # denominator is one
|
|
795
|
+
if frac.numerator == 1 and symbol:
|
|
796
|
+
string = f"{symbol:s}"
|
|
797
|
+
elif frac.numerator == -1 and symbol:
|
|
798
|
+
string = f"-{symbol:s}"
|
|
799
|
+
else:
|
|
800
|
+
string = f"{frac.numerator:d}{symbol:s}"
|
|
801
|
+
else:
|
|
802
|
+
if frac.numerator == 1 and symbol: # numerator is +/-1
|
|
803
|
+
string = f"{symbol:s}/{frac.denominator:d}"
|
|
804
|
+
elif frac.numerator == -1 and symbol:
|
|
805
|
+
string = f"-{symbol:s}/{frac.denominator:d}"
|
|
806
|
+
else: # and again make sure we use unicode minus!
|
|
807
|
+
string = f"{frac.numerator:d}{symbol:s}/{frac.denominator:d}"
|
|
808
|
+
string = AutoFormatter._minus_format(string)
|
|
809
|
+
return string
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
class _CartopyFormatter(object):
|
|
813
|
+
"""
|
|
814
|
+
Mixin class for cartopy formatters.
|
|
815
|
+
"""
|
|
816
|
+
|
|
817
|
+
# NOTE: Cartopy formatters pre 0.18 required axis, and *always* translated
|
|
818
|
+
# input values from map projection coordinates to Plate Carrée coordinates.
|
|
819
|
+
# After 0.18 you can avoid this behavior by not setting axis but really
|
|
820
|
+
# dislike that inconsistency. Solution is temporarily assign PlateCarre().
|
|
821
|
+
def __init__(self, *args, **kwargs):
|
|
822
|
+
import cartopy # noqa: F401 (ensure available)
|
|
823
|
+
|
|
824
|
+
super().__init__(*args, **kwargs)
|
|
825
|
+
|
|
826
|
+
def __call__(self, value, pos=None):
|
|
827
|
+
ctx = context._empty_context()
|
|
828
|
+
if self.axis is not None:
|
|
829
|
+
ctx = context._state_context(self.axis.axes, projection=ccrs.PlateCarree())
|
|
830
|
+
with ctx:
|
|
831
|
+
return super().__call__(value, pos)
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
class DegreeFormatter(_CartopyFormatter, _PlateCarreeFormatter):
|
|
835
|
+
"""
|
|
836
|
+
Formatter for longitude and latitude gridline labels.
|
|
837
|
+
Adapted from cartopy.
|
|
838
|
+
"""
|
|
839
|
+
|
|
840
|
+
@docstring._snippet_manager
|
|
841
|
+
def __init__(self, *args, **kwargs):
|
|
842
|
+
"""
|
|
843
|
+
%(ticker.dms)s
|
|
844
|
+
"""
|
|
845
|
+
super().__init__(*args, **kwargs)
|
|
846
|
+
|
|
847
|
+
def _apply_transform(self, value, *args, **kwargs): # noqa: U100
|
|
848
|
+
return value
|
|
849
|
+
|
|
850
|
+
def _hemisphere(self, value, *args, **kwargs): # noqa: U100
|
|
851
|
+
return ""
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
class LongitudeFormatter(_CartopyFormatter, LongitudeFormatter):
|
|
855
|
+
"""
|
|
856
|
+
Format longitude gridline labels. Adapted from
|
|
857
|
+
`cartopy.mpl.ticker.LongitudeFormatter`.
|
|
858
|
+
"""
|
|
859
|
+
|
|
860
|
+
@docstring._snippet_manager
|
|
861
|
+
def __init__(self, *args, **kwargs):
|
|
862
|
+
"""
|
|
863
|
+
%(ticker.dms)s
|
|
864
|
+
"""
|
|
865
|
+
super().__init__(*args, **kwargs)
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
class LatitudeFormatter(_CartopyFormatter, LatitudeFormatter):
|
|
869
|
+
"""
|
|
870
|
+
Format latitude gridline labels. Adapted from
|
|
871
|
+
`cartopy.mpl.ticker.LatitudeFormatter`.
|
|
872
|
+
"""
|
|
873
|
+
|
|
874
|
+
@docstring._snippet_manager
|
|
875
|
+
def __init__(self, *args, **kwargs):
|
|
876
|
+
"""
|
|
877
|
+
%(ticker.dms)s
|
|
878
|
+
"""
|
|
879
|
+
super().__init__(*args, **kwargs)
|