KleinerKeks
KleinerKeks

Reputation: 17

One colorbar for two imshows

i have the following code and somehow i can not place the colorbar in such a place that it is not overlapping with the imshow itself and if I place it further outside it is cutted off :( I tried already a lot of things, but nothing worked for this problem. If the colorbar is not horizontal that would work for me, too, but then the label of the axis need to be perpendicular too.

HELP

import numpy as np
import matplotlib
import matplotlib.pyplot as plt


vegetables = [ "One magnet", "Two magnets","washer",
              "ST37 - 1", "ST37 - 2", "ST37 - 3", "RVS"]



farmers0 = ["1 cm/s", "1.25 cm/s"]



mask0 = np.array([[False, False, False, False, False, False, False],
                    [False, False, False, True, True, True, True]])

harvest1 = np.array([[ 1.9, 1.6,1.1,1.2,1.1,0.5,0.7],
                    [ 1.6, 0.8,0.9, 0,0,0,0]])

harvest1 = np.ma.array(harvest1, mask=mask0)

harvest2 = np.array([[ 0.9, 1.0,0.7,1.0,1.1,0.4,0.6],
                    [ 0.9, 0.8,0.8, 0,0,0,0]])
harvest2 = np.ma.array(harvest2, mask=mask0)




fig, ax = plt.subplots(2, sharex=True, sharey=False)



im0 = ax[0].imshow(harvest1, cmap='RdYlGn_r', vmin = 0.5, vmax = 1.65)

# We want to show all ticks...
ax[0].set_xticks(np.arange(len(vegetables)))
ax[0].set_yticks(np.arange(len(farmers0)))
# ... and label them with the respective list entries
ax[0].set_xticklabels(vegetables)
ax[0].set_yticklabels(farmers0)


# Rotate the tick labels and set their alignment.
plt.setp(ax[0].get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")



for i in range(len(farmers0)):
    for j in range(len(vegetables)):
        text = ax[0].text(j, i, harvest1[i, j],
                       ha="center", va="center", color="k")
    

im0 = ax[1].imshow(harvest2, cmap='RdYlGn_r', vmin = 0.5, vmax = 1.65)

# We want to show all ticks...
ax[1].set_xticks(np.arange(len(vegetables)))
ax[1].set_yticks(np.arange(len(farmers0)))
# ... and label them with the respective list entries
ax[1].set_xticklabels(vegetables)
ax[1].set_yticklabels(farmers0)


# Rotate the tick labels and set their alignment.
plt.setp(ax[1].get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")



for i in range(len(farmers0)):
    for j in range(len(vegetables)):
        text = ax[1].text(j, i, harvest2[i, j],
                       ha="center", va="center", color="k")
 
#fig.colorbar(im0, ax=ax.ravel().tolist(), orientation = 'horizontal')



#plt.gcf().subplots_adjust(top=1.5)

fig.tight_layout()

cbaxes = fig.add_axes([0.15,0.9,0.82,0.05]) #links, hight
#cax = divider.append.axes("bottom", size= "5%", pad = 0.05)
bar2 = plt.colorbar(im0, cax = cbaxes , orientation = 'horizontal')

bar2.ax.set_title('90 % confidence interval of $d$')



plt.show()

Upvotes: 1

Views: 162

Answers (2)

raphael
raphael

Reputation: 2970

here's a version that uses GridSpec to get more control over the axis-grid (e.g. so you can adjust the spacing between colorbar and axes etc.)

also note that i use aspect='auto' in the ax.imshow calls to allow non-square pixels!

import numpy as np
import matplotlib
import matplotlib.pyplot as plt

from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec

vegetables = [ "One magnet", "Two magnets","washer",
              "ST37 - 1", "ST37 - 2", "ST37 - 3", "RVS"]



farmers0 = ["1 cm/s", "1.25 cm/s"]



mask0 = np.array([[False, False, False, False, False, False, False],
                    [False, False, False, True, True, True, True]])

harvest1 = np.array([[ 1.9, 1.6,1.1,1.2,1.1,0.5,0.7],
                    [ 1.6, 0.8,0.9, 0,0,0,0]])

harvest1 = np.ma.array(harvest1, mask=mask0)

harvest2 = np.array([[ 0.9, 1.0,0.7,1.0,1.1,0.4,0.6],
                    [ 0.9, 0.8,0.8, 0,0,0,0]])
harvest2 = np.ma.array(harvest2, mask=mask0)


# -----------------------------------------------
# manually create an axes to have full control over spacing etc.
gs = GridSpec(2, 1, 
              height_ratios=(.5, 9.5))
gs_ax = GridSpecFromSubplotSpec(2, 1, gs[1], 
                                hspace=.5)

fig = plt.figure(figsize=(7, 7))
ax = []
ax.append(fig.add_subplot(gs_ax[0]))
ax.append(fig.add_subplot(gs_ax[1]))

cbaxes = fig.add_subplot(gs[0])

# manually ensure that x- and y- axes are shared
ax[0].get_shared_x_axes().join(ax[1])
ax[0].get_shared_y_axes().join(ax[1])
# -----------------------------------------------

im0 = ax[0].imshow(harvest1, cmap='RdYlGn_r', vmin = 0.5, vmax = 1.65,
                   aspect="auto")

# We want to show all ticks...
ax[0].set_xticks(np.arange(len(vegetables)))
ax[0].set_yticks(np.arange(len(farmers0)))
# ... and label them with the respective list entries
ax[0].set_xticklabels(vegetables)
ax[0].set_yticklabels(farmers0)


# Rotate the tick labels and set their alignment.
plt.setp(ax[0].get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")



for i in range(len(farmers0)):
    for j in range(len(vegetables)):
        text = ax[0].text(j, i, harvest1[i, j],
                       ha="center", va="center", color="k")
    

im0 = ax[1].imshow(harvest2, cmap='RdYlGn_r', vmin = 0.5, vmax = 1.65,
                   aspect="auto")

# We want to show all ticks...
ax[1].set_xticks(np.arange(len(vegetables)))
ax[1].set_yticks(np.arange(len(farmers0)))
# ... and label them with the respective list entries
ax[1].set_xticklabels(vegetables)
ax[1].set_yticklabels(farmers0)


# Rotate the tick labels and set their alignment.
plt.setp(ax[1].get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")



for i in range(len(farmers0)):
    for j in range(len(vegetables)):
        text = ax[1].text(j, i, harvest2[i, j],
                       ha="center", va="center", color="k")
 

#cax = divider.append.axes("bottom", size= "5%", pad = 0.05)
bar2 = plt.colorbar(im0, cax = cbaxes , orientation = 'horizontal')

bar2.ax.set_title('90 % confidence interval of $d$')

fig.tight_layout()

plt.show()

enter image description here

Upvotes: 1

raphael
raphael

Reputation: 2970

matplotlib actually warns you that tight_layout will not work with manually added axes...

UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect. fig.tight_layout()

use fig.subplots_adjust to set the boundaries of your plot manually!

so basically... just add this line at the very end and you're fine :-)

fig.tight_layout()
fig.subplots_adjust(top=0.8)

and maybe also explicitly specify the figure-size by changing your call to plt.subplots to:

fig, ax = plt.subplots(2, figsize=(7, 5), sharex=True, sharey=False)

enter image description here

Upvotes: 2

Related Questions