For plotting a heatmap I did:
f, ax = plt.subplots(1, 1, dpi=dpi)
im0 = ax.imshow(data, cmap='Wistia')
Due to the dimensionality of data with (300K, 20) resulting Y-axis was squeezed.
Maybe squeezing of Y-axis happened because of :
from mpl_toolkits.axes_grid1 import make_axes_locatable
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im0, cax=cax)
How can I get heatmap more look like (with full Y-range [0, 20]):
Related
Consider this MWE:
import seaborn
import matplotlib
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
a = np.random.randn(int(1e3))
b = np.random.rand(int(1e3))
vmin = -10
vmax = 10
seaborn.histplot(x=a, y=b, cmap='PuBu_r', cbar=True, vmin=vmin, vmax=vmax)
plt.show()
plt.close()
ax = seaborn.histplot(x=a, y=b)
# Add colorbar with help of axis divier.
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
sm = plt.cm.ScalarMappable(cmap='PuBu_r', norm=norm)
sm.set_array([])
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
plt.colorbar(sm, cax=cax)
plt.show()
plt.close()
Naively, I'd expect both histograms to look alike, with the only difference being that the first histogram should be somewhat smaller than the second one, since the second histogram puts the colorbar with an axis divider.
However, the output is:
To be honest, I cannot explain the difference in the color scheme between the two histograms to myself. Isn't seaborn (or matplotlib) mixing things up here?
EDIT: As was pointed out in the comments, putting vmin and vmax explicitly into the seaborn.histplot() calls fixed the problem. However, when comparing the output of
seaborn.histplot(x=a, y=b, cmap='PuBu_r', cbar=False, vmin=vmin, vmax=vmax)
and
ax = seaborn.histplot(x=a, y=b)
# Add colorbar with help of axis divier.
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
sm = plt.cm.ScalarMappable(cmap='PuBu_r', norm=norm)
sm.set_array([])
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
plt.colorbar(sm, cax=cax)
I noticed that the second image (leaving out the colorbar) does not have the same size as the first image:
Is there any way to enforce this?
This question already has answers here:
Change the labels of a colorbar from increasing to decreasing values
(3 answers)
Closed 2 years ago.
This is an example in the web https://matplotlib.org/gallery/axes_grid1/simple_colorbar.html#sphx-glr-gallery-axes-grid1-simple-colorbar-py
I want to invert the legend make it look like this:
That means the max in the bottom and min in the top in the legend.
making the colorbar "mirrored"
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
ax = plt.subplot(111)
im = ax.imshow(np.arange(100).reshape((10, 10)))
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
plt.show()
You can access the ax of the colorbar and then call invert_yaxis(). This will invert both the colors and the tick labels of the colorbar.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
ax = plt.subplot(111)
im = ax.imshow(np.arange(100).reshape((10, 10)))
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
cax.invert_yaxis()
plt.show()
PS: If the ax of the colorbar isn't provided, you can access it as
cbar = plt.colorbar(im)
cbar.ax.invert_yaxis()
Is it possible to have a colorbar smaller than the height of figure?
I know that we can adjust the size of colorbar with
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="3%", pad=0.05)
pl.colorbar(im, cax=cax)
size only adjust the width of colorbar. but how about the height?
I am looking for a colorbar at upper right, with the half height of the figure.
You can use fig.add_axes and fine-tune the parameters as you wish:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
fig = plt.figure()
ax = plt.subplot(111)
im = ax.imshow(np.arange(100).reshape((10, 10)))
c = plt.colorbar(im, cax = fig.add_axes([0.78, 0.5, 0.03, 0.38]))
How can I fix this plot?
I want:
both color bars not overlap.
make their height equal to the plot.
Here is my code:
combined = (...) # some irrelevant to question data praparation - this variable contain square matrix with RGBA chanels
plt.figure(dpi=300, figsize=(2.1,1.9))
gs = gridspec.GridSpec(1, 3, width_ratios=[20,1,1])
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
ax3 = plt.subplot(gs[2])
cax = ax1.imshow(combined, interpolation="None")
mpl.colorbar.ColorbarBase(ax2, cmap=cmap_top, norm=norm_top)
mpl.colorbar.ColorbarBase(ax3, cmap=cmap_top, norm=norm_top)
I'm using python 3.6 and matplotlib 2.0.
I would consider two possibilities for problem number 1:
a. Modify the wspace parameter that controls horizontal space between figures i.e. :
gs = gridspec.GridSpec(1, 3, width_ratios=[20,1,1])
gs.update(wspace=0.05)
b. Add an extra column between the first and second colorbar that acts as some void space:
gs = gridspec.GridSpec(1, 4, width_ratios=[20,1,0.15,1])
As for problem number 2, I would write it differently:
ax2=plt.subplot(gs[0,1] )
cb1 = matplotlib.colorbar.ColorbarBase(ax2, cmap="RdBu_r")
Hope it helps!
A suggestion would be not to use gridspec in this case. You can create new colorbar axes by using the make_axes_locatable class from the mpl_toolkits.axes_grid1.
You would then need to find some fitting parameters for the padding of the divider, as well as for the figure margins (using subplots_adjust).
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.colorbar
import numpy as np; np.random.seed(1)
a = -np.log10(np.random.rand(25,25))
fig, ax = plt.subplots(dpi=300, figsize=(2.1,1.9))
fig.subplots_adjust(left=0.15,right=.78)
cmap=plt.cm.terrain
norm = matplotlib.colors.LogNorm(1e-3, 4)
im = ax.imshow(a, interpolation="None", cmap=cmap, norm=norm)
divider = make_axes_locatable(ax)
cax = divider.new_horizontal(size="5%", pad=0.05)
cax2 = divider.new_horizontal(size="5%", pad=0.45)
fig.add_axes(cax)
fig.add_axes(cax2)
plt.colorbar(im, cax=cax)
plt.colorbar(im, cax=cax2)
plt.show()
Making enough space such that the colorbar ticklabels don't overlap takes in this case almost half the figure width, but I suppose this is how you want it.
I need to plot a mesh grid with "temperature map" values, currently I'm using imshow, with a colormap. This is described in the Matplotlib overview, so I modified the example to force custom aspect of the figure:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)), aspect=0.5)
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
plt.savefig("test.png")
But the result is not what I want, the colorbar is higher than the master axis:
Interestingly, when the colormap is horizontal, it is scaled properly:
cax = divider.append_axes("bottom", size="5%", pad=0.05)
plt.colorbar(im, cax=cax, orientation="horizontal")
What happens here is that you applied an aspect of 0.5 to the imshow image. This divides the vertical extend of your image by 2, while the colorbar keeps the original extent. I see 2 solutions
you can manually set the size of the colorbar using:
cax = fig.add_axes([0.85, 0.3, 0.04, 0.4])
...or you can apply an aspect to cax to keep its y-dimension consequent with the image. In your case as you set size to 5%, setting aspect=1 would give you an image with 1/20 of the original vertical-extent. To obtain 1/2 as for the image set aspect to 20*0.5= 10. You could create a variable for aspect, if you want to experiment with changing the aspect on the figure, the colorbar will follow.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
fig = plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)), aspect=0.5)
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05, aspect=10)
#cax = fig.add_axes([0.85, 0.3, 0.04, 0.4])
plt.colorbar(im, cax=cax)
plt.show()
You can match the size of the colorbar to the size of the axes containing your data using the following snippet.
def match_colorbar(cb, ax=None):
"""
Match the size of the colorbar with the size of the axes.
Args:
ax: Axes from which the colorbar "stole" space.
cb: Colorbar to match to `ax`.
"""
ax = ax or plt.gca()
bbox = ax.get_position()
cb_bbox = cb.ax.get_position()
if cb.orientation == "vertical":
# Update bottom and height.
left = cb_bbox.xmin
width = cb_bbox.width
bottom = bbox.ymin
height = bbox.height
else:
# Update left and width.
left = bbox.xmin
width = bbox.width
bottom = cb_bbox.ymin
height = cb_bbox.height
pos = [left, bottom, width, height]
cb.ax.set_position(pos)
Here is an example.
fig, ax = plt.subplots()
im = ax.imshow(np.arange(100).reshape((10,10)), aspect=0.5)
cb = fig.colorbar(im)
match_colorbar(cb)