matplotlib colorbar in each subplot - python

I would like to add a separate colorbar to each subplot in a 2x2 plot.
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
plt.colorbar(z1_plot,cax=ax1)
z2_plot = ax2.scatter(x,y,c = z2,vmin=0.0,vmax=40)
plt.colorbar(z1_plot,cax=ax2)
z3_plot = ax3.scatter(x,y,c = z3,vmin=0.0,vmax=894)
plt.colorbar(z1_plot,cax=ax3)
z4_plot = ax4.scatter(x,y,c = z4,vmin=0.0,vmax=234324)
plt.colorbar(z1_plot,cax=ax4)
plt.show()
I thought that this is how you do it, but the resulting plot is really messed up; it just has an all grey background and ignores the set_xlim , set_ylim commands I have (not shown here for simplicity). + it shows no color bars. Is this the right way to do it?
I also tried getting rid of the "cax = ...", but then the colorbar all goes on the bottom right plot and not to each separate plot!

This can be easily solved with the the utility make_axes_locatable. I provide a minimal example that shows how this works and should be readily adaptable:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
m1 = np.random.rand(3, 3)
m2 = np.arange(0, 3*3, 1).reshape((3, 3))
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(121)
im1 = ax1.imshow(m1, interpolation='None')
divider = make_axes_locatable(ax1)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im1, cax=cax, orientation='vertical')
ax2 = fig.add_subplot(122)
im2 = ax2.imshow(m2, interpolation='None')
divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im2, cax=cax, orientation='vertical');

In plt.colorbar(z1_plot,cax=ax1), use ax= instead of cax=, i.e. plt.colorbar(z1_plot,ax=ax1)

Specify the ax argument to matplotlib.pyplot.colorbar(), e.g.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2)
for i in range(2):
for j in range(2):
data = np.array([[i, j], [i+0.5, j+0.5]])
im = ax[i, j].imshow(data)
plt.colorbar(im, ax=ax[i, j])
plt.show()

Please have a look at this matplotlib example page. There it is shown how to get the following plot with four individual colorbars for each subplot:
I hope this helps.
You can further have a look here, where you can find a lot of what you can do with matplotlib.

Try to use the func below to add colorbar:
def add_colorbar(mappable):
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
last_axes = plt.gca()
ax = mappable.axes
fig = ax.figure
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = fig.colorbar(mappable, cax=cax)
plt.sca(last_axes)
return cbar
Then you codes need to be modified as:
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
add_colorbar(z1_plot)

Related

Adjust size of 2 contour maps to height of color bar [duplicate]

I use the following code to generate side-by-size images and I need to add colorbar only to the second image in the row. I use the following code for it
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.gridspec as gridspec
def plotting(x):
gs1 = gridspec.GridSpec(1, 2)
gs1.update(wspace=0.005, hspace=0.005)
plt.subplot(gs1[0])
plt.imshow(x)
plt.axis('off')
plt.title('dog')
ax1 = plt.subplot(gs1[1])
imc = plt.imshow(x, cmap='hot', interpolation='nearest')
plt.axis('off')
plt.title('dog')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(imc, cax=cax)
plt.tight_layout()
plt.show()
However it comes out the size of side-by-side images are not equal. I wonder how I could fix this issue?
You can use ImageGrid, which was created exactly for this purpose:
from mpl_toolkits.axes_grid1 import ImageGrid
x = np.random.random(size=(10,10))
fig = plt.figure()
grid = ImageGrid(fig, 111,
nrows_ncols = (1,2),
axes_pad = 0.05,
cbar_location = "right",
cbar_mode="single",
cbar_size="5%",
cbar_pad=0.05
)
grid[0].imshow(x)
grid[0].axis('off')
grid[0].set_title('dog')
imc = grid[1].imshow(x, cmap='hot', interpolation='nearest')
grid[1].axis('off')
grid[1].set_title('dog')
plt.colorbar(imc, cax=grid.cbar_axes[0])

How to set a vector as the y-axis with pcolor

I would like to set a y-axis with pcolor, such as the y-axis would be depth. in this example, I would like to set the vector z as the y-axis, how can I do that?
this is my code:
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.colors import LogNorm
from matplotlib.ticker import LogLocator
z=np.arange(1,90,2)
mrectest = np.random.rand(45, 15)
fig, ax = plt.subplots(figsize=(20,20))
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.1)
im = ax.pcolor(mrectest,vmin = 0.1, vmax = 800, norm = LogNorm(),cmap= 'jet')
cbar = fig.colorbar(im,cax=cax, orientation='vertical')
cbar.ax.yaxis.set_major_locator(LogLocator()) # <- Why? See above.
#ax.invert_yaxis()
#cbar.set_ticks(cbar.ax.yaxis.get_major_locator().tick_values(0.01, 1000))
plt.savefig('mrec_exp_28_02'+'.png',bbox_inches = "tight", format='png', dpi=1000)
plt.show()

Align matplotlib subplot axes with and without colorbars (for more than 2 axes)

