0

I have a problem mapping the two histogram subplots with different ranges (8.53,9.09) and (9.55,10.83) to one colorbar. But colorbar is drawn using pcolormesh from first or second subplot, and because they don't have overlap the colorbar don't display correct color.

#first histogram subplot

binx=np.linspace(9.1,11.35,20)
biny=np.linspace(-1.45,0.8,20)
median=np.random.uniform(9.55,10.83, size=(20,20))
#finding min and max values of median
dim=np.size(median)
median1=np.reshape(median, (dim, ))
median1=median1[median1!=0]
vmin1=np.sort(median1)[0]
vmax1=np.sort(median1)[-1]  


hist1=ax1.pcolormesh(binx, biny, median.T, norm=LogNorm(), cmap='viridis')
hist1.set_clim(vmin1,vmax1)

#the second subplot histogram
man_mass=np.linspace(9.1,11.35,16)
man_sfr=np.linspace(-1.45,0.8,16)

man_med=np.array([[0.,0.,0.,0.,0.,0.,0.,8.56,0.,0.,0.,0.,0.,0.,0.,0.],
                 [0.,0.,0.,0.,0.,8.7,8.7,8.65,8.58,8.53,0.,0.,0.,0.,0.,0.],
                 [0.,0.,8.77,8.76,8.73,8.75,8.76,8.71,8.69,8.64,8.58,8.53,0.,0.,0.,0.],
                 [0.,8.83,8.82,8.82,8.81,8.79,8.79,8.77,8.78,8.74,8.69,8.66,8.59,0.,0.,0.],
                 [8.90,8.90,8.90,8.88,8.88,8.87,8.86,8.85,8.83,8.81,8.79,8.72,8.69,8.64,8.63,0.],
                 [8.98,8.96,8.95,8.94,8.94,8.93,8.93,8.92,8.90,8.88,8.85,8.82,8.77,8.72,8.71,0.],
                 [9.02,9.01,8.99,8.98,8.98,8.98,8.98,8.97,8.96,8.94,8.92,8.89,8.85,8.82,8.79,0.],
                 [9.05,9.04,9.03,9.02,9.02,9.02,9.01,9.01,9.01,8.99,8.97,8.96,8.92,8.88,8.86,8.84],
                 [0.0,9.06,9.05,9.04,9.04,9.03,9.03,9.03,9.03,9.03,9.02,8.99,8.98,8.94,8.90,0.0],
                 [0.0,9.08,9.07,9.05,9.05,9.05,9.05,9.05,9.05,9.05,9.04,9.04,9.01,9.0,8.97,8.93],
                 [0.0,9.09,9.07,9.06,9.06,9.06,9.06,9.06,9.06,9.06,9.06,9.05,9.04,9.03,9.0,8.98],
                 [0.0,0.0,9.09,9.07,9.06,9.07,9.06,9.06,9.06,9.06,9.07,9.07,9.06,9.05,9.04,9.02],
                 [0.0,0.0,0.0,9.09,9.08,9.08,9.07,9.07,9.07,9.07,9.07,9.07,9.06,9.07,9.06,9.04],
                 [0.0,0.0,0.0,0.0,0.0,9.09,9.07,9.07,9.07,9.07,9.07,9.06,9.07,9.07,9.07,0.0],
                 [0.0,0.0,0.0,0.0,0.0,0.0,9.09,9.08,9.08,9.07,9.07,9.07,9.07,9.08,9.05,0.0],
                 [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.06,9.07,9.07,9.06,9.06,0.0,0.0,0.0] ])

#max and min values of second median
dim=np.size(man_med)
man_med1=np.reshape(man_med, (dim, ))
man_med1=man_med1[man_med1!=0]
#print np.partition(median1,1)[1]
vmin2=np.sort(man_med1)[0]
vmax2=np.sort(man_med1)[-1]

hist2=ax2.pcolormesh(man_mass, man_sfr, man_med.T, norm=LogNorm(), cmap='viridis')
hist2.set_clim(vmin1,vmax1)

#pozition and spacing of subplots
plt.subplots_adjust(wspace=0,hspace=0,left=0.2, right=0.85, bottom=0.3)

p0 = ax1.get_position().get_points().flatten()
p1 = ax2.get_position().get_points().flatten()


#colorbar
ax_cbar = fig.add_axes([p0[0], 0.1, p1[2]-p0[0], 0.03])
cbar=plt.colorbar(hist1, cax=ax_cbar, orientation='horizontal')


plt.show()
plt.close()

I would like my colorbar to show values (colors) from smallest of the median values to largest (from vmin2=8.53 to vmax1=10.83) and to histograms show correct colors. This code as it is shows: colorbar mapped to first histogram (range of color (9.55,10.83)), and colors of the subplots are not connected so I have dark blue for 9.55 on first subplot and for 8.53 on second, and brightest yellow for 10.83 on first subplot and for 9.09 on second.

