【问题标题】:Make x-axes of all subplots same length on the page使页面上所有子图的 x 轴长度相同
【发布时间】:2017-09-16 08:30:54
【问题描述】:

我是 matplotlib 的新手,并试图通过循环从 pandas 数据帧创建和保存图。每个图应该有一个相同的 x 轴,但不同的 y 轴长度和标签。创建和保存具有不同 y 轴长度和标签的图没有问题,但是当我创建图时,matplotlib 会根据左侧的 y 轴标签需要多少空间来重新调整 x 轴图。

这些数字用于技术报告。我计划在报告的每一页上放置一个,并且我希望所有 x 轴在页面上占用相同的空间。

这是一个 MSPaint 版本,其中包含我正在获得的内容以及我想要获得的内容。

希望这是足够的代码来提供帮助。我敢肯定这其中有很多非最佳部分。

import pandas as pd
import matplotlib.pyplot as plt
import pylab as pl
from matplotlib import collections as mc
from matplotlib.lines import Line2D
import seaborn as sns

# elements for x-axis
start = -1600
end = 2001
interval = 200 # x-axis tick interval
xticks = [x for x in range(start, end, interval)] # create x ticks

# items needed for legend construction
lw_bins = [0,10,25,50,75,90,100] # bins for line width
lw_labels = [3,6,9,12,15,18] # line widths
def make_proxy(zvalue, scalar_mappable, **kwargs):
    color = 'black'
    return Line2D([0, 1], [0, 1], color=color, solid_capstyle='butt', **kwargs)

# generic image ID
img_path = r'C:\\Users\\user\\chart'
img_ID = 0

for line_subset in data:
    # create line collection for this run through loop
    lc = mc.LineCollection(line_subset)

    # create plot and set properties
    sns.set(style="ticks")
    sns.set_context("notebook")
    fig, ax = pl.subplots(figsize=(16, len(line_subset)*0.5)) # I want the height of the figure to change based on number of labels on y-axis
                                                              # Figure width should stay the same
    ax.add_collection(lc)
    ax.set_xlim(left=start, right=end)
    ax.set_xticks(xticks)
    ax.set_ylim(0, len(line_subset)+1)
    ax.margins(0.05)
    sns.despine(left=True)
    ax.xaxis.set_ticks_position('bottom')
    ax.set_yticks(line_subset['order'])
    ax.set_yticklabels(line_subset['ylabel'])
    ax.tick_params(axis='y', length=0)

    # legend
    proxies = [make_proxy(item, lc, linewidth=item) for item in lw_labels]
    ax.legend(proxies, ['0-10%', '10-25%', '25-50%', '50-75%', '75-90%', '90-100%'], bbox_to_anchor=(1.05, 1.0), 
              loc=2, ncol=2, labelspacing=1.25, handlelength=4.0, handletextpad=0.5, markerfirst=False, 
              columnspacing=1.0)

    # title
    ax.text(0, len(line_subset)+2, s=str(img_ID), fontsize=20)

    # save as .png images
    plt.savefig(r'C:\\Users\\user\\Desktop\\chart' + str(img_ID) + '.png', dpi=300, bbox_inches='tight')

【问题讨论】:

    标签: python python-2.7 matplotlib seaborn subplot


    【解决方案1】:

    除非您使用明确定义纵横比的轴(例如在 imshow 图中或通过调用 .set_aspect("equal")),否则轴占用的空间应仅取决于沿该方向的图形大小和设置为图形的间距.

    因此,您几乎要求默认行为,而唯一阻止您获得默认行为的是您在 savefig 命令中使用 bbox_inches='tight'

    bbox_inches='tight' 会改变图形大小!所以不要使用它,轴的大小将保持不变。 `

    根据我对问题的理解,您定义为figsize=(16, len(line_subset)*0.5) 的图形大小似乎是有道理的。所以剩下的就是确保图中的轴是你想要的大小。您可以通过使用fig.add_axes 手动放置它来做到这一点

    fig.add_axes([left, bottom, width, height])
    

    其中left, bottom, width, height 在图形坐标中,范围从 0 到 1。或者,您可以使用 subplots_adjust 调整子图外的间距

    plt.subplots_adjust(left, bottom, right, top)
    

    【讨论】:

    • 这就是我不加批判地蚕食我发现的一些代码的结果。然而,当我拿走bbox_inches='tight' 时,我的y 轴标签只有在我将figsize 设置为一个巨大的x 值(>25 英寸)时才会完全出现。我可以以某种方式将其全部强制为 8.5x11 英寸大小吗?
    【解决方案2】:

    要获得匹配的子图 x 轴(每个子图的 x 轴长度相同),您需要在子图之间共享 x 轴。

    在此处查看示例https://matplotlib.org/examples/pylab_examples/shared_axis_demo.html

    【讨论】:

    • 有没有办法存储 x 轴,以便我可以在下一次循环运行时使用它?我不希望所有的情节都在一个连续的数字上;它们需要保存为单独的 .png 文件。
    • 您可以将 x 限制存储在临时变量中。让我们说从第零次运行并将其应用于下一次运行(第一次运行)。但是您可能会遇到问题,即对于第二次运行,您将从第一次运行开始应用限制。你可能不想要那个。
    猜你喜欢
    • 2021-12-07
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多