FrankTheTank
FrankTheTank

Reputation: 1689

Python: subplots with different total sizes

Original Post

I need to make several subplots with different sizes.

I have simulation areas of the size (x y) 35x6µm to 39x2µm and I want to plot them in one figure. All subplots have the same x-ticklabels (there is a grid line every 5µm on the x-axis).

When I plot the subplots into one figure, then the graphs with the small x-area are streched, so that the x-figuresize is completely used. Therefore, the x-gridlines do not match together anymore.

How can I achieve that the subplots aren't streched anymore and are aligned on the left?

Edit: Here is some code:

    size=array([[3983,229],[3933,350],[3854,454],[3750,533],[3500,600]], dtype=np.float)
    resolution=array([[1024,256],[1024,320],[1024,448],[1024,512],[1024,640]], dtype=np.float)

    aspect_ratios=(resolution[:,0]/resolution[:,1])*(size[:,1]/size[:,0])

    number_of_graphs=len(data)
    fig, ax=plt.subplots(nrows=number_of_graphs, sharex=xshare)
    fig.set_size_inches(12,figheight)

    for i in range(number_of_graphs):
        temp=np.rot90(np.loadtxt(path+'/'+data[i])) 
        img=ax[i].imshow(temp, 
                 interpolation="none",
                 cmap=mapping, 
                 norm=specific_norm,
                 aspect=aspect_ratios[i]
                 )
        ax[i].set_adjustable('box-forced')

        #Here I have to set some ticks and labels....
        ax[i].xaxis.set_ticks(np.arange(0,int(size[i,0]),stepwidth_width)*resolution[i,0]/size[i,0])
        ax[i].set_xticklabels((np.arange(0, int(size[i,0]), stepwidth_width)))
        ax[i].yaxis.set_ticks(np.arange(0,int(size[i,1]),stepwidth_height)*resolution[i,1]/size[i,1])
        ax[i].set_yticklabels((np.arange(0, int(size[i,1]), stepwidth_height)))
        ax[i].set_title(str(mag[i]))
        grid(True)


    savefig(path+'/'+name+'all.pdf', bbox_inches='tight', pad_inches=0.05) #saves graph

Here are some examples: If I plot different matrices in a for loop, the iPhython generates an output which is pretty much what I want. The y-distande between each subplot is constant, and the size of each figure is correct. You can see, that the x-labels match to each other: enter image description here

When I plot the matrices in one figure using subplots, then this is not the case: The x-ticks do not fit together, and every subplot has the same size on the canvas (which means, that for thin subplots there is more white space reservated on the canvas...). enter image description here

I simply want the first result from iPython in one output file using subplots.

Using GridSpec

After the community told me to use GridSpec to determine the size of my subplots directly I wrote a code for automatic plotting:

size=array([[3983,229],[3933,350],[3854,454],[3750,533],[3500,600]], dtype=np.float)

#total size of the figure
total_height=int(sum(size[:,1]))
total_width=int(size.max())

#determines steps of ticks
stepwidth_width=500
stepwidth_height=200


fig, ax=plt.subplots(nrows=len(size))
fig.set_size_inches(size.max()/300., total_height/200)

gs = GridSpec(total_height, total_width)
gs.update(left=0, right=0.91, hspace=0.2)

height=0
for i in range (len(size)):    
    ax[i] = plt.subplot(gs[int(height):int(height+size[i,1]), 0:int(size[i,0])])

    temp=np.rot90(np.loadtxt(path+'/'+FFTs[i])) 
    img=ax[i].imshow(temp, 
             interpolation="none", 
             vmin=-100,
             vmax=+100,
             aspect=aspect_ratios[i],
             )

    #Some rescaling            
    ax[i].xaxis.set_ticks(np.arange(0,int(size[i,0]),stepwidth_width)*resolution[i,0]/size[i,0])
    ax[i].set_xticklabels((np.arange(0, int(size[i,0]), stepwidth_width)))
    ax[i].yaxis.set_ticks(np.arange(0,int(size[i,1]),stepwidth_height)*resolution[i,1]/size[i,1])
    ax[i].set_yticklabels((np.arange(0, int(size[i,1]), stepwidth_height)))
    ax[i].axvline(antenna[i]) #at the antenna position a vertical line is plotted
    grid(True)

    #colorbar
    cbaxes = fig.add_axes([0.93, 0.2, 0.01, 0.6])  #[left, bottom, width, height]
    cbar = plt.colorbar(img, cax = cbaxes, orientation='vertical')  
    tick_locator = ticker.MaxNLocator(nbins=3)
    cbar.locator = tick_locator
    cbar.ax.yaxis.set_major_locator(matplotlib.ticker.AutoLocator())
    cbar.set_label('Intensity', 
               #fontsize=12
               )
    cbar.update_ticks()

    height=height+size[i,1]


plt.show()

And here is the result.... enter image description here Do you have any ideas?

Upvotes: 2

Views: 1051

Answers (1)

wflynny
wflynny

Reputation: 18521

What about using matplotlib.gridspec.GridSpec? Docs.

You could try something like

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

gs = GridSpec(8, 39)
ax1 = plt.subplot(gs[:6, :35])
ax2 = plt.subplot(gs[6:, :])

data1 = np.random.rand(6, 35)
data2 = np.random.rand(2, 39)

ax1.imshow(data1)
ax2.imshow(data2)
plt.show()

enter image description here

Upvotes: 2

Related Questions