【问题标题】:Matplotlib with fixed axes size and legend outside of axesMatplotlib 具有固定的轴大小和轴外的图例
【发布时间】:2019-02-13 05:22:17
【问题描述】:

我想用 matplotlib 生成出版质量图。出于一致性原因,我希望所有图表(轴)看起来都一样,尤其是在大小上。我浏览了许多教程并提出了以下想法: 1. 创建一个绘图并确定轴的高度(以英寸为单位) 2.添加图例并确定图例的高度(以英寸为单位) 3.将图形高度放大图例高度(以英寸为单位) 4. 将新坐标轴高度缩小到原始坐标轴高度,以保持图例区域中的图例

很遗憾,这没有按预期工作。 关于守则的任何建议?

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

# GENERATE DATA
x       = np.arange(-2.*np.pi,4.*np.pi,0.01)
sin_arr = [np.sin(x-dx) for dx in np.arange(0.,2.*np.pi,0.5)]
# SET FIGURE SIZE AND RCPARAMETERS
plt.rcParams.update( {'figure.figsize' : [5.90551197, 3.64980712]} )
params = {
    'text.usetex'        : True,
    'backend'            :'ps',
    ## FONTS 
    "font.family"    : "serif",
    "font.serif"     : [],          # blank entries should cause plots to inherit fonts from the document
    "font.monospace" : [],
    ## FONT SIZES
    'axes.labelsize' : 12,
    'font.size'      : 12,
    'legend.fontsize': 12,
    'xtick.labelsize': 12,
    'ytick.labelsize': 12,
    ## LINEWIDTH
    'axes.linewidth' : 0.5,
    'patch.linewidth': 0.5,    # legend frame
    'lines.linewidth': 1.5,
    ## LEGEND
    'legend.edgecolor':'black',
    'legend.frameon'  :True,
    'legend.fancybox' :False,
} 
plt.rcParams.update(params)
# GENERATE PLOT
fig = plt.figure()
ax  = fig.add_subplot(111)

for i,sin in enumerate(sin_arr):
    ax.plot(x,sin,label=r'$\sin(x)$ '+str(i))
ax.set_xlabel(r'$\varepsilon$')  
ax.set_ylabel(r'$\sigma$ in [MPa]', labelpad=15)
ax.set_xlim([0.,2.*np.pi])
# SHRINK PADDING
plt.tight_layout(pad=0)  

# ADD LEGEND ON TOP OF AXES WITHOUT CHANGING AXES SIZE
legend    = ax.legend( bbox_to_anchor=(0., 1.02, 1., .102), 
                    loc='lower left',
                    ncol=3,
                    borderaxespad=0.,mode="expand" )

# GET LEGEND / AXES HEIGHT IN INCHES 
ax_box  = ax.get_window_extent()        # AXES BBOX IN DISPLAY UNITS
leg_box = legend.get_bbox_to_anchor()   # LEGEND BBOX IN DISPLAY UNITS

ax_box_inch  = ax_box.transformed( fig.dpi_scale_trans.inverted() )  # TRANSFORM TO INCHES
leg_box_inch = leg_box.transformed( fig.dpi_scale_trans.inverted() ) # TRANSFORM TO INCHES

# ORIGINAL_AX_HEIGHT
ax_height_inch_orig = ax_box_inch.height

# CHANGE FINGURE TO FIT LEGEND
fig.set_size_inches(fig.get_figwidth(), fig.get_figheight() + leg_box_inch.height)

# GET NEW HEIGHT OF AXES 
ax_box_new_inch    = ax.get_window_extent().transformed( fig.dpi_scale_trans.inverted() )
ax_height_inch_new = ax_box_new_inch.height
factor = ax_height_inch_orig/ax_height_inch_new

# GET AXES BBOX IN FIGURE COORDINATES
ax_box = ax.get_window_extent().transformed( fig.transFigure.inverted() )

# CHANGE AXES TO ORIGINAL HEIHGT BUT WITH LEGEND FULLY VISIBLE
ax.set_position([ax_box.x0, ax_box.y0,ax_box.width, ax_box.height*factor])

plt.savefig('test.pdf',format='pdf',dpi=90)

【问题讨论】:

  • 你到底想要什么,能具体点吗?您的代码生成了一个不错的图形,但预期的图形是什么?

标签: python matplotlib transform legend


【解决方案1】:

使用savefigbbox_inches 参数,您似乎可以更轻松地实现预期结果。

plt.savefig("output.pdf", bbox_inches="tight", pad_inches=0)

如果您不需要图形只保存它,则此方法有效。

import matplotlib.pyplot as plt
import numpy as np

# GENERATE DATA
x       = np.arange(-2.*np.pi,4.*np.pi,0.01)
sin_arr = [np.sin(x-dx) for dx in np.arange(0.,2.*np.pi,0.5)]
# SET FIGURE SIZE AND RCPARAMETERS
plt.rcParams.update( {'figure.figsize' : [5.90551197, 3.64980712]} )

fig, ax = plt.subplots()

for i,sin in enumerate(sin_arr):
    ax.plot(x,sin,label=r'$\sin(x)$ '+str(i))
ax.set_xlabel(r'$\varepsilon$')  
ax.set_ylabel(r'$\sigma$ in [MPa]', labelpad=15)
ax.set_xlim([0.,2.*np.pi])
# SHRINK PADDING
fig.tight_layout(pad=0)  

# ADD LEGEND ON TOP OF AXES WITHOUT CHANGING AXES SIZE
legend    = ax.legend( bbox_to_anchor=(0., 1.02, 1., .102), 
                    loc='lower left',
                    ncol=3,
                    borderaxespad=0.,mode="expand" )

plt.savefig("output.pdf", bbox_inches="tight", pad_inches=0)

请注意,如果您使用plt.tight_layout,如果您使用不同的 x 或 y 标签(例如,如果它们有时包含大写字母或低于基线的字母,例如“p”或“G”)。在这种情况下,最好手动决定一些参数,并将tight_layout替换为

fig.subplots_adjust(left=0.151, bottom=0.130, right=0.994, top=0.990) 

或任何其他适合你的参数,给定正在使用的字体大小。


因此,恒定轴大小的问题相当容易解决。更复杂的是反过来。具有恒定的图形大小,但缩小轴以使图形仍能容纳图例。这将显示在这个问题Creating figure with exact size and no padding (and legend outside the axes)

【讨论】:

  • 感谢您的 cmets。我认为bbox_inches="tight", pad_inches=0 暂时解决了它。一般来说,我希望在一个宽度为 5.90551197 英寸的图形中有一个固定的轴尺寸(例如 5 英寸 x 3 英寸),以完全适合我的乳胶文档。然后我想把传说放在上面。根据图表的数量,图例框的大小会发生变化,因此图形高度也会发生变化。这样,所有轴都保持不变,我可以在我的乳胶文档中包含生成的 pdf 而无需缩放。
  • 这就是我想说的关于 subplots_adjust 的内容,因此您可以使用 `subplots_adjust(left=(1.-5/5.9055)/2, right=1.-(1. -5/5.9055)/2, ...) 以获得所需的轴大小。
猜你喜欢
  • 2019-12-30
  • 2021-02-23
  • 1970-01-01
  • 2013-08-01
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多