Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using colorbar with secondary y axis

I am trying to add a colorbar to a chart that has a secondary y-axis. A minimal-ish example of my difficulties is given below. The trouble is that I cannot add a colorbar to an AxesSubplot object, and adding it directly as plt.colorbar puts it on top of my graph- see how it overlaps the rightmost y-axis. How can I fix this? Cheers.

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

time=[]
temp=[]
temp_f=[]
height=[]
for ti in np.arange( 0, 10, 0.5 ):
    for te in np.arange( -12, 12, 0.5 ):
        height.append( np.sqrt(1+ti)/(1+te*te)+ti*te/12.5 )
        time.append(ti)
        temp.append(te)
        temp_f.append( 32+9.0*te/5)

time=np.array(time)
temp=np.array(temp)
temp_f=np.array(temp_f)
height=np.array(height)

xi, yi = np.linspace(time.min(), time.max(),25), np.linspace(temp.min(), temp.max(), 25)
xi, yi = np.meshgrid(xi, yi)

rbf = scipy.interpolate.Rbf(time, temp, height, function='linear')
zi = rbf(xi, yi)

fig = plt.figure()
ax1 = plt.gca()
ax1.set_xlabel( "Time (s)" )
ax1.set_ylabel( "Celsius" )

ax2 = ax1.twinx()
ax2.set_ylabel( "Fahrenheit" )
ax2.set_ylim( [temp_f.min(), temp_f.max()] )

img = ax1.imshow( zi, vmin=height.min(), vmax=height.max(), origin='lower', 
       extent=[time.min(), time.max(), temp.min(), temp.max()],
       aspect='auto', cmap='YlOrRd')

plt.colorbar(img, label=r"Height (cm)",format='%1.1f', ax=ax1)

plt.show()
like image 488
TheBigH Avatar asked Oct 30 '25 17:10

TheBigH


2 Answers

See positioning the colorbar.

You can manually specify the location of the colorbar by:

cbaxes = fig.add_axes([1, 0.15, 0.03, 0.7])
plt.colorbar(img, label=r"Height (cm)",format='%1.1f', ax=ax1, cax=cbaxes)
like image 90
yangjie Avatar answered Nov 01 '25 05:11

yangjie


plt.colorbar does a good job for simple plots with one axes. With more complex setups it can get confused. So it is better to manually setup the axes for the colorbar. You can use the subplots function for that. By supplying gridspec_kw you can tell the underlying GridSpec object how you want the widths to be specified:

fig, [ax1, cax] = plt.subplots(1,2, gridspec_kw=dict(width_ratios=[10,1]))

when creating the colorbar you want to specify the axes which should be used to create the colorbar in:

plt.colorbar(img, label=r"Height (cm)",format='%1.1f', ax=ax1, cax=cax)

So with the full code:

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

time=[]
temp=[]
temp_f=[]
height=[]
for ti in np.arange( 0, 10, 0.5 ):
    for te in np.arange( -12, 12, 0.5 ):
        height.append( np.sqrt(1+ti)/(1+te*te)+ti*te/12.5 )
        time.append(ti)
        temp.append(te)
        temp_f.append( 32+9.0*te/5)

time=np.array(time)
temp=np.array(temp)
temp_f=np.array(temp_f)
height=np.array(height)

xi, yi = np.linspace(time.min(), time.max(),25), np.linspace(temp.min(), temp.max(), 25)
xi, yi = np.meshgrid(xi, yi)

rbf = scipy.interpolate.Rbf(time, temp, height, function='linear')
zi = rbf(xi, yi)

fig, [ax1, cax] = plt.subplots(1,2, gridspec_kw=dict(width_ratios=[10,1]))
ax1.set_xlabel( "Time (s)" )
ax1.set_ylabel( "Celsius" )

ax2 = ax1.twinx()
ax2.set_ylabel( "Fahrenheit" )
ax2.set_ylim( [temp_f.min(), temp_f.max()] )

img = ax1.imshow( zi, vmin=height.min(), vmax=height.max(), origin='lower', 
       extent=[time.min(), time.max(), temp.min(), temp.max()],
       aspect='auto', cmap='YlOrRd')

plt.colorbar(img, label=r"Height (cm)",format='%1.1f', ax=ax1, cax=cax)

plt.show()

You get:

enter image description here

like image 20
hitzg Avatar answered Nov 01 '25 06:11

hitzg