2

I need to share the same colorbar for a row of subplots. Each subplot has a symmetric logarithmic scaling to the color function. Each of these tasks has a nice solution explained here on stackoverflow: For sharing the color bar and for nicely formatted symmetric logarithmic scaling.

However, when I combine both tricks in the same code, the colorbar "forgets" that is is supposed to be symmetric logarithmic. Is there a way to work around this problem?

Testing code is the following, for which I combined the two references above in obvious ways:

import numpy as np                                                                                  
import matplotlib.pyplot as plt                                                                     
from mpl_toolkits.axes_grid1 import ImageGrid                                                       
from matplotlib import colors, ticker                                                               

# Set up figure and image grid                                                                      
fig = plt.figure(figsize=(9.75, 3))                                                                 

grid = ImageGrid(fig, 111,          # as in plt.subplot(111)                                        
                 nrows_ncols=(1,3),                                                                 
                 axes_pad=0.15,                                                                     
                 share_all=True,                                                                    
                 cbar_location="right",                                                             
                 cbar_mode="single",                                                                
                 cbar_size="7%",                                                                    
                 cbar_pad=0.15,                                                                     
                 )                                                                                  

data = np.random.normal(size=(3,10,10))                                                             
vmax = np.amax(np.abs(data))                                                                        

logthresh=4                                                                                         
logstep=1                                                                                           
linscale=1                                                                                          

maxlog=int(np.ceil(np.log10(vmax)))                                                                 

#generate logarithmic ticks                                                                         
tick_locations=([-(10**x) for x in xrange(-logthresh, maxlog+1, logstep)][::-1]                     
                +[0.0]                                                                              
                +[(10**x) for x in xrange(-logthresh,maxlog+1, logstep)] )                          

# Add data to image grid                                                                            
for ax, z in zip(grid,data):                                                                        
    print z                                                                                         
    im = ax.imshow(z, vmin=-vmax, vmax=vmax,                                                        
                   norm=colors.SymLogNorm(10**-logthresh, linscale=linscale))                       

# Colorbar                                                                                          
ax.cax.colorbar(im,ticks=tick_locations, format=ticker.LogFormatter())                              
ax.cax.toggle_label(True)                                                                           

#plt.tight_layout()    # Works, but may still require rect paramater to keep colorbar labels visible
plt.show()

The generated output is the following: enter image description here

mjo
  • 189
  • 1
  • 7

2 Answers2

0

Is that what you are trying to achieve?

import numpy as np                                                                                  
import matplotlib.pyplot as plt                                                                     
from mpl_toolkits.axes_grid1 import ImageGrid                                                       
from matplotlib import colors, ticker                                                               

# Set up figure and image grid                                                                      
fig = plt.figure(figsize=(9.75, 3))                                                                 

grid = ImageGrid(fig, 111,          # as in plt.subplot(111)                                        
                 nrows_ncols=(1,3),                                                                 
                 axes_pad=0.15,                                                                     
                 share_all=True                                                                                                                                        
                 )                                                                                  

data = np.random.normal(size=(3,10,10))                                                             
vmax = np.amax(np.abs(data))                                                                        

logthresh=4                                                                                         
logstep=1                                                                                           
linscale=1                                                                                          

maxlog=int(np.ceil(np.log10(vmax)))                                                                 

#generate logarithmic ticks                                                                         
tick_locations=([-(10**x) for x in xrange(-logthresh, maxlog+1, logstep)][::-1]                     
                +[0.0]                                                                              
                +[(10**x) for x in xrange(-logthresh,maxlog+1, logstep)] )                          


# Add data to image grid                                                                            
for ax, z in zip(grid,data):                                                                        
    print z                                                                                        
    im = ax.imshow(z, vmin=-vmax, vmax=vmax,                                                        
                   norm=colors.SymLogNorm(10**-logthresh, linscale=linscale)) 

cbaxes = fig.add_axes([0.9, 0.125, 0.02, 0.77])                     
fig.colorbar(im, format=ticker.LogFormatter(), ticks=tick_locations, cax = cbaxes)
ax.cax.toggle_label(True)   


#plt.tight_layout()    # Works, but may still require rect paramater to keep colorbar labels visible
plt.show()

Output: enter image description here

Erba Aitbayev
  • 4,167
  • 12
  • 46
  • 81
  • Yes, this is excactly what I was trying to achieve, thanks! Based on your answer, I managed to modify my original example code so that it runs without the need to hand-tune the axes dimensions as in your solution. I'll post this as a separate answer as I think that would be the preferred method for doing it. – mjo Sep 27 '16 at 19:33
0

Based on the solution by Erba Aitbayev, I found that it suffices to replace the line

ax.cax.colorbar(im,ticks=tick_locations, format=ticker.LogFormatter())

in the example code originally posted by the line

fig.colorbar(im,ticks=tick_locations, format=ticker.LogFormatter(), cax = ax.cax)

and everything works without the need to specify explicit dimensions for the colorbar. I have no idea why one works and the other doesn't, though. It would be good to add a corresponding comment in the post on sharing colorbars. I checked and the linear color scale in that example still works if colorbar is called as in the second of the two alternatives above. (I don't have sufficient reputation to add a comment there.)

mjo
  • 189
  • 1
  • 7