excalibur1491 excalibur1491 - 1 month ago 19
Python Question

matplotlib: subplots of same size?

I am having trouble with matplotlib in Python trying to create two plots side by side. I managed to make them stay next to each other, but I need them to have the exact same size: each point in the right one should be easily mapped to a location on the left one with the naked eye.
Instead, my right one (which is a scatter plot) has some margins that make it appear slightly smaller than the left (a heatmap).

enter image description here

The way I generate the heatmap is:

def plot_map(matrix):
# Plot it out
#fig, ax = plt.subplots()
fig = plt.figure()
ax = plt.subplot(1,2,1)
c = m.colors.ColorConverter().to_rgb
cm = make_colormap([(0,1,0), (1,1,0), 0.1, (1,1,0), (1,0.5,0), 0.66, (1,0.5,0),(1,0,0)])
heatmap = ax.pcolor(matrix, cmap=cm)

# Format
fig = plt.gcf()
fig.set_size_inches(20, 20)
plt.gca().set_aspect('equal')
# turn off the frame
ax.set_frame_on(False)

# put the major ticks at the middle of each cell
ax.set_yticks(np.arange(matrix.shape[0]) + 0.5, minor=False)
ax.set_xticks(np.arange(matrix.shape[1]) + 0.5, minor=False)

# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()

# note I could have used matrix.columns but made "labels" instead
ax.set_xticklabels(range(0,matrix.shape[0]), minor=False)
ax.set_yticklabels(range(0,matrix.shape[1]), minor=False)
ax.grid(False)

# Turn off all the ticks
ax = plt.gca()

for t in ax.xaxis.get_major_ticks():
t.tick1On = False
t.tick2On = False
for t in ax.yaxis.get_major_ticks():
t.tick1On = False
t.tick2On = False

divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(heatmap,cax=cax)

return (fig,ax)


Then the ax is passed over to another function to plot the little blue lines on the map:

def plot_chosen(edges,endnodes,side,ax):
for e in edges:
u = endnodes[e - 1][0]
v = endnodes[e - 1][1]
xu, yu = get_center(u,side)
xv, yv = get_center(v,side)
ax.plot([xu+0.5, xv+0.5], [yu+0.5, yv+0.5], 'k-', lw=4, color='blue',alpha=0.5)


Finally, I plot the scatter like this

def plot_satter(edges,endnodes,side,xs,ys,data):
plt.margins(0)
ax = plt.subplot(1, 2, 2)
# Format
fig = plt.gcf()
fig.set_size_inches(20, 20)
plt.gca().set_aspect('equal')
# turn off the frame
ax.set_frame_on(False)

# put the major ticks at the middle of each cell
ax.set_yticks(np.arange(side) + 0.5, minor=False)
ax.set_xticks(np.arange(side) + 0.5, minor=False)

# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()

ax.set_xmargin(0)
ax.set_ymargin(0)

# note I could have used matrix.columns but made "labels" instead
ax.set_xticklabels(range(0,side), minor=False)
ax.set_yticklabels(range(0,side), minor=False)
ax.grid(False)

# Turn off all the ticks
ax = plt.gca()

for t in ax.xaxis.get_major_ticks():
t.tick1On = False
t.tick2On = False
for t in ax.yaxis.get_major_ticks():
t.tick1On = False
t.tick2On = False
cm = make_colormap([(0,0,1), (0,1,1), 0.1, (0,1,1), (1,1,0), 0.66, (1,1,0),(1,0,0)])
resmap = plt.scatter(xs,ys, c=data,cmap=cm,edgecolors='none',alpha=0.5,s=data)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(resmap,cax=cax)


But I find no way of making the scatter plot as big as the heatmap. Actually, it's supposed to be as big as its colorbar, but that doesn't work either... Si this makes me think there is some margin around the scatter....

Also, is there a way I could make the whole PNG file not so square? Could it be a rectangle?

Thanks!

Answer

In order to get help, you need to provide a minimal working example. You will find out that producing such a minimal working example, almost always makes you find the problem and a corresponding solution yourself.
Also, structure your code!!

As we do not have the necessary knowledge of your data and the variables you are using, it is almost impossible to come up with a solution.

What you need to do is break down the problem. You are looking for the difference between two things - so make them as equal as possible. If you apply everything to both plots simultaneously, how can they be different after all?

The following code shows how you would do that and it acutally shows no difference in size of the two plots. So start from there and add the stuff you might need accordingly. One step at a time, until you find the piece of code that causes problems.

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable

x = np.linspace(0,100,101)
X, Y = np.meshgrid(x,x)
data = np.sin(X/2.3)*np.cos(Y/2.7)*np.cos(X*Y/20.)

fig = plt.figure(figsize=(10,5))
ax1=fig.add_subplot(121)
ax2=fig.add_subplot(122)
plt.subplots_adjust(wspace = 0.33 )

heatmap = ax1.pcolor(data, cmap="RdPu")
resmap =  ax2.scatter(X,Y, c=data, cmap="YlGnBu",edgecolors='none',alpha=0.5)


for ax in [ax1,ax2]:
    ax.set_frame_on(False)

    ax.set_aspect('equal')

    ax.invert_yaxis()
    ax.xaxis.tick_top()

    ax.set_xmargin(0)
    ax.set_ymargin(0)

    ax.grid(False)

    for t in ax.xaxis.get_major_ticks():
        t.tick1On = False
        t.tick2On = False
    for t in ax.yaxis.get_major_ticks():
        t.tick1On = False
        t.tick2On = False

    ax.set_xlim([x[0],x[-1]])
    ax.set_ylim([x[0],x[-1]])


divider1 = make_axes_locatable(ax1)       
cax1 = divider1.append_axes("right", size="5%", pad=0.05)
plt.colorbar(heatmap,cax=cax1)

divider2 = make_axes_locatable(ax2)       
cax2 = divider2.append_axes("right", size="5%", pad=0.05)
plt.colorbar(resmap,cax=cax2)

plt.show()

And btw, fig = plt.figure(figsize=(10,5)) produces a rectangle, while fig = plt.figure(figsize=(20,20)) produces a square.