Shrink/adjust the colorbar inside the plot - python

I am trying to shrink a colorbar, which is positioned inside the plot. When I position it outside of the plot (i. e. pad=0.05), it works just fine.
Here's a MWE:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
z = np.random.random((10,10))
fig, ax = plt.subplots()
ima = ax.matshow(z)
divider = make_axes_locatable(ax)
cb = fig.colorbar(ima, cax=divider.append_axes('right', size="4%", pad=-0.5),shrink=0.75,fraction=0.75)
plt.show()
I have tried both shrink and fraction but none of them seem to do the trick. I am attaching the output. Any help is greatly appreciated!

Your basic problem is that shrink and fraction don't work if you specify cax; it just fills the axes you specify.
I would do this with an inset_axes, where you should play with the positioning to get what you are after:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
z = np.random.random((10,10))
fig, ax = plt.subplots()
ima = ax.matshow(z)
divider = make_axes_locatable(ax)
cb = fig.colorbar(ima, cax=ax.inset_axes((0.9, 0.125, 0.05, 0.75)))
plt.show()

Related

Matplotlib - Tight layout of multiple subplots with colorbar

I have a series of subplots in a single row, all sharing the same colorbar and I would like to use plt.tight_layout().
However when used naively, the colorbar messes everything up. Luckily, I found this in the matplotlib documentation, but it works only for one subplot.
Minimal Working Example
I tried to adapt it to multiple subplots but the subplot to which the colorbar is assigned to ends up being smaller.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
plt.close('all')
arr = np.arange(100).reshape((10, 10))
fig, ax = plt.subplots(ncols=2, figsize=(8, 4))
im0 = ax[0].imshow(arr, interpolation="none")
im1 = ax[1].imshow(arr, interpolation='none')
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "5%", pad="3%")
plt.colorbar(im0, cax=cax)
plt.tight_layout()
This is what the result looks like.
With the newest matplotlib (3.6), there is a new option layout='compressed' for this situation:
import matplotlib.pyplot as plt
import numpy as np
arr = np.arange(100).reshape((10, 10))
fig, ax = plt.subplots(ncols=2, figsize=(4, 2), layout='compressed')
im0 = ax[0].imshow(arr)
im1 = ax[1].imshow(arr)
plt.colorbar(im0, ax=ax)
plt.show()

Matplotlib: Is there a way to get a colorbar axis from a parent axis?

I am doing a plot something like this:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
fig = plt.gcf()
ax = plt.gca()
ax.pcolormesh(np.random.rand(10, 10))
fig.colorbar(mpl.cm.ScalarMappable(), ax=ax)
The last line adds a colorbar and a second axis
fig.axes
>>> [<AxesSubplot:>, <AxesSubplot:label='<colorbar>'>]
My question:
Is there any relation between the two axes that can be used to get the axis of the colorbar (second in the list above) using only the axis returned by ax = plt.gca() (first returned in the list above)?
As far as I know, if you define pcolormesh and colorbar that way, no.
Anyway, you can define an ax for the pcolormesh and a cax for the colorbar beforehand. Then you can pass cax as parameter to matplotlib.pyplot.colorbar. In this way you can access to both axis ax and cax as you need.
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
grid_kws = {'width_ratios': (0.9, 0.05), 'wspace': 0.2}
fig, (ax, cax) = plt.subplots(1, 2, gridspec_kw = grid_kws, figsize = (10, 8))
ax.pcolormesh(np.random.rand(10, 10))
plt.colorbar(mpl.cm.ScalarMappable(), cax=cax)
plt.show()
In general, focusing on your code:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
fig = plt.gcf()
ax = plt.gca()
ax.pcolormesh(np.random.rand(10, 10))
fig.colorbar(mpl.cm.ScalarMappable(), ax=ax)
starting from ax, you can get its figure with ax.figure. From there, you can get the list of all figure axes with ax.figure.axes. So, if you want to get colobar's axis using only pcolormesh' axis, you should use:
ax.figure.axes[1]
The parent figure, as far as I know, is the only relation between the two axes.

Colorbar at the top of a figure: matplotlib [duplicate]

