I have a figure with multiple subplot rows that all share an x axis.
Some of the rows require a color bar, but the other rows don't.
If I just use the color bar function, the subplots will be misaligned.
How do I place the color bars outside of the subplots such that all the rows will still be aligned?
I made a function that may help:
import numpy as np
from matplotlib import pyplot as plt
#function to add colorbar for imshow data and axis
def add_colorbar_outside(im,ax):
fig = ax.get_figure()
bbox = ax.get_position() #bbox contains the [x0 (left), y0 (bottom), x1 (right), y1 (top)] of the axis.
width = 0.01
eps = 0.01 #margin between plot and colorbar
# [left most position, bottom position, width, height] of color bar.
cax = fig.add_axes([bbox.x1 + eps, bbox.y0, width, bbox.height])
cbar = fig.colorbar(im, cax=cax)
#Example code:
x = np.random.random((10, 100))
fig, axes = plt.subplots(5,1, sharex = True)
im = axes[0].imshow(x, cmap = "Reds", aspect="auto", origin="lower")
add_colorbar_outside(im, axes[0])
im2 = axes[2].imshow(x, cmap = "coolwarm", aspect="auto", origin="lower")
add_colorbar_outside(im2, axes[2])
plt.show()
Related
Here I plot a bar graph and a line graph in the same figure:
There are 2 y-axes, money and increase_rate, each on a different scale.
How can I set the ticks of the two y-axes to be at the same hight?
import numpy as np
import matplotlib.pyplot as plt
time = [2000,2001,2002,2003]
money = [1000,2000,4000,6000]
increase_rate =[2,1,6,12]
fig, ax1 = plt.subplots()
width = 0.75
ax1.set_xlabel("")
ax1.set_ylabel("")
ax1.bar(time, money ,width = width, color = "#9370DB", alpha=0.6)
ax1.tick_params(axis='y')
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.spines['bottom'].set_visible(False)
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
ax2.set_ylabel("")
ax2.plot(time, increase_rate, color = "#FFFF00", lw = 3)
ax2.tick_params(axis='y')
ax2.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['top'].set_visible(False)
ax2.grid(color='black', linestyle='dotted', linewidth=0.8, alpha = 0.5)
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()
Use the set_yticks to set the tick positions.
ax1.set_yticks(np.linspace(0, max(money), 5))
ax2.set_yticks(np.linspace(0, max(increase_rate), 5))
Does anyone have a matplotlib example of two plots sharing the y-axis (with no space between the plots) with a single color bar pertaining to both subplots? I have not been able to find examples of this yet.
I created the following code based on your question. Personally I do not like it to have no space between the subplots at all. If you do want to change this at some point all you need to do is to replace plt.subplots_adjust(wspace = -.059) with plt.tight_layout().
Hope this helps
import numpy
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
#Random data
data = numpy.random.random((10, 10))
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1, aspect = "equal")
ax2 = fig.add_subplot(1,2,2, aspect = "equal", sharey = ax1) #Share y-axes with subplot 1
#Set y-ticks of subplot 2 invisible
plt.setp(ax2.get_yticklabels(), visible=False)
#Plot data
im1 = ax1.pcolormesh(data)
im2 = ax2.pcolormesh(data)
#Define locations of colorbars for both subplot 1 and 2
divider1 = make_axes_locatable(ax1)
cax1 = divider1.append_axes("right", size="5%", pad=0.05)
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("right", size="5%", pad=0.05)
#Create and remove the colorbar for the first subplot
cbar1 = fig.colorbar(im1, cax = cax1)
fig.delaxes(fig.axes[2])
#Create second colorbar
cbar2 = fig.colorbar(im2, cax = cax2)
#Adjust the widths between the subplots
plt.subplots_adjust(wspace = -.059)
plt.show()
The result is the following:
I am using matplotlib to make some plots and I have run into a few difficulties that I need help with.
problem 1) In order to keep a consistent colorscheme I need to only use half of the color axis. There are only positive values, so I want the zero values to be green, the mid values to be yellow and the highest values to be red. The color scheme that most closely matches this is gist_rainbow_r, but I only want the top half of it.
problem 2) I can't seem to figure out how to get the colorbar on the right hand side of the plot to show up or how to get it to let me label the axes.
If it helps, I am using the latest version of Anaconda wth the latext version of matplotlib
cmap = plt.get_cmap('gist_rainbow_r')
edosfig2 = plt.figure(2)
edossub2 = edosfig.add_subplot(1,1,1)
edossub2 = plt.contourf(eVec,kints,smallEDOS,cmap=cmap)
edosfig2.show()
If you have a specific set of colors that you want to use for you colormap, you can build it based on those. For example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
cmap = LinearSegmentedColormap.from_list('name', ['green', 'yellow', 'red'])
# Generate some data similar to yours
y, x = np.mgrid[-200:1900, -300:2000]
z = np.cos(np.hypot(x, y) / 100) + 1
fig, ax = plt.subplots()
cax = ax.contourf(x, y, z, cmap=cmap)
cbar = fig.colorbar(cax)
cbar.set_label('Z-Values')
plt.show()
However, if you did just want the top half of some particularly complex colormap, you can copy a portion of it by evaluating the colormap over the range you're interested in. For example, if you wanted the "top" half, you'd evaluate it from 0.5 to 1:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
# Evaluate an existing colormap from 0.5 (midpoint) to 1 (upper end)
cmap = plt.get_cmap('gist_earth')
colors = cmap(np.linspace(0.5, 1, cmap.N // 2))
# Create a new colormap from those colors
cmap2 = LinearSegmentedColormap.from_list('Upper Half', colors)
y, x = np.mgrid[-200:1900, -300:2000]
z = np.cos(np.hypot(x, y) / 100) + 1
fig, axes = plt.subplots(ncols=2)
for ax, cmap in zip(axes.flat, [cmap, cmap2]):
cax = ax.imshow(z, cmap=cmap, origin='lower',
extent=[x.min(), x.max(), y.min(), y.max()])
cbar = fig.colorbar(cax, ax=ax, orientation='horizontal')
cbar.set_label(cmap.name)
plt.show()
I have a plot in which I merge two datas. Given that, I have to show two different color bars, one for each data. I'm currently plotting my datas as follows:
plt.figure()
# Data 1
fig = plt.imshow(data1, interpolation='nearest', cmap='binary', vmin=0, vmax=1)
# Plotting just the nonzero values of data2
data2_x = numpy.nonzero(data2)[0]
data2_y = numpy.nonzero(data2)[1]
pts = plt.scatter(data2_x, data2_y, marker='s', c=data2[data2_x, data2_y])
plt.colorbar(pts)
plt.colorbar(fig, orientation="horizontal")
And this is the plot that I get:
However, I would like to reposition the color bars to have something like this (made with Photoshop):
Is that possible?
Thank you in advance.
Probably the 'easiest' way to do this is to lay the axes to be used for the color bars out by hand (via cbax = fig.add_axes([....])). You can then pass that axes to the color bar calls:
Something like:
from matplotlib import pyplot as plt
import numpy as np
fig = plt.figure(figsize=(8, 8))
ax = fig.add_axes([.1, .1, .8, .8])
im = ax.imshow(np.random.rand(150, 150), cmap='gray', interpolation='none')
sc = ax.scatter(2 + 146 * np.random.rand(150), 2 + 146 * np.random.rand(150),
c=np.random.rand(150), cmap='Accent', s=50, lw=0)
ax_cb1 = fig.add_axes([.1, .05, .8, .02])
ax_cb2 = fig.add_axes([.92, .1, .02, .8])
cb1 = fig.colorbar(im, cax=ax_cb1, orientation='horizontal')
cb1.ax.xaxis.set_label_position('top')
cb2 = fig.colorbar(sc, cax=ax_cb2, orientation='vertical')
you can link the colorbar to the axes with the ax-keyword, plt.gca() gives you the current axes:
plt.colorbar(object1, ax=plt.gca())
Is there a way to keep the same padding as the one used by a colorbar without seeing any colobar ?
Why ? Indeed, this will allow me to do one visual effect when passing from one plot without the color shading informations to the one using the colobar.
Here is one starting code coming from this post.
from matplotlib.pylab import *
import matplotlib.cm as cm
min_val = 0
max_val = 1
# See : http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps
my_cmap = cm.get_cmap('jet') # or any other one
norm = matplotlib.colors.Normalize(min_val, max_val) # the color maps work for [0, 1]
cmmapable = cm.ScalarMappable(norm, my_cmap)
cmmapable.set_array(range(min_val, max_val))
figure()
ax = gca()
cbar = colorbar(cmmapable, ticks=[0, 1])
cbar.ax.set_yticklabels(['Min', 'Max'])
show()
What I understand is that you want to make a presentation or so with two slides, one with a plot without color bar and the next slide with the same plot with the color bar. The plots in the two slides should have the same sizes so that when you change the slides the plot does not jump or resize.
Setting the colormap will resize the original Axes instance. You can use ax.get_position() to get the bounding box of the resized Axes. It returns a bounding box: Bbox(array([[ 0.125, 0.1 ], [ 0.745, 0.9 ]])) It gives left, bottom, right and top edge. I find it easier to cheat a bit and use ax._position.bounds, which gives a rect (left edge, bottom edge, width, height) that you can directly use to make a new axes, as shown below.
import matplotlib
import matplotlib.pyplot as plt
min_val = 0
max_val = 1
my_cmap = matplotlib.cm.get_cmap('jet')
norm = matplotlib.colors.Normalize(min_val, max_val)
cmmapable = matplotlib.cm.ScalarMappable(norm, my_cmap)
cmmapable.set_array(range(min_val, max_val))
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
cbar = plt.colorbar(cmmapable, ax = ax1, ticks=[0, 1])
cbar.ax.set_yticklabels(['Min', 'Max'])
# gives bounding box with left, right, bottom, top
print(ax1.get_position())
# gives rectangle with left, bottom, width, height
print(ax1._position.bounds)
fig2 = plt.figure()
ax2 = fig2.add_axes(ax1._position.bounds)
plt.show()
UPDATE: In the above solution there is no color bar, in the solution below there is a color bar, but you make it white and you remove the labels and the spines. If the background color of the figure is non-white, you'll see a white rectangle where the color bar is supposed to be.
import matplotlib
import matplotlib.pyplot as plt
min_val = 0
max_val = 1
my_cmap = matplotlib.cm.get_cmap('jet')
norm = matplotlib.colors.Normalize(min_val, max_val)
cmmapable = matplotlib.cm.ScalarMappable(norm, my_cmap)
cmmapable.set_array(range(min_val, max_val))
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
# set opacity to 0
cbar = plt.colorbar(cmmapable, ax = ax1, ticks=[0, 1], alpha = 0)
# remove the tick labels
cbar.ax.set_yticklabels(['', ''])
# set the tick length to 0
cbar.ax.tick_params(axis = 'y', which = "both", length = 0)
# set everything that has a linewidth to 0
for a in cbar.ax.get_children():
try:
a.set_linewidth(0)
except:
pass
plt.show()