matplotlib 将最佳定位也延伸到地块外

vohkndzv  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(128)

我试图绘制几个数据,在某些情况下,占据了整个图。
版本2中的默认选项应为“最佳”,该选项尝试查找图例在图中的最佳位置。如果空间不足,是否有方法扩展选项,以便能够将图例放置在图外?
否则,matplotlib是否有一个选项(不取所有序列的最大值并添加手动填充)来自动添加ylim填充并为图例给予空间并放置在图中?
主要思想是避免手动调整图,自动创建多个图。
简单的MWE如下:

%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import scipy as sc
import matplotlib.pyplot as plt
plt.close('all')

x = sc.linspace(0, 1, 50)
y = sc.array([sc.ones(50)*0.5, x, x**2, (1-x), (1-x**2)]).T
fig = plt.figure('Fig')
ax = fig.add_subplot(111)
lines = ax.plot(x, y)
leg = ax.legend([lines[0], lines[1], lines[2], lines[3], lines[4]],
                [r'$\mathrm{line} = 0.5$', r'$\mathrm{line} = x$', r'$\mathrm{line} = x^2$',
                 r'$\mathrm{line} = 1-x$',r'$\mathrm{line} = 1-x^2$'], ncol=2)
fig.tight_layout()

icnyk63a

icnyk63a1#

没有自动方法将图例放置在轴外的“最佳”位置。

情节内部

您可以决定始终在轴内留出足够的空间,以便图例不会与任何东西重叠。为此,您可以使用ax.margins。例如

ax.margins(y=0.25)

将在y轴两端产生25%的边距,如果图例有3列,则足够空间容纳图例。

然后,您可以决定始终使用相同的位置,例如:loc="upper center",所有图的结果一致。这样做的缺点是它取决于图形大小,并且它还在轴的另一端添加了(可能不期望的)余量。如果您可以接受该保证金,则自动确定所需保证金的方法如下:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms

x = np.linspace(0, 1, 50)
y = np.array([np.ones(50)*0.5, x, x**2, (1-x), (1-x**2)]).T
fig = plt.figure('Fig')
ax = fig.add_subplot(111)
lines = ax.plot(x, y)

def legend_adjust(legend, ax=None ):
    if ax == None: ax  =plt.gca()
    ax.figure.canvas.draw()
    bbox = legend.get_window_extent().transformed(ax.transAxes.inverted() )
    print bbox.height
    ax.margins(y = 2.*bbox.height)
    
leg = plt.legend(handles=[lines[0], lines[1], lines[2], lines[3], lines[4]],
       labels= [r'$\mathrm{line} = 0.5$', r'$\mathrm{line} = x$', r'$\mathrm{line} = x^2$',
                 r'$\mathrm{line} = 1-x$',r'$\mathrm{line} = 1-x^2$'], loc="upper center", 
                  ncol=2)
legend_adjust(leg)
plt.show()

如果设置限制对您来说没问题,您也可以调整限制本身:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms

x = np.linspace(0, 1, 50)
y = np.array([np.ones(50)*0.5, x, x**2, (1-x), (1-x**2)]).T
fig = plt.figure('Fig')
ax = fig.add_subplot(111)
lines = ax.plot(x, y)

def legend_adjust(legend, ax=None, pad=0.05 ):
    if ax == None: ax  =plt.gca()
    ax.figure.canvas.draw()
    bbox = legend.get_window_extent().transformed(ax.transAxes.inverted() )
    ymin, ymax = ax.get_ylim()
    ax.set_ylim(ymin, ymax+(ymax-ymin)*(1.+pad-bbox.y0))
    

    
leg = plt.legend(handles=[lines[0], lines[1], lines[2], lines[3], lines[4]],
       labels= [r'$\mathrm{line} = 0.5$', r'$\mathrm{line} = x$', r'$\mathrm{line} = x^2$',
                 r'$\mathrm{line} = 1-x$',r'$\mathrm{line} = 1-x^2$'], loc="upper center", 
                  ncol=2)
legend_adjust(leg)
plt.show()

出图

否则,你可能会决定总是把图例放在情节之外。一些技术收集在this answer中。
特别感兴趣的可能是将图例放置在图形外部而不更改图形大小,如本问题中所述:Creating figure with exact size and no padding (and legend outside the axes)
将其改编为这种情况看起来像:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms

x = np.linspace(0, 1, 50)
y = np.array([np.ones(50)*0.5, x, x**2, (1-x), (1-x**2)]).T
fig = plt.figure('Fig')
ax = fig.add_subplot(111)
lines = ax.plot(x, y)

def legend(ax=None, x0=1,y0=1, direction = "v", padpoints = 3,**kwargs):
    if ax == None: ax  =plt.gca()
    otrans = ax.figure.transFigure
    t = ax.legend(bbox_to_anchor=(x0,y0), loc=1, bbox_transform=otrans,**kwargs)
    plt.tight_layout()
    ax.figure.canvas.draw()
    plt.tight_layout()
    ppar = [0,-padpoints/72.] if direction == "v" else [-padpoints/72.,0] 
    trans2=matplotlib.transforms.ScaledTranslation(ppar[0],ppar[1],fig.dpi_scale_trans)+\
             ax.figure.transFigure.inverted() 
    tbox = t.get_window_extent().transformed(trans2 )
    bbox = ax.get_position()
    if direction=="v":
        ax.set_position([bbox.x0, bbox.y0,bbox.width, tbox.y0-bbox.y0]) 
    else:
        ax.set_position([bbox.x0, bbox.y0,tbox.x0-bbox.x0, bbox.height]) 

legend(handles=[lines[0], lines[1], lines[2], lines[3], lines[4]],
       labels= [r'$\mathrm{line} = 0.5$', r'$\mathrm{line} = x$', r'$\mathrm{line} = x^2$',
                 r'$\mathrm{line} = 1-x$',r'$\mathrm{line} = 1-x^2$'], 
                 y0=0.8, direction="h", borderaxespad=0.2)

plt.show()

相关问题