Matplotlib: Getting subplots to fill figure

感情迁移 提交于 2019-11-29 14:10:12

First, you're using calls to plt when you have Axes objects as your disposal. That road leads to pain. Second, imshow sets the aspect ratio of the axes scales to 1. That's why the axes are so narrow. Knowing all that, your example becomes:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.rand(10,4)

#creating a wide figure with 2 subplots in 1 row
fig, axes = plt.subplots(1, 2, figsize=(9,3))  

for ax in axes.flatten():  # flatten in case you have a second row at some point
    img = ax.imshow(data, interpolation='nearest')
    ax.set_aspect('auto')

plt.colorbar(img)

On my system, that looks like this:

You can adjust your axis area by using the ax.set_position method. It works with relative coordinates, so if you want to make an A4 image, then:

import numpy as np
import matplotlib.pyplot as plt

# figsize keyword talks some obscure units which need a conversion from standard units
plt.figure(figsize=np.array([210,297]) / 25.4)

x = np.linspace(0,2*np.pi, 100)
plt.plot(x, np.sin(x))

plt.gca().set_position([0, 0, 1, 1])

plt.show()

Now the axis area (plot area) fills the whole page.

The coordinates given to the set_position are relative coordinates [left, lower, width, height], where each direction is scaled by the page size.

As pointed out in the other answers, imshow and matshow try sometimes to keep the pixels in the picture square. There is a rather special interplay with the axis ratio and imshow.

  • if imshow is called without extent=[...] or aspect='auto' keyword arguments, it does what is instructed in the local defaults, usually tries to keep the pixels square
  • if this happens (or aspect='equal' is set), the axes act as if plt.axis('scaled') had been called, i.e. keeps X and Y coordinates equal length (pixels per unit) and change the axis size to match the extents
  • this can be overridden by setting plt.axis('tight') (which makes the x and y limits to fit the image exactly)

Th old trick is to use axis('auto') or axis('normal'), but these are nowadays deprecated (use scaled, equal, or tight).

Yes, it is a bit of a mess.

A friend came up with a solution that seems to work reasonably well, which I thought I would post for anybody with a similar problem - setting aspect='auto' in imshow seems to do the trick, for any choice of nx, figsize, nplots_hori and nplots_vert below.

import numpy as np
import matplotlib.pyplot as plt

nx=5
data=np.random.rand(10,nx)

figsize=[10,8]
nplots_hori=2
nplots_vert=2

fig,ax=plt.subplots(nplots_vert, nplots_hori, figsize=figsize)
if nplots_vert==1: ax=ax.reshape(1,len(ax))

plt.tight_layout()
for i in range(nplots_hori):
    for j in range(nplots_vert):
        plt.sca(ax[j,i])
        plt.imshow(data, aspect='auto')

plt.tight_layout()
plt.show()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!