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/constructor.py
ADDED
|
@@ -0,0 +1,1633 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
T"he constructor functions used to build class instances from simple shorthand arguments.
|
|
4
|
+
"""
|
|
5
|
+
# NOTE: These functions used to be in separate files like crs.py and
|
|
6
|
+
# ticker.py but makes more sense to group them together to ensure usage is
|
|
7
|
+
# consistent and so online documentation is easier to understand. Also in
|
|
8
|
+
# future version classes will not be imported into top-level namespace. This
|
|
9
|
+
# change will be easier to do with all constructor functions in separate file.
|
|
10
|
+
# NOTE: Used to include the raw variable names that define string keys as
|
|
11
|
+
# part of documentation, but this is redundant and pollutes the namespace.
|
|
12
|
+
# User should just inspect docstrings, use trial-error, or see online tables.
|
|
13
|
+
import copy
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
from functools import partial
|
|
17
|
+
from numbers import Number
|
|
18
|
+
|
|
19
|
+
import cycler
|
|
20
|
+
import matplotlib.colors as mcolors
|
|
21
|
+
import matplotlib.dates as mdates
|
|
22
|
+
import matplotlib.projections.polar as mpolar
|
|
23
|
+
import matplotlib.scale as mscale
|
|
24
|
+
import matplotlib.ticker as mticker
|
|
25
|
+
import numpy as np
|
|
26
|
+
|
|
27
|
+
from . import colors as pcolors
|
|
28
|
+
from . import proj as pproj
|
|
29
|
+
from . import scale as pscale
|
|
30
|
+
from . import ticker as pticker
|
|
31
|
+
from .config import rc
|
|
32
|
+
from .internals import ic # noqa: F401
|
|
33
|
+
from .internals import _not_none, _pop_props, _version_cartopy, _version_mpl, warnings
|
|
34
|
+
from .utils import get_colors, to_hex, to_rgba
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from mpl_toolkits.basemap import Basemap
|
|
38
|
+
except ImportError:
|
|
39
|
+
Basemap = object
|
|
40
|
+
try:
|
|
41
|
+
import cartopy.crs as ccrs
|
|
42
|
+
from cartopy.crs import Projection
|
|
43
|
+
except ModuleNotFoundError:
|
|
44
|
+
ccrs = None
|
|
45
|
+
Projection = object
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"Proj",
|
|
49
|
+
"Locator",
|
|
50
|
+
"Formatter",
|
|
51
|
+
"Scale",
|
|
52
|
+
"Colormap",
|
|
53
|
+
"Norm",
|
|
54
|
+
"Cycle",
|
|
55
|
+
"Colors", # deprecated
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
# Color cycle constants
|
|
59
|
+
# TODO: Also automatically truncate the 'bright' end of colormaps
|
|
60
|
+
# when building color cycles from colormaps? Or add simple option.
|
|
61
|
+
DEFAULT_CYCLE_SAMPLES = 10
|
|
62
|
+
DEFAULT_CYCLE_LUMINANCE = 90
|
|
63
|
+
|
|
64
|
+
# Normalizer registry
|
|
65
|
+
NORMS = {
|
|
66
|
+
"none": mcolors.NoNorm,
|
|
67
|
+
"null": mcolors.NoNorm,
|
|
68
|
+
"div": pcolors.DivergingNorm,
|
|
69
|
+
"diverging": pcolors.DivergingNorm,
|
|
70
|
+
"segmented": pcolors.SegmentedNorm,
|
|
71
|
+
"segments": pcolors.SegmentedNorm,
|
|
72
|
+
"log": mcolors.LogNorm,
|
|
73
|
+
"linear": mcolors.Normalize,
|
|
74
|
+
"power": mcolors.PowerNorm,
|
|
75
|
+
"symlog": mcolors.SymLogNorm,
|
|
76
|
+
}
|
|
77
|
+
if hasattr(mcolors, "TwoSlopeNorm"):
|
|
78
|
+
NORMS["twoslope"] = mcolors.TwoSlopeNorm
|
|
79
|
+
|
|
80
|
+
# Locator registry
|
|
81
|
+
# NOTE: Will raise error when you try to use degree-minute-second
|
|
82
|
+
# locators with cartopy < 0.18.
|
|
83
|
+
LOCATORS = {
|
|
84
|
+
"none": mticker.NullLocator,
|
|
85
|
+
"null": mticker.NullLocator,
|
|
86
|
+
"auto": mticker.AutoLocator,
|
|
87
|
+
"log": mticker.LogLocator,
|
|
88
|
+
"maxn": mticker.MaxNLocator,
|
|
89
|
+
"linear": mticker.LinearLocator,
|
|
90
|
+
"multiple": mticker.MultipleLocator,
|
|
91
|
+
"fixed": mticker.FixedLocator,
|
|
92
|
+
"index": pticker.IndexLocator,
|
|
93
|
+
"discrete": pticker.DiscreteLocator,
|
|
94
|
+
"discreteminor": partial(pticker.DiscreteLocator, minor=True),
|
|
95
|
+
"symlog": mticker.SymmetricalLogLocator,
|
|
96
|
+
"logit": mticker.LogitLocator,
|
|
97
|
+
"minor": mticker.AutoMinorLocator,
|
|
98
|
+
"date": mdates.AutoDateLocator,
|
|
99
|
+
"microsecond": mdates.MicrosecondLocator,
|
|
100
|
+
"second": mdates.SecondLocator,
|
|
101
|
+
"minute": mdates.MinuteLocator,
|
|
102
|
+
"hour": mdates.HourLocator,
|
|
103
|
+
"day": mdates.DayLocator,
|
|
104
|
+
"weekday": mdates.WeekdayLocator,
|
|
105
|
+
"month": mdates.MonthLocator,
|
|
106
|
+
"year": mdates.YearLocator,
|
|
107
|
+
"lon": partial(pticker.LongitudeLocator, dms=False),
|
|
108
|
+
"lat": partial(pticker.LatitudeLocator, dms=False),
|
|
109
|
+
"deglon": partial(pticker.LongitudeLocator, dms=False),
|
|
110
|
+
"deglat": partial(pticker.LatitudeLocator, dms=False),
|
|
111
|
+
}
|
|
112
|
+
if hasattr(mpolar, "ThetaLocator"):
|
|
113
|
+
LOCATORS["theta"] = mpolar.ThetaLocator
|
|
114
|
+
if _version_cartopy >= "0.18":
|
|
115
|
+
LOCATORS["dms"] = partial(pticker.DegreeLocator, dms=True)
|
|
116
|
+
LOCATORS["dmslon"] = partial(pticker.LongitudeLocator, dms=True)
|
|
117
|
+
LOCATORS["dmslat"] = partial(pticker.LatitudeLocator, dms=True)
|
|
118
|
+
|
|
119
|
+
# Formatter registry
|
|
120
|
+
# NOTE: Critical to use SimpleFormatter for cardinal formatters rather than
|
|
121
|
+
# AutoFormatter because latter fails with Basemap formatting.
|
|
122
|
+
# NOTE: Define cartopy longitude/latitude formatters with dms=True because that
|
|
123
|
+
# is their distinguishing feature relative to ultraplot formatter.
|
|
124
|
+
# NOTE: Will raise error when you try to use degree-minute-second
|
|
125
|
+
# formatters with cartopy < 0.18.
|
|
126
|
+
FORMATTERS = { # note default LogFormatter uses ugly e+00 notation
|
|
127
|
+
"none": mticker.NullFormatter,
|
|
128
|
+
"null": mticker.NullFormatter,
|
|
129
|
+
"auto": pticker.AutoFormatter,
|
|
130
|
+
"date": mdates.AutoDateFormatter,
|
|
131
|
+
"scalar": mticker.ScalarFormatter,
|
|
132
|
+
"simple": pticker.SimpleFormatter,
|
|
133
|
+
"fixed": mticker.FixedLocator,
|
|
134
|
+
"index": pticker.IndexFormatter,
|
|
135
|
+
"sci": pticker.SciFormatter,
|
|
136
|
+
"sigfig": pticker.SigFigFormatter,
|
|
137
|
+
"frac": pticker.FracFormatter,
|
|
138
|
+
"func": mticker.FuncFormatter,
|
|
139
|
+
"strmethod": mticker.StrMethodFormatter,
|
|
140
|
+
"formatstr": mticker.FormatStrFormatter,
|
|
141
|
+
"datestr": mdates.DateFormatter,
|
|
142
|
+
"log": mticker.LogFormatterSciNotation, # NOTE: this is subclass of Mathtext class
|
|
143
|
+
"logit": mticker.LogitFormatter,
|
|
144
|
+
"eng": mticker.EngFormatter,
|
|
145
|
+
"percent": mticker.PercentFormatter,
|
|
146
|
+
"e": partial(pticker.FracFormatter, symbol=r"$e$", number=np.e),
|
|
147
|
+
"pi": partial(pticker.FracFormatter, symbol=r"$\pi$", number=np.pi),
|
|
148
|
+
"tau": partial(pticker.FracFormatter, symbol=r"$\tau$", number=2 * np.pi),
|
|
149
|
+
"lat": partial(pticker.SimpleFormatter, negpos="SN"),
|
|
150
|
+
"lon": partial(pticker.SimpleFormatter, negpos="WE", wraprange=(-180, 180)),
|
|
151
|
+
"deg": partial(pticker.SimpleFormatter, suffix="\N{DEGREE SIGN}"),
|
|
152
|
+
"deglat": partial(pticker.SimpleFormatter, suffix="\N{DEGREE SIGN}", negpos="SN"),
|
|
153
|
+
"deglon": partial(
|
|
154
|
+
pticker.SimpleFormatter,
|
|
155
|
+
suffix="\N{DEGREE SIGN}",
|
|
156
|
+
negpos="WE",
|
|
157
|
+
wraprange=(-180, 180),
|
|
158
|
+
), # noqa: E501
|
|
159
|
+
"math": mticker.LogFormatterMathtext, # deprecated (use SciNotation subclass)
|
|
160
|
+
}
|
|
161
|
+
if hasattr(mpolar, "ThetaFormatter"):
|
|
162
|
+
FORMATTERS["theta"] = mpolar.ThetaFormatter
|
|
163
|
+
if hasattr(mdates, "ConciseDateFormatter"):
|
|
164
|
+
FORMATTERS["concise"] = mdates.ConciseDateFormatter
|
|
165
|
+
if _version_cartopy >= "0.18":
|
|
166
|
+
FORMATTERS["dms"] = partial(pticker.DegreeFormatter, dms=True)
|
|
167
|
+
FORMATTERS["dmslon"] = partial(pticker.LongitudeFormatter, dms=True)
|
|
168
|
+
FORMATTERS["dmslat"] = partial(pticker.LatitudeFormatter, dms=True)
|
|
169
|
+
|
|
170
|
+
# Scale registry and presets
|
|
171
|
+
SCALES = mscale._scale_mapping
|
|
172
|
+
SCALES_PRESETS = {
|
|
173
|
+
"quadratic": (
|
|
174
|
+
"power",
|
|
175
|
+
2,
|
|
176
|
+
),
|
|
177
|
+
"cubic": (
|
|
178
|
+
"power",
|
|
179
|
+
3,
|
|
180
|
+
),
|
|
181
|
+
"quartic": (
|
|
182
|
+
"power",
|
|
183
|
+
4,
|
|
184
|
+
),
|
|
185
|
+
"height": ("exp", np.e, -1 / 7, 1013.25, True),
|
|
186
|
+
"pressure": ("exp", np.e, -1 / 7, 1013.25, False),
|
|
187
|
+
"db": ("exp", 10, 1, 0.1, True),
|
|
188
|
+
"idb": ("exp", 10, 1, 0.1, False),
|
|
189
|
+
"np": ("exp", np.e, 1, 1, True),
|
|
190
|
+
"inp": ("exp", np.e, 1, 1, False),
|
|
191
|
+
}
|
|
192
|
+
mscale.register_scale(pscale.CutoffScale)
|
|
193
|
+
mscale.register_scale(pscale.ExpScale)
|
|
194
|
+
mscale.register_scale(pscale.FuncScale)
|
|
195
|
+
mscale.register_scale(pscale.InverseScale)
|
|
196
|
+
mscale.register_scale(pscale.LogScale)
|
|
197
|
+
mscale.register_scale(pscale.LinearScale)
|
|
198
|
+
mscale.register_scale(pscale.LogitScale)
|
|
199
|
+
mscale.register_scale(pscale.MercatorLatitudeScale)
|
|
200
|
+
mscale.register_scale(pscale.PowerScale)
|
|
201
|
+
mscale.register_scale(pscale.SineLatitudeScale)
|
|
202
|
+
mscale.register_scale(pscale.SymmetricalLogScale)
|
|
203
|
+
|
|
204
|
+
# Cartopy projection registry and basemap default keyword args
|
|
205
|
+
# NOTE: Normally basemap raises error if you omit keyword args
|
|
206
|
+
PROJ_DEFAULTS = {
|
|
207
|
+
"geos": {"lon_0": 0},
|
|
208
|
+
"eck4": {"lon_0": 0},
|
|
209
|
+
"moll": {"lon_0": 0},
|
|
210
|
+
"hammer": {"lon_0": 0},
|
|
211
|
+
"kav7": {"lon_0": 0},
|
|
212
|
+
"sinu": {"lon_0": 0},
|
|
213
|
+
"vandg": {"lon_0": 0},
|
|
214
|
+
"mbtfpq": {"lon_0": 0},
|
|
215
|
+
"robin": {"lon_0": 0},
|
|
216
|
+
"ortho": {"lon_0": 0, "lat_0": 0},
|
|
217
|
+
"nsper": {"lon_0": 0, "lat_0": 0},
|
|
218
|
+
"aea": {"lon_0": 0, "lat_0": 90, "width": 15000e3, "height": 15000e3},
|
|
219
|
+
"eqdc": {"lon_0": 0, "lat_0": 90, "width": 15000e3, "height": 15000e3},
|
|
220
|
+
"cass": {"lon_0": 0, "lat_0": 90, "width": 15000e3, "height": 15000e3},
|
|
221
|
+
"gnom": {"lon_0": 0, "lat_0": 90, "width": 15000e3, "height": 15000e3},
|
|
222
|
+
"poly": {"lon_0": 0, "lat_0": 0, "width": 10000e3, "height": 10000e3},
|
|
223
|
+
"npaeqd": {"lon_0": 0, "boundinglat": 10}, # NOTE: everything breaks if you
|
|
224
|
+
"nplaea": {"lon_0": 0, "boundinglat": 10}, # try to set boundinglat to zero
|
|
225
|
+
"npstere": {"lon_0": 0, "boundinglat": 10},
|
|
226
|
+
"spaeqd": {"lon_0": 0, "boundinglat": -10},
|
|
227
|
+
"splaea": {"lon_0": 0, "boundinglat": -10},
|
|
228
|
+
"spstere": {"lon_0": 0, "boundinglat": -10},
|
|
229
|
+
"lcc": {
|
|
230
|
+
"lon_0": 0,
|
|
231
|
+
"lat_0": 40,
|
|
232
|
+
"lat_1": 35,
|
|
233
|
+
"lat_2": 45, # use cartopy defaults
|
|
234
|
+
"width": 20000e3,
|
|
235
|
+
"height": 15000e3,
|
|
236
|
+
},
|
|
237
|
+
"tmerc": {"lon_0": 0, "lat_0": 0, "width": 10000e3, "height": 10000e3},
|
|
238
|
+
"merc": {"llcrnrlat": -80, "urcrnrlat": 84, "llcrnrlon": -180, "urcrnrlon": 180},
|
|
239
|
+
"omerc": {
|
|
240
|
+
"lat_0": 0,
|
|
241
|
+
"lon_0": 0,
|
|
242
|
+
"lat_1": -10,
|
|
243
|
+
"lat_2": 10,
|
|
244
|
+
"lon_1": 0,
|
|
245
|
+
"lon_2": 0,
|
|
246
|
+
"width": 10000e3,
|
|
247
|
+
"height": 10000e3,
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
if ccrs is None:
|
|
251
|
+
PROJS = {}
|
|
252
|
+
else:
|
|
253
|
+
PROJS = {
|
|
254
|
+
"aitoff": pproj.Aitoff,
|
|
255
|
+
"hammer": pproj.Hammer,
|
|
256
|
+
"kav7": pproj.KavrayskiyVII,
|
|
257
|
+
"wintri": pproj.WinkelTripel,
|
|
258
|
+
"npgnom": pproj.NorthPolarGnomonic,
|
|
259
|
+
"spgnom": pproj.SouthPolarGnomonic,
|
|
260
|
+
"npaeqd": pproj.NorthPolarAzimuthalEquidistant,
|
|
261
|
+
"spaeqd": pproj.SouthPolarAzimuthalEquidistant,
|
|
262
|
+
"nplaea": pproj.NorthPolarLambertAzimuthalEqualArea,
|
|
263
|
+
"splaea": pproj.SouthPolarLambertAzimuthalEqualArea,
|
|
264
|
+
}
|
|
265
|
+
PROJS_MISSING = {
|
|
266
|
+
"aea": "AlbersEqualArea",
|
|
267
|
+
"aeqd": "AzimuthalEquidistant",
|
|
268
|
+
"cyl": "PlateCarree", # only basemap name not matching PROJ
|
|
269
|
+
"eck1": "EckertI",
|
|
270
|
+
"eck2": "EckertII",
|
|
271
|
+
"eck3": "EckertIII",
|
|
272
|
+
"eck4": "EckertIV",
|
|
273
|
+
"eck5": "EckertV",
|
|
274
|
+
"eck6": "EckertVI",
|
|
275
|
+
"eqc": "PlateCarree", # actual PROJ name
|
|
276
|
+
"eqdc": "EquidistantConic",
|
|
277
|
+
"eqearth": "EqualEarth", # better looking Robinson; not in basemap
|
|
278
|
+
"euro": "EuroPP", # Europe; not in basemap or PROJ
|
|
279
|
+
"geos": "Geostationary",
|
|
280
|
+
"gnom": "Gnomonic",
|
|
281
|
+
"igh": "InterruptedGoodeHomolosine", # not in basemap
|
|
282
|
+
"laea": "LambertAzimuthalEqualArea",
|
|
283
|
+
"lcc": "LambertConformal",
|
|
284
|
+
"lcyl": "LambertCylindrical", # not in basemap or PROJ
|
|
285
|
+
"merc": "Mercator",
|
|
286
|
+
"mill": "Miller",
|
|
287
|
+
"moll": "Mollweide",
|
|
288
|
+
"npstere": "NorthPolarStereo", # np/sp stuff not in PROJ
|
|
289
|
+
"nsper": "NearsidePerspective",
|
|
290
|
+
"ortho": "Orthographic",
|
|
291
|
+
"osgb": "OSGB", # UK; not in basemap or PROJ
|
|
292
|
+
"osni": "OSNI", # Ireland; not in basemap or PROJ
|
|
293
|
+
"pcarree": "PlateCarree", # common alternate name
|
|
294
|
+
"robin": "Robinson",
|
|
295
|
+
"rotpole": "RotatedPole",
|
|
296
|
+
"sinu": "Sinusoidal",
|
|
297
|
+
"spstere": "SouthPolarStereo",
|
|
298
|
+
"stere": "Stereographic",
|
|
299
|
+
"tmerc": "TransverseMercator",
|
|
300
|
+
"utm": "UTM", # not in basemap
|
|
301
|
+
}
|
|
302
|
+
for _key, _cls in tuple(PROJS_MISSING.items()):
|
|
303
|
+
if hasattr(ccrs, _cls):
|
|
304
|
+
PROJS[_key] = getattr(ccrs, _cls)
|
|
305
|
+
del PROJS_MISSING[_key]
|
|
306
|
+
if PROJS_MISSING:
|
|
307
|
+
warnings._warn_ultraplot(
|
|
308
|
+
"The following cartopy projection(s) are unavailable: "
|
|
309
|
+
+ ", ".join(map(repr, PROJS_MISSING))
|
|
310
|
+
+ " . Please consider updating cartopy."
|
|
311
|
+
)
|
|
312
|
+
PROJS_TABLE = "The known cartopy projection classes are:\n" + "\n".join(
|
|
313
|
+
" " + key + " " * (max(map(len, PROJS)) - len(key) + 10) + cls.__name__
|
|
314
|
+
for key, cls in PROJS.items()
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# Geographic feature properties
|
|
318
|
+
FEATURES_CARTOPY = { # positional arguments passed to NaturalEarthFeature
|
|
319
|
+
"land": ("physical", "land"),
|
|
320
|
+
"ocean": ("physical", "ocean"),
|
|
321
|
+
"lakes": ("physical", "lakes"),
|
|
322
|
+
"coast": ("physical", "coastline"),
|
|
323
|
+
"rivers": ("physical", "rivers_lake_centerlines"),
|
|
324
|
+
"borders": ("cultural", "admin_0_boundary_lines_land"),
|
|
325
|
+
"innerborders": ("cultural", "admin_1_states_provinces_lakes"),
|
|
326
|
+
}
|
|
327
|
+
FEATURES_BASEMAP = { # names of relevant basemap methods
|
|
328
|
+
"land": "fillcontinents",
|
|
329
|
+
"coast": "drawcoastlines",
|
|
330
|
+
"rivers": "drawrivers",
|
|
331
|
+
"borders": "drawcountries",
|
|
332
|
+
"innerborders": "drawstates",
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# Resolution names
|
|
336
|
+
# NOTE: Maximum basemap resolutions are much finer than cartopy
|
|
337
|
+
RESOS_CARTOPY = {
|
|
338
|
+
"lo": "110m",
|
|
339
|
+
"med": "50m",
|
|
340
|
+
"hi": "10m",
|
|
341
|
+
"x-hi": "10m", # extra high
|
|
342
|
+
"xx-hi": "10m", # extra extra high
|
|
343
|
+
}
|
|
344
|
+
RESOS_BASEMAP = {
|
|
345
|
+
"lo": "c", # coarse
|
|
346
|
+
"med": "l",
|
|
347
|
+
"hi": "i", # intermediate
|
|
348
|
+
"x-hi": "h",
|
|
349
|
+
"xx-hi": "f", # fine
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _modify_colormap(cmap, *, cut, left, right, reverse, shift, alpha, samples):
|
|
354
|
+
"""
|
|
355
|
+
Modify colormap using a variety of methods.
|
|
356
|
+
"""
|
|
357
|
+
if cut is not None or left is not None or right is not None:
|
|
358
|
+
if isinstance(cmap, pcolors.DiscreteColormap):
|
|
359
|
+
if cut is not None:
|
|
360
|
+
warnings._warn_ultraplot(
|
|
361
|
+
"Invalid argument 'cut' for ListedColormap. Ignoring."
|
|
362
|
+
)
|
|
363
|
+
cmap = cmap.truncate(left=left, right=right)
|
|
364
|
+
else:
|
|
365
|
+
cmap = cmap.cut(cut, left=left, right=right)
|
|
366
|
+
if reverse:
|
|
367
|
+
cmap = cmap.reversed()
|
|
368
|
+
if shift is not None:
|
|
369
|
+
cmap = cmap.shifted(shift)
|
|
370
|
+
if alpha is not None:
|
|
371
|
+
cmap = cmap.copy(alpha=alpha)
|
|
372
|
+
if samples is not None:
|
|
373
|
+
if isinstance(cmap, pcolors.DiscreteColormap):
|
|
374
|
+
cmap = cmap.copy(N=samples)
|
|
375
|
+
else:
|
|
376
|
+
cmap = cmap.to_discrete(samples)
|
|
377
|
+
return cmap
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
@warnings._rename_kwargs(
|
|
381
|
+
"0.8.0", fade="saturation", shade="luminance", to_listed="discrete"
|
|
382
|
+
)
|
|
383
|
+
def Colormap(
|
|
384
|
+
*args,
|
|
385
|
+
name=None,
|
|
386
|
+
listmode="perceptual",
|
|
387
|
+
filemode="continuous",
|
|
388
|
+
discrete=False,
|
|
389
|
+
cycle=None,
|
|
390
|
+
save=False,
|
|
391
|
+
save_kw=None,
|
|
392
|
+
**kwargs,
|
|
393
|
+
):
|
|
394
|
+
"""
|
|
395
|
+
Generate, retrieve, modify, and/or merge instances of
|
|
396
|
+
`~ultraplot.colors.PerceptualColormap`,
|
|
397
|
+
`~ultraplot.colors.ContinuousColormap`, and
|
|
398
|
+
`~ultraplot.colors.DiscreteColormap`.
|
|
399
|
+
|
|
400
|
+
Parameters
|
|
401
|
+
----------
|
|
402
|
+
*args : colormap-spec
|
|
403
|
+
Positional arguments that individually generate colormaps. If more
|
|
404
|
+
than one argument is passed, the resulting colormaps are *merged* with
|
|
405
|
+
`~ultraplot.colors.ContinuousColormap.append`
|
|
406
|
+
or `~ultraplot.colors.DiscreteColormap.append`.
|
|
407
|
+
The arguments are interpreted as follows:
|
|
408
|
+
|
|
409
|
+
* If a registered colormap name, that colormap instance is looked up.
|
|
410
|
+
If colormap instance is a native matplotlib colormap class, it is
|
|
411
|
+
converted to a ultraplot colormap class.
|
|
412
|
+
* If a filename string with valid extension, the colormap data
|
|
413
|
+
is loaded with `ultraplot.colors.ContinuousColormap.from_file` or
|
|
414
|
+
`ultraplot.colors.DiscreteColormap.from_file` depending on the value of
|
|
415
|
+
`filemode` (see below). Default behavior is to load a
|
|
416
|
+
`~ultraplot.colors.ContinuousColormap`.
|
|
417
|
+
* If RGB tuple or color string, a `~ultraplot.colors.PerceptualColormap`
|
|
418
|
+
is generated with `~ultraplot.colors.PerceptualColormap.from_color`.
|
|
419
|
+
If the string ends in ``'_r'``, the monochromatic map will be
|
|
420
|
+
*reversed*, i.e. will go from dark to light instead of light to dark.
|
|
421
|
+
* If sequence of RGB tuples or color strings, a
|
|
422
|
+
`~ultraplot.colors.DiscreteColormap`, `~ultraplot.colors.PerceptualColormap`,
|
|
423
|
+
or `~ultraplot.colors.ContinuousColormap` is generated depending on
|
|
424
|
+
the value of `listmode` (see below). Default behavior is to generate a
|
|
425
|
+
`~ultraplot.colors.PerceptualColormap`.
|
|
426
|
+
* If dictionary, a `~ultraplot.colors.PerceptualColormap` is
|
|
427
|
+
generated with `~ultraplot.colors.PerceptualColormap.from_hsl`.
|
|
428
|
+
The dictionary should contain the keys ``'hue'``, ``'saturation'``,
|
|
429
|
+
``'luminance'``, and optionally ``'alpha'``, or their aliases (see below).
|
|
430
|
+
|
|
431
|
+
name : str, optional
|
|
432
|
+
Name under which the final colormap is registered. It can
|
|
433
|
+
then be reused by passing ``cmap='name'`` to plotting
|
|
434
|
+
functions. Names with leading underscores are ignored.
|
|
435
|
+
filemode : {'perceptual', 'continuous', 'discrete'}, optional
|
|
436
|
+
Controls how colormaps are generated when you input list(s) of colors.
|
|
437
|
+
The options are as follows:
|
|
438
|
+
|
|
439
|
+
* If ``'perceptual'`` or ``'continuous'``, a colormap is generated using
|
|
440
|
+
`~ultraplot.colors.ContinuousColormap.from_file`. The resulting
|
|
441
|
+
colormap may be a `~ultraplot.colors.ContinuousColormap` or
|
|
442
|
+
`~ultraplot.colors.PerceptualColormap` depending on the data file.
|
|
443
|
+
* If ``'discrete'``, a `~ultraplot.colors.DiscreteColormap` is generated
|
|
444
|
+
using `~ultraplot.colors.ContinuousColormap.from_file`.
|
|
445
|
+
|
|
446
|
+
Default is ``'continuous'`` when calling `Colormap` directly and
|
|
447
|
+
``'discrete'`` when `Colormap` is called by `Cycle`.
|
|
448
|
+
listmode : {'perceptual', 'continuous', 'discrete'}, optional
|
|
449
|
+
Controls how colormaps are generated when you input sequence(s)
|
|
450
|
+
of colors. The options are as follows:
|
|
451
|
+
|
|
452
|
+
* If ``'perceptual'``, a `~ultraplot.colors.PerceptualColormap`
|
|
453
|
+
is generated with `~ultraplot.colors.PerceptualColormap.from_list`.
|
|
454
|
+
* If ``'continuous'``, a `~ultraplot.colors.ContinuousColormap` is
|
|
455
|
+
generated with `~ultraplot.colors.ContinuousColormap.from_list`.
|
|
456
|
+
* If ``'discrete'``, a `~ultraplot.colors.DiscreteColormap` is generated
|
|
457
|
+
by simply passing the colors to the class.
|
|
458
|
+
|
|
459
|
+
Default is ``'perceptual'`` when calling `Colormap` directly and
|
|
460
|
+
``'discrete'`` when `Colormap` is called by `Cycle`.
|
|
461
|
+
samples : int or sequence of int, optional
|
|
462
|
+
For `~ultraplot.colors.ContinuousColormap`\\ s, this is used to
|
|
463
|
+
generate `~ultraplot.colors.DiscreteColormap`\\ s with
|
|
464
|
+
`~ultraplot.colors.ContinuousColormap.to_discrete`. For
|
|
465
|
+
`~ultraplot.colors.DiscreteColormap`\\ s, this is used to updates the
|
|
466
|
+
number of colors in the cycle. If `samples` is integer, it applies
|
|
467
|
+
to the final *merged* colormap. If it is a sequence of integers,
|
|
468
|
+
it applies to each input colormap individually.
|
|
469
|
+
discrete : bool, optional
|
|
470
|
+
If ``True``, when the final colormap is a
|
|
471
|
+
`~ultraplot.colors.DiscreteColormap`, we leave it alone, but when it is a
|
|
472
|
+
`~ultraplot.colors.ContinuousColormap`, we always call
|
|
473
|
+
`~ultraplot.colors.ContinuousColormap.to_discrete` with a
|
|
474
|
+
default `samples` value of ``10``. This argument is not
|
|
475
|
+
necessary if you provide the `samples` argument.
|
|
476
|
+
left, right : float or sequence of float, optional
|
|
477
|
+
Truncate the left or right edges of the colormap.
|
|
478
|
+
Passed to `~ultraplot.colors.ContinuousColormap.truncate`.
|
|
479
|
+
If float, these apply to the final *merged* colormap. If sequence
|
|
480
|
+
of float, these apply to each input colormap individually.
|
|
481
|
+
cut : float or sequence of float, optional
|
|
482
|
+
Cut out the center of the colormap. Passed to
|
|
483
|
+
`~ultraplot.colors.ContinuousColormap.cut`. If float,
|
|
484
|
+
this applies to the final *merged* colormap. If sequence of
|
|
485
|
+
float, these apply to each input colormap individually.
|
|
486
|
+
reverse : bool or sequence of bool, optional
|
|
487
|
+
Reverse the colormap. Passed to
|
|
488
|
+
`~ultraplot.colors.ContinuousColormap.reversed`. If
|
|
489
|
+
float, this applies to the final *merged* colormap. If
|
|
490
|
+
sequence of float, these apply to each input colormap individually.
|
|
491
|
+
shift : float or sequence of float, optional
|
|
492
|
+
Cyclically shift the colormap.
|
|
493
|
+
Passed to `~ultraplot.colors.ContinuousColormap.shifted`.
|
|
494
|
+
If float, this applies to the final *merged* colormap. If sequence
|
|
495
|
+
of float, these apply to each input colormap individually.
|
|
496
|
+
a
|
|
497
|
+
Shorthand for `alpha`.
|
|
498
|
+
alpha : float or color-spec or sequence, optional
|
|
499
|
+
The opacity of the colormap or the opacity gradation. Passed to
|
|
500
|
+
`ultraplot.colors.ContinuousColormap.set_alpha`
|
|
501
|
+
or `ultraplot.colors.DiscreteColormap.set_alpha`. If float, this applies
|
|
502
|
+
to the final *merged* colormap. If sequence of float, these apply to
|
|
503
|
+
each colormap individually.
|
|
504
|
+
h, s, l, c
|
|
505
|
+
Shorthands for `hue`, `luminance`, `saturation`, and `chroma`.
|
|
506
|
+
hue, saturation, luminance : float or color-spec or sequence, optional
|
|
507
|
+
The channel value(s) used to generate colormaps with
|
|
508
|
+
`~ultraplot.colors.PerceptualColormap.from_hsl` and
|
|
509
|
+
`~ultraplot.colors.PerceptualColormap.from_color`.
|
|
510
|
+
|
|
511
|
+
* If you provided no positional arguments, these are used to create
|
|
512
|
+
an arbitrary perceptually uniform colormap with
|
|
513
|
+
`~ultraplot.colors.PerceptualColormap.from_hsl`. This
|
|
514
|
+
is an alternative to passing a dictionary as a positional argument
|
|
515
|
+
with `hue`, `saturation`, and `luminance` as dictionary keys (see `args`).
|
|
516
|
+
* If you did provide positional arguments, and any of them are
|
|
517
|
+
color specifications, these control the look of monochromatic colormaps
|
|
518
|
+
generated with `~ultraplot.colors.PerceptualColormap.from_color`.
|
|
519
|
+
To use different values for each colormap, pass a sequence of floats
|
|
520
|
+
instead of a single float. Note the default `luminance` is ``90`` if
|
|
521
|
+
`discrete` is ``True`` and ``100`` otherwise.
|
|
522
|
+
|
|
523
|
+
chroma
|
|
524
|
+
Alias for `saturation`.
|
|
525
|
+
cycle : str, optional
|
|
526
|
+
The registered cycle name used to interpret color strings like ``'C0'``
|
|
527
|
+
and ``'C2'``. Default is from the active property :rcraw:`cycle`. This lets
|
|
528
|
+
you make monochromatic colormaps using colors selected from arbitrary cycles.
|
|
529
|
+
save : bool, optional
|
|
530
|
+
Whether to call the colormap/color cycle save method, i.e.
|
|
531
|
+
`ultraplot.colors.ContinuousColormap.save` or
|
|
532
|
+
`ultraplot.colors.DiscreteColormap.save`.
|
|
533
|
+
save_kw : dict-like, optional
|
|
534
|
+
Ignored if `save` is ``False``. Passed to the colormap/color cycle
|
|
535
|
+
save method, i.e. `ultraplot.colors.ContinuousColormap.save` or
|
|
536
|
+
`ultraplot.colors.DiscreteColormap.save`.
|
|
537
|
+
|
|
538
|
+
Other parameters
|
|
539
|
+
----------------
|
|
540
|
+
**kwargs
|
|
541
|
+
Passed to `ultraplot.colors.ContinuousColormap.copy`,
|
|
542
|
+
`ultraplot.colors.PerceptualColormap.copy`, or
|
|
543
|
+
`ultraplot.colors.DiscreteColormap.copy`.
|
|
544
|
+
|
|
545
|
+
Returns
|
|
546
|
+
-------
|
|
547
|
+
matplotlib.colors.Colormap
|
|
548
|
+
A `~ultraplot.colors.ContinuousColormap` or
|
|
549
|
+
`~ultraplot.colors.DiscreteColormap` instance.
|
|
550
|
+
|
|
551
|
+
See also
|
|
552
|
+
--------
|
|
553
|
+
matplotlib.colors.Colormap
|
|
554
|
+
matplotlib.colors.LinearSegmentedColormap
|
|
555
|
+
matplotlib.colors.ListedColormap
|
|
556
|
+
ultraplot.constructor.Norm
|
|
557
|
+
ultraplot.constructor.Cycle
|
|
558
|
+
ultraplot.utils.get_colors
|
|
559
|
+
"""
|
|
560
|
+
|
|
561
|
+
# Helper function
|
|
562
|
+
# NOTE: Very careful here! Try to support common use cases. For example
|
|
563
|
+
# adding opacity gradations to colormaps with Colormap('cmap', alpha=(0.5, 1))
|
|
564
|
+
# or sampling maps with Colormap('cmap', samples=np.linspace(0, 1, 11)) should
|
|
565
|
+
# be allowable.
|
|
566
|
+
# If *args is singleton try to preserve it.
|
|
567
|
+
def _pop_modification(key):
|
|
568
|
+
value = kwargs.pop(key, None)
|
|
569
|
+
if not np.iterable(value) or isinstance(value, str):
|
|
570
|
+
values = (None,) * len(args)
|
|
571
|
+
elif len(args) == len(value):
|
|
572
|
+
values, value = tuple(value), None
|
|
573
|
+
elif len(args) == 1: # e.g. Colormap('cmap', alpha=(0.5, 1))
|
|
574
|
+
values = (None,)
|
|
575
|
+
else:
|
|
576
|
+
raise ValueError(
|
|
577
|
+
f"Got {len(args)} colormap-specs "
|
|
578
|
+
f"but {len(value)} values for {key!r}."
|
|
579
|
+
)
|
|
580
|
+
return value, values
|
|
581
|
+
|
|
582
|
+
# Parse keyword args that can apply to the merged colormap or each one
|
|
583
|
+
hsla = _pop_props(kwargs, "hsla")
|
|
584
|
+
if not args and hsla.keys() - {"alpha"}:
|
|
585
|
+
args = (hsla,)
|
|
586
|
+
else:
|
|
587
|
+
kwargs.update(hsla)
|
|
588
|
+
default_luminance = kwargs.pop("default_luminance", None) # used internally
|
|
589
|
+
cut, cuts = _pop_modification("cut")
|
|
590
|
+
left, lefts = _pop_modification("left")
|
|
591
|
+
right, rights = _pop_modification("right")
|
|
592
|
+
shift, shifts = _pop_modification("shift")
|
|
593
|
+
reverse, reverses = _pop_modification("reverse")
|
|
594
|
+
samples, sampless = _pop_modification("samples")
|
|
595
|
+
alpha, alphas = _pop_modification("alpha")
|
|
596
|
+
luminance, luminances = _pop_modification("luminance")
|
|
597
|
+
saturation, saturations = _pop_modification("saturation")
|
|
598
|
+
if luminance is not None:
|
|
599
|
+
luminances = (luminance,) * len(args)
|
|
600
|
+
if saturation is not None:
|
|
601
|
+
saturations = (saturation,) * len(args)
|
|
602
|
+
|
|
603
|
+
# Issue warnings and errors
|
|
604
|
+
if not args:
|
|
605
|
+
raise ValueError(
|
|
606
|
+
"Colormap() requires either positional arguments or "
|
|
607
|
+
"'hue', 'chroma', 'saturation', and/or 'luminance' keywords."
|
|
608
|
+
)
|
|
609
|
+
deprecated = {"listed": "discrete", "linear": "continuous"}
|
|
610
|
+
if listmode in deprecated:
|
|
611
|
+
oldmode, listmode = listmode, deprecated[listmode]
|
|
612
|
+
warnings._warn_ultraplot(
|
|
613
|
+
f"Please use listmode={listmode!r} instead of listmode={oldmode!r}."
|
|
614
|
+
"Option was renamed in v0.8 and will be removed in a future relase."
|
|
615
|
+
)
|
|
616
|
+
options = {"discrete", "continuous", "perceptual"}
|
|
617
|
+
for key, mode in zip(("listmode", "filemode"), (listmode, filemode)):
|
|
618
|
+
if mode not in options:
|
|
619
|
+
raise ValueError(
|
|
620
|
+
f"Invalid {key}={mode!r}. Options are: "
|
|
621
|
+
+ ", ".join(map(repr, options))
|
|
622
|
+
+ "."
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
# Loop through colormaps
|
|
626
|
+
cmaps = []
|
|
627
|
+
for (
|
|
628
|
+
arg,
|
|
629
|
+
icut,
|
|
630
|
+
ileft,
|
|
631
|
+
iright,
|
|
632
|
+
ireverse,
|
|
633
|
+
ishift,
|
|
634
|
+
isamples,
|
|
635
|
+
iluminance,
|
|
636
|
+
isaturation,
|
|
637
|
+
ialpha,
|
|
638
|
+
) in zip( # noqa: E501
|
|
639
|
+
args,
|
|
640
|
+
cuts,
|
|
641
|
+
lefts,
|
|
642
|
+
rights,
|
|
643
|
+
reverses,
|
|
644
|
+
shifts,
|
|
645
|
+
sampless,
|
|
646
|
+
luminances,
|
|
647
|
+
saturations,
|
|
648
|
+
alphas, # noqa: E501
|
|
649
|
+
):
|
|
650
|
+
# Load registered colormaps and maps on file
|
|
651
|
+
# TODO: Document how 'listmode' also affects loaded files
|
|
652
|
+
if isinstance(arg, str):
|
|
653
|
+
if "." in arg and os.path.isfile(arg):
|
|
654
|
+
if filemode == "discrete":
|
|
655
|
+
arg = pcolors.DiscreteColormap.from_file(arg)
|
|
656
|
+
else:
|
|
657
|
+
arg = pcolors.ContinuousColormap.from_file(arg)
|
|
658
|
+
else:
|
|
659
|
+
# FIXME: This error is baffling too me. Colors and colormaps
|
|
660
|
+
# are used interchangeable here
|
|
661
|
+
try:
|
|
662
|
+
arg = pcolors._cmap_database.get_cmap(arg)
|
|
663
|
+
except KeyError:
|
|
664
|
+
pass
|
|
665
|
+
|
|
666
|
+
# Convert matplotlib colormaps to subclasses
|
|
667
|
+
if isinstance(arg, mcolors.Colormap):
|
|
668
|
+
cmap = pcolors._translate_cmap(arg)
|
|
669
|
+
|
|
670
|
+
# Dictionary of hue/sat/luminance values or 2-tuples
|
|
671
|
+
elif isinstance(arg, dict):
|
|
672
|
+
cmap = pcolors.PerceptualColormap.from_hsl(**arg)
|
|
673
|
+
|
|
674
|
+
# List of color tuples or color strings, i.e. iterable of iterables
|
|
675
|
+
elif (
|
|
676
|
+
not isinstance(arg, str)
|
|
677
|
+
and np.iterable(arg)
|
|
678
|
+
and all(np.iterable(color) for color in arg)
|
|
679
|
+
):
|
|
680
|
+
if listmode == "discrete":
|
|
681
|
+
cmap = pcolors.DiscreteColormap(arg)
|
|
682
|
+
elif listmode == "continuous":
|
|
683
|
+
cmap = pcolors.ContinuousColormap.from_list(arg)
|
|
684
|
+
else:
|
|
685
|
+
cmap = pcolors.PerceptualColormap.from_list(arg)
|
|
686
|
+
|
|
687
|
+
# Monochrome colormap from input color
|
|
688
|
+
# NOTE: Do not print color names in error message. Too long to be useful.
|
|
689
|
+
else:
|
|
690
|
+
jreverse = isinstance(arg, str) and arg[-2:] == "_r"
|
|
691
|
+
if jreverse:
|
|
692
|
+
arg = arg[:-2]
|
|
693
|
+
try:
|
|
694
|
+
color = to_rgba(arg, cycle=cycle)
|
|
695
|
+
except (ValueError, TypeError):
|
|
696
|
+
message = f"Invalid colormap, color cycle, or color {arg!r}."
|
|
697
|
+
if isinstance(arg, str) and arg[:1] != "#":
|
|
698
|
+
message += (
|
|
699
|
+
" Options include: "
|
|
700
|
+
+ ", ".join(sorted(map(repr, pcolors._cmap_database)))
|
|
701
|
+
+ "."
|
|
702
|
+
)
|
|
703
|
+
raise ValueError(message) from None
|
|
704
|
+
iluminance = _not_none(iluminance, default_luminance)
|
|
705
|
+
cmap = pcolors.PerceptualColormap.from_color(
|
|
706
|
+
color, luminance=iluminance, saturation=isaturation
|
|
707
|
+
)
|
|
708
|
+
ireverse = _not_none(ireverse, False)
|
|
709
|
+
ireverse = ireverse ^ jreverse # xor
|
|
710
|
+
|
|
711
|
+
# Modify the colormap
|
|
712
|
+
cmap = _modify_colormap(
|
|
713
|
+
cmap,
|
|
714
|
+
cut=icut,
|
|
715
|
+
left=ileft,
|
|
716
|
+
right=iright,
|
|
717
|
+
reverse=ireverse,
|
|
718
|
+
shift=ishift,
|
|
719
|
+
alpha=ialpha,
|
|
720
|
+
samples=isamples,
|
|
721
|
+
)
|
|
722
|
+
cmaps.append(cmap)
|
|
723
|
+
|
|
724
|
+
# Merge the resulting colormaps
|
|
725
|
+
if len(cmaps) > 1: # more than one map and modify arbitrary properties
|
|
726
|
+
cmap = cmaps[0].append(*cmaps[1:], **kwargs)
|
|
727
|
+
else:
|
|
728
|
+
cmap = cmaps[0].copy(**kwargs)
|
|
729
|
+
|
|
730
|
+
# Modify the colormap
|
|
731
|
+
if discrete and isinstance(cmap, pcolors.ContinuousColormap): # noqa: E501
|
|
732
|
+
samples = _not_none(samples, DEFAULT_CYCLE_SAMPLES)
|
|
733
|
+
cmap = _modify_colormap(
|
|
734
|
+
cmap,
|
|
735
|
+
cut=cut,
|
|
736
|
+
left=left,
|
|
737
|
+
right=right,
|
|
738
|
+
reverse=reverse,
|
|
739
|
+
shift=shift,
|
|
740
|
+
alpha=alpha,
|
|
741
|
+
samples=samples,
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
# Initialize
|
|
745
|
+
if not cmap._isinit:
|
|
746
|
+
cmap._init()
|
|
747
|
+
|
|
748
|
+
# Register the colormap
|
|
749
|
+
if name is None:
|
|
750
|
+
name = cmap.name # may have been modified by e.g. reversed()
|
|
751
|
+
else:
|
|
752
|
+
cmap.name = name
|
|
753
|
+
if not isinstance(name, str):
|
|
754
|
+
raise ValueError("The colormap name must be a string.")
|
|
755
|
+
pcolors._cmap_database.register(cmap, name=name)
|
|
756
|
+
|
|
757
|
+
# Save the colormap
|
|
758
|
+
if save:
|
|
759
|
+
save_kw = save_kw or {}
|
|
760
|
+
cmap.save(**save_kw)
|
|
761
|
+
|
|
762
|
+
return cmap
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
def Cycle(*args, N=None, samples=None, name=None, **kwargs):
|
|
766
|
+
"""
|
|
767
|
+
Generate and merge `~cycler.Cycler` instances in a variety of ways.
|
|
768
|
+
|
|
769
|
+
Parameters
|
|
770
|
+
----------
|
|
771
|
+
*args : colormap-spec or cycle-spec, optional
|
|
772
|
+
Positional arguments control the *colors* in the `~cycler.Cycler`
|
|
773
|
+
object. If zero arguments are passed, the single color ``'black'``
|
|
774
|
+
is used. If more than one argument is passed, the resulting cycles
|
|
775
|
+
are merged. Arguments are interpreted as follows:
|
|
776
|
+
|
|
777
|
+
* If a `~cycler.Cycler`, nothing more is done.
|
|
778
|
+
* If a sequence of RGB tuples or color strings, these colors are used.
|
|
779
|
+
* If a `~ultraplot.colors.DiscreteColormap`, colors from the ``colors``
|
|
780
|
+
attribute are used.
|
|
781
|
+
* If a string cycle name, that `~ultraplot.colors.DiscreteColormap`
|
|
782
|
+
is looked up and its ``colors`` are used.
|
|
783
|
+
* In all other cases, the argument is passed to `Colormap`, and
|
|
784
|
+
colors from the resulting `~ultraplot.colors.ContinuousColormap`
|
|
785
|
+
are used. See the `samples` argument.
|
|
786
|
+
|
|
787
|
+
If the last positional argument is numeric, it is used for the
|
|
788
|
+
`samples` keyword argument.
|
|
789
|
+
N
|
|
790
|
+
Shorthand for `samples`.
|
|
791
|
+
samples : float or sequence of float, optional
|
|
792
|
+
For `~ultraplot.colors.DiscreteColormap`\\ s, this is the number of
|
|
793
|
+
colors to select. For example, ``Cycle('538', 4)`` returns the first 4
|
|
794
|
+
colors of the ``'538'`` color cycle.
|
|
795
|
+
For `~ultraplot.colors.ContinuousColormap`\\ s, this is either a
|
|
796
|
+
sequence of sample coordinates used to draw colors from the colormap, or
|
|
797
|
+
an integer number of colors to draw. If the latter, the sample coordinates
|
|
798
|
+
are ``np.linspace(0, 1, samples)``. For example, ``Cycle('Reds', 5)``
|
|
799
|
+
divides the ``'Reds'`` colormap into five evenly spaced colors.
|
|
800
|
+
|
|
801
|
+
Other parameters
|
|
802
|
+
----------------
|
|
803
|
+
c, color, colors : sequence of color-spec, optional
|
|
804
|
+
A sequence of colors passed as keyword arguments. This is equivalent
|
|
805
|
+
to passing a sequence of colors as the first positional argument and is
|
|
806
|
+
included for consistency with `~matplotlib.axes.Axes.set_prop_cycle`.
|
|
807
|
+
If positional arguments were passed, the colors in this list are
|
|
808
|
+
appended to the colors resulting from the positional arguments.
|
|
809
|
+
lw, ls, d, a, m, ms, mew, mec, mfc
|
|
810
|
+
Shorthands for the below keywords.
|
|
811
|
+
linewidth, linestyle, dashes, alpha, marker, markersize, markeredgewidth, \
|
|
812
|
+
markeredgecolor, markerfacecolor : object or sequence of object, optional
|
|
813
|
+
Lists of `~matplotlib.lines.Line2D` properties that can be added to the
|
|
814
|
+
`~cycler.Cycler` instance. If the input was already a `~cycler.Cycler`,
|
|
815
|
+
these are added or appended to the existing cycle keys. If the lists have
|
|
816
|
+
unequal length, they are repeated to their least common multiple (unlike
|
|
817
|
+
`~cycler.cycler`, which throws an error in this case). For more info
|
|
818
|
+
on cyclers see `~matplotlib.axes.Axes.set_prop_cycle`. Also see
|
|
819
|
+
the `line style reference \
|
|
820
|
+
<https://matplotlib.org/2.2.5/gallery/lines_bars_and_markers/line_styles_reference.html>`__,
|
|
821
|
+
the `marker reference \
|
|
822
|
+
<https://matplotlib.org/stable/gallery/lines_bars_and_markers/marker_reference.html>`__,
|
|
823
|
+
and the `custom dashes reference \
|
|
824
|
+
<https://matplotlib.org/stable/gallery/lines_bars_and_markers/line_demo_dash_control.html>`__.
|
|
825
|
+
linewidths, linestyles, dashes, alphas, markers, markersizes, markeredgewidths, \
|
|
826
|
+
markeredgecolors, markerfacecolors
|
|
827
|
+
Aliases for the above keywords.
|
|
828
|
+
**kwargs
|
|
829
|
+
If the input is not already a `~cycler.Cycler` instance, these are passed
|
|
830
|
+
to `Colormap` and used to build the `~ultraplot.colors.DiscreteColormap`
|
|
831
|
+
from which the cycler will draw its colors.
|
|
832
|
+
|
|
833
|
+
Returns
|
|
834
|
+
-------
|
|
835
|
+
cycler.Cycler
|
|
836
|
+
A `~cycler.Cycler` instance that can be passed
|
|
837
|
+
to `~matplotlib.axes.Axes.set_prop_cycle`.
|
|
838
|
+
|
|
839
|
+
See also
|
|
840
|
+
--------
|
|
841
|
+
cycler.cycler
|
|
842
|
+
cycler.Cycler
|
|
843
|
+
matplotlib.axes.Axes.set_prop_cycle
|
|
844
|
+
ultraplot.constructor.Colormap
|
|
845
|
+
ultraplot.constructor.Norm
|
|
846
|
+
ultraplot.utils.get_colors
|
|
847
|
+
"""
|
|
848
|
+
# Parse keyword arguments that rotate through other properties
|
|
849
|
+
# besides color cycles.
|
|
850
|
+
props = _pop_props(kwargs, "line")
|
|
851
|
+
if "sizes" in kwargs: # special case, gets translated back by scatter()
|
|
852
|
+
props.setdefault("markersize", kwargs.pop("sizes"))
|
|
853
|
+
samples = _not_none(samples=samples, N=N) # trigger Colormap default
|
|
854
|
+
for key, value in tuple(props.items()): # permit in-place modification
|
|
855
|
+
if value is None:
|
|
856
|
+
return
|
|
857
|
+
elif not np.iterable(value) or isinstance(value, str):
|
|
858
|
+
value = (value,)
|
|
859
|
+
props[key] = list(value) # ensure mutable list
|
|
860
|
+
|
|
861
|
+
# If args is non-empty, means we want color cycle; otherwise is black
|
|
862
|
+
if not args:
|
|
863
|
+
props.setdefault("color", ["black"])
|
|
864
|
+
if kwargs:
|
|
865
|
+
warnings._warn_ultraplot(f"Ignoring Cycle() keyword arg(s) {kwargs}.")
|
|
866
|
+
dicts = ()
|
|
867
|
+
|
|
868
|
+
# Merge cycler objects and/or update cycler objects with input kwargs
|
|
869
|
+
elif all(isinstance(arg, cycler.Cycler) for arg in args):
|
|
870
|
+
if kwargs:
|
|
871
|
+
warnings._warn_ultraplot(f"Ignoring Cycle() keyword arg(s) {kwargs}.")
|
|
872
|
+
if len(args) == 1 and not props:
|
|
873
|
+
return args[0]
|
|
874
|
+
dicts = tuple(arg.by_key() for arg in args)
|
|
875
|
+
|
|
876
|
+
# Get a cycler from a colormap
|
|
877
|
+
# NOTE: Passing discrete=True does not imply default_luminance=90 because
|
|
878
|
+
# someone might be trying to make qualitative colormap for use in 2D plot
|
|
879
|
+
else:
|
|
880
|
+
if isinstance(args[-1], Number):
|
|
881
|
+
args, samples = args[:-1], _not_none(
|
|
882
|
+
samples_positional=args[-1], samples=samples
|
|
883
|
+
) # noqa: #501
|
|
884
|
+
kwargs.setdefault("listmode", "discrete")
|
|
885
|
+
kwargs.setdefault("filemode", "discrete")
|
|
886
|
+
kwargs["discrete"] = True # triggers application of default 'samples'
|
|
887
|
+
kwargs["default_luminance"] = DEFAULT_CYCLE_LUMINANCE
|
|
888
|
+
cmap = Colormap(*args, name=name, samples=samples, **kwargs)
|
|
889
|
+
name = _not_none(name, cmap.name)
|
|
890
|
+
dict_ = {"color": [c if isinstance(c, str) else to_hex(c) for c in cmap.colors]}
|
|
891
|
+
dicts = (dict_,)
|
|
892
|
+
|
|
893
|
+
# Update the cyler property
|
|
894
|
+
dicts = dicts + (props,)
|
|
895
|
+
props = {}
|
|
896
|
+
for dict_ in dicts:
|
|
897
|
+
for key, value in dict_.items():
|
|
898
|
+
props.setdefault(key, []).extend(value)
|
|
899
|
+
|
|
900
|
+
# Build cycler with matching property lengths
|
|
901
|
+
maxlen = np.lcm.reduce([len(value) for value in props.values()])
|
|
902
|
+
props = {key: value * (maxlen // len(value)) for key, value in props.items()}
|
|
903
|
+
cycle = cycler.cycler(**props)
|
|
904
|
+
cycle.name = _not_none(name, "_no_name")
|
|
905
|
+
|
|
906
|
+
return cycle
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
def Norm(norm, *args, **kwargs):
|
|
910
|
+
"""
|
|
911
|
+
Return an arbitrary `~matplotlib.colors.Normalize` instance. See this
|
|
912
|
+
`tutorial <https://matplotlib.org/stable/tutorials/colors/colormapnorms.html>`__
|
|
913
|
+
for an introduction to matplotlib normalizers.
|
|
914
|
+
|
|
915
|
+
Parameters
|
|
916
|
+
----------
|
|
917
|
+
norm : str or `~matplotlib.colors.Normalize`
|
|
918
|
+
The normalizer specification. If a `~matplotlib.colors.Normalize`
|
|
919
|
+
instance already, a `copy.copy` of the instance is returned.
|
|
920
|
+
Otherwise, `norm` should be a string corresponding to one of
|
|
921
|
+
the "registered" colormap normalizers (see below table).
|
|
922
|
+
|
|
923
|
+
If `norm` is a list or tuple and the first element is a "registered"
|
|
924
|
+
normalizer name, subsequent elements are passed to the normalizer class
|
|
925
|
+
as positional arguments.
|
|
926
|
+
|
|
927
|
+
.. _norm_table:
|
|
928
|
+
|
|
929
|
+
=============================== =====================================
|
|
930
|
+
Key(s) Class
|
|
931
|
+
=============================== =====================================
|
|
932
|
+
``'null'``, ``'none'`` `~matplotlib.colors.NoNorm`
|
|
933
|
+
``'diverging'``, ``'div'`` `~ultraplot.colors.DivergingNorm`
|
|
934
|
+
``'segmented'``, ``'segments'`` `~ultraplot.colors.SegmentedNorm`
|
|
935
|
+
``'linear'`` `~matplotlib.colors.Normalize`
|
|
936
|
+
``'log'`` `~matplotlib.colors.LogNorm`
|
|
937
|
+
``'power'`` `~matplotlib.colors.PowerNorm`
|
|
938
|
+
``'symlog'`` `~matplotlib.colors.SymLogNorm`
|
|
939
|
+
=============================== =====================================
|
|
940
|
+
|
|
941
|
+
Other parameters
|
|
942
|
+
----------------
|
|
943
|
+
*args, **kwargs
|
|
944
|
+
Passed to the `~matplotlib.colors.Normalize` initializer.
|
|
945
|
+
|
|
946
|
+
Returns
|
|
947
|
+
-------
|
|
948
|
+
matplotlib.colors.Normalize
|
|
949
|
+
A `~matplotlib.colors.Normalize` instance.
|
|
950
|
+
|
|
951
|
+
See also
|
|
952
|
+
--------
|
|
953
|
+
matplotlib.colors.Normalize
|
|
954
|
+
ultraplot.colors.DiscreteNorm
|
|
955
|
+
ultraplot.constructor.Colormap
|
|
956
|
+
"""
|
|
957
|
+
if np.iterable(norm) and not isinstance(norm, str):
|
|
958
|
+
norm, *args = *norm, *args
|
|
959
|
+
if isinstance(norm, mcolors.Normalize):
|
|
960
|
+
return copy.copy(norm)
|
|
961
|
+
if not isinstance(norm, str):
|
|
962
|
+
raise ValueError(f"Invalid norm name {norm!r}. Must be string.")
|
|
963
|
+
if norm not in NORMS:
|
|
964
|
+
raise ValueError(
|
|
965
|
+
f"Unknown normalizer {norm!r}. Options are: "
|
|
966
|
+
+ ", ".join(map(repr, NORMS))
|
|
967
|
+
+ "."
|
|
968
|
+
)
|
|
969
|
+
if norm == "symlog" and not args and "linthresh" not in kwargs:
|
|
970
|
+
kwargs["linthresh"] = 1 # special case, needs argument
|
|
971
|
+
return NORMS[norm](*args, **kwargs)
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def Locator(locator, *args, discrete=False, **kwargs):
|
|
975
|
+
"""
|
|
976
|
+
Return a `~matplotlib.ticker.Locator` instance.
|
|
977
|
+
|
|
978
|
+
Parameters
|
|
979
|
+
----------
|
|
980
|
+
locator : `~matplotlib.ticker.Locator`, str, bool, float, or sequence
|
|
981
|
+
The locator specification, interpreted as follows:
|
|
982
|
+
|
|
983
|
+
* If a `~matplotlib.ticker.Locator` instance already,
|
|
984
|
+
a `copy.copy` of the instance is returned.
|
|
985
|
+
* If ``False``, a `~matplotlib.ticker.NullLocator` is used, and if
|
|
986
|
+
``True``, the default `~matplotlib.ticker.AutoLocator` is used.
|
|
987
|
+
* If a number, this specifies the *step size* between tick locations.
|
|
988
|
+
Returns a `~matplotlib.ticker.MultipleLocator`.
|
|
989
|
+
* If a sequence of numbers, these points are ticked. Returns
|
|
990
|
+
a `~matplotlib.ticker.FixedLocator` by default or a
|
|
991
|
+
`~ultraplot.ticker.DiscreteLocator` if `discrete` is ``True``.
|
|
992
|
+
|
|
993
|
+
Otherwise, `locator` should be a string corresponding to one
|
|
994
|
+
of the "registered" locators (see below table). If `locator` is a
|
|
995
|
+
list or tuple and the first element is a "registered" locator name,
|
|
996
|
+
subsequent elements are passed to the locator class as positional
|
|
997
|
+
arguments. For example, ``pplt.Locator(('multiple', 5))`` is
|
|
998
|
+
equivalent to ``pplt.Locator('multiple', 5)``.
|
|
999
|
+
|
|
1000
|
+
.. _locator_table:
|
|
1001
|
+
|
|
1002
|
+
======================= ============================================ =====================================================================================
|
|
1003
|
+
Key Class Description
|
|
1004
|
+
======================= ============================================ =====================================================================================
|
|
1005
|
+
``'null'``, ``'none'`` `~matplotlib.ticker.NullLocator` No ticks
|
|
1006
|
+
``'auto'`` `~matplotlib.ticker.AutoLocator` Major ticks at sensible locations
|
|
1007
|
+
``'minor'`` `~matplotlib.ticker.AutoMinorLocator` Minor ticks at sensible locations
|
|
1008
|
+
``'date'`` `~matplotlib.dates.AutoDateLocator` Default tick locations for datetime axes
|
|
1009
|
+
``'fixed'`` `~matplotlib.ticker.FixedLocator` Ticks at these exact locations
|
|
1010
|
+
``'discrete'`` `~ultraplot.ticker.DiscreteLocator` Major ticks restricted to these locations but subsampled depending on the axis length
|
|
1011
|
+
``'discreteminor'`` `~ultraplot.ticker.DiscreteLocator` Minor ticks restricted to these locations but subsampled depending on the axis length
|
|
1012
|
+
``'index'`` `~ultraplot.ticker.IndexLocator` Ticks on the non-negative integers
|
|
1013
|
+
``'linear'`` `~matplotlib.ticker.LinearLocator` Exactly ``N`` ticks encompassing axis limits, spaced as ``numpy.linspace(lo, hi, N)``
|
|
1014
|
+
``'log'`` `~matplotlib.ticker.LogLocator` For log-scale axes
|
|
1015
|
+
``'logminor'`` `~matplotlib.ticker.LogLocator` For log-scale axes on the 1st through 9th multiples of each power of the base
|
|
1016
|
+
``'logit'`` `~matplotlib.ticker.LogitLocator` For logit-scale axes
|
|
1017
|
+
``'logitminor'`` `~matplotlib.ticker.LogitLocator` For logit-scale axes with ``minor=True`` passed to `~matplotlib.ticker.LogitLocator`
|
|
1018
|
+
``'maxn'`` `~matplotlib.ticker.MaxNLocator` No more than ``N`` ticks at sensible locations
|
|
1019
|
+
``'multiple'`` `~matplotlib.ticker.MultipleLocator` Ticks every ``N`` step away from zero
|
|
1020
|
+
``'symlog'`` `~matplotlib.ticker.SymmetricalLogLocator` For symlog-scale axes
|
|
1021
|
+
``'symlogminor'`` `~matplotlib.ticker.SymmetricalLogLocator` For symlog-scale axes on the 1st through 9th multiples of each power of the base
|
|
1022
|
+
``'theta'`` `~matplotlib.projections.polar.ThetaLocator` Like the base locator but default locations are every `numpy.pi` / 8 radians
|
|
1023
|
+
``'year'`` `~matplotlib.dates.YearLocator` Ticks every ``N`` years
|
|
1024
|
+
``'month'`` `~matplotlib.dates.MonthLocator` Ticks every ``N`` months
|
|
1025
|
+
``'weekday'`` `~matplotlib.dates.WeekdayLocator` Ticks every ``N`` weekdays
|
|
1026
|
+
``'day'`` `~matplotlib.dates.DayLocator` Ticks every ``N`` days
|
|
1027
|
+
``'hour'`` `~matplotlib.dates.HourLocator` Ticks every ``N`` hours
|
|
1028
|
+
``'minute'`` `~matplotlib.dates.MinuteLocator` Ticks every ``N`` minutes
|
|
1029
|
+
``'second'`` `~matplotlib.dates.SecondLocator` Ticks every ``N`` seconds
|
|
1030
|
+
``'microsecond'`` `~matplotlib.dates.MicrosecondLocator` Ticks every ``N`` microseconds
|
|
1031
|
+
``'lon'``, ``'deglon'`` `~ultraplot.ticker.LongitudeLocator` Longitude gridlines at sensible decimal locations
|
|
1032
|
+
``'lat'``, ``'deglat'`` `~ultraplot.ticker.LatitudeLocator` Latitude gridlines at sensible decimal locations
|
|
1033
|
+
``'dms'`` `~ultraplot.ticker.DegreeLocator` Gridlines on nice minute and second intervals
|
|
1034
|
+
``'dmslon'`` `~ultraplot.ticker.LongitudeLocator` Longitude gridlines on nice minute and second intervals
|
|
1035
|
+
``'dmslat'`` `~ultraplot.ticker.LatitudeLocator` Latitude gridlines on nice minute and second intervals
|
|
1036
|
+
======================= ============================================ =====================================================================================
|
|
1037
|
+
|
|
1038
|
+
Other parameters
|
|
1039
|
+
----------------
|
|
1040
|
+
*args, **kwargs
|
|
1041
|
+
Passed to the `~matplotlib.ticker.Locator` class.
|
|
1042
|
+
|
|
1043
|
+
Returns
|
|
1044
|
+
-------
|
|
1045
|
+
matplotlib.ticker.Locator
|
|
1046
|
+
A `~matplotlib.ticker.Locator` instance.
|
|
1047
|
+
|
|
1048
|
+
See also
|
|
1049
|
+
--------
|
|
1050
|
+
matplotlib.ticker.Locator
|
|
1051
|
+
ultraplot.axes.CartesianAxes.format
|
|
1052
|
+
ultraplot.axes.PolarAxes.format
|
|
1053
|
+
ultraplot.axes.GeoAxes.format
|
|
1054
|
+
ultraplot.axes.Axes.colorbar
|
|
1055
|
+
ultraplot.constructor.Formatter
|
|
1056
|
+
""" # noqa: E501
|
|
1057
|
+
if (
|
|
1058
|
+
np.iterable(locator)
|
|
1059
|
+
and not isinstance(locator, str)
|
|
1060
|
+
and not all(isinstance(num, Number) for num in locator)
|
|
1061
|
+
):
|
|
1062
|
+
locator, *args = *locator, *args
|
|
1063
|
+
if isinstance(locator, mticker.Locator):
|
|
1064
|
+
return copy.copy(locator)
|
|
1065
|
+
if isinstance(locator, str):
|
|
1066
|
+
if locator == "index": # defaults
|
|
1067
|
+
args = args or (1,)
|
|
1068
|
+
if len(args) == 1:
|
|
1069
|
+
args = (*args, 0)
|
|
1070
|
+
elif locator in ("logminor", "logitminor", "symlogminor"): # presets
|
|
1071
|
+
locator, _ = locator.split("minor")
|
|
1072
|
+
if locator == "logit":
|
|
1073
|
+
kwargs.setdefault("minor", True)
|
|
1074
|
+
else:
|
|
1075
|
+
kwargs.setdefault("subs", np.arange(1, 10))
|
|
1076
|
+
if locator in LOCATORS:
|
|
1077
|
+
locator = LOCATORS[locator](*args, **kwargs)
|
|
1078
|
+
else:
|
|
1079
|
+
raise ValueError(
|
|
1080
|
+
f"Unknown locator {locator!r}. Options are: "
|
|
1081
|
+
+ ", ".join(map(repr, LOCATORS))
|
|
1082
|
+
+ "."
|
|
1083
|
+
)
|
|
1084
|
+
elif locator is True:
|
|
1085
|
+
locator = mticker.AutoLocator(*args, **kwargs)
|
|
1086
|
+
elif locator is False:
|
|
1087
|
+
locator = mticker.NullLocator(*args, **kwargs)
|
|
1088
|
+
elif isinstance(locator, Number): # scalar variable
|
|
1089
|
+
locator = mticker.MultipleLocator(locator, *args, **kwargs)
|
|
1090
|
+
elif np.iterable(locator):
|
|
1091
|
+
locator = np.array(locator)
|
|
1092
|
+
if discrete:
|
|
1093
|
+
locator = pticker.DiscreteLocator(locator, *args, **kwargs)
|
|
1094
|
+
else:
|
|
1095
|
+
locator = mticker.FixedLocator(locator, *args, **kwargs)
|
|
1096
|
+
else:
|
|
1097
|
+
raise ValueError(f"Invalid locator {locator!r}.")
|
|
1098
|
+
return locator
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
def Formatter(formatter, *args, date=False, index=False, **kwargs):
|
|
1102
|
+
"""
|
|
1103
|
+
Return a `~matplotlib.ticker.Formatter` instance.
|
|
1104
|
+
|
|
1105
|
+
Parameters
|
|
1106
|
+
----------
|
|
1107
|
+
formatter : `~matplotlib.ticker.Formatter`, str, bool, callable, or sequence
|
|
1108
|
+
The formatter specification, interpreted as follows:
|
|
1109
|
+
|
|
1110
|
+
* If a `~matplotlib.ticker.Formatter` instance already,
|
|
1111
|
+
a `copy.copy` of the instance is returned.
|
|
1112
|
+
* If ``False``, a `~matplotlib.ticker.NullFormatter` is used, and if
|
|
1113
|
+
``True``, the default `~ultraplot.ticker.AutoFormatter` is used.
|
|
1114
|
+
* If a function, the labels will be generated using this function.
|
|
1115
|
+
Returns a `~matplotlib.ticker.FuncFormatter`.
|
|
1116
|
+
* If sequence of strings, the ticks are labeled with these strings.
|
|
1117
|
+
Returns a `~matplotlib.ticker.FixedFormatter` by default or
|
|
1118
|
+
an `~ultraplot.ticker.IndexFormatter` if `index` is ``True``.
|
|
1119
|
+
* If a string containing ``{x}`` or ``{x:...}``, ticks will be
|
|
1120
|
+
formatted by calling ``string.format(x=number)``. Returns
|
|
1121
|
+
a `~matplotlib.ticker.StrMethodFormatter`.
|
|
1122
|
+
* If a string containing ``'%'`` and `date` is ``False``, ticks
|
|
1123
|
+
will be formatted using the C-style ``string % number`` method. See
|
|
1124
|
+
`this page <https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting>`__
|
|
1125
|
+
for a review. Returns a `~matplotlib.ticker.FormatStrFormatter`.
|
|
1126
|
+
* If a string containing ``'%'`` and `date` is ``True``, ticks
|
|
1127
|
+
will be formatted using `~datetime.datetime.strfrtime`. See
|
|
1128
|
+
`this page <https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes>`__
|
|
1129
|
+
for a review. Returns a `~matplotlib.dates.DateFormatter`.
|
|
1130
|
+
|
|
1131
|
+
Otherwise, `formatter` should be a string corresponding to one of the
|
|
1132
|
+
"registered" formatters or formatter presets (see below table). If
|
|
1133
|
+
`formatter` is a list or tuple and the first element is a "registered"
|
|
1134
|
+
formatter name, subsequent elements are passed to the formatter class
|
|
1135
|
+
as positional arguments. For example, ``pplt.Formatter(('sigfig', 3))`` is
|
|
1136
|
+
equivalent to ``Formatter('sigfig', 3)``.
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
.. _tau: https://tauday.com/tau-manifesto
|
|
1140
|
+
|
|
1141
|
+
.. _formatter_table:
|
|
1142
|
+
|
|
1143
|
+
====================== ============================================== =================================================================
|
|
1144
|
+
Key Class Description
|
|
1145
|
+
====================== ============================================== =================================================================
|
|
1146
|
+
``'null'``, ``'none'`` `~matplotlib.ticker.NullFormatter` No tick labels
|
|
1147
|
+
``'auto'`` `~ultraplot.ticker.AutoFormatter` New default tick labels for axes
|
|
1148
|
+
``'sci'`` `~ultraplot.ticker.SciFormatter` Format ticks with scientific notation
|
|
1149
|
+
``'simple'`` `~ultraplot.ticker.SimpleFormatter` New default tick labels for e.g. contour labels
|
|
1150
|
+
``'sigfig'`` `~ultraplot.ticker.SigFigFormatter` Format labels using the first ``N`` significant digits
|
|
1151
|
+
``'frac'`` `~ultraplot.ticker.FracFormatter` Rational fractions
|
|
1152
|
+
``'date'`` `~matplotlib.dates.AutoDateFormatter` Default tick labels for datetime axes
|
|
1153
|
+
``'concise'`` `~matplotlib.dates.ConciseDateFormatter` More concise date labels introduced in matplotlib 3.1
|
|
1154
|
+
``'datestr'`` `~matplotlib.dates.DateFormatter` Date formatting with C-style ``string % format`` notation
|
|
1155
|
+
``'eng'`` `~matplotlib.ticker.EngFormatter` Engineering notation
|
|
1156
|
+
``'fixed'`` `~matplotlib.ticker.FixedFormatter` List of strings
|
|
1157
|
+
``'formatstr'`` `~matplotlib.ticker.FormatStrFormatter` From C-style ``string % format`` notation
|
|
1158
|
+
``'func'`` `~matplotlib.ticker.FuncFormatter` Use an arbitrary function
|
|
1159
|
+
``'index'`` `~ultraplot.ticker.IndexFormatter` List of strings corresponding to non-negative integer positions
|
|
1160
|
+
``'log'`` `~matplotlib.ticker.LogFormatterSciNotation` For log-scale axes with scientific notation
|
|
1161
|
+
``'logit'`` `~matplotlib.ticker.LogitFormatter` For logistic-scale axes
|
|
1162
|
+
``'percent'`` `~matplotlib.ticker.PercentFormatter` Trailing percent sign
|
|
1163
|
+
``'scalar'`` `~matplotlib.ticker.ScalarFormatter` The default matplotlib formatter
|
|
1164
|
+
``'strmethod'`` `~matplotlib.ticker.StrMethodFormatter` From the ``string.format`` method
|
|
1165
|
+
``'theta'`` `~matplotlib.projections.polar.ThetaFormatter` Formats radians as degrees, with a degree symbol
|
|
1166
|
+
``'e'`` `~ultraplot.ticker.FracFormatter` preset Fractions of *e*
|
|
1167
|
+
``'pi'`` `~ultraplot.ticker.FracFormatter` preset Fractions of :math:`\\pi`
|
|
1168
|
+
``'tau'`` `~ultraplot.ticker.FracFormatter` preset Fractions of the `one true circle constant <tau_>`_ :math:`\\tau`
|
|
1169
|
+
``'lat'`` `~ultraplot.ticker.AutoFormatter` preset Cardinal "SN" indicator
|
|
1170
|
+
``'lon'`` `~ultraplot.ticker.AutoFormatter` preset Cardinal "WE" indicator
|
|
1171
|
+
``'deg'`` `~ultraplot.ticker.AutoFormatter` preset Trailing degree symbol
|
|
1172
|
+
``'deglat'`` `~ultraplot.ticker.AutoFormatter` preset Trailing degree symbol and cardinal "SN" indicator
|
|
1173
|
+
``'deglon'`` `~ultraplot.ticker.AutoFormatter` preset Trailing degree symbol and cardinal "WE" indicator
|
|
1174
|
+
``'dms'`` `~ultraplot.ticker.DegreeFormatter` Labels with degree/minute/second support
|
|
1175
|
+
``'dmslon'`` `~ultraplot.ticker.LongitudeFormatter` Longitude labels with degree/minute/second support
|
|
1176
|
+
``'dmslat'`` `~ultraplot.ticker.LatitudeFormatter` Latitude labels with degree/minute/second support
|
|
1177
|
+
====================== ============================================== =================================================================
|
|
1178
|
+
|
|
1179
|
+
date : bool, optional
|
|
1180
|
+
Toggles the behavior when `formatter` contains a ``'%'`` sign
|
|
1181
|
+
(see above).
|
|
1182
|
+
index : bool, optional
|
|
1183
|
+
Controls the behavior when `formatter` is a sequence of strings
|
|
1184
|
+
(see above).
|
|
1185
|
+
|
|
1186
|
+
Other parameters
|
|
1187
|
+
----------------
|
|
1188
|
+
*args, **kwargs
|
|
1189
|
+
Passed to the `~matplotlib.ticker.Formatter` class.
|
|
1190
|
+
|
|
1191
|
+
Returns
|
|
1192
|
+
-------
|
|
1193
|
+
matplotlib.ticker.Formatter
|
|
1194
|
+
A `~matplotlib.ticker.Formatter` instance.
|
|
1195
|
+
|
|
1196
|
+
See also
|
|
1197
|
+
--------
|
|
1198
|
+
matplotlib.ticker.Formatter
|
|
1199
|
+
ultraplot.axes.CartesianAxes.format
|
|
1200
|
+
ultraplot.axes.PolarAxes.format
|
|
1201
|
+
ultraplot.axes.GeoAxes.format
|
|
1202
|
+
ultraplot.axes.Axes.colorbar
|
|
1203
|
+
ultraplot.constructor.Locator
|
|
1204
|
+
""" # noqa: E501
|
|
1205
|
+
if (
|
|
1206
|
+
np.iterable(formatter)
|
|
1207
|
+
and not isinstance(formatter, str)
|
|
1208
|
+
and not all(isinstance(item, str) for item in formatter)
|
|
1209
|
+
):
|
|
1210
|
+
formatter, *args = *formatter, *args
|
|
1211
|
+
if isinstance(formatter, mticker.Formatter):
|
|
1212
|
+
return copy.copy(formatter)
|
|
1213
|
+
if isinstance(formatter, str):
|
|
1214
|
+
if re.search(r"{x(:.+)?}", formatter): # str.format
|
|
1215
|
+
formatter = mticker.StrMethodFormatter(formatter, *args, **kwargs)
|
|
1216
|
+
elif "%" in formatter: # str % format
|
|
1217
|
+
cls = mdates.DateFormatter if date else mticker.FormatStrFormatter
|
|
1218
|
+
formatter = cls(formatter, *args, **kwargs)
|
|
1219
|
+
elif formatter in FORMATTERS:
|
|
1220
|
+
formatter = FORMATTERS[formatter](*args, **kwargs)
|
|
1221
|
+
else:
|
|
1222
|
+
raise ValueError(
|
|
1223
|
+
f"Unknown formatter {formatter!r}. Options are: "
|
|
1224
|
+
+ ", ".join(map(repr, FORMATTERS))
|
|
1225
|
+
+ "."
|
|
1226
|
+
)
|
|
1227
|
+
elif formatter is True:
|
|
1228
|
+
formatter = pticker.AutoFormatter(*args, **kwargs)
|
|
1229
|
+
elif formatter is False:
|
|
1230
|
+
formatter = mticker.NullFormatter(*args, **kwargs)
|
|
1231
|
+
elif np.iterable(formatter):
|
|
1232
|
+
formatter = (mticker.FixedFormatter, pticker.IndexFormatter)[index](formatter)
|
|
1233
|
+
elif callable(formatter):
|
|
1234
|
+
formatter = mticker.FuncFormatter(formatter, *args, **kwargs)
|
|
1235
|
+
else:
|
|
1236
|
+
raise ValueError(f"Invalid formatter {formatter!r}.")
|
|
1237
|
+
return formatter
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
def Scale(scale, *args, **kwargs):
|
|
1241
|
+
"""
|
|
1242
|
+
Return a `~matplotlib.scale.ScaleBase` instance.
|
|
1243
|
+
|
|
1244
|
+
Parameters
|
|
1245
|
+
----------
|
|
1246
|
+
scale : `~matplotlib.scale.ScaleBase`, str, or tuple
|
|
1247
|
+
The axis scale specification. If a `~matplotlib.scale.ScaleBase` instance
|
|
1248
|
+
already, a `copy.copy` of the instance is returned. Otherwise, `scale`
|
|
1249
|
+
should be a string corresponding to one of the "registered" axis scales
|
|
1250
|
+
or axis scale presets (see below table).
|
|
1251
|
+
|
|
1252
|
+
If `scale` is a list or tuple and the first element is a
|
|
1253
|
+
"registered" scale name, subsequent elements are passed to the
|
|
1254
|
+
scale class as positional arguments.
|
|
1255
|
+
|
|
1256
|
+
.. _scale_table:
|
|
1257
|
+
|
|
1258
|
+
================= ====================================== ===============================================
|
|
1259
|
+
Key Class Description
|
|
1260
|
+
================= ====================================== ===============================================
|
|
1261
|
+
``'linear'`` `~ultraplot.scale.LinearScale` Linear
|
|
1262
|
+
``'log'`` `~ultraplot.scale.LogScale` Logarithmic
|
|
1263
|
+
``'symlog'`` `~ultraplot.scale.SymmetricalLogScale` Logarithmic beyond finite space around zero
|
|
1264
|
+
``'logit'`` `~ultraplot.scale.LogitScale` Logistic
|
|
1265
|
+
``'inverse'`` `~ultraplot.scale.InverseScale` Inverse
|
|
1266
|
+
``'function'`` `~ultraplot.scale.FuncScale` Arbitrary forward and backwards transformations
|
|
1267
|
+
``'sine'`` `~ultraplot.scale.SineLatitudeScale` Sine function (in degrees)
|
|
1268
|
+
``'mercator'`` `~ultraplot.scale.MercatorLatitudeScale` Mercator latitude function (in degrees)
|
|
1269
|
+
``'exp'`` `~ultraplot.scale.ExpScale` Arbitrary exponential function
|
|
1270
|
+
``'power'`` `~ultraplot.scale.PowerScale` Arbitrary power function
|
|
1271
|
+
``'cutoff'`` `~ultraplot.scale.CutoffScale` Arbitrary piecewise linear transformations
|
|
1272
|
+
``'quadratic'`` `~ultraplot.scale.PowerScale` (preset) Quadratic function
|
|
1273
|
+
``'cubic'`` `~ultraplot.scale.PowerScale` (preset) Cubic function
|
|
1274
|
+
``'quartic'`` `~ultraplot.scale.PowerScale` (preset) Quartic function
|
|
1275
|
+
``'db'`` `~ultraplot.scale.ExpScale` (preset) Ratio expressed as `decibels <db_>`_
|
|
1276
|
+
``'np'`` `~ultraplot.scale.ExpScale` (preset) Ratio expressed as `nepers <np_>`_
|
|
1277
|
+
``'idb'`` `~ultraplot.scale.ExpScale` (preset) `Decibels <db_>`_ expressed as ratio
|
|
1278
|
+
``'inp'`` `~ultraplot.scale.ExpScale` (preset) `Nepers <np_>`_ expressed as ratio
|
|
1279
|
+
``'pressure'`` `~ultraplot.scale.ExpScale` (preset) Height (in km) expressed linear in pressure
|
|
1280
|
+
``'height'`` `~ultraplot.scale.ExpScale` (preset) Pressure (in hPa) expressed linear in height
|
|
1281
|
+
================= ====================================== ===============================================
|
|
1282
|
+
|
|
1283
|
+
.. _db: https://en.wikipedia.org/wiki/Decibel
|
|
1284
|
+
.. _np: https://en.wikipedia.org/wiki/Neper
|
|
1285
|
+
|
|
1286
|
+
Other parameters
|
|
1287
|
+
----------------
|
|
1288
|
+
*args, **kwargs
|
|
1289
|
+
Passed to the `~matplotlib.scale.ScaleBase` class.
|
|
1290
|
+
|
|
1291
|
+
Returns
|
|
1292
|
+
-------
|
|
1293
|
+
matplotlib.scale.ScaleBase
|
|
1294
|
+
A `~matplotlib.scale.ScaleBase` instance.
|
|
1295
|
+
|
|
1296
|
+
See also
|
|
1297
|
+
--------
|
|
1298
|
+
matplotlib.scale.ScaleBase
|
|
1299
|
+
ultraplot.scale.LinearScale
|
|
1300
|
+
ultraplot.axes.CartesianAxes.format
|
|
1301
|
+
ultraplot.axes.CartesianAxes.dualx
|
|
1302
|
+
ultraplot.axes.CartesianAxes.dualy
|
|
1303
|
+
""" # noqa: E501
|
|
1304
|
+
# NOTE: Why not try to interpret FuncScale arguments, like when lists
|
|
1305
|
+
# of numbers are passed to Locator? Because FuncScale *itself* accepts
|
|
1306
|
+
# ScaleBase classes as arguments... but constructor functions cannot
|
|
1307
|
+
# do anything but return the class instance upon receiving one.
|
|
1308
|
+
if np.iterable(scale) and not isinstance(scale, str):
|
|
1309
|
+
scale, *args = *scale, *args
|
|
1310
|
+
if isinstance(scale, mscale.ScaleBase):
|
|
1311
|
+
return copy.copy(scale)
|
|
1312
|
+
if not isinstance(scale, str):
|
|
1313
|
+
raise ValueError(f"Invalid scale name {scale!r}. Must be string.")
|
|
1314
|
+
scale = scale.lower()
|
|
1315
|
+
if scale in SCALES_PRESETS:
|
|
1316
|
+
if args or kwargs:
|
|
1317
|
+
warnings._warn_ultraplot(
|
|
1318
|
+
f"Scale {scale!r} is a scale *preset*. Ignoring positional "
|
|
1319
|
+
"argument(s): {args} and keyword argument(s): {kwargs}. "
|
|
1320
|
+
)
|
|
1321
|
+
scale, *args = SCALES_PRESETS[scale]
|
|
1322
|
+
if scale in SCALES:
|
|
1323
|
+
scale = SCALES[scale]
|
|
1324
|
+
else:
|
|
1325
|
+
raise ValueError(
|
|
1326
|
+
f"Unknown scale or preset {scale!r}. Options are: "
|
|
1327
|
+
+ ", ".join(map(repr, (*SCALES, *SCALES_PRESETS)))
|
|
1328
|
+
+ "."
|
|
1329
|
+
)
|
|
1330
|
+
return scale(*args, **kwargs)
|
|
1331
|
+
|
|
1332
|
+
|
|
1333
|
+
def Proj(
|
|
1334
|
+
name,
|
|
1335
|
+
backend=None,
|
|
1336
|
+
lon0=None,
|
|
1337
|
+
lon_0=None,
|
|
1338
|
+
lat0=None,
|
|
1339
|
+
lat_0=None,
|
|
1340
|
+
lonlim=None,
|
|
1341
|
+
latlim=None,
|
|
1342
|
+
**kwargs,
|
|
1343
|
+
):
|
|
1344
|
+
"""
|
|
1345
|
+
Return a `cartopy.crs.Projection` or `~mpl_toolkits.basemap.Basemap` instance.
|
|
1346
|
+
|
|
1347
|
+
Parameters
|
|
1348
|
+
----------
|
|
1349
|
+
name : str, `cartopy.crs.Projection`, or `~mpl_toolkits.basemap.Basemap`
|
|
1350
|
+
The projection name or projection class instance. If the latter, it
|
|
1351
|
+
is simply returned. If the former, it must correspond to one of the
|
|
1352
|
+
`PROJ <https://proj.org>`__ projection name shorthands, like in
|
|
1353
|
+
basemap.
|
|
1354
|
+
|
|
1355
|
+
The following table lists the valid projection name shorthands,
|
|
1356
|
+
their full names (with links to the relevant `PROJ documentation
|
|
1357
|
+
<https://proj.org/operations/projections>`__),
|
|
1358
|
+
and whether they are available in the cartopy and basemap packages.
|
|
1359
|
+
(added) indicates a projection class that ultraplot has "added" to
|
|
1360
|
+
cartopy using the cartopy API.
|
|
1361
|
+
|
|
1362
|
+
.. _proj_table:
|
|
1363
|
+
|
|
1364
|
+
============= =============================================== ========= =======
|
|
1365
|
+
Key Name Cartopy Basemap
|
|
1366
|
+
============= =============================================== ========= =======
|
|
1367
|
+
``'aea'`` `Albers Equal Area <aea_>`_ ✓ ✓
|
|
1368
|
+
``'aeqd'`` `Azimuthal Equidistant <aeqd_>`_ ✓ ✓
|
|
1369
|
+
``'aitoff'`` `Aitoff <aitoff_>`_ ✓ (added) ✗
|
|
1370
|
+
``'cass'`` `Cassini-Soldner <cass_>`_ ✗ ✓
|
|
1371
|
+
``'cea'`` `Cylindrical Equal Area <cea_>`_ ✗ ✓
|
|
1372
|
+
``'cyl'`` `Cylindrical Equidistant <eqc_>`_ ✓ ✓
|
|
1373
|
+
``'eck1'`` `Eckert I <eck1_>`_ ✓ ✗
|
|
1374
|
+
``'eck2'`` `Eckert II <eck2_>`_ ✓ ✗
|
|
1375
|
+
``'eck3'`` `Eckert III <eck3_>`_ ✓ ✗
|
|
1376
|
+
``'eck4'`` `Eckert IV <eck4_>`_ ✓ ✓
|
|
1377
|
+
``'eck5'`` `Eckert V <eck5_>`_ ✓ ✗
|
|
1378
|
+
``'eck6'`` `Eckert VI <eck6_>`_ ✓ ✗
|
|
1379
|
+
``'eqdc'`` `Equidistant Conic <eqdc_>`_ ✓ ✓
|
|
1380
|
+
``'eqc'`` `Cylindrical Equidistant <eqc_>`_ ✓ ✓
|
|
1381
|
+
``'eqearth'`` `Equal Earth <eqearth_>`_ ✓ ✗
|
|
1382
|
+
``'europp'`` Euro PP (Europe) ✓ ✗
|
|
1383
|
+
``'gall'`` `Gall Stereographic Cylindrical <gall_>`_ ✗ ✓
|
|
1384
|
+
``'geos'`` `Geostationary <geos_>`_ ✓ ✓
|
|
1385
|
+
``'gnom'`` `Gnomonic <gnom_>`_ ✓ ✓
|
|
1386
|
+
``'hammer'`` `Hammer <hammer_>`_ ✓ (added) ✓
|
|
1387
|
+
``'igh'`` `Interrupted Goode Homolosine <igh_>`_ ✓ ✗
|
|
1388
|
+
``'kav7'`` `Kavrayskiy VII <kav7_>`_ ✓ (added) ✓
|
|
1389
|
+
``'laea'`` `Lambert Azimuthal Equal Area <laea_>`_ ✓ ✓
|
|
1390
|
+
``'lcc'`` `Lambert Conformal <lcc_>`_ ✓ ✓
|
|
1391
|
+
``'lcyl'`` Lambert Cylindrical ✓ ✗
|
|
1392
|
+
``'mbtfpq'`` `McBryde-Thomas Flat-Polar Quartic <mbtfpq_>`_ ✗ ✓
|
|
1393
|
+
``'merc'`` `Mercator <merc_>`_ ✓ ✓
|
|
1394
|
+
``'mill'`` `Miller Cylindrical <mill_>`_ ✓ ✓
|
|
1395
|
+
``'moll'`` `Mollweide <moll_>`_ ✓ ✓
|
|
1396
|
+
``'npaeqd'`` North-Polar Azimuthal Equidistant ✓ (added) ✓
|
|
1397
|
+
``'npgnom'`` North-Polar Gnomonic ✓ (added) ✗
|
|
1398
|
+
``'nplaea'`` North-Polar Lambert Azimuthal ✓ (added) ✓
|
|
1399
|
+
``'npstere'`` North-Polar Stereographic ✓ ✓
|
|
1400
|
+
``'nsper'`` `Near-Sided Perspective <nsper_>`_ ✓ ✓
|
|
1401
|
+
``'osni'`` OSNI (Ireland) ✓ ✗
|
|
1402
|
+
``'osgb'`` OSGB (UK) ✓ ✗
|
|
1403
|
+
``'omerc'`` `Oblique Mercator <omerc_>`_ ✗ ✓
|
|
1404
|
+
``'ortho'`` `Orthographic <ortho_>`_ ✓ ✓
|
|
1405
|
+
``'pcarree'`` `Cylindrical Equidistant <eqc_>`_ ✓ ✓
|
|
1406
|
+
``'poly'`` `Polyconic <poly_>`_ ✗ ✓
|
|
1407
|
+
``'rotpole'`` Rotated Pole ✓ ✓
|
|
1408
|
+
``'sinu'`` `Sinusoidal <sinu_>`_ ✓ ✓
|
|
1409
|
+
``'spaeqd'`` South-Polar Azimuthal Equidistant ✓ (added) ✓
|
|
1410
|
+
``'spgnom'`` South-Polar Gnomonic ✓ (added) ✗
|
|
1411
|
+
``'splaea'`` South-Polar Lambert Azimuthal ✓ (added) ✓
|
|
1412
|
+
``'spstere'`` South-Polar Stereographic ✓ ✓
|
|
1413
|
+
``'stere'`` `Stereographic <stere_>`_ ✓ ✓
|
|
1414
|
+
``'tmerc'`` `Transverse Mercator <tmerc_>`_ ✓ ✓
|
|
1415
|
+
``'utm'`` `Universal Transverse Mercator <utm_>`_ ✓ ✗
|
|
1416
|
+
``'vandg'`` `van der Grinten <vandg_>`_ ✗ ✓
|
|
1417
|
+
``'wintri'`` `Winkel tripel <wintri_>`_ ✓ (added) ✗
|
|
1418
|
+
============= =============================================== ========= =======
|
|
1419
|
+
|
|
1420
|
+
backend : {'cartopy', 'basemap'}, default: :rc:`geo.backend`
|
|
1421
|
+
Whether to return a cartopy `~cartopy.crs.Projection` instance
|
|
1422
|
+
or a basemap `~mpl_toolkits.basemap.Basemap` instance.
|
|
1423
|
+
lon0, lat0 : float, optional
|
|
1424
|
+
The central projection longitude and latitude. These are translated to
|
|
1425
|
+
`central_longitude`, `central_latitude` for cartopy projections.
|
|
1426
|
+
lon_0, lat_0 : float, optional
|
|
1427
|
+
Aliases for `lon0`, `lat0`.
|
|
1428
|
+
lonlim : 2-tuple of float, optional
|
|
1429
|
+
The longitude limits. Translated to `min_longitude` and `max_longitude` for
|
|
1430
|
+
cartopy projections and `llcrnrlon` and `urcrnrlon` for basemap projections.
|
|
1431
|
+
latlim : 2-tuple of float, optional
|
|
1432
|
+
The latitude limits. Translated to `min_latitude` and `max_latitude` for
|
|
1433
|
+
cartopy projections and `llcrnrlon` and `urcrnrlon` for basemap projections.
|
|
1434
|
+
|
|
1435
|
+
Other parameters
|
|
1436
|
+
----------------
|
|
1437
|
+
**kwargs
|
|
1438
|
+
Passed to the cartopy `~cartopy.crs.Projection` or
|
|
1439
|
+
basemap `~mpl_toolkits.basemap.Basemap` class.
|
|
1440
|
+
|
|
1441
|
+
Returns
|
|
1442
|
+
-------
|
|
1443
|
+
proj : mpl_toolkits.basemap.Basemap or cartopy.crs.Projection
|
|
1444
|
+
A cartopy or basemap projection instance.
|
|
1445
|
+
|
|
1446
|
+
See also
|
|
1447
|
+
--------
|
|
1448
|
+
mpl_toolkits.basemap.Basemap
|
|
1449
|
+
cartopy.crs.Projection
|
|
1450
|
+
ultraplot.ui.subplots
|
|
1451
|
+
ultraplot.axes.GeoAxes
|
|
1452
|
+
|
|
1453
|
+
References
|
|
1454
|
+
----------
|
|
1455
|
+
For more information on map projections, see the
|
|
1456
|
+
`wikipedia page <https://en.wikipedia.org/wiki/Map_projection>`__ and the
|
|
1457
|
+
`PROJ <https://proj.org>`__ documentation.
|
|
1458
|
+
|
|
1459
|
+
.. _aea: https://proj.org/operations/projections/aea.html
|
|
1460
|
+
.. _aeqd: https://proj.org/operations/projections/aeqd.html
|
|
1461
|
+
.. _aitoff: https://proj.org/operations/projections/aitoff.html
|
|
1462
|
+
.. _cass: https://proj.org/operations/projections/cass.html
|
|
1463
|
+
.. _cea: https://proj.org/operations/projections/cea.html
|
|
1464
|
+
.. _eqc: https://proj.org/operations/projections/eqc.html
|
|
1465
|
+
.. _eck1: https://proj.org/operations/projections/eck1.html
|
|
1466
|
+
.. _eck2: https://proj.org/operations/projections/eck2.html
|
|
1467
|
+
.. _eck3: https://proj.org/operations/projections/eck3.html
|
|
1468
|
+
.. _eck4: https://proj.org/operations/projections/eck4.html
|
|
1469
|
+
.. _eck5: https://proj.org/operations/projections/eck5.html
|
|
1470
|
+
.. _eck6: https://proj.org/operations/projections/eck6.html
|
|
1471
|
+
.. _eqdc: https://proj.org/operations/projections/eqdc.html
|
|
1472
|
+
.. _eqc: https://proj.org/operations/projections/eqc.html
|
|
1473
|
+
.. _eqearth: https://proj.org/operations/projections/eqearth.html
|
|
1474
|
+
.. _gall: https://proj.org/operations/projections/gall.html
|
|
1475
|
+
.. _geos: https://proj.org/operations/projections/geos.html
|
|
1476
|
+
.. _gnom: https://proj.org/operations/projections/gnom.html
|
|
1477
|
+
.. _hammer: https://proj.org/operations/projections/hammer.html
|
|
1478
|
+
.. _igh: https://proj.org/operations/projections/igh.html
|
|
1479
|
+
.. _kav7: https://proj.org/operations/projections/kav7.html
|
|
1480
|
+
.. _laea: https://proj.org/operations/projections/laea.html
|
|
1481
|
+
.. _lcc: https://proj.org/operations/projections/lcc.html
|
|
1482
|
+
.. _mbtfpq: https://proj.org/operations/projections/mbtfpq.html
|
|
1483
|
+
.. _merc: https://proj.org/operations/projections/merc.html
|
|
1484
|
+
.. _mill: https://proj.org/operations/projections/mill.html
|
|
1485
|
+
.. _moll: https://proj.org/operations/projections/moll.html
|
|
1486
|
+
.. _nsper: https://proj.org/operations/projections/nsper.html
|
|
1487
|
+
.. _omerc: https://proj.org/operations/projections/omerc.html
|
|
1488
|
+
.. _ortho: https://proj.org/operations/projections/ortho.html
|
|
1489
|
+
.. _eqc: https://proj.org/operations/projections/eqc.html
|
|
1490
|
+
.. _poly: https://proj.org/operations/projections/poly.html
|
|
1491
|
+
.. _sinu: https://proj.org/operations/projections/sinu.html
|
|
1492
|
+
.. _stere: https://proj.org/operations/projections/stere.html
|
|
1493
|
+
.. _tmerc: https://proj.org/operations/projections/tmerc.html
|
|
1494
|
+
.. _utm: https://proj.org/operations/projections/utm.html
|
|
1495
|
+
.. _vandg: https://proj.org/operations/projections/vandg.html
|
|
1496
|
+
.. _wintri: https://proj.org/operations/projections/wintri.html
|
|
1497
|
+
""" # noqa: E501
|
|
1498
|
+
# Parse input arguments
|
|
1499
|
+
# NOTE: Underscores are permitted for consistency with cartopy only here.
|
|
1500
|
+
# In format() underscores are not allowed for constistency with reset of API.
|
|
1501
|
+
lon0 = _not_none(lon0=lon0, lon_0=lon_0)
|
|
1502
|
+
lat0 = _not_none(lat0=lat0, lat_0=lat_0)
|
|
1503
|
+
lonlim = _not_none(lonlim, default=(None, None))
|
|
1504
|
+
latlim = _not_none(latlim, default=(None, None))
|
|
1505
|
+
is_crs = Projection is not object and isinstance(name, Projection)
|
|
1506
|
+
is_basemap = Basemap is not object and isinstance(name, Basemap)
|
|
1507
|
+
include_axes = kwargs.pop("include_axes", False) # for error message
|
|
1508
|
+
if backend is not None and backend not in ("cartopy", "basemap"):
|
|
1509
|
+
raise ValueError(
|
|
1510
|
+
f"Invalid backend={backend!r}. Options are 'cartopy' or 'basemap'."
|
|
1511
|
+
)
|
|
1512
|
+
if not is_crs and not is_basemap:
|
|
1513
|
+
backend = _not_none(backend, rc["geo.backend"])
|
|
1514
|
+
if not isinstance(name, str):
|
|
1515
|
+
raise ValueError(
|
|
1516
|
+
f"Unexpected projection {name!r}. Must be PROJ string name, "
|
|
1517
|
+
"cartopy.crs.Projection, or mpl_toolkits.basemap.Basemap."
|
|
1518
|
+
)
|
|
1519
|
+
for key_proj, key_cartopy, value in (
|
|
1520
|
+
("lon_0", "central_longitude", lon0),
|
|
1521
|
+
("lat_0", "central_latitude", lat0),
|
|
1522
|
+
("llcrnrlon", "min_longitude", lonlim[0]),
|
|
1523
|
+
("urcrnrlon", "max_longitude", lonlim[1]),
|
|
1524
|
+
("llcrnrlat", "min_latitude", latlim[0]),
|
|
1525
|
+
("urcrnrlat", "max_latitude", latlim[1]),
|
|
1526
|
+
):
|
|
1527
|
+
if value is None:
|
|
1528
|
+
continue
|
|
1529
|
+
if backend == "basemap" and key_proj == "lon_0" and value > 0:
|
|
1530
|
+
value -= 360 # see above comment
|
|
1531
|
+
kwargs[key_proj if backend == "basemap" else key_cartopy] = value
|
|
1532
|
+
|
|
1533
|
+
# Projection instances
|
|
1534
|
+
if is_crs or is_basemap:
|
|
1535
|
+
if backend is not None:
|
|
1536
|
+
kwargs["backend"] = backend
|
|
1537
|
+
if kwargs:
|
|
1538
|
+
warnings._warn_ultraplot(f"Ignoring Proj() keyword arg(s): {kwargs!r}.")
|
|
1539
|
+
proj = name
|
|
1540
|
+
backend = "cartopy" if is_crs else "basemap"
|
|
1541
|
+
|
|
1542
|
+
# Cartopy name
|
|
1543
|
+
# NOTE: Error message matches basemap invalid projection message
|
|
1544
|
+
elif backend == "cartopy":
|
|
1545
|
+
# Parse keywoard arguments
|
|
1546
|
+
import cartopy # ensure present # noqa: F401
|
|
1547
|
+
|
|
1548
|
+
for key in ("round", "boundinglat"):
|
|
1549
|
+
value = kwargs.pop(key, None)
|
|
1550
|
+
if value is not None:
|
|
1551
|
+
raise ValueError(
|
|
1552
|
+
"Ignoring Proj() keyword {key}={value!r}. Must be passed "
|
|
1553
|
+
"to GeoAxes.format() when cartopy is the backend."
|
|
1554
|
+
)
|
|
1555
|
+
|
|
1556
|
+
# Retrieve projection and initialize with nice error message
|
|
1557
|
+
try:
|
|
1558
|
+
crs = PROJS[name]
|
|
1559
|
+
except KeyError:
|
|
1560
|
+
message = f"{name!r} is an unknown cartopy projection class.\n"
|
|
1561
|
+
message += "The known cartopy projection classes are:\n"
|
|
1562
|
+
message += "\n".join(
|
|
1563
|
+
" " + key + " " * (max(map(len, PROJS)) - len(key) + 10) + cls.__name__
|
|
1564
|
+
for key, cls in PROJS.items()
|
|
1565
|
+
)
|
|
1566
|
+
if include_axes:
|
|
1567
|
+
from . import axes as paxes # avoid circular imports
|
|
1568
|
+
|
|
1569
|
+
message = message.replace("class.", "class or axes subclass.")
|
|
1570
|
+
message += "\nThe known axes subclasses are:\n" + paxes._cls_table
|
|
1571
|
+
raise ValueError(message) from None
|
|
1572
|
+
if name == "geos": # fix common mistake
|
|
1573
|
+
kwargs.pop("central_latitude", None)
|
|
1574
|
+
proj = crs(**kwargs)
|
|
1575
|
+
|
|
1576
|
+
# Basemap name
|
|
1577
|
+
# NOTE: Known issue that basemap sometimes produces backwards maps:
|
|
1578
|
+
# https://stackoverflow.com/q/56299971/4970632
|
|
1579
|
+
# NOTE: We set rsphere to fix non-conda installed basemap issue:
|
|
1580
|
+
# https://github.com/matplotlib/basemap/issues/361
|
|
1581
|
+
# NOTE: Adjust lon_0 to fix issues with Robinson (and related?) projections
|
|
1582
|
+
# https://stackoverflow.com/questions/56299971/ (also triggers 'no room for axes')
|
|
1583
|
+
# NOTE: Unlike cartopy, basemap resolution is configured
|
|
1584
|
+
# on initialization and controls *all* features.
|
|
1585
|
+
else:
|
|
1586
|
+
# Parse input arguments
|
|
1587
|
+
from mpl_toolkits import basemap # ensure present # noqa: F401
|
|
1588
|
+
|
|
1589
|
+
if name in ("eqc", "pcarree"):
|
|
1590
|
+
name = "cyl" # PROJ package aliases
|
|
1591
|
+
defaults = {"fix_aspect": True, **PROJ_DEFAULTS.get(name, {})}
|
|
1592
|
+
if name[:2] in ("np", "sp"):
|
|
1593
|
+
defaults["round"] = rc["geo.round"]
|
|
1594
|
+
if name == "geos":
|
|
1595
|
+
defaults["rsphere"] = (6378137.00, 6356752.3142)
|
|
1596
|
+
for key, value in defaults.items():
|
|
1597
|
+
if kwargs.get(key, None) is None: # allow e.g. boundinglat=None
|
|
1598
|
+
kwargs[key] = value
|
|
1599
|
+
|
|
1600
|
+
reso = _not_none(
|
|
1601
|
+
reso=kwargs.pop("reso", None),
|
|
1602
|
+
resolution=kwargs.pop("resolution", None),
|
|
1603
|
+
default=rc["reso"],
|
|
1604
|
+
)
|
|
1605
|
+
if reso in RESOS_BASEMAP:
|
|
1606
|
+
reso = RESOS_BASEMAP[reso]
|
|
1607
|
+
else:
|
|
1608
|
+
raise ValueError(
|
|
1609
|
+
f"Invalid resolution {reso!r}. Options are: "
|
|
1610
|
+
+ ", ".join(map(repr, RESOS_BASEMAP))
|
|
1611
|
+
+ "."
|
|
1612
|
+
)
|
|
1613
|
+
kwargs.update({"resolution": reso, "projection": name})
|
|
1614
|
+
try:
|
|
1615
|
+
proj = Basemap(**kwargs) # will raise helpful warning
|
|
1616
|
+
except ValueError as err:
|
|
1617
|
+
message = str(err)
|
|
1618
|
+
message = message.strip()
|
|
1619
|
+
message = message.replace("projection", "basemap projection")
|
|
1620
|
+
message = message.replace("supported", "known")
|
|
1621
|
+
if include_axes:
|
|
1622
|
+
from . import axes as paxes # avoid circular imports
|
|
1623
|
+
|
|
1624
|
+
message = message.replace("projection.", "projection or axes subclass.")
|
|
1625
|
+
message += "\nThe known axes subclasses are:\n" + paxes._cls_table
|
|
1626
|
+
raise ValueError(message) from None
|
|
1627
|
+
|
|
1628
|
+
proj._proj_backend = backend
|
|
1629
|
+
return proj
|
|
1630
|
+
|
|
1631
|
+
|
|
1632
|
+
# Deprecated
|
|
1633
|
+
Colors = warnings._rename_objs("0.8.0", Colors=get_colors)
|