Colorbar With subplots - python-2.7

How do I get colorbar when there is a figure and two subplots . I want separate colorbar for all subplots .
For Example
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.set_title('PC')
ax2.set_title('MC')
im=ax1.imshow(topo.sim.PC.activity,interpolation='nearest')
im1=ax2.imshow(topo.sim.MC.activity,interpolation='nearest')
I tried plt.colorbar() and ax1.colorbar() as well. Doesn't seem working.
I have animation on both the images in later part of the code.

If you rewrite your code as follows, then it will work. When using colorbar, you need to specify in which axis you want to put it. This is easy to figure out when looking at the examples in the matplotlib gallery.
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.set_title('PC')
ax2.set_title('MC')
im=ax1.imshow(topo.sim.PC.activity,interpolation='nearest')
im1=ax2.imshow(topo.sim.MC.activity,interpolation='nearest')
plt.colorbar(im, ax=ax1)
plt.colorbar(im1, ax=ax2)
If the colour bar is too big, you may want to use shrink kwarg.

Related

matplotlib legend bars and texts are not aligned

I use matplotlib in python2.7 to get a figure with multiple trajectories. I am getting this figure as the output of my code:
However, as you see the title of each trajectory is not aligned with the corresponding color line. I played with the options of legend, but did not figure out the solution.
Do you have any idea?
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
liste = range(1,13)
labels = ['3-3','3-4','3-5','3-6','4-3','4-4',
'4-5','4-6','5-3','5-4','5-5','5-6',
'6-3','6-4','6-5','6-6']
plt.figure(1)
plt.subplot(2,1,1)
for cnt, j in enumerate(labels):
a1 = range(100) # iter
a2 = np.random.randint(10,size=[100]) # dnn
a3 = np.ones((100)) # optimal
if cnt == 0:
plt.plot(a1,a3,label='BS', color='blue')
plt.plot(a1, np.divide(a3,a3), color='blue')
title_font = {'size':'11', 'color':'black', 'weight':'normal',
'verticalalignment':'bottom'}
plt.plot(a1,a2,label=j, color='red')
plt.xlabel('episode')
plt.ylabel('cost')
plt.grid(True)
lgd=plt.legend(bbox_to_anchor=(0., 1.0, 1.0, 0.102),
loc=3, ncol=len(liste), mode="expand", borderaxespad=0.)
plt.show()
The legend handles and labels do not fit into the legend box. You may see that when removing the mode="expand" label.
To get the legend entries take less space, use the handlelength, handletextpad and the columnspacing and play with the parameters until they fit. If that would still not be the case, using less columns is necessary. Set the ncols to a lower number.
E.g. with the following
lgd=plt.legend(bbox_to_anchor=(0., 1.02, 1.0, 0.102),
handlelength=0.9, handletextpad=0.3,columnspacing=0.7,
loc=3, ncol=9, mode="expand", borderaxespad=0.)
one would get an image with all legend entries fitting

Show all colors on colorbar with scatter plot

