Colorbar sticking to axes - python

I've got a small problem with the positioning of a colorbar using matplotlib. I'm plotting several subplots and one of them is an image. I want this image to have a colorbar but I want it to be "stuck" to the figure, so that there is no space between the two axes (the one from the figure and the one from the colorbar). Even if the figure is resized, the colorbar should always stick to the image axes.
PS - I don't mind if ax3 (the axes of my image) is deformed.
Here's what I've got for the moment:
# Imports
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from scipy import *
# Generating data
data = (rand(2048,2048), rand(2048,2048)+1000)
colorplot = "blue"
metadata = ("Test1", "Test2", "spectral")
# Generating figure and subplots
fig = plt.figure()
fig.subplots_adjust(right = 0.8)
gs1 = gridspec.GridSpec(3, 5)
gs1.update(left=0.05,\
right=0.95,\
top=0.95,\
bottom=0.05,\
wspace=0.2,\
hspace=0.05)
ax1 = fig.add_subplot(gs1[0,0])
ax2 = fig.add_subplot(gs1[0,1])
ax3 = fig.add_subplot(gs1[1:3,0:2])
ax4 = fig.add_subplot(gs1[:,2:])
list_axes = [ax1, ax2, ax3, ax4]
for i in list_axes:
i.autoscale_view(tight=False, scalex=False, scaley=True)
# Misc computation
array = data[1]-data[0]
mean_value = np.mean(array)
std_value = np.std(array)
nb_sigma = 5
ax1.imshow(data[0], interpolation = "nearest", cmap = metadata[2])
ax2.imshow(data[1], interpolation = "nearest", cmap = metadata[2])
im = ax3.imshow(array, vmin = np.min(array[array>mean_value-nb_sigma*std_value]), vmax = np.max(array[array<mean_value+nb_sigma*std_value]), interpolation = "nearest", cmap = metadata[2])
ax3.set_adjustable('box-forced')
# Creating axes for the colorbar
axes_cb = fig.add_axes([ax3.get_position().bounds[0],ax3.get_position().bounds[1], ax3.get_position().bounds[2], 0.05])
fig.colorbar(im, cax = axes_cb, orientation = 'horizontal')
axes_cb.yaxis.tick_left()
n, bins, patches = ax4.hist(array.flatten(), color = colorplot, bins = 50, normed = True)
plt.show()
Thank you!

Related

matplotlib: colorbar make subplots unequal size

I make two subplots with a common shared colorbar. So naturally I want to plot the colorbar only once.
However, when I do so, then my subplots become unequal in size.
How to place the colorbar outside the subplots on the right?
Minimal working example below
import numpy as np
from matplotlib import colors
import matplotlib.pyplot as plt
res = 100
x = np.linspace(0, 2*np.pi, res)
y = np.sin(x)
z = np.cos(x)
y2 = -np.sin(x)+0.4
z2 = 0.5*np.cos(2*x)
fig_width = 200/25.4
fig_height = 100/25.4
fig = plt.figure(figsize=(fig_width, fig_height))
gs = fig.add_gridspec(1, 2, wspace=0)
(ax, ax2) = gs.subplots(sharey='row')
images = []
images.append(ax.scatter(x, y, c=z))
images.append(ax2.scatter(x, y2, c=z2))
vmin = min(image.get_array().min() for image in images)
vmax = max(image.get_array().max() for image in images)
norm = colors.Normalize(vmin=vmin, vmax=vmax)
for im in images:
im.set_norm(norm)
cbar = fig.colorbar(images[0], ax=ax2)
cbar.set_label("mylabel", loc='top')
fig.tight_layout()
plt.show()
Try 1) pass the two axes as ax, and 2) move tight_layout before colorbar:
# other stuff
fig.tight_layout()
cbar = plt.colorbar(images[0], ax=(ax,ax2))
# other - other stuff
Output:

Increase Size of Heatmap in Matplotlib

