去除保存图像周围的空白空间。

323

我需要获取一张图片并在处理后保存它。当我显示这个图像时,它看起来很好,但是在保存图像之后,图像周围出现了一些白色空间。我已经尝试使用'tight'选项和savefig方法,但都没能解决问题。代码如下:

import matplotlib.image as mpimg
import matplotlib.pyplot as plt

fig = plt.figure(1)
img = mpimg.imread("image.jpg")
plt.imshow(img)
ax = fig.add_subplot(1, 1, 1)

extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches=extent)

plt.axis('off') 
plt.show()

我正在尝试使用NetworkX在图形上绘制基本图形并保存它。我发现在没有图形的情况下它可以工作,但是一旦添加了图形,保存的图像周围就会出现白色空间;

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import networkx as nx

G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_edge(1, 3)
G.add_edge(1, 2)
pos = {1:[100, 120], 2:[200, 300], 3:[50, 75]}

fig = plt.figure(1)
img = mpimg.imread("image.jpg")
plt.imshow(img)
ax = fig.add_subplot(1, 1, 1)

nx.draw(G, pos=pos)

extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches=extent)

plt.axis('off') 
plt.show()

15个回答

376

58
这并不是完全正确的。当你使用bbox_inches选项时,还有另一个默认选项会留出一些空间。如果你真的想把所有东西都去掉,你需要同时使用pad_inches=0.0。当然,这样紧密的边距经常会裁剪掉指数等内容... - Mike
7
为了去除黑边,你可能需要将 pad_inches 设为 -0.1 - lenhhoxung
15
这并不起作用,你仍然会在图形周围得到空白。设置透明选项(如某些答案中所述)也没有真正帮助,空白仍然存在,只是透明而已。 - BjornW
1
@piperchester 这是个好问题,但最好作为一个新问题提出,以免被评论遗忘。不过你应该将新问题链接到旧问题! - Hooked
1
为什么这不是默认设置??这样会好得多。 - Aditya Kashi
显示剩余8条评论

297

我不能断言我确切知道我的“解决方案”为什么或如何工作,但这是我想要将几个翼型的轮廓线绘制到PDF文件中而不带有白色边距时必须执行的操作。(请注意,我在IPython笔记本中使用了matplotlib,并使用了-pylab标志。)

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.savefig("filename.pdf", bbox_inches = 'tight',
    pad_inches = 0)

我已经尝试去除这个的不同部分,但这总是导致白边出现在某个地方。为了防止边界处的宽线条被裁剪掉而留下空白边缘,您甚至可能需要修改它。


9
终于有东西管用了,非常感谢!顺便说一下,在我的情况下,只有使用set_major_locator的两行代码是必需的。 - Florian Brucker
10
我花了最近一个小时尝试了各种方法,但无法去除1像素的白色边框。这是唯一有效的方法 - 特别是pad_inches=0,其他答案没有提到。 - AnnanFay
26
pad_inches 对我很有帮助。 - Myles Baker
4
你是个该死的英雄。 - JHolyhead
5
matplotlib.ticker.NullLocator() - Joop
显示剩余14条评论

40

尝试上述答案无果后(以及大量其他堆栈帖子),最终对我有效的方法只是

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.pdf")

重要的是,这不包括bbox或padding参数。


9
这应该是被接受的答案。此外,你甚至不需要调用 set_axis_off。由于在 subplots_adjust 后轴位于图形范围之外且不会被绘制,因此它不会影响保存的图像。然而在 Jupyter 笔记本中,你需要显式地禁用轴,因为内联后端会覆盖这些设置。 - MaxPowers
1
同意。这应该被接受为答案。我为此问题苦苦挣扎了几天,只有这段代码解决了我的问题。我尝试了很多(几个)stackoverflow的技巧和提示,解决方法等,但都没有成功。非常感谢@SuaveSouris。 - MGB.py

31

11
transparent=True会使得看起来好像没有问题,但实际上它只是隐藏了空白部分,图像尺寸不正确。 - Vlady Veselinov
谢谢提到 pad_inches!我希望早些知道这个选项! - ingomueller.net
1
这适用于大多数图,但会移除混淆矩阵的右边框。只需添加一个小填充pad_inches=.25即可。 - YTZ
以下的选项都对我没用,所以我也选择了transparent=True。我使用的是matplotlib==3.5.1版本。 - undefined

18
下面的函数包含了以上johannes-s的答案。我已经测试过它与plt.figureplt.subplots()函数一起使用,可以处理多个坐标轴,效果很好。
def save(filepath, fig=None):
    '''Save the current image with no whitespace
    Example filepath: "myfig.png" or r"C:\myfig.pdf" 
    '''
    import matplotlib.pyplot as plt
    if not fig:
        fig = plt.gcf()

    plt.subplots_adjust(0,0,1,1,0,0)
    for ax in fig.axes:
        ax.axis('off')
        ax.margins(0,0)
        ax.xaxis.set_major_locator(plt.NullLocator())
        ax.yaxis.set_major_locator(plt.NullLocator())
    fig.savefig(filepath, pad_inches = 0, bbox_inches='tight')

运行得非常好。之前的答案是我导出中需要的一些命令。 - Kevin S

16

最直接的方法是使用plt.tight_layout转换,这实际上更可取,因为在使用plt.savefig时不会进行不必要的裁剪。

import matplotlib as plt    
plt.plot([1,2,3], [1,2,3])
plt.tight_layout(pad=0)
plt.savefig('plot.png')

然而,对于修改图形的复杂情节可能不是首选。如果是这种情况,请参考Johannes S的答案,使用plt.subplots_adjust


15

以下是我的解决方案 plt.savefig(save_path, bbox_inches='tight', pad_inches=0, transparent=True)


3
我不确定这个回答与其他在此发布的答案有什么不同。 - BigBen
因为一个是保存图像,另一个是绘制图像。这是唯一对我有效的方法。虽然其他方法在笔记本中绘制时看起来合理,但保存的图像却有一个奇怪的大空白区域。使用这个解决方案,bbox_inches='tight', pad_inches=0可以去除所有无用的空白区域。 - lesolorzanov

11

我发现以下代码完美地完成了这项工作。

fig = plt.figure(figsize=[6,6])
ax = fig.add_subplot(111)
ax.imshow(data)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
plt.savefig('data.png', dpi=400, bbox_inches='tight',pad_inches=0)

2
通常情况下,如果答案包含代码的意图和解决问题的原因,而不会引入其他问题,那么这些答案会更有帮助。 - Tim Diekmann

8
我按照这个步骤操作,结果非常顺利。
plt.axis("off")
fig=plt.imshow(image array,interpolation='nearest')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('destination_path.pdf',
    bbox_inches='tight', pad_inches=0, format='pdf', dpi=1200)

1
实际上,我发现这个答案很容易且更方便使用。 - sikisis
2
这个对我起作用了,被接受的答案没有。 - Joe
1
在我的情况下,使用 savefig 命令中的两个参数 bbox_inches='tight'pad_inches=0 完美地解决了问题。 - Basilique

6
我发现一个更简单的方法是使用 plt.imsave
    import matplotlib.pyplot as plt
    arr = plt.imread(path)
    plt.imsave('test.png', arr)

被低估的答案。在长时间寻找如何保留分辨率和使用 plt.savefig() 去除空白后,这对我很有帮助。 - nihal111
1
这仅适用于想将数组保存为图像的情况!它不允许保存任意的图形。 - MaxPowers
1
“任意图像”是什么意思?难道图像不就是一个值数组吗? - Parth92

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接