In the following I use scatter and an own ListedColormap to plot some coloured data points. In addition the corresponding colorbar is also plotted.
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, ListedColormap, BoundaryNorm
from numpy import arange
fig, ax = plt.subplots()
my_cm = ListedColormap(['#a71b1b','#94258f','#ea99e6','#ec9510','#ece43b','#a3f8ff','#2586df','#035e0d'])
bounds=range(8)
norm = BoundaryNorm(bounds, my_cm.N)
data = [1,2,1,3,0,5,3,4]
ret = ax.scatter(range(my_cm.N), [1]*my_cm.N, c=data, edgecolors='face', cmap=my_cm, s=50)
cbar = fig.colorbar(ret, ax=ax, boundaries=arange(-0.5,8,1), ticks=bounds, norm=norm)
cbar.ax.tick_params(axis='both', which='both',length=0)
If my data is not covering each value of the boundary interval, the colorbar does not show all colours (like in the added figure). If data would be set to range(8), I get a dot of each colour and the colorbar also shows all colours.
How can I force the colorbar to show all defined colours even if data does not contain all boundary values?
You need to manually set vminand vmax in your call to ax.scatter:
ret = ax.scatter(range(my_cm.N), [1]*my_cm.N, c=data, edgecolors='face', cmap=my_cm, s=50, vmin=0, vmax=7)
resulting in
If my data is not covering each value of the boundary interval, the colorbar does not show all colours (like in the added figure).
If either vminor vmax are `None the color limits are set via the method
autoscale_None, and the minimum and maximum of your data are therefore used.
So using your code it is actually not necessary for showing all colors in the colorbar that every value of the boundary interval is covered, only the minimum and maximum need to be included.
Using e.g. data = [0,0,0,0,0,0,0,7] results in the following:
When looking for something else, I found another solution to that problem: colorbar-for-matplotlib-plot-surface-command.
In that case, I do not need to set vmin and vmax and it is also working in cases if the arrays/lists of points to plot are empty. Instead a ScalarMappable is defined and provided to colorbar instead of the scatterinstance.
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, ListedColormap, BoundaryNorm
import matplotlib.cm as cm
from numpy import arange
fig, ax = plt.subplots()
my_cm = ListedColormap(['#a71b1b','#94258f','#ea99e6','#ec9510','#ece43b','#a3f8ff','#2586df','#035e0d'])
bounds=range(8)
norm = BoundaryNorm(bounds, my_cm.N)
mappable = cm.ScalarMappable(cmap=my_cm)
mappable.set_array(bounds)
data = [] # also x and y can be []
ax.scatter(x=range(my_cm.N), y=[1]*my_cm.N, c=data, edgecolors='face', cmap=my_cm, s=50)
cbar = fig.colorbar(mappable, ax=ax, boundaries=arange(-0.5,8,1), ticks=bounds, norm=norm)
cbar.ax.tick_params(axis='both', which='both',length=0)

Setting axes height - stretch axes height to legend height

I have a plot with a legend whose height is bigger than the axes height (like the result of the code below). Now, I would like to stretch the axes height in such a way that it ends at the legend's end.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 10.5, 0.5)
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
ax.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
What I would like to have is something like that (it does not matter, if the bottom of the grid or the bottom of the ticks ends with the legend)
I tried to reach my goal with appending following code but without any effect (legend_h is always =1.0):
legend_h = ax.get_legend().get_window_extent().height
ax_height = ax.get_window_extent().height
if ax_height < legend_h:
fig.set_figheight(legend_h/ax_height * fig.get_figheight())
Further on, it would be nice if I could only change the properties of the axes itself and not of the whole figure.
Edit:
My main purpose is to run the figure generation from a script but I also tried it in the Ipython notebook. One try was also to temporarily store the figure before getting the heights and setting the new figure height. But that also did not produce correct results.
I think you can achieve what you want by simply adding plt.draw() to what you already have, e.g.
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
ax.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
plt.draw()
legend_h = ax.get_legend().get_window_extent().height
ax_height = ax.get_window_extent().height
if ax_height < legend_h:
fig.set_figheight(legend_h/ax_height * fig.get_figheight())
Update: Also, you can try (which should work from a script, and based on this answer):
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 10.5, 0.5)
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
lgd = ax.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
fig.tight_layout()
fig.savefig('script.png', bbox_extra_artists=(lgd,), bbox_inches='tight')
In principle, #Matt Pitkin's answer shows the right approach. However, rather than set_figheight one would use set_size_inches. The calculation also needs to include the figure margins, which can be obtained from the fig.subplotpars.
Additionally to the height, we can also set the width of the figure, such that the legend is included.
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0,10); c=20
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
bbox = (1.01,1)
ax.legend(bbox_to_anchor=bbox, loc=2, borderaxespad=0.)
fig.canvas.draw()
legend_h = ax.get_legend().get_window_extent().height
ax_height = ax.get_window_extent().height
if ax_height < legend_h:
w,h = fig.get_size_inches()
h =legend_h/fig.dpi/(fig.subplotpars.top-fig.subplotpars.bottom)
fig.set_size_inches(w,h)
# set width as well
w,h = fig.get_size_inches()
r = ax.get_legend().get_window_extent().width/fig.dpi/w
fig.subplots_adjust(right=1-1.1*r)
plt.show()
The picture below is when running this as a script.
In Ipython or jupyter, the figure will automatically be cropped or expanded, because the png shown is automatically saved using the bbox_inches='tight' option. Therefore, the width adjustment is not necessary for a jupyter notebook.

matplotlib correlation matrix heatmap with grouped colors as labels

I have a correlation matrix hat I am trying to visualize with matplotlib. I can create a heatmap style figure just fine, but I am running into problems with how I want the labels. I'm not even sure if this is possible, but this is what I'm trying to do and can't seem to make it work:
My correlation matrix is 150 X 150. On either the x or y (or both...this doesn't matter) axis, I would like to group the labels and then simply label them with a color, or a white label on a color background.
To clarify, let's say I'd like to have 1-15 as "Group 1" and either simply be a Blue bar, or "Group 1" text on a blue bar. Then 16-20 as "Group 2" on a red bar, or simply a red bar. Etc, through all of the items in the matrix.
I have been failing at both grouping axis labels as well as getting any color on them. Any help would be greatly appreciated. My code is below, though it's quite basic and I don't know if it will help.
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
# COREELATION MATRIX TEST #
corr = np.genfromtxt(csv_path,delimiter=',')
fig = plt.figure()
ax1 = fig.add_subplot(111)
cmap = cm.get_cmap('jet', 30)
cax = ax1.imshow(corr, cmap=cmap)
ax1.grid(True)
plt.title('THIS IS MY TITLE')
fig.colorbar(cax, ticks=[-1,-0.8,-0.6,-0.4,-0.2,0.0,0.2,0.4,0.6,0.8,1.0])
plt.show()
You may create auxilary axes next to the plot and plot colored bar plots to them. Turning the axes spines off lets those bars look like labelboxes.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# COREELATION MATRIX TEST #
corr = 2*np.random.rand(150,150)-1
# labels [start,end]
labels = np.array([[0,15],[16,36],[37,82],[83,111],[112,149]])
colors = ["crimson", "limegreen","gold","orchid","turquoise"]
fig, ax = plt.subplots()
im = ax.imshow(corr, cmap="Blues")
ax.set_title('THIS IS MY TITLE')
fig.colorbar(im, ticks=[-1,-0.8,-0.6,-0.4,-0.2,0.0,0.2,0.4,0.6,0.8,1.0])
# create axes next to plot
divider = make_axes_locatable(ax)
axb = divider.append_axes("bottom", "10%", pad=0.06, sharex=ax)
axl = divider.append_axes("left", "10%", pad=0.06, sharey=ax)
axb.invert_yaxis()
axl.invert_xaxis()
axb.axis("off")
axl.axis("off")
# plot colored bar plots to the axes
barkw = dict( color=colors, linewidth=0.72, ec="k", clip_on=False, align='edge',)
axb.bar(labels[:,0],np.ones(len(labels)),
width=np.diff(labels, axis=1).flatten(), **barkw)
axl.barh(labels[:,0],np.ones(len(labels)),
height=np.diff(labels, axis=1).flatten(), **barkw)
# set margins to zero again
ax.margins(0)
ax.tick_params(axis="both", bottom=0, left=0, labelbottom=0,labelleft=0)
# Label the boxes
textkw = dict(ha="center", va="center", fontsize="small")
for k,l in labels:
axb.text((k+l)/2.,0.5, "{}-{}".format(k,l), **textkw)
axl.text(0.5,(k+l)/2., "{}-{}".format(k,l), rotation=-90,**textkw)
plt.show()

Difference between plt.subplots() and plt.figure()

In python matplotlib, there are two convention used to draw plots:
1.
plt.figure(1,figsize=(400,8))
2.
fig,ax = plt.subplots()
fig.set_size_inches(400,8)
Both have different ways of doing the same thing. eg defining axis label.
Which one is better to use? What is the advantage of one over the other?
Or what is the "Good Practice" for plotting a graph using matplotlib?
Although #tacaswell already gave a brief comment on the key difference. I will add more to this question only from my own experience with matplotlib.
plt.figure just creates a Figure (but with no Axes in it), this means you have to specify the ax to place your data (lines, scatter points, images). Minimum code should look like this:
import numpy as np
import matplotlib.pyplot as plt
# create a figure
fig = plt.figure(figsize=(7.2, 7.2))
# generate ax1
ax1 = fig.add_axes([0.1, 0.1, 0.5, 0.5])
# generate ax2, make it red to distinguish
ax2 = fig.add_axes([0.6, 0.6, 0.3, 0.3], fc='red')
# add data
x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x)
ax1.plot(x, y)
ax2.scatter(x, y)
In the case of plt.subplots(nrows=, ncols=), you will get Figure and an array of Axes(AxesSubplot). It is mostly used for generating many subplots at the same time. Some example code:
def display_axes(axes):
for i, ax in enumerate(axes.ravel()):
ax.text(0.5, 0.5, s='ax{}'.format(i+1), transform=ax.transAxes)
# create figures and (2x2) axes array
fig, axes = plt.subplots(2, 2, figsize=(7.2, 7.2))
# four (2*2=4) axes
ax1, ax2, ax3, ax4 = axes.ravel()
# for illustration purpose
display_axes(axes)
Summary:
plt.figure() is usually used when you want more customization to you axes, such as positions, sizes, colors and etc. You can see artist tutorial for more details. (I personally prefer this for individual plot).
plt.subplots() is recommended for generating multiple subplots in grids. You can also achieve higher flexibility using 'gridspec' and 'subplots', see details here.