I have a matplotlib plot with a colorbar attached. I want to position the colorbar so that it is horizontal, and underneath my plot.
I have almost done this via the following:
plt.colorbar(orientation="horizontal",fraction=0.07,anchor=(1.0,0.0))
But the colorbar is still overlapping with the plot slightly (and the labels of the x axis). I want to move the colorbar further down, but I can't figure out how to do it.
using padding pad
In order to move the colorbar relative to the subplot, one may use the pad argument to fig.colorbar.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")
fig.colorbar(im, orientation="horizontal", pad=0.2)
plt.show()
using an axes divider
One can use an instance of make_axes_locatable to divide the axes and create a new axes which is perfectly aligned to the image plot. Again, the pad argument would allow to set the space between the two axes.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np; np.random.seed(1)
fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")
divider = make_axes_locatable(ax)
cax = divider.new_vertical(size="5%", pad=0.7, pack_start=True)
fig.add_axes(cax)
fig.colorbar(im, cax=cax, orientation="horizontal")
plt.show()
using subplots
One can directly create two rows of subplots, one for the image and one for the colorbar. Then, setting the height_ratios as gridspec_kw={"height_ratios":[1, 0.05]} in the figure creation, makes one of the subplots much smaller in height than the other and this small subplot can host the colorbar.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
fig, (ax, cax) = plt.subplots(nrows=2,figsize=(4,4),
gridspec_kw={"height_ratios":[1, 0.05]})
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")
fig.colorbar(im, cax=cax, orientation="horizontal")
plt.show()
Edit: Updated for matplotlib version >= 3.
Three great ways to do this have already been shared in this answer.
The matplotlib documentation advises to use inset_locator. This would work as follows:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np
rng = np.random.default_rng(1)
fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(rng.random((11, 16)))
ax.set_xlabel("x label")
axins = inset_axes(ax,
width="100%",
height="5%",
loc='lower center',
borderpad=-5
)
fig.colorbar(im, cax=axins, orientation="horizontal")

Undesired colorbar and axis labels/plot titles interaction

Dear fellow Python users,
I try to produce colormaps by combining LinearSegmentedColormap in combination with Imshow, using matplotlib library, and I'm having a hard time with the actual colorbar.
The colorbar does not behaves the way I want by default, that is, it is much too big for my graph. By default, I get this:
So, I used the following code lines to fix colorbar height, in reference to this post:
ax = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(img2, cax=cax)
An then I got this very strange result:
I'm not able to figure out why the added code lines interact with my axis and plot titles... Why do they go with the colorbar?
Here is the complete code:
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import matplotlib.colors as colors
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
#random data for example
clmap = np.random.rand(30,500)
#plot 2D color map
fig = plt.figure()
cmap2 = colors.LinearSegmentedColormap.from_list('my_colormap', ['blue','green','red'], 256)
img2 = plt.imshow(clmap,interpolation='nearest',cmap = cmap2,origin='lower')
ax = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(img2, cmap = cmap2, cax=cax)
plt.title('color map of atom probab at iteration 1')
plt.xlabel('atom id')
plt.ylabel('layer')
fig.savefig("map_p_1.png")
plt.gcf().clear()
You're mixing the pyplot state machine (plt) with the object oriented API.
After creating the second axes object (cax), it will be the current axes. All pyplot commands comming afterwards are applied to this axes.
The easiest way out is to apply the pyplot commands before creating the new axes:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
#random data for example
clmap = np.random.rand(30,500)
#plot 2D color map
fig = plt.figure()
plt.title('color map of atom probab at iteration 1')
plt.xlabel('atom id')
plt.ylabel('layer')
cmap2 = colors.LinearSegmentedColormap.from_list('my_colormap', ['blue','green','red'], 256)
img2 = plt.imshow(clmap,interpolation='nearest',cmap = cmap2,origin='lower')
ax = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(img2, cmap = cmap2, cax=cax)
fig.savefig("map_p_1.png")
plt.show()

Set scale of axis in plot using matplotlib

I am unable to scale the y-axis. My code is as follows:
import matplotlib.pyplot as pt
import numpy as np
fig = pt.figure()
ax = fig.add_subplot(111)
sample = 20
x=np.arange(sample)
y=10*np.sin(2*np.pi*x/20)
pt.plot(x,y)
pt.show()
The y axis has scale of 5. I'm trying to make it 1.
You can do so using set_yticks this way:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
sample = 20
x=np.arange(sample)
y=10*np.sin(2*np.pi*x/20)
ax.plot(x,y)
ax.set_yticks(np.arange(min(y), max(y)+1, 1.0)) # setting the ticks
ax.set_xlabel('x')
ax.set_ylabel('y')
fig.show()
Which produces this image wherein y-axis has a scale of 1.

Categories

Resources