首页 > 解决方案 > 如何将分钟和小时的刻度添加到对数秒的 y 轴?

问题描述

我的代码现在看起来像这样:

import math 
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.pyplot import figure

rows = np.around(np.logspace(math.log10(50),math.log10(10000),8))
rows = rows.astype(int)

# Plot runtimes
sns.set_style("whitegrid")
plt.rcParams["font.family"] = "Times New Roman"
figure(num=None,figsize=(9, 6), dpi=160, facecolor='w', edgecolor='k')
runtime = np.zeros((3,len(rows)))

runtime[0]=[1,1,3,34,104,445,2000,8000]
runtime[1]=[4,20,100,5000,26000,200000,'nan','nan']
runtime[2]=[0.5,0.5,3,30,80,300,1300,5000]

extraticks=[60]
extravalue=[60]

plt.plot(rows,runtime[0], label="A", marker='o')
plt.plot(rows,runtime[1], label="B", marker='o')
plt.plot(rows,runtime[2], label="C", marker='o')

plt.xscale("log"), plt.yscale("log")
plt.xticks(rows, labels=rows)
#plt.yticks(list(plt.yticks()[0])+extraticks,list(plt.yticks()[0])+extravalue)

plt.xlabel("Sample size")
plt.ylabel("Runtime [s]")
plt.legend()

这给了我以下结果(我画了额外的线条来显示预期的结果):

在此处输入图像描述

我将如何添加那些额外的线条和刻度?正如您在注释行中看到的那样,我尝试了类似的方法,但它弄乱了我之前工作的刻度和标签。

标签: pythonmatplotlib

解决方案


一个想法是为标签和额外的网格线使用次要的 y 刻度。一个特殊的格式化程序将标签显示为分钟、小时、天。(matplotlib 3.4 需要直接设置格式化程序,旧版本需要FunctionFormatter设置自定义格式化程序)。可选地,可以为这些新刻度使用不同的颜色和字体大小。

为了在 10 5处省略重叠的 y 刻度标签,特殊的格式化程序可以测试该功率并设置一个空标签。仍然会绘制相应的网格线,因为仍然会有刻度位置。

import matplotlib.pyplot as plt
from matplotlib.ticker import FixedLocator, ScalarFormatter
import seaborn as sns
import numpy as np

def show_pow_10(x, pos):
    power = np.log10(x)
    return '' if power == 5 else f'$10^{power:.0f}$'

def show_day_hour_min(x, pos):
    if x < 60:
        return f'{x:.0f} s'
    else:
        x = np.round(x / 60)
        if x < 60:
            return f'{x:.0f} min'
        else:
            x = np.round(x / 60)
            return f'{x:.0f} h'

rows = np.around(np.logspace(np.log10(50), np.log10(10000), 8))
rows = rows.astype(int)

# Plot runtimes
sns.set_style("whitegrid")
plt.rcParams["font.family"] = "Times New Roman"
plt.figure(num=None, figsize=(9, 6), dpi=160, facecolor='w', edgecolor='k')
ax = plt.gca()
runtime = np.zeros((3, len(rows)))

runtime[0] = [1, 1, 3, 34, 104, 445, 2000, 8000]
runtime[1] = [4, 20, 100, 5000, 26000, 200000, np.nan, np.nan]
runtime[2] = [0.5, 0.5, 3, 30, 80, 300, 1300, 5000]

# extraticks = [60, 60 * 60, 24 * 60 * 60]
extraticks = [60, 10*60, 60 * 60, 10*60*60, 24 * 60 * 60]

ax.plot(rows, runtime[0], label="A", marker='o')
ax.plot(rows, runtime[1], label="B", marker='o')
ax.plot(rows, runtime[2], label="C", marker='o')

ax.set_xscale("log")
ax.set_yscale("log")
ax.xaxis.set_major_locator(FixedLocator(rows))
ax.xaxis.set_major_formatter(ScalarFormatter())
ax.yaxis.set_major_formatter(show_pow_10)
ax.set_yticks(extraticks, minor=True)
ax.tick_params(axis='y', which='minor', labelcolor='dodgerblue', labelsize=9)
ax.yaxis.set_minor_locator(FixedLocator(extraticks))
ax.yaxis.set_minor_formatter(show_day_hour_min)

ax.set_xlabel("Sample size")
ax.set_ylabel("Runtime [s]")
ax.grid(True, which='minor', axis='y', color='dodgerblue', ls='--', lw=0.5, alpha=0.6)
ax.legend()
plt.show()

使用小刻度来表示分钟、小时、天


推荐阅读