Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Cannot create custom colorbar with SymLogNorm #16269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dstansby opened this issue Jan 20, 2020 · 2 comments
Closed

Cannot create custom colorbar with SymLogNorm #16269

dstansby opened this issue Jan 20, 2020 · 2 comments

Comments

@dstansby
Copy link
Member

Bug report

Bug summary
Creating a colorbar with a SymLogNorm fails, using the fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax) example given in the docs.

Code for reproduction

import matplotlib.pyplot as plt
import matplotlib.colors as mcolor
import matplotlib.cm as cm

norm = mcolor.SymLogNorm(5)

fig, ax = plt.subplots()
fig.colorbar(cm.ScalarMappable(norm=norm, cmap='viridis'), cax=ax)

Actual outcome

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    fig.colorbar(cm.ScalarMappable(norm=norm, cmap='viridis'), cax=ax)
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/figure.py", line 2201, in colorbar
    cb = cbar.colorbar_factory(cax, mappable, **cb_kw)
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/colorbar.py", line 1686, in colorbar_factory
    cb = Colorbar(cax, mappable, **kwargs)
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/colorbar.py", line 1210, in __init__
    ColorbarBase.__init__(self, ax, **kwargs)
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/colorbar.py", line 472, in __init__
    self.draw_all()
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/colorbar.py", line 495, in draw_all
    self._process_values()
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/colorbar.py", line 945, in _process_values
    b = self.norm.inverse(self._uniform_y(self.cmap.N + 1))
  File "/Users/dstansby/github/matplotlib/lib/matplotlib/colors.py", line 1276, in inverse
    val = val * (self._upper - self._lower) + self._lower
AttributeError: 'SymLogNorm' object has no attribute '_upper'

Expected outcome

No error

Matplotlib version

  • Operating system: macOS 10.15.2
  • Matplotlib version: '3.2.0rc2.post1221+g20805b805'
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.7
  • Jupyter version (if applicable):
  • Other libraries:
@anntzer
Copy link
Contributor

anntzer commented Jan 21, 2020

diff --git i/lib/matplotlib/colors.py w/lib/matplotlib/colors.py
index 2f8c89265..598956d76 100644
--- i/lib/matplotlib/colors.py
+++ w/lib/matplotlib/colors.py
@@ -1213,8 +1213,14 @@ class SymLogNorm(Normalize):
         Normalize.__init__(self, vmin, vmax, clip)
         self.linthresh = float(linthresh)
         self._linscale_adj = (linscale / (1.0 - np.e ** -1))
-        if vmin is not None and vmax is not None:
-            self._transform_vmin_vmax()
+
+    @property
+    def _lower(self):
+        return self._transform(np.array(self.vmin, float))
+
+    @property
+    def _upper(self):
+        return self._transform(np.array(self.vmax, float))
 
     def __call__(self, value, clip=None):
         if clip is None:
@@ -1263,12 +1269,6 @@ class SymLogNorm(Normalize):
         a[~masked] /= self._linscale_adj
         return a
 
-    def _transform_vmin_vmax(self):
-        """Calculates vmin and vmax in the transformed system."""
-        vmin, vmax = self.vmin, self.vmax
-        arr = np.array([vmax, vmin]).astype(float)
-        self._upper, self._lower = self._transform(arr)
-
     def inverse(self, value):
         if not self.scaled():
             raise ValueError("Not invertible until scaled")
@@ -1276,16 +1276,6 @@ class SymLogNorm(Normalize):
         val = val * (self._upper - self._lower) + self._lower
         return self._inv_transform(val)
 
-    def autoscale(self, A):
-        # docstring inherited.
-        super().autoscale(A)
-        self._transform_vmin_vmax()
-
-    def autoscale_None(self, A):
-        # docstring inherited.
-        super().autoscale_None(A)
-        self._transform_vmin_vmax()
-
 
 class PowerNorm(Normalize):
     """

appears to fix it (and is also likely more correct against the case where the user directly assigns to .vmin/.vmax). I guess we could cache _upper and _lower and detect when vmin/vmax change (e.g. using lru_cache or whatnot)... but I doubt that the recomputation is a bottleneck (you're going to compute the transform over a large number of actual values other than vmin/vmax, anyways).

I'm not volunteering to write tests, though :)

@QuLogic
Copy link
Member

QuLogic commented Jul 8, 2021

This was fixed by #16457.

@QuLogic QuLogic closed this as completed Jul 8, 2021
@QuLogic QuLogic added this to the v3.4.0 milestone Jul 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants