簡體   English   中英

在 python matplotlib 中格式化損壞的 y 軸

[英]Formatting a broken y axis in python matplotlib

我有一個(相當復雜的)條形圖,我正在 matplotlib 中處理它。 它包含來自多個源的匯總數據,每個源都沿 x 軸進行標記,y 軸上有一系列結果。 許多結果是異常值,我嘗試使用斷開的 y 軸來顯示這些結果,同時使用此方法插入斷開的 y 軸,並使用此方法在網格上對齊子圖(異常值集中在特定點周圍,因此上圖可能非常小)。

結果圖看起來有點像這樣

示例圖

問題是對角線在 y 軸上的中斷點上方和下方顯然處於不同的角度。 我不明白為什么。

我正在使用的代碼如下。 為復雜性道歉,我不得不對不同的軸進行大量修改才能使這項工作...

    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    from matplotlib.gridspec import GridSpec

    data = pd.DataFrame.from_dict(
        {
            "low": {
                "Record 1": 5,
                "Record 2": 10,
                "Record 3": 15,
                "Record 4": 20,
                "Record 5": 25,
                "Record 6": 30,
                "Record 7": 35,
                "Record 8": 40,
                "Record 9": 45,
                "Record 10": 50,
            },
            "high": {
                "Record 1": 25,
                "Record 2": 100,
                "Record 3": 225,
                "Record 4": 25,
                "Record 5": 100,
                "Record 6": 10000,
                "Record 7": 25,
                "Record 8": 100,
                "Record 9": 225,
                "Record 10": 25,
            },
        }
    )

    mm = (146, 90)  # x value then y value
    inches = (mm[0] / 25.4, mm[1] / 25.4)

    fig = plt.figure(figsize=inches)
    fig.text(0.02, 0.6, r"Y axis label", va="center", rotation="vertical", fontsize=12)
    gs = GridSpec(2, 2, height_ratios=[1, 4])

    ax = fig.add_subplot(gs.new_subplotspec((0, 0), colspan=2))
    ax2 = fig.add_subplot(gs.new_subplotspec((1, 0), colspan=2))
    palette = plt.get_cmap("tab20")

    indx = np.arange(len(data.index))

    labs = data.index.tolist()
    labs.insert(0, "")

    ax.tick_params(axis="both", which="major", labelsize=10)
    ax2.tick_params(axis="both", which="major", labelsize=10)
    ax2.set_xticklabels((labs), rotation=45, fontsize=10, horizontalalignment="right")
    ax.set_xticklabels(())
    ax.set_xticks(np.arange(-1, len(data.index) + 1, 1.0))
    ax2.set_xticks(np.arange(-1, len(data.index) + 1, 1.0))

    ax.set_yticks(np.arange(0, max(data["high"]) + 10, 100))
    ax2.set_yticks(np.arange(0, max(data["high"]) + 10, 100))

    # plot the same data on both axes
    bar_lower = ax2.bar(
        x=indx,
        height=data["high"] - data["low"],
        bottom=data["low"],
        width=-0.5,
        align="center",
        color=palette(1),
        edgecolor="k",
        linewidth=0.5,
        zorder=10,
    )

    bar_upper = ax.bar(
        x=indx,
        height=data["high"] - data["low"],
        bottom=data["low"],
        width=-0.5,
        align="center",
        color=palette(1),
        edgecolor="k",
        linewidth=0.5,
        zorder=10,
    )

    # zoom-in / limit the view to different portions of the data
    ax.set_ylim(9950, 10050)  # outliers only
    ax2.set_ylim(0, 450)  # most of the data
    ax.set_xlim(-0.5, len(data.index) - 0.25)  # outliers only
    ax2.set_xlim(-0.5, len(data.index) - 0.25)  # most of the data


    ax.spines["bottom"].set_visible(False)
    ax2.spines["top"].set_visible(False)

    ax.grid(color="k", alpha=0.5, linestyle=":", zorder=1)
    ax2.grid(color="k", alpha=0.5, linestyle=":", zorder=1)

    ax.tick_params(axis="x", which="both", length=0)
    ax.tick_params(labeltop="off")
    ax2.tick_params(labeltop="off")
    ax2.xaxis.tick_bottom()

    d = 0.015  # how big to make the diagonal lines in axes coordinates
    # arguments to pass to plot, just so we don't keep repeating them
    kwargs = dict(transform=ax.transAxes, color="k", clip_on=False)  # linewidth=1)
    ax.plot((-d, +d), (-d, +d), **kwargs)  # top-left diagonal
    ax.plot((1 - d, 1 + d), (-d, +d), **kwargs)  # top-right diagonal

    kwargs.update(transform=ax2.transAxes)  # switch to the bottom axes
    ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs)  # bottom-left diagonal
    ax2.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs)  # bottom-right diagonal

    plt.subplots_adjust(
        top=0.943, bottom=0.214, left=0.103, right=0.97, hspace=0.133, wspace=0.062
    )
    plt.show()

OK,我也做了一些修改,現在可(只是不太我會原本打算),並有一個新的解決方案在這里。我們會盡快推到matplotlib頁面。

關鍵代碼是這一段

# arguments to pass to plot, just so we don't keep repeating them
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False)
ax.plot((-d, +d), (-d, +d), **kwargs)        # top-left diagonal
ax.plot((1 - d, 1 + d), (-d, +d), **kwargs)  # top-right diagonal

kwargs.update(transform=ax2.transAxes)  # switch to the bottom axes
ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs)  # bottom-left diagonal
ax2.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs)  # bottom-right diagonal

你可以修改為

axis_break1 = 450
axis_break2 = 9951
x_min = -0.75
x_max = len(data.index)
l = 0.2  # "break" line length
kwargs = dict(color="k", clip_on=False, linewidth=1)
ax.plot((x_min - l, x_min + l), (axis_break2, axis_break2), **kwargs)# top-left
ax.plot((x_max - l, x_max + l), (axis_break2, axis_break2), **kwargs)# top-right
ax2.plot((x_min - l, x_min + l), (axis_break1, axis_break1), **kwargs)# bottom-left
ax2.plot((x_max - l, x_max + l), (axis_break1, axis_break1), **kwargs)# bottom-right

這給我們留下了一個整潔的(如果稍微不那么花哨)結果。 結果圖

或者修改后(更優雅)的版本(來自 ImportanceOfBeingErnest ):

d = .25  # proportion of vertical to horizontal extent of the slanted line
kwargs = dict(marker=[(-1, -d), (1, d)], markersize=12,
              linestyle="none", color='k', mec='k', mew=1, clip_on=False)
ax.plot([0, 1], [0, 0], transform=ax.transAxes, **kwargs)
ax2.plot([0, 1], [1, 1], transform=ax2.transAxes, **kwargs)

這導致最初預期的對角線。 在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM