[英]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.