From 9ef1caa0d5adcc7d6274d4b530037f6cd265e7f3 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 6 Jul 2021 08:29:11 -0700 Subject: [PATCH 1/2] FIX: fix twoslope norm for colorbars --- lib/matplotlib/colors.py | 13 +++++++---- .../test_colorbar/colorbar_twoslope.png | Bin 5886 -> 5932 bytes lib/matplotlib/tests/test_colorbar.py | 5 +++-- tutorials/colors/colormapnorms.py | 21 ++++++++++++++---- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index e0c42c5b69d5..53ac34dfa3db 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -1300,9 +1300,13 @@ def __call__(self, value, clip=None): if not self.vmin <= self.vcenter <= self.vmax: raise ValueError("vmin, vcenter, vmax must increase monotonically") + # must linearly extrapolate for ticks on colorbars that go + # beyond vmin and vmax: + min = self.vmin - (self.vcenter - self.vmin) + max = self.vmax + (self.vmax - self.vcenter) result = np.ma.masked_array( - np.interp(result, [self.vmin, self.vcenter, self.vmax], - [0, 0.5, 1.]), mask=np.ma.getmask(result)) + np.interp(result, [min, self.vcenter, max], + [-0.5, 0.5, 1.5]), mask=np.ma.getmask(result)) if is_scalar: result = np.atleast_1d(result)[0] return result @@ -1313,8 +1317,9 @@ def inverse(self, value): (vmin,), _ = self.process_value(self.vmin) (vmax,), _ = self.process_value(self.vmax) (vcenter,), _ = self.process_value(self.vcenter) - - result = np.interp(value, [0, 0.5, 1.], [vmin, vcenter, vmax]) + min = vmin - (vcenter - vmin) + max = vmax + (vmax - vcenter) + result = np.interp(value, [-0.5, 0.5, 1.5], [min, vcenter, max]) return result diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_twoslope.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_twoslope.png index 27d9227dcfe00c31b6ab1cb05484412a646662b1..b92103ae134756ab315f9c36ff1ac4434031da39 100644 GIT binary patch literal 5932 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 XFiMMfoLl5;0RFf-d+cC+8+hVh9%L>L literal 5886 zcmd^DdpMMN|NhQ2ITUJY<*OioR2{i2B8(m|5m zZH>f^)Y@T)X)zSCn$;wS5m6e9(=<*qe&6R|X4>7~dtJZ(->%EmFwggSK8O3hKlkUk z_z#aA>Wg$20RYr@x;T0QfTaO|=~7XGf3a?Ee-HoLLw52bdqsqjDThvm0QW=W$nXeq z_|ZUv=#Z09M74AD7zw@Tv8SH2x>9w9x z?(%BcVA818^7A%}0Jq;A);a*?)46u%DOjva-G$_VC+c0bb?1U_`n3I%`RQM^-PsQ_ z7k;aI$!#2-azp@5T2KFH4y$)0}hw?&(NgEd*dVL>1|#H!XEFA(^nhaDgSA#7XM7tGD5ANq}0R1qkFK8sUJ7cTYq!pQ%nA*rp8emdr{NfZOKVV zXSPmS-i;RAq3;gqUqqr5^>rHt`cqElS0wBSd0OmL!nEdG=eN~s9xO|~)h!;W&8%FR z-5cibU)^NMsjTMLT)X6RK+Cd5$d_7vo{kS^wq>RXq`lw3$oRTv-ik)tnR`oa@6Mk+ z!*0qIzMf9rVi=fmipT5|P)bL`n0?tW1X7JSdXS(MRuL^U@3`q_HSW&5XsmhpqI*}R(;iwquhz65ZRD952A1ExVfM~fi~FLGxR(+iR*_&jTjVDyp5CQn)ESpi*g_$; z-1oOrT1!yew1b|^I78Jc%J9Y@Mx!B7Snb z7O{qVr_2KT(nE1*U?F=P)}!m1Mq-t6Vd9~rL)t4IUI==u1e5Has+dYjdNUY(A|@s# z>P}YHw=-EM)+1GHC~{^`OYDDX8*HpSH9NW#U}(GFl9>892jsIs1}R9(g0dX>Bmfh` zAyT5-j)Du;k5zH9E_?u1C{kFAWJaOi0vlCYD*`9C%KrQC*Ed?G)sLeRWtI0PDABbs zhm8TOC)VH#yuHEwiooe{o*pIh0P`Jtb=gKMs!Y%jd6Z@! zJLN}x5D7-|HplaK94u1(QD2n!7)|?AE!+D}eUAZH^{jAql6PWMw8cC`hgWu$QtlUV z951Md#^ZZ>V+3EDb8>c-cC4^|XmuIF`vOyJKuxKg#*l?9wxRX#U!aW*K+(t*UC(qVz_>N7RD#n% z1L2_790U5MY-yR7#(2{X$5XdgE6;!1ljU%0jyOn0sf9?Ils}Wl8OX}RjLs@cgiHEyuk|#QZ36!y^NE?;2px|ZEYcM39enVnz*5^s;w}W!!pCZ7% z#~mbs3hn(j2r4A>w2B`V_(hqeokKcFj^D#n{ZW|eryjPtTh{IogCl)#5?)CGb$arQ z8j3nq&zB>DKyM5Gfgk?xrSWFGz6_=A29UfM10BqqI-s>QfnA7{LsO=Btcv`_w0KJO zF+U^Buu8@3;28Du`14mGah@4;*x(lOiDI%U<+g9!prIi>xgPyf=}_!`&MAJ|i5gyn zh&L4I&pN;V>C^I*31Ln?Eew^C&7p3YTk2V5U+W}Im3aAdtU66?8`IOeBRVlIjg>O$}rR>h+ z7!X8qS@SrqKd%i{Ctcu4A9uU&A5X7c4(me6q$G*f?E5sHOUO04i=I! zJG*vramc=C1zkZx{^F8818dCissrUzd_-q? zsqN=!$*VOOc5P=GElk661GXaZkanQ<1?ZQ+1495A*}3=@GEsxMBK%V#yB(Q0;dV+F zbmW5d^~yOwUIuk)ayq*8vtHD)sm532G0LycWR%$-dueQqv=@P(LY~R-y=DQDf1^kG zT#UM^-VHxXL?_uXlb|&?wh?tyJp0vdj|!xjCfpLTD$``o&0RMmnb3VDC7mqo7En$V zkrz@-xJYyNkBFiMS21QMJG7?v@tQDk6V9pP4?|Fkp$gZ~7L<9MOyjwyzy&U#JOhN8{xCP=%35UzQVS zv}2wfs9`daO_{&nrnWo5LIy*Bg=+Msvla?iTX7Gj-5z`Hj$GhciqvYe{G?U%yfYiX zhNj|WGebvalGd0|F#10&d;LO1rt}Tou5Oy&%Gm5eckIyKGgFV64Lj(S=Diy-dgIIk zHgwIPxm;T2<#Z|E_Gaxf`F-5rXpUXvHfR3e;Q6apL?S{M03o{r*j?byY_EQDEhm5C zM}`}0QGNnzAM1RXyWlAtn3k7!?TO4M4T_^{2wHf2@28Xf%Sg=bGZgrFG!T9kiP{L} zL~J`cCG*m6nY^VUl}B{1!G?&4Wo9iK%#VKvBJ{y-In{pyCzTbo;t3b}b1`;-mIYUl zz}_ru&{KRVD9g60E1{O5Vu)%kz8Uj5UR2sJkwb;W95_~ybPKb9IOxdtsRbV2jB6$u}5 z=BhkhuZwx}0F!s|YK93990Pr*S9%SsYUTZF@N-SkB$m&sx(f%YjW$L$QFZQ*W;vw# zs)nrrFh^J!#kmwXIuPIcNvo;nSQ$b*Q|>Fx_J^4aD4ZnI*@Y#a1kAp-hQ5+0Jihs| zDRjM+(Uw0^MEfQ`=bC>mrsq{3fff>NWRVp>3K^h|EVPKd(^=_&YF>j)%m0*|=-ss~ zPhrG4DyZ(PhT8r`G|J!2EhZdKTkL_!t>1j#B+oGAPeVS+`uZF1^ChMji){+;EF1F( z_MO?X8O!l}xT*G{tw%fY*YCU`Q>?UQ{t%D5TFT>iYleXcjIColXbGk zCC{%Ro}FJ&=HC#+XL`SkM05)6D z)z9sE7`RO1B9<625nn8YZm9091%CmKtQ~1*4=I!?^MyvhM?gpM>9wxeXW)I-0M-MQ zBiB6t1%Ctd!}I76zMGk`gOrLmps$g*FdyzEPv9ilLK8Ng+1 zyPn7~R&Ppx4wD&kauhL_TrL;w>)nEh&V*R2^{~Zv6T~98Wc2q_1T*o=@FR`S5%V&U zP$MErdk5jD<9ZvKu&CBwyHNFzJm_vg=|>B;WVb6M8Cf`rO9#1v52W*YRdo znrkuMNB4e;g9FOPjQ=g{1--r!X$d_!`zExJJ(H|5<(@qPX$z%zuTYq7&0B##QCjK; z*8$j?Cj1B!z8mr?joZVknHKPizpyv1L2Fo}You$|iV_Jk-$a*nyb1xsNdw|(s&r=Z z@MOEN^J%jFnHfvzcrL-`4CC6hYt-q_gUb4`lcOQ!F`|c4QBUkJkAB_gJ~AZ|P(Kgs zB@>xs+w6{akx9^H&n@_`dhJXY9aW{#r~E4uw|*`*&8gl^kbFg$8QwlF`LO@22z`n6 zKzRO!r~OnLeZj3-)&~Pqo>+2ty0XN&jl`5*vAYr`j${y5@`UeFPY=TPIccM(hepTy zxzwrg{=>6d>`0r=B2yWlFEHz7+bq;ZMtgS&2&>q|u{JzLssJ8enbC^F&UO30<&Ea8 a*@fgacZ&*=ZD#@ex6{ePk@5F{fBrAgYcjV0 diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index bb4781f131ed..75e12d3b44cc 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -776,11 +776,12 @@ def test_inset_colorbar_layout(): @image_comparison(['colorbar_twoslope.png'], remove_text=True, style='mpl20') def test_twoslope_colorbar(): - # Note that the first tick = 20, and should be in the middle + # Note that the second tick = 20, and should be in the middle # of the colorbar (white) + # There should be no tick right at the bottom, nor at the top. fig, ax = plt.subplots() - norm = mcolors.TwoSlopeNorm(20, 0, 100) + norm = mcolors.TwoSlopeNorm(20, 5, 95) pc = ax.pcolormesh(np.arange(1, 11), np.arange(1, 11), np.arange(100).reshape(10, 10), norm=norm, cmap='RdBu_r') diff --git a/tutorials/colors/colormapnorms.py b/tutorials/colors/colormapnorms.py index 41aa6310949a..56ad0d948715 100644 --- a/tutorials/colors/colormapnorms.py +++ b/tutorials/colors/colormapnorms.py @@ -277,7 +277,8 @@ # longitude depends on latitude. ax.set_aspect(1 / np.cos(np.deg2rad(49))) ax.set_title('TwoSlopeNorm(x)') -fig.colorbar(pcm, shrink=0.6) +cb = fig.colorbar(pcm, shrink=0.6) +cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000]) plt.show() @@ -312,7 +313,8 @@ def _inverse(x): # ---------------------------------------------------------- # # The `.TwoSlopeNorm` described above makes a useful example for -# defining your own norm. +# defining your own norm. Note for the colorbar to work, you must +# define an inverse for your norm: class MidpointNormalize(colors.Normalize): @@ -323,9 +325,18 @@ def __init__(self, vmin=None, vmax=None, vcenter=None, clip=False): def __call__(self, value, clip=None): # I'm ignoring masked values and all kinds of edge cases to make a # simple example... - x, y = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1] + # Note also that we must extrapolate linearly beyond vmin/vmax + min = self.vmin - (self.vcenter - self.vmin) + max = self.vmax + (self.vmax - self.vcenter) + x, y = [min, self.vcenter, max], [-0.5, 0.5, 1.5] return np.ma.masked_array(np.interp(value, x, y)) + def inverse(self, value): + min = self.vmin - (self.vcenter - self.vmin) + max = self.vmax + (self.vmax - self.vcenter) + y, x = [min, self.vcenter, max], [-0.5, 0.5, 1.5] + return np.interp(value, x, y) + fig, ax = plt.subplots() midnorm = MidpointNormalize(vmin=-500., vcenter=0, vmax=4000) @@ -334,5 +345,7 @@ def __call__(self, value, clip=None): cmap=terrain_map, shading='auto') ax.set_aspect(1 / np.cos(np.deg2rad(49))) ax.set_title('Custom norm') -fig.colorbar(pcm, shrink=0.6, extend='both') +cb = fig.colorbar(pcm, shrink=0.6, extend='both') +cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000]) + plt.show() From 38ad08e50c086844bf4e1f829cd2ab694a9c77e5 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Wed, 7 Jul 2021 14:14:03 -0700 Subject: [PATCH 2/2] FIX: use left and right --- lib/matplotlib/colors.py | 15 ++++++--------- tutorials/colors/colormapnorms.py | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 53ac34dfa3db..01005aabf282 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -1300,13 +1300,11 @@ def __call__(self, value, clip=None): if not self.vmin <= self.vcenter <= self.vmax: raise ValueError("vmin, vcenter, vmax must increase monotonically") - # must linearly extrapolate for ticks on colorbars that go - # beyond vmin and vmax: - min = self.vmin - (self.vcenter - self.vmin) - max = self.vmax + (self.vmax - self.vcenter) + # note that we must extrapolate for tick locators: result = np.ma.masked_array( - np.interp(result, [min, self.vcenter, max], - [-0.5, 0.5, 1.5]), mask=np.ma.getmask(result)) + np.interp(result, [self.vmin, self.vcenter, self.vmax], + [0, 0.5, 1], left=-np.inf, right=np.inf), + mask=np.ma.getmask(result)) if is_scalar: result = np.atleast_1d(result)[0] return result @@ -1317,9 +1315,8 @@ def inverse(self, value): (vmin,), _ = self.process_value(self.vmin) (vmax,), _ = self.process_value(self.vmax) (vcenter,), _ = self.process_value(self.vcenter) - min = vmin - (vcenter - vmin) - max = vmax + (vmax - vcenter) - result = np.interp(value, [-0.5, 0.5, 1.5], [min, vcenter, max]) + result = np.interp(value, [0, 0.5, 1], [vmin, vcenter, vmax], + left=-np.inf, right=np.inf) return result diff --git a/tutorials/colors/colormapnorms.py b/tutorials/colors/colormapnorms.py index 56ad0d948715..ae3ac8825602 100644 --- a/tutorials/colors/colormapnorms.py +++ b/tutorials/colors/colormapnorms.py @@ -325,17 +325,14 @@ def __init__(self, vmin=None, vmax=None, vcenter=None, clip=False): def __call__(self, value, clip=None): # I'm ignoring masked values and all kinds of edge cases to make a # simple example... - # Note also that we must extrapolate linearly beyond vmin/vmax - min = self.vmin - (self.vcenter - self.vmin) - max = self.vmax + (self.vmax - self.vcenter) - x, y = [min, self.vcenter, max], [-0.5, 0.5, 1.5] - return np.ma.masked_array(np.interp(value, x, y)) + # Note also that we must extrapolate beyond vmin/vmax + x, y = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1.] + return np.ma.masked_array(np.interp(value, x, y, + left=-np.inf, right=np.inf)) def inverse(self, value): - min = self.vmin - (self.vcenter - self.vmin) - max = self.vmax + (self.vmax - self.vcenter) - y, x = [min, self.vcenter, max], [-0.5, 0.5, 1.5] - return np.interp(value, x, y) + y, x = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1] + return np.interp(value, x, y, left=-np.inf, right=np.inf) fig, ax = plt.subplots() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy