Figure size changes with colorbar - python

The following question arose while toying around with figure sizes. I am trying to create figures of the same size (let's say 5 by 5 inches). Thing is, when I change the notation of the colorbar, the figure size seems to change. In the code below, this can be achieved by changing the final if to tick_check=False. How can I force the figures to be the same size, regardless of the colorbar notation?
Here's my MWE:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
def foo(arr, sub, fig, _str, vmin, vmax, ticks, fontsize, check, tick_check):
cm=plt.cm.jet
P2A=0.12; box_size=5
image=sub.matshow(arr,origin='low',cmap=cm,vmin=vmin,vmax=vmax,extent=[-10.92,10.92,-10.92,10.92],interpolation='bilinear')
sub.axis([-box_size,box_size,-box_size,box_size])
divider = make_axes_locatable(sub)
sub.set_title(_str,fontsize=fontsize); sub.set_xlabel(r"A",fontsize=fontsize); sub.set_ylabel(r"B",fontsize=fontsize)
if tick_check: cbar=fig.colorbar(image, cax=divider.append_axes("right", size="5%", pad=0.05), format='%.1E')
else: cbar=fig.colorbar(image, cax=divider.append_axes("right", size="5%", pad=0.05), format='%.1f')
cbar.set_ticks(ticks); sub.xaxis.tick_bottom(); sub.tick_params(labelsize=10);sub.set_title(_str, y=1.01); plt.tight_layout(h_pad=1)
d_arr=np.random.rand(182,182)
fig0, (a1) = plt.subplots(ncols=1,figsize=(5,5))
im=foo(d_arr,a1,fig0,r'Test',np.min(d_arr),np.max(d_arr),np.arange(np.min(d_arr),np.max(d_arr),0.1),10,False,True)
plt.savefig('Foo.eps',bbox_inches='tight',dpi=100)
Any help is appreciated.

Turns out, the solution to this problem is the keyword aspect, which needs to be set to auto. So:
image=sub.matshow(arr,origin='low',cmap=cm,vmin=vmin,vmax=vmax,extent=[-10.92,10.92,-10.92,10.92],interpolation='bilinear', aspect='auto')

Related

Total figure width with external legend in matplotlib

I'm using
plt.legend(bbox_to_anchor = (1,1))
to put the legend outside my figure. The journal to which I'm submitting requires specific sizes for the figures. When I use this method, it increases the total width of my figure beyond the required size. I want to have the figure sized exactly to specification. Is there a way to calculate the total width of the figure including the external legend, so that I can reduce my figsize parameter accordingly?
The following works fine; I've just coloured the figure so you can see its size.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
fig, ax = plt.subplots(figsize=(3, 3), constrained_layout=True)
fig.set_facecolor('0.5')
ax.plot(np.arange(10), label='Boo')
ax.legend(bbox_to_anchor=(1, 1))
fig.savefig('boo.png')

Display a colorbar without associated image map

I have matplotlib figure that displays an image, histogram and a colobar under the histogram, generated by the following code:
import numpy as np
import imageio
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
image = imageio.imread('imageio:camera.png')
fig, axes = plt.subplots(2,1,figsize=(8,4))
divider = make_axes_locatable(axes[1])
cbar_ax = divider.append_axes("bottom", size='15%', pad=0.02)
im = axes[0].imshow(image,cmap='gray')
values, bins, patches = axes[1].hist(image.ravel(), 255, color='#cccccc', density=True)
cbar = plt.colorbar(im, cax=cbar_ax, orientation='horizontal')
fig.savefig('test.png', dpi=300)
plt.show()
This code generates exactly this image below
Since it's a recurrent image (I'm studying the histogram), I would like to create a figure just displaying the histogram and the associated colorbar below it.
But to display a colorbar is mandatory provides a image_map as argument and I need to call ax.imshow() to have a image_map. The exact output I want is something like
And I don't know how to achieve that.
Of course I could edit my images in some editor (as I did), but this isn't acceptable, since every update takes me a huge effort editing many image.

figsize in matplotlib is not changing the figure size? [duplicate]

This question already has answers here:
How do I change the size of figures drawn with Matplotlib?
(14 answers)
Closed 4 years ago.
As you can see the code produces a barplot that is not as clear and I want to make the figure larger so the values can be seen better. This doesn't do it. What is the correct way?
x is a dataframe and x['user'] is the x axis in the plot and x['number'] is the y.
import matplotlib.pyplot as plt
%matplotlib inline
plt.bar(x['user'], x['number'], color="blue")
plt.figure(figsize=(20,10))
The line with the plt.figure doesn't change the initial dimensions.
One option (as mentioned by #tda), and probably the best/most standard way, is to put the plt.figure before the plt.bar:
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plt.bar(x['user'], x['number'], color="blue")
Another option, if you want to set the figure size after creating the figure, is to use fig.set_size_inches (note I used plt.gcf here to get the current figure):
import matplotlib.pyplot as plt
plt.bar(x['user'], x['number'], color="blue")
plt.gcf().set_size_inches(20, 10)
It is possible to do this all in one line, although its not the cleanest code. First you need to create the figure, then get the current axis (fig.gca), and plot the barplot on there:
import matplotlib.pyplot as plt
plt.figure(figsize=(20, 10)).gca().bar(x['user'], x['number'], color="blue")
Finally, I will note that it is often better to use the matplotlib object-oriented approach, where you save a reference to the current Figure and Axes and call all plotting functions on them directly. It may add more lines of code, but it is usually clearer code (and you can avoid using things like gcf() and gca()). For example:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111)
ax.bar(x['user'], x['number'], color="blue")
Try setting up the size of the figure before assigning what to plot, as below:
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(20,10))
plt.bar(x['user'], x['number'], color="blue")