How do you align the axes of different subplots when some have a colorbar and the others don't?
import numpy as np
import matplotlib.pyplot as plt
data1 = np.random.random([15,15])
data2 = np.random.random(15)
fig, [[ax1, ax2], [ax3, ax4], [ax5, ax6]] = plt.subplots(3,2)
for ax in [ax1, ax2, ax4, ax5, ax6]:
plt.sca(ax)
plt.pcolormesh(data1)
plt.colorbar()
plt.sca(ax3)
plt.plot(data2)
I would like to add white space to the left of ax3 so it is aligned with the other figures.
This was the best way so far of how to do this (based on https://stackoverflow.com/a/54473867/2383070).
I still wonder if there is an easier way, like simply adding whitespace to the left side of an axes.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
data1 = np.random.random([15,15])
data2 = np.random.random(15)
fig, [[ax1, ax2], [ax3, ax4], [ax5, ax6]] = plt.subplots(3,2)
for ax in [ax1, ax2, ax4, ax5, ax6]:
im1 = ax.pcolormesh(data1, cmap='magma')
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=.05)
plt.colorbar(im1, cax=cax)
im2 = ax3.plot(data2)
divider2 = make_axes_locatable(ax3)
cax2 = divider2.append_axes("right", size="5%", pad=.05)
cax2.remove()
This is on of the things constrained_layout is designed to do: https://matplotlib.org/tutorials/intermediate/constrainedlayout_guide.html
fig, [[ax1, ax2], [ax3, ax4], [ax5, ax6]] = plt.subplots(3,2,
constrained_layout=True)

Aligning x-axis with sharex using subplots and colorbar with matplotlib

I'm trying to create a set of subplots with a shared x axis using pyplot. This is all fine and dandy when the graphs are simple and all the x-axes align fine. However when I include a subplot that includes a colorbar, this compresses the width of that particular subplot to include the colorbar, resulting in the subplots no longer sharing the x-axis.
I've searched the web with no success with this. I've tried several different methods, but the simplest example I include below. I plot the exact same data in each subplot, but plot one with a colorbar. You can see the data no longer align along the x-axis.
Thanks in advance for your help!
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12))
im1 = ax1.scatter(x, y, c=y, cmap='magma')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=.05)
plt.colorbar(im1, cax=cax)
im2 = ax2.plot(x, y,'.')
plt.show()
Suggest using constrained_layout=True: https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12),
constrained_layout=True)
im1 = ax1.scatter(x, y, c=y, cmap='magma')
f.colorbar(im1, ax=ax1)
im2 = ax2.plot(x, y,'.')
This is one hacky way to do it.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12))
im1 = ax1.scatter(x, y, c=y, cmap='magma')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=.05)
plt.colorbar(im1, cax=cax)
im2 = ax2.plot(x, y,'.')
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("right", size="5%", pad=.05)
cax2.remove()
plt.show()
results in
You can account for the needed with of the colorbar already when you create the subplots. Instead of using the divider, generate four subplots with different widths using gridspec_kw. You can then delete the unneeded cax for the second subplot:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
##creating four subplots with unequally divided widths:
f, axes = plt.subplots(
2,2, sharex='col', figsize=(8,12),
gridspec_kw = {'width_ratios' : (10,1)},
)
ax1,ax2 = axes[:,0]
##remove unneeded Axes instance:
axes[1,1].remove()
im1 = ax1.scatter(x, y, c=y, cmap='magma')
plt.colorbar(im1, cax=axes[0,1])
im2 = ax2.plot(x, y,'.')
f.savefig('sharex_colorbar.png')
The result looks like this:
As an alternative to deleting the unneded subplot instances, you can also first generate the gridspec explicitly and generate only the needed subplots. This might be more suitable if you have many plots:
from matplotlib.gridspec import GridSpec
gs = GridSpec(nrows=2, ncols=2, width_ratios = (10,1))
f = plt.figure(figsize=(8,12))
ax1 = f.add_subplot(gs[0,0])
ax2 = f.add_subplot(gs[1,0],sharex=ax1)
cax = f.add_subplot(gs[0,1])
im1 = ax1.scatter(x, y, c=y, cmap='magma')
plt.colorbar(im1, cax=cax)

How to adjust size of two subplots, one with colorbar and another without, in pyplot ?

Consider this example
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
plt.subplot(121)
img = plt.imshow([np.arange(0,1,.1)],aspect="auto")
ax = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes("bottom", size="3%", pad=0.5)
plt.colorbar(img, cax=cax, orientation='horizontal')
plt.subplot(122)
plt.plot(range(2))
plt.show()
I want to make these two figures (plot region without colorbar) of the same size.
The size is automatically adjusted if the colorbar is plotted vertically or if two rows are used (211, 212) instead of two columns.
One can basically do the same for the second subplot as for the first, i.e. create a divider and append an axes with identical parameters, just that in this case, we don't want a colorbar in the axes, but instead simply turn the axis off.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
ax = plt.subplot(121)
img = ax.imshow([np.arange(0,1,.1)],aspect="auto")
divider = make_axes_locatable(ax)
cax = divider.append_axes("bottom", size="3%", pad=0.5)
plt.colorbar(img, cax=cax, orientation='horizontal')
ax2 = plt.subplot(122)
ax2.plot(range(2))
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("bottom", size="3%", pad=0.5)
cax2.axis('off')
plt.show()
You can now do this without recourse to an extra toolkit by using constrained_layout:
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, constrained_layout=True)
ax = axs[0]
img = ax.imshow([np.arange(0,1,.1)],aspect="auto")
fig.colorbar(img, ax=ax, orientation='horizontal')
axs[1].plot(range(2))
plt.show()

Categories