像plt.tight_layout()这样的函数可以改变图形大小而不是轴大小

时间:2018-04-04 10:07:35

标签: python matplotlib

plt.tight_layout()通过更改轴大小来工作,因此图中的所有元素都适合该图框。

请参阅:

y=np.random.normal(size=100)
fig, ax = plt.subplots(); plt.plot(y)
plt.xlabel('time / s.', fontsize=40)
fig.set_size_inches([5, 2])
plt.tight_layout()

调整轴的大小,使所有元素都适合图形。我希望我的轴尺寸保持不变。是否有替代方案可以在保持轴不变的情况下调整图形的大小?

1 个答案:

答案 0 :(得分:1)

轴的尺寸以图形坐标表示。即默认情况下,单个子图是图宽宽的77.5%,图高的77%是高。因此,在更改图形尺寸时,不能保持轴不受影响,因为一个轴取决于另一个。

现在它取决于调用tight_layout的目标和所需的输出。

问题

运行问题中的代码会产生下图,

enter image description here

可以看出,超大的x标签被切断了。

保存数字

例如,如果你有兴趣保存你的数字,你可以不调用tight_layout()而是在savefig调用中指定bbox_inches="tight"

plt.savefig("some.png", bbox_inches="tight") 

这将生成一个比原始图形大的图形,而不会改变内部对象的任何位置。因此它与tight_layout不同,因为它根本不会改变布局和间距。这里的缺点是它只会影响保存的图形,而不会影响屏幕上显示的图形。

显示数字

现在你原则上可以对你屏幕上的数字做同样的事情。这非常hacky,会对轴的存储方式产生影响。以下是一个函数tight_figure,它将图像视为已保存,但让它保留在屏幕上的原始画布中。

import numpy as np
import matplotlib.pyplot as plt

import io
from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
from matplotlib import  tight_bbox

def tight_figure(fig,**kwargs):
    canvas = fig.canvas._get_output_canvas("png")
    print_method = getattr(canvas, 'print_png')
    print_method(io.BytesIO(), dpi=fig.dpi,
                 facecolor=fig.get_facecolor(), dryrun=True)
    renderer = fig._cachedRenderer
    bbox_inches = fig.get_tightbbox(renderer)


    bbox_artists = fig.get_default_bbox_extra_artists()

    bbox_filtered = []
    for a in bbox_artists:
        bbox = a.get_window_extent(renderer)
        if a.get_clip_on():
            clip_box = a.get_clip_box()
            if clip_box is not None:
                bbox = Bbox.intersection(bbox, clip_box)
            clip_path = a.get_clip_path()
            if clip_path is not None and bbox is not None:
                clip_path = \
                    clip_path.get_fully_transformed_path()
                bbox = Bbox.intersection(
                    bbox, clip_path.get_extents())
        if bbox is not None and (
                bbox.width != 0 or bbox.height != 0):
            bbox_filtered.append(bbox)

    if bbox_filtered:
        _bbox = Bbox.union(bbox_filtered)
        trans = Affine2D().scale(1.0 / fig.dpi)
        bbox_extra = TransformedBbox(_bbox, trans)
        bbox_inches = Bbox.union([bbox_inches, bbox_extra])

    pad = kwargs.pop("pad_inches", None)
    if pad is None:
        pad = plt.rcParams['savefig.pad_inches']

    bbox_inches = bbox_inches.padded(pad)

    tight_bbox.adjust_bbox(fig, bbox_inches, canvas.fixed_dpi)

    w = bbox_inches.x1 - bbox_inches.x0
    h = bbox_inches.y1 - bbox_inches.y0
    fig.set_size_inches(w,h)


y=np.random.normal(size=100)
fig, ax = plt.subplots(); plt.plot(y)
plt.xlabel('time / s.', fontsize=40)
fig.set_size_inches([5, 2])

tight_figure(fig)

plt.show()

输出 tight_figure看起来像是 enter image description here