Please note: this post Set Colorbar Range in matplotlib should answer my question, but doesn't work for me, I'm not sure why. In it the ranges of color overlap, so they can use last od the images in plt.colorbar. I can't do that because my ranges don't overlap, I just want to expand colorbar to include both ranges.

Please help!

EDIT:

enter image description here

elizevin
  • 101
  • 1
  • 9
  • Please include a sample of `dff` – Charles Landau Apr 02 '19 at 13:05
  • Please provide a [mcve]. – ImportanceOfBeingErnest Apr 02 '19 at 13:15
  • @ImportanceOfBeingErnest Can you please elaborate what kind of data I should here post? I provided sample of data. Anything more I would need to attach some kind of file with complete data. I work with histograms here, so very large amount of mock data would be needed to make the code work correctly. I would be glad to send you original data if you can tell me how to attach it to my question. – elizevin Apr 02 '19 at 13:35
  • I don't think the problem is specific to your actual data. So you can provide code that generates some data and shows the problem in a minimal and runnable fashion. – ImportanceOfBeingErnest Apr 02 '19 at 13:40
  • @ImportanceOfBeingErnest Ok, I made up mock up median matrix for my first subplot. – elizevin Apr 02 '19 at 14:06

1 Answers1

1

The following should be a minimal example of the problem with a solution, namely to use the same norm for both plots.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm

x = np.arange(11)

a = np.linspace(1,5,100).reshape((10,10))
b = np.linspace(6,10,100).reshape((10,10))

fig, (ax1, ax2) = plt.subplots(ncols=2)

norm=LogNorm(min(a.min(),b.min()), max(a.max(),b.max()))
p1 = ax1.pcolormesh(x,x,a, norm=norm)
p2 = ax2.pcolormesh(x,x,b, norm=norm)

fig.colorbar(p1, ax=ax1)
fig.colorbar(p2, ax=ax2)

fig.tight_layout()
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thank you, this maps color consistently across both subplots. But I need just one colorbar which goes across both ranges of color (from 8.53 to 10.83). I can specify range of color with cbar.set_clim(8.53,10.83), but my colorbar still shows just range of (9.55 to 10.83). Strangely, it shows the same whether I write: cbar=plt.colorbar(hist1, cax=ax_cbar, orientation='horizontal') or cbar=plt.colorbar(hist2, cax=ax_cbar, orientation='horizontal'). I'm nor sure why. – elizevin Apr 03 '19 at 18:41
  • Sorry, I don't know where the numbers 8.53, 9.55 and 10.83 come from. Maybe you want to exchange the role of p1 and p2 in terms of the norm used? – ImportanceOfBeingErnest Apr 03 '19 at 18:52
  • The numbers comefrom my calculations. But here is what I need in your code's terms: if the color range for your first subplot is (0,4) (not (0,10)) and second (5,10) (and not (5,7)) AND you want to map them on the SAME colorbar. I need one colorbar to show both ranges of color - in your problem that's from (0,10) where the first subplot is mapped on the first half of the colorbar (from deep blue to blue-green), and the second subplot is mapped on second half of the colorbar (with green to bright yellow). – elizevin Apr 04 '19 at 16:27
  • I see. What makes this a bit hard it the use of `0` in a logarithmic norm, which would in principle need to result in an infinite colorbar. Can we define the range differently, or is 0 part of the data? – ImportanceOfBeingErnest Apr 04 '19 at 16:33
  • Oh, no, we can do anything really, as long as the ranges don't overlap. – elizevin Apr 04 '19 at 16:50
  • Ok, I updated the answer with one range being (1,5) and the other (6,10). This will work as long as no negative or zero data is present. – ImportanceOfBeingErnest Apr 04 '19 at 16:54
  • That is perfect in terms of mapping the color. Can we go to the part of drawing the same colorbar for both subplots please? – elizevin Apr 04 '19 at 17:21
  • Because both are the same, just remove one of the `fig.colorbar` lines. – ImportanceOfBeingErnest Apr 04 '19 at 17:24
  • I edited original post to include my image, as I'm thinking that maybe logarithmic scale of color is not the best choice maybe? Is there a way to modify the code for linear color scale, but keep correct mapping across subplots? – elizevin Apr 04 '19 at 18:00
  • A linear norm would be accomplished by replacing `LogNorm` in this answer by `Normalize`. Everything else would stay the same. – ImportanceOfBeingErnest Apr 04 '19 at 18:22
  • Wow, thank you so much for all your help. I found one mistake in my code which resulted in problem with my colorbar on the image above, I set color limit for second histogram. Now everything looks good :) – elizevin Apr 04 '19 at 18:47