My heatmap does not change size when changing the figsize parameters. I use Latex style for my plots and have set general parameters for the plots:
# Ploting:
import matplotlib
from matplotlib import rc
import matplotlib.pyplot as plt
%matplotlib inline
rc('text', usetex=True)
matplotlib.rcParams['text.latex.preamble'] = [r'\usepackage{amsmath}']
plt.style.reload_library()
plt.style.use('science')
matplotlib.rcParams['figure.figsize'] = (7.39, 4.567)
matplotlib.rcParams['lines.linewidth'] = 0.5
matplotlib.rcParams["legend.frameon"] = True # When you need legend background color
matplotlib.rcParams['patch.linewidth'] = 0.2
matplotlib.rcParams['axes.grid'] = True
matplotlib.rcParams['grid.color'] = '#b5b5b5'
matplotlib.rcParams['grid.linestyle'] = '-'
matplotlib.rcParams['grid.linewidth'] = 0.2
Here is the code for the actual heatmap:
fig, ax = plt.subplots(figsize = (16,5))
im = ax.imshow(Granger, cmap=cmap, interpolation='none', norm=norm)
cbar = fig.colorbar(im, extend='max')
cbar.cmap.set_over('green')
fig.axes[1].set_visible(False)
# We want to show all ticks...
ax.set_xticks(np.arange(len(Granger_colnames)))
ax.set_yticks(np.arange(len(Granger_rownames)))
# ... and label them with the respective list entries
ax.set_xticklabels(Granger_colnames)
ax.set_yticklabels(Granger_rownames)
#plt.show()
plt.savefig("/content/drive/MyDrive/Plots/Granger.pdf")
I want to space out the rows and columns so that the text is better visible.

Create symmetric figures when using matplotlib labels

I am using plt.subplots with both ax.set_ylabel and fig.supylabel. However, this creates figures that are off-centered.
Is it possible to automatically increase the right margin such that the red line is at the center of the figure?
In the case I am doing this manually, how can I precisely measure by how much I should increase the right margin?
How about this:
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
x = np.arange(50)
ax1.plot(x,np.sin(x))
ax2.plot(x,np.sin(x))
ax1.set_ylim(-1,1)
ax2.set_ylim(-1,1)
ax2.set_yticklabels('')
ax1.set_title('damped')
ax2.set_title('undamped')
ax1.set_ylabel('amplitude')
fig.suptitle('Different types of oscillations')
Output:
---edit---
Try this:
import matplotlib.gridspec as grd
fig = plt.subplots()
gs = grd.GridSpec(1, 2, wspace=0.5)
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
x = np.arange(50)
ax1.plot(x,np.sin(x))
ax2.plot(x,np.sin(x))
ax1.set_title('damped')
ax2.set_title('undamped')
ax1.set_ylabel('amplitude')
The keypoint is gs = grd.GridSpec(1, 2, wspace=0.5). Adjust wspace as you like. The plot below is for wspace=0.5

add colorbar on voxel

I need to add colorbar on my voxel, where the facecolors base on a array (in my case, the facecolors base on "data" array). This is my script:
x,y,z = np.mgrid[1:10,3:18,0:5]
data = np.random.normal(0,10,[x.shape[0]-1,x.shape[1]-1,x.shape[2]-1])
visiblebox = np.random.choice([True,False],data.shape)
ax = plt.figure().add_subplot(111,projection ='3d')
colors = plt.cm.plasma(data)
ax.voxels(x,y,z,visiblebox,facecolors=colors,alpha = 0.5,edgecolor='k')
plt.colorbar(colors)
plt.show()
i have try this:
fig = plt.figure()
ax = fig.add_subplot(111,projection ='3d')
p = ax.voxels(x,y,z,visiblebox,facecolors=colors,alpha = 0.5,edgecolor='k')
fig.colorbar(p)
But I get error. I am not sure how to get colorbar to work.
Colorbar for matplotlib plot_surface using facecolorsWhen I looked up SO, I found this answer. I'm not sure about the color bar, but I fixed it while looking at the answer and the color bar showed up.
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.colors
x,y,z = np.mgrid[1:10,3:18,0:5]
data = np.random.normal(0,10,[x.shape[0]-1,x.shape[1]-1,x.shape[2]-1])
visiblebox = np.random.choice([True,False],data.shape)
ax = plt.figure().add_subplot(111,projection ='3d')
colors = plt.cm.plasma(data)
norm = matplotlib.colors.Normalize(vmin=0, vmax=16)
vox = ax.voxels(x,y,z,visiblebox,facecolors=colors,alpha = 0.5,edgecolor='k')
m = cm.ScalarMappable(cmap=plt.cm.plasma, norm=norm)
m.set_array([])
plt.colorbar(m)
plt.show()

How to adjust columns widths with gridspec?

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.

Categories