Save figure with clip box from another figure

Normally if you plot two different figures using the default settings in pyplot, they will be exactly the same size, and if saved can be neatly aligned in PowerPoint or the like. I'd like to generate one figure, however, which has a legend outside of the figure. The script I'm using is shown below.
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0,1,201)
y1=x**2
y2=np.sin(x)
fig1=plt.figure(1)
plt.plot(x,y1,label='y1')
handles1,labels1=plt.gca().get_legend_handles_labels()
lgd1=plt.gca().legend(handles1,labels1,bbox_to_anchor=(1.27,1),borderaxespad=0.)
fig2=plt.figure(2)
plt.plot(x,y2)
fig1.savefig('fig1',bbox_extra_artists=(lgd1,),bbox_inches='tight')
fig2.savefig('fig2')
plt.show()
The problem is that in PowerPoint, I can no longer align the two figures left and have their axes aligned. Due to the use of the 'extra artists' and 'bbox_inches=tight' arguments for the first figure, the width of its margins becomes different from the second figure.
Is there any way to 'transfer' the clip box from the first figure to the second figure, such that they can be aligned by 'align left' in PowerPoint?
I think an easier way to achieve what you want is to just construct one figure with two subplots, and let matplotlib align everything for you.
Do you think doing something like this is a good idea?
import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(0,1,201)
y1=x**2
y2=np.sin(x)
fig = plt.figure()
a = fig.add_subplot(211)
a.plot(x,y1, label='y1')
lgd1 = a.legend(bbox_to_anchor = (1.27,1), borderaxespad=0.)
a = fig.add_subplot(212)
a.plot(x,y2)
fig.savefig('fig',bbox_extra_artists=(lgd1,),bbox_inches='tight')

Enlarging plot in mplot3D

I'm trying to compose an image with both 2D and 3D plot. so far I've done the following:
import idlsave
import matplotlib
from matplotlib import *
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import rc
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
fig = plt.figure(figsize=(18,5))
ax = fig.add_subplot(1,3,1, projection='3d',azim=-133,elev=14)
l = ax.plot3D(X3D,Y3D,Z3D,lw=2,color='red')
ax.set_xlim3d(-10,10)
ax.set_ylim3d(-10,10)
ax.set_zlim3d(-10,10)
ax.text(-2,-7,-11,'b$_r$ [mT]','x')
ax.text(-5,-1,-11,'b$_p$ [mT]','y')
ax.set_zlabel(r'b$_t$ [mT]')
ax.plot([bEq[0],-bEq[0]],[bEq[1],-bEq[1]],[bEq[2],-bEq[2]],'b--',lw=2)
ax.plot([pLe[0],-pLe[0]],[pLe[1],-pLe[1]],[pLe[2],-pLe[2]],color='black',lw=2)
ax.text(3,12,9.2,'(a)', fontsize=14)
ax = fig.add_subplot(1,3,2)
l = ax.plot(br,bp,'k-',lw=2)
ax.set_xlabel(r'b$_{\lambda_1}$ [mT]')
ax.set_ylabel(r'b$_{\lambda_2}$ [mT]')
ax.set_xlim(-2,6.3)
ax.set_ylim(-5.5,5.5)
ax.plot([0,0],[-5.5,5.5],'k-.')
ax.plot([-2,6.3],[0,0],'k-.')
e=Ellipse((pf[2],pf[3]),2*pf[0],2*pf[1],- pf[4]*57.2958,fc='none',lw=2,ls='dashed',ec='red')
ax.add_artist(e)
ax.text(-1,4, '(b)', fontsize=14)
ax = fig.add_subplot(1,3,3)
ax.plot(-bxDip,-byDip,'b-',lw=2,label='$\mathcal{D}$')
ax.plot(-bxMon,-byMon,'r-',lw=2,label='$\mathcal{M}$')
ax.set_xlabel(r'b$_{\lambda_1}$')
ax.set_ylabel(r'b$_{\lambda_2}$')
ax.set_xlim(-4,12)
ax.set_ylim(-6,7)
ax.plot([-4,12],[0,0],'k-.')
ax.plot([0,0],[-6,7],'k-.')
ax.legend(loc='upper right')
ax.text(-3,5.5, '(c)', fontsize=14)
plt.savefig("../pdf_box/fig3.pdf",bbox_inches='tight')
Wit the present code I was able to produce the figure reported here http://img219.imageshack.us/i/fig3e.png/
There are two question which puzzle me.
1) As you can see the 3D plot is smaller than the other two and there is enough white spaces between the subplots to increase the size. How can I do this? i.e. How can I enlarge the size of one subplot, eventually decreasing the other two?
2) I would like to exclude the grey background in the 3D plot.
Any help is very welcomed.
Change ax.dist for the 3D plot. This will cause the rendered graphic to fill more of the subplot area. Here is a similar question. You may find some more info there.
You may also want to adjust the widths of the subplots with respect to each other (increase the width of the 3d plot and shrink the 2D plots. This can be accomplished with subplots_adjust

Categories