当前位置:首页>python>《15节课Python绘图从入门到精通》10——图面精细标注实操——解决审稿人关于刻度与标签的疑问

《15节课Python绘图从入门到精通》10——图面精细标注实操——解决审稿人关于刻度与标签的疑问

  • 2026-06-24 22:17:15
《15节课Python绘图从入门到精通》10——图面精细标注实操——解决审稿人关于刻度与标签的疑问

本文主要内容

本节从审稿维度出发,从下面四个任务入手对图面精细标注。

  • 实操任务1:将X轴刻度设置为化学分子式,添加下标、斜体,优化刻度字体与大小
  • 实操任务2:构造双Y轴图表,使两侧轴颜色与对应数据曲线一致,调整轴标签位置
  • 实操任务3:在图例中添加矩形色块,用于表示数据总体标准差,优化图例布局
  • 实操任务4:在图内空白处添加带箭头的文本框,详细解释异常数据点的成因

前置数据准备

为保证所有程序可直接运行,先运行以下代码生成所需的示例数据。

import numpy as np
import pandas as pd

np.random.seed(2024)

# ---------- 10.1 化学分子式X轴数据 ----------
molecules = ['H₂O''CO₂''CH₄''NH₃''C₂H₅OH''C₆H₁₂O₆']
values = [18.044.016.017.046.0180.0]
df_molecules = pd.DataFrame({'分子': molecules, '分子量': values})
df_molecules.to_csv('分子量数据.csv', index=False, encoding='utf-8-sig')

# ---------- 10.2 双Y轴数据(温度与湿度)----------
time = np.linspace(024100)  # 小时
temp = 15 + 8 * np.sin(2*np.pi*(time-6)/24) + np.random.normal(00.5100)
humidity = 60 - 15 * np.sin(2*np.pi*(time-6)/24) + 5 * np.random.normal(01100)
df_dual = pd.DataFrame({'时间': time, '温度': temp, '湿度': humidity})
df_dual.to_csv('温湿度数据.csv', index=False, encoding='utf-8-sig')

# ---------- 10.3 带标准差的图例数据 ----------
x = np.linspace(01050)
y1 = 2*x + 5 + np.random.normal(0250)
y2 = 1.5*x + 8 + np.random.normal(0350)
df_std = pd.DataFrame({'x': x, '实验组': y1, '对照组': y2})
df_std.to_csv('实验数据_含标准差.csv', index=False, encoding='utf-8-sig')

# ---------- 10.4 含异常点的数据 ----------
x_anom = np.linspace(02040)
y_anom = 0.5 * x_anom + 2 + np.random.normal(01.540)
# 人为插入两个异常点
y_anom[10] = 25# 异常高值
y_anom[25] = -3# 异常低值
df_anom = pd.DataFrame({'时间': x_anom, '信号': y_anom})
df_anom.to_csv('异常点数据.csv', index=False, encoding='utf-8-sig')

print("数据生成完成:")
print("- 分子量数据.csv(10.1节用)")
print("- 温湿度数据.csv(10.2节用)")
print("- 实验数据_含标准差.csv(10.3节用)")
print("- 异常点数据.csv(10.4节用)")

实操任务1:将X轴刻度设置为化学分子式,添加下标、斜体,优化刻度字体与大小

本任务从基础的文本刻度替换入手,逐步进阶到LaTeX渲染、自定义字体、旋转对齐及多行刻度。

基础版:使用文本数组替换刻度标签

直接用分子式字符串替换X轴刻度,matplotlib默认支持Unicode下标(如'₂')。

import pandas as pd
import matplotlib.pyplot as plt

# 学术样式设置
defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('分子量数据.csv')
molecules = df['分子'].values
weights = df['分子量'].values

fig, ax = plt.subplots(figsize=(4.53.5))
bars = ax.bar(range(len(molecules)), weights, color='
#4472C4', alpha=0.7, edgecolor='black', linewidth=0.5)

# 设置X轴刻度和标签
ax.set_xticks(range(len(molecules)))
ax.set_xticklabels(molecules, fontsize=9)
ax.set_xlabel('分子式')
ax.set_ylabel('分子量 (g/mol)')
ax.set_ylim(0, max(weights)*1.1)

# 添加数值标注
for bar, w in zip(bars, weights):
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1
f'{w:.1f}', ha='center', va='bottom', fontsize=8)

plt.tight_layout()
plt.show()
fig.savefig('分子式刻度_基础.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('分子式刻度_基础.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 使用Unicode字符'₂'、'₃'、'₄'、'₆'实现了下标效果,无需额外渲染引擎。
  • 刻度标签清晰显示H₂O、CO₂等,满足化学式基本表示要求。
  • 若需更复杂的斜体或自定义字体,需进一步配置。

进阶1:启用LaTeX样式实现专业排版

通过设置plt.rcParams['mathtext.fontset'] = 'cm',使用 LaTeX 的 Computer Modern 字体,获得漂亮的化

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['text.usetex'] = False
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['mathtext.fontset'] = 'cm'# latex 字体 Computer Modern
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('分子量数据.csv')
# LaTeX格式分子式
latex_molecules = [r'H$_2$O'r'CO$_2$'r'CH$_4$'r'NH$_3$'r'C$_2$H$_5$OH'r'C$_6$H$_{12}$O$_6$']
weights = df['分子量'].values

fig, ax = plt.subplots(figsize=(4.53.5))
bars = ax.bar(range(len(latex_molecules)), weights, color='#4472C4', alpha=0.7, edgecolor='black', linewidth=0.5)

ax.set_xticks(range(len(latex_molecules)))
ax.set_xticklabels(latex_molecules, fontsize=10)
ax.set_xlabel('分子式')
ax.set_ylabel('分子量 (g/mol)')
ax.set_ylim(0, max(weights)*1.1)

for bar, w in zip(bars, weights):
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1,
f'{w:.1f}', ha='center', va='bottom', fontsize=8)

plt.tight_layout()
plt.show()
fig.savefig('分子式刻度2_LaTeX.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('分子式刻度2_LaTeX.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • LaTeX渲染的分子式下标对齐精准,字体为Computer Modern,符合学术期刊化学式排版规范。
  • 斜体通过$...$数学模式自动实现,变量字母为斜体,数字和下标为正体。

进阶2:自定义刻度字体(粗体、颜色、旋转)

对特定分子式设置不同字体属性,如将CO₂设为红色粗体以强调。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['mathtext.fontset'] = 'cm'
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('分子量数据.csv')
math_molecules = [r'$H_2O$'r'$CO_2$'r'$CH_4$'r'$NH_3$'r'$C_2H_5OH$'r'$C_6H_{12}O_6$']
weights = df['分子量'].values

fig, ax = plt.subplots(figsize=(5.03.5))
bars = ax.bar(range(len(math_molecules)), weights, color='#4472C4', alpha=0.7, edgecolor='black', linewidth=0.5)

ax.set_xticks(range(len(math_molecules)))
ax.set_xticklabels(math_molecules, fontsize=9)

# 单独设置CO₂为红色粗体
xticklabels = ax.get_xticklabels()
for i, label in enumerate(xticklabels):
if'CO'in label.get_text():
        label.set_color('red')
        label.set_fontweight('bold')
        label.set_fontsize(10)

ax.set_xlabel('分子式')
ax.set_ylabel('分子量 (g/mol)')

plt.tight_layout()
plt.show()
fig.savefig('分子式刻度_强调特定标签.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('分子式刻度_强调特定标签.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 通过获取xticklabels列表,可对单个标签设置颜色、粗细、大小等属性。
  • 适用于审稿人要求突出显示特定数据点对应类别的场景。
  • 也可批量应用样式,如将所有碳氢化合物设为绿色。

进阶3:多行刻度与旋转对齐(处理长分子式)

当分子式名称过长时,可换行显示并适当旋转,避免重叠。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['mathtext.fontset'] = 'cm'
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 300
set_academic_style()

df = pd.read_csv('分子量数据.csv')
# 添加更长的名称演示多行
molecules_long = ['H₂O''CO₂''CH₄''NH₃''乙醇\nC₂H₅OH''葡萄糖\nC₆H₁₂O₆']
weights = df['分子量'].values

fig, ax = plt.subplots(figsize=(5.04.0))
bars = ax.bar(range(len(molecules_long)), weights, color='#4472C4', alpha=0.7, edgecolor='black', linewidth=0.5)

ax.set_xticks(range(len(molecules_long)))
ax.set_xticklabels(molecules_long, fontsize=8, ha='center')

ax.set_xlabel('分子式')
ax.set_ylabel('分子量 (g/mol)')
ax.set_xlim(-0.5, len(molecules_long)-0.5)

# 调整底部边距以容纳多行标签
plt.subplots_adjust(bottom=0.15)

plt.show()
fig.savefig('分子式刻度_多行标签.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('分子式刻度_多行标签.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 通过在字符串中插入\n实现换行,第一行为常用名,第二行为分子式。
  • 适当增加底部边距(subplots_adjust)防止标签被截断。
  • 若仍重叠,可进一步旋转标签:ax.set_xticklabels(..., rotation=30, ha='right')

实操任务2:构造双Y轴图表,使两侧轴颜色与对应数据曲线一致,调整轴标签位置

本任务从基础双轴图入手,逐步进阶到颜色同步、图例整合、多曲线及共享X轴子图。

基础版:双Y轴基本绘制

使用twinx()创建共享X轴的第二Y轴。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('温湿度数据.csv')
time = df['时间']
temp = df['温度']
hum = df['湿度']

fig, ax1 = plt.subplots(figsize=(5.03.5))

# 左轴:温度
ax1.plot(time, temp, 'r-', linewidth=1.5, label='温度')
ax1.set_xlabel('时间 (h)')
ax1.set_ylabel('温度 (°C)', color='red')
ax1.tick_params(axis='y', labelcolor='red')

# 右轴:湿度
ax2 = ax1.twinx()
ax2.plot(time, hum, 'b--', linewidth=1.5, label='湿度')
ax2.set_ylabel('相对湿度 (%)', color='blue')
ax2.tick_params(axis='y', labelcolor='blue')

plt.tight_layout()
plt.show()
fig.savefig('双Y轴_基础.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('双Y轴_基础.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 温度(红色实线)对应左轴红色标签,湿度(蓝色虚线)对应右轴蓝色标签。
  • 轴颜色与曲线颜色一致,符合审稿人对“可读性”的要求。
  • 未添加图例,进阶版将整合图例。

进阶1:双轴颜色同步 + 统一图例

将两条曲线的图例合并显示,避免重复。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('温湿度数据.csv')
time, temp, hum = df['时间'], df['温度'], df['湿度']

fig, ax1 = plt.subplots(figsize=(5.03.5))
ax2 = ax1.twinx()

line1, = ax1.plot(time, temp, color='#C00000', linewidth=1.8, label='温度')
line2, = ax2.plot(time, hum, color='#0066CC', linewidth=1.8, linestyle='--', label='相对湿度')

ax1.set_xlabel('时间 (h)')
ax1.set_ylabel('温度 (°C)', color='#C00000')
ax2.set_ylabel('相对湿度 (%)', color='#0066CC')
ax1.tick_params(axis='y', labelcolor='#C00000')
ax2.tick_params(axis='y', labelcolor='#0066CC')

# 合并图例
lines = [line1, line2]
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper right', fontsize=8, frameon=False)

plt.tight_layout()
plt.show()
fig.savefig('双Y轴_统一图例.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('双Y轴_统一图例.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 图例同时包含温度和湿度,置于右上角,简洁明了。
  • 颜色统一使用十六进制精确控制,确保与轴标签一致。
  • 图例框去除边框,符合学术风格。

进阶2:调整轴标签位置(偏移与旋转)

通过labelpadset_position调整轴标签与轴的距离,避免与刻度数字重叠。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('温湿度数据.csv')
time, temp, hum = df['时间'], df['温度'], df['湿度']

fig, ax1 = plt.subplots(figsize=(5.03.5))
ax2 = ax1.twinx()

ax1.plot(time, temp, color='#C00000', linewidth=1.8, label='温度')
ax2.plot(time, hum, color='#0066CC', linewidth=1.8, linestyle='--', label='湿度')

ax1.set_xlabel('时间 (h)')
ax1.set_ylabel('温度 (°C)', color='#C00000', labelpad=10)  # 增加标签与轴的距离
ax2.set_ylabel('相对湿度 (%)', color='#0066CC', labelpad=15)
# 右轴标签旋转(可选)
ax2.yaxis.set_label_coords(1.080.5)  # 调整标签水平位置

ax1.tick_params(axis='y', labelcolor='#C00000')
ax2.tick_params(axis='y', labelcolor='#0066CC')

lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1+lines2, labels1+labels2, loc='upper right', fontsize=8)

plt.tight_layout()
plt.show()
fig.savefig('双Y轴_标签位置调整.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('双Y轴_标签位置调整.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • labelpad控制标签与轴线的距离,避免与刻度数字重叠。
  • set_label_coords可精细调整标签位置,适用于标签较长或需要特殊对齐时。
  • 右轴标签水平位置移至1.08(略超出默认1.0),与图例错开。

进阶3:多曲线双Y轴(左轴多条,右轴单条)

左轴绘制多条温度曲线(如不同实验组),右轴仍为湿度。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('温湿度数据.csv')
time = df['时间']
temp1 = df['温度']  # 实验组1
# 模拟实验组2和3
np.random.seed(42)
temp2 = temp1 + 2 + np.random.normal(00.8, len(time))
temp3 = temp1 - 1.5 + np.random.normal(00.6, len(time))
hum = df['湿度']

fig, ax1 = plt.subplots(figsize=(5.53.8))
ax2 = ax1.twinx()

# 左轴:三条温度曲线
l1, = ax1.plot(time, temp1, color='#C00000', linewidth=1.5, label='实验组1')
l2, = ax1.plot(time, temp2, color='#ED7D31', linewidth=1.5, linestyle='-.', label='实验组2')
l3, = ax1.plot(time, temp3, color='#70AD47', linewidth=1.5, linestyle=':', label='实验组3')
# 右轴:湿度
l4, = ax2.plot(time, hum, color='#0066CC', linewidth=1.8, linestyle='--', label='相对湿度')

ax1.set_xlabel('时间 (h)')
ax1.set_ylabel('温度 (°C)')
ax2.set_ylabel('相对湿度 (%)', color='#0066CC')
ax1.tick_params(axis='y')
ax2.tick_params(axis='y', labelcolor='#0066CC')

# 图例整合
lines = [l1, l2, l3, l4]
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper left', fontsize=7, frameon=False, ncol=2)

plt.tight_layout()
plt.show()
fig.savefig('双Y轴_多曲线.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('双Y轴_多曲线.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 左轴三条温度曲线用不同颜色和线型区分,右轴单条湿度曲线。
  • 图例分两列显示,节省纵向空间。
  • 适用于展示多个实验条件下,某一关键变量与另一参考变量的协同变化。

进阶4:共享X轴的双Y轴子图(多面板)

使用subplots创建上下两个子图,各自拥有双Y轴,共享X轴。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('温湿度数据.csv')
time = df['时间']
temp = df['温度']
hum = df['湿度']
# 模拟另一组数据(风速)
wind = 2 + 1.5 * np.sin(2*np.pi*(time-3)/12) + np.random.normal(00.3, len(time))

fig, (ax1, ax3) = plt.subplots(21, figsize=(5.05.0), sharex=True)

# 上图:温度(左)+ 湿度(右)
ax2 = ax1.twinx()
ax1.plot(time, temp, 'r-', label='温度')
ax2.plot(time, hum, 'b--', label='湿度')
ax1.set_ylabel('温度 (°C)', color='red')
ax2.set_ylabel('湿度 (%)', color='blue')
ax1.tick_params(axis='y', labelcolor='red')
ax2.tick_params(axis='y', labelcolor='blue')

# 下图:温度(左)+ 风速(右)
ax4 = ax3.twinx()
ax3.plot(time, temp, 'r-', label='温度')
ax4.plot(time, wind, 'g-.', label='风速')
ax3.set_xlabel('时间 (h)')
ax3.set_ylabel('温度 (°C)', color='red')
ax4.set_ylabel('风速 (m/s)', color='green')
ax3.tick_params(axis='y', labelcolor='red')
ax4.tick_params(axis='y', labelcolor='green')

# 图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1+lines2, labels1+labels2, loc='upper right', fontsize=7)

lines3, labels3 = ax3.get_legend_handles_labels()
lines4, labels4 = ax4.get_legend_handles_labels()
ax3.legend(lines3+lines4, labels3+labels4, loc='upper right', fontsize=7)

plt.tight_layout()
plt.show()
fig.savefig('双Y轴_共享X子图.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('双Y轴_共享X子图.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 两个子图共享X轴,上图展示温湿度关系,下图展示温度与风速关系。
  • 每个子图独立拥有双Y轴,颜色区分清晰。
  • 适用于展示同一自变量与多组因变量的关系对比。

实操任务3:在图例中添加矩形色块,用于表示数据总体标准差,优化图例布局

本任务从手动创建图例句柄入手,逐步进阶到自定义色块、标准差阴影图例、多色块及图例位置精细调整。

基础版:自定义图例句柄(添加矩形色块)

使用Patch创建自定义图例元素,表示数据标准差。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('实验数据_含标准差.csv')
x = df['x']
y_exp = df['实验组']
y_ctrl = df['对照组']

# 计算总体标准差(示例)
std_exp = np.std(y_exp)
std_ctrl = np.std(y_ctrl)

fig, ax = plt.subplots(figsize=(5.03.5))
line1, = ax.plot(x, y_exp, 'o-', color='#C00000', markersize=4, label='实验组')
line2, = ax.plot(x, y_ctrl, 's-', color='#0066CC', markersize=4, label='对照组')

# 创建自定义图例句柄:矩形色块表示标准差
std_patch1 = mpatches.Patch(color='#C00000', alpha=0.3, label=f'实验组 SD = {std_exp:.2f}')
std_patch2 = mpatches.Patch(color='#0066CC', alpha=0.3, label=f'对照组 SD = {std_ctrl:.2f}')

# 合并默认图例句柄与自定义
handles, labels = ax.get_legend_handles_labels()
handles.extend([std_patch1, std_patch2])
labels.extend([std_patch1.get_label(), std_patch2.get_label()])
ax.legend(handles=handles, labels=labels, loc='upper left', fontsize=8, frameon=False)

ax.set_xlabel('x')
ax.set_ylabel('测量值')
ax.set_title('实验数据(图例含标准差)', fontsize=10)

plt.tight_layout()
plt.show()
fig.savefig('图例_标准差色块_基础.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('图例_标准差色块_基础.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 使用mpatches.Patch创建半透明矩形,颜色与对应曲线一致,alpha表示“范围”概念。
  • 图例中增加了两行,分别显示各组标准差数值。
  • 审稿人可快速了解数据离散程度,无需查看全文。

进阶1:在图中绘制标准差阴影,并同步图例

先绘制带标准差的阴影区域,再在图例中用相同样式的色块表示。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('实验数据_含标准差.csv')
x = df['x']
y_exp = df['实验组']
y_ctrl = df['对照组']

# 计算均值和标准差(按x分组计算更合理,此处简化用总体标准差展示方法)
# 实际应用中应对每个x点计算重复测量的std,此处仅演示图例
mean_exp = np.mean(y_exp)
mean_ctrl = np.mean(y_ctrl)
std_exp = np.std(y_exp)
std_ctrl = np.std(y_ctrl)

fig, ax = plt.subplots(figsize=(5.03.5))

# 绘制带标准差的阴影区域(使用总体均值±std示意)
x_fill = np.array([x.min(), x.max(), x.max(), x.min()])
y_fill_exp = np.array([mean_exp-std_exp, mean_exp-std_exp, mean_exp+std_exp, mean_exp+std_exp])
y_fill_ctrl = np.array([mean_ctrl-std_ctrl, mean_ctrl-std_ctrl, mean_ctrl+std_ctrl, mean_ctrl+std_ctrl])

ax.fill(x_fill, y_fill_exp, color='#C00000', alpha=0.2, label='_nolegend_')
ax.fill(x_fill, y_fill_ctrl, color='#0066CC', alpha=0.2, label='_nolegend_')
line1, = ax.plot(x, y_exp, 'o-', color='#C00000', markersize=4, label='实验组')
line2, = ax.plot(x, y_ctrl, 's-', color='#0066CC', markersize=4, label='对照组')

# 自定义图例
std_patch1 = mpatches.Patch(color='#C00000', alpha=0.2, label=f'实验组 SD = {std_exp:.2f}')
std_patch2 = mpatches.Patch(color='#0066CC', alpha=0.2, label=f'对照组 SD = {std_ctrl:.2f}')
handles = [line1, std_patch1, line2, std_patch2]
ax.legend(handles=handles, loc='upper left', fontsize=8, frameon=False)

ax.set_xlabel('x')
ax.set_ylabel('测量值')

plt.tight_layout()
plt.show()
fig.savefig('图例_标准差阴影同步.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('图例_标准差阴影同步.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 图中半透明色带直观表示数据的波动范围,图例中对应的色块使读者无需猜测。
  • label='_nolegend_'防止fill对象自动进入图例,保持图例简洁。
  • 注意:此示例简化了标准差计算,实际应按重复测量计算逐点标准差。

进阶2:多标准差色块(不同置信区间)

用不同透明度的色块表示68%、95%置信区间,并在图例中分别标注。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['mathtext.fontset'] = 'cm'
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('实验数据_含标准差.csv')
x = df['x']
y = df['实验组']
mean_y = np.mean(y)
std_y = np.std(y)

fig, ax = plt.subplots(figsize=(5.03.5))

# 绘制68% (±1σ) 和 95% (±2σ) 区间
x_fill = np.array([x.min(), x.max(), x.max(), x.min()])
y_fill_1 = [mean_y-std_y, mean_y-std_y, mean_y+std_y, mean_y+std_y]
y_fill_2 = [mean_y-2*std_y, mean_y-2*std_y, mean_y+2*std_y, mean_y+2*std_y]

ax.fill(x_fill, y_fill_2, color='#4472C4', alpha=0.15, label='_nolegend_')
ax.fill(x_fill, y_fill_1, color='#4472C4', alpha=0.3, label='_nolegend_')
line, = ax.plot(x, y, 'o', color='#4472C4', markersize=4, alpha=0.6, label='数据点')
ax.axhline(mean_y, color='#4472C4', linestyle='--', linewidth=1, label='均值')

# 图例
patch_95 = mpatches.Patch(color='#4472C4', alpha=0.15, label='95% CI ($\pm 2 \sigma$)')
patch_68 = mpatches.Patch(color='#4472C4', alpha=0.3, label='68% CI ($\pm 1 \sigma$)')
handles = [line, ax.get_lines()[0], patch_68, patch_95]  # 均值线是第二个Line2D对象
labels = ['数据点'f'均值 = {mean_y:.2f}''68% CI ($\pm 1 \sigma$)''95% CI ($\pm 2 \sigma$)']
ax.legend(handles=handles, labels=labels, loc='lower right', fontsize=8, frameon=False)

ax.set_xlabel('x')
ax.set_ylabel('测量值')
ax.set_title('置信区间可视化', fontsize=10)

plt.tight_layout()
plt.show()
fig.savefig('图例_多级标准差色块.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('图例_多级标准差色块.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 两种透明度的蓝色色块分别表示 和  范围,图例清晰标注。
  • 均值线用虚线表示,图例中一并说明。
  • 适用于展示数据分布的集中趋势和离散程度。

进阶3:图例布局优化(分列、标题、边框)

将图例分为多列,添加标题,并设置半透明背景以融入图表。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('实验数据_含标准差.csv')
x, y_exp, y_ctrl = df['x'], df['实验组'], df['对照组']

fig, ax = plt.subplots(figsize=(5.53.8))
line1, = ax.plot(x, y_exp, 'o-', color='#C00000', markersize=4, label='实验组')
line2, = ax.plot(x, y_ctrl, 's-', color='#0066CC', markersize=4, label='对照组')

std_patch1 = mpatches.Patch(color='#C00000', alpha=0.3, label=f'实验组 SD = {np.std(y_exp):.2f}')
std_patch2 = mpatches.Patch(color='#0066CC', alpha=0.3, label=f'对照组 SD = {np.std(y_ctrl):.2f}')

# 图例:分两列,带标题,半透明背景
legend = ax.legend(handles=[line1, std_patch1, line2, std_patch2],
                   loc='upper center', bbox_to_anchor=(0.5-0.15),
                   ncol=2, fontsize=8, frameon=True, fancybox=False,
                   edgecolor='black', facecolor='white', framealpha=0.8)
legend.set_title('图例说明', prop={'size'9'weight''bold'})

ax.set_xlabel('x')
ax.set_ylabel('测量值')
plt.subplots_adjust(bottom=0.25)  # 为图例留空间

plt.show()
fig.savefig('图例_布局优化.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('图例_布局优化.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 图例置于图下方中央,分两列排列,节省横向空间。
  • 启用边框(frameon=True)并设置fancybox=False获得直角矩形,framealpha=0.8使背景半透。
  • 添加图例标题,增强可读性。

进阶4:使用HandlerTuple组合图例(线+色块)

将曲线和对应的标准差色块组合为单个图例条目,更紧凑。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerTuple

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('实验数据_含标准差.csv')
x, y_exp, y_ctrl = df['x'], df['实验组'], df['对照组']

fig, ax = plt.subplots(figsize=(5.03.5))
line1, = ax.plot(x, y_exp, 'o-', color='#C00000', markersize=4)
line2, = ax.plot(x, y_ctrl, 's-', color='#0066CC', markersize=4)

# 创建组合图例句柄:每个组由(线, 色块)组成
from matplotlib.patches import Patch
std_patch1 = Patch(color='#C00000', alpha=0.3)
std_patch2 = Patch(color='#0066CC', alpha=0.3)

ax.legend([(line1, std_patch1), (line2, std_patch2)],
          [f'实验组 (SD={np.std(y_exp):.2f})'f'对照组 (SD={np.std(y_ctrl):.2f})'],
          handler_map={tuple: HandlerTuple(ndivide=None)},
          loc='upper left', fontsize=8, frameon=False)

ax.set_xlabel('x')
ax.set_ylabel('测量值')

plt.tight_layout()
plt.show()
fig.savefig('图例_组合句柄.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('图例_组合句柄.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 使用HandlerTuple将线条和色块组合为一个图例条目,图例更加紧凑。
  • 每个条目左侧显示线条样式和颜色,右侧显示半透明色块,一目了然。
  • 适用于多组数据且每组有多个图形元素需同时说明的场景。

实操任务4:在图内空白处添加带箭头的文本框,详细解释异常数据点的成因

本任务从基础的annotate文本标注入手,逐步进阶到箭头样式自定义、多异常点标注、框体美化及自动定位。

基础版:使用annotate标注单个异常点

annotate在异常点旁添加文本框和箭头。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('异常点数据.csv')
x = df['时间']
y = df['信号']

fig, ax = plt.subplots(figsize=(5.03.5))
ax.plot(x, y, 'o-', color='#4472C4', markersize=4, linewidth=1)

# 标注异常高值点(索引10,x≈5,y≈25)
idx_high = 10
ax.annotate('异常高值\n(仪器饱和)',
            xy=(x[idx_high], y[idx_high]),
            xytext=(x[idx_high]+3, y[idx_high]-5),
            arrowprops=dict(arrowstyle='->', color='red', lw=1.5),
            fontsize=8, color='red', ha='center',
            bbox=dict(boxstyle='round,pad=0.3', facecolor='white', edgecolor='red', alpha=0.8))

ax.set_xlabel('时间')
ax.set_ylabel('信号强度')
ax.set_title('异常点标注', fontsize=10)

plt.tight_layout()
plt.show()
fig.savefig('异常点标注_基础.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('异常点标注_基础.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • xy指定箭头指向的坐标,xytext指定文本框位置。
  • 文本框带圆角边框,白色半透明背景,不遮挡数据。
  • 红色字体和箭头突出异常性质。

进阶1:自定义箭头样式(弧形、虚线、不同颜色)

修改arrowprops字典,实现更丰富的箭头外观。

import pandas as pd
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('异常点数据.csv')
x, y = df['时间'], df['信号']

fig, ax = plt.subplots(figsize=(5.03.5))
ax.plot(x, y, 'o-', color='#4472C4', markersize=4, linewidth=1)

idx_low = 25
ax.annotate('异常低值\n(传感器故障)',
            xy=(x[idx_low], y[idx_low]),
            xytext=(x[idx_low]-4, y[idx_low]+10),
            arrowprops=dict(arrowstyle='fancy', connectionstyle='arc3,rad=0.3',
                            color='red', lw=1.5, linestyle='--'),
            fontsize=8, color='red', ha='center',
            bbox=dict(boxstyle='round,pad=0.3', facecolor='lightyellow', edgecolor='blue', alpha=0.9))

ax.set_xlabel('时间')
ax.set_ylabel('信号强度')

plt.tight_layout()
plt.show()
fig.savefig('异常点标注_自定义箭头.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('异常点标注_自定义箭头.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • arrowstyle='fancy'生成带弧度的箭头,connectionstyle='arc3,rad=0.3'控制弯曲程度。
  • 虚线样式(linestyle='--')使箭头更柔和。
  • 文本框使用浅黄色背景,与异常低值的警示含义匹配。

进阶2:标注多个异常点(带编号与图例)

在图上标注多个异常点,并为每个异常点添加编号,同时在图例中说明。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('异常点数据.csv')
x, y = df['时间'], df['信号']

fig, ax = plt.subplots(figsize=(5.54.0))
ax.plot(x, y, 'o-', color='#4472C4', markersize=4, linewidth=1, label='正常信号')

# 定义异常点及其说明
anomalies = [(10'高值饱和'), (25'低值故障'), (35'尖峰干扰')]
colors = ['red''blue''green']
for i, (idx, desc) in enumerate(anomalies):
# 标记异常点(大星号)
    ax.plot(x[idx], y[idx], marker='*', color=colors[i], markersize=12,
            markeredgecolor='black', markeredgewidth=0.5, label=f'异常{i+1}{desc}')
# 添加文本框
    ax.annotate(f'异常{i+1}{desc}',
                xy=(x[idx], y[idx]),
                xytext=(x[idx]+(-1if i%2==0else2), y[idx]+(-3if i==1else5)),
                arrowprops=dict(arrowstyle='->', color=colors[i], lw=1.2),
                fontsize=7, color=colors[i],
                bbox=dict(boxstyle='round,pad=0.2', facecolor='white', edgecolor=colors[i], alpha=0.7))

ax.set_xlabel('时间')
ax.set_ylabel('信号强度')
ax.legend(loc='upper right', fontsize=7, ncol=2, frameon=True, fancybox=False, edgecolor='gray')

plt.tight_layout()
plt.show()
fig.savefig('异常点标注_多异常点.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('异常点标注_多异常点.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • 三个异常点用不同颜色的星号标记,并在图例中给出简短说明。
  • 每个异常点旁有详细文本框解释成因。
  • 图例分两列显示,节省空间。

进阶3:框体样式美化(阴影、渐变、圆角)

为文本框添加阴影和更精致的边框样式。

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
import matplotlib.patheffects as path_effects

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('异常点数据.csv')
x, y = df['时间'], df['信号']

fig, ax = plt.subplots(figsize=(5.03.5))
ax.plot(x, y, 'o-', color='#4472C4', markersize=4, linewidth=1)

idx_high = 10
# 使用带阴影效果的文本框
text = ax.annotate('异常高值\n(仪器饱和)',
                   xy=(x[idx_high], y[idx_high]),
                   xytext=(x[idx_high]+3, y[idx_high]-5),
                   arrowprops=dict(arrowstyle='wedge,tail_width=0.5',
                                   color='darkred', lw=1.5, shrinkA=5, shrinkB=5),
                   fontsize=9, color='darkred', ha='center', weight='bold',
                   bbox=dict(boxstyle='round,pad=0.5', facecolor='#FFF0F0',
                             edgecolor='darkred', linewidth=1.5, alpha=0.95))

# 添加文字阴影效果(需在渲染后获取text对象)
# text.set_path_effects([path_effects.withSimplePatchShadow(offset=(2,-2), shadow_rgbFace='gray', alpha=0.5)])

ax.set_xlabel('时间')
ax.set_ylabel('信号强度')

plt.tight_layout()
plt.show()
fig.savefig('异常点标注_美化框体.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('异常点标注_美化框体.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • arrowstyle='wedge,tail_width=0.5'产生楔形箭头,更醒目。
  • 文本框使用浅红色背景、深红色边框、加粗字体,强调异常严重性。
  • 若需阴影效果,可启用path_effects(注释部分),但需注意兼容性。

进阶4:自动定位文本框(避免重叠的智能算法)

当异常点较多时,手动指定xytext易导致重叠。可通过简单的偏移策略或第三方库adjustText自动优化。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from adjustText import adjust_text  # 需安装:pip install adjustText

defset_academic_style():
    plt.rcParams['font.family'] = ['Times New Roman''SimSun']
    plt.rcParams['font.size'] = 9
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['axes.linewidth'] = 1.0
    plt.rcParams['xtick.major.width'] = 1.0
    plt.rcParams['ytick.major.width'] = 1.0
    plt.rcParams['xtick.major.size'] = 3.5
    plt.rcParams['ytick.major.size'] = 3.5
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rcParams['legend.frameon'] = False
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['savefig.dpi'] = 1200
set_academic_style()

df = pd.read_csv('异常点数据.csv')
x, y = df['时间'], df['信号']

# 模拟更多异常点
np.random.seed(42)
anom_indices = [101520253035]
descs = ['饱和''尖峰''漂移''故障''噪声''干扰']

fig, ax = plt.subplots(figsize=(6.04.0))
ax.plot(x, y, 'o-', color='#4472C4', markersize=4, linewidth=1)

texts = []
for idx, desc in zip(anom_indices, descs):
# 初始位置在点右上方随机偏移
    xytext = (x[idx] + np.random.uniform(13), y[idx] + np.random.uniform(25))
    txt = ax.annotate(desc, xy=(x[idx], y[idx]), xytext=xytext,
                      arrowprops=dict(arrowstyle='->', color='gray', lw=1),
                      fontsize=7, bbox=dict(boxstyle='round,pad=0.2', facecolor='white', alpha=0.8))
    texts.append(txt)

# 自动调整文本位置避免重叠
adjust_text(texts, x=x[anom_indices], y=y[anom_indices], arrowprops=dict(arrowstyle='->', color='gray', lw=1),
            expand_text=(1.21.5), expand_points=(1.51.8))

ax.set_xlabel('时间')
ax.set_ylabel('信号强度')
ax.set_title('自动避让的异常点标注', fontsize=10)

plt.tight_layout()
plt.show()
fig.savefig('异常点标注_自动定位.pdf', bbox_inches='tight', pad_inches=0.05)
fig.savefig('异常点标注_自动定位.png', bbox_inches='tight', pad_inches=0.05)

执行结果分析:

  • adjust_text库迭代调整文本框位置,最小化重叠,同时保持箭头指向原始点。
  • 适用于异常点密集或需要批量标注的场景。
  • 若不想引入外部库,可自行实现基于力导向的简单调整算法。

- END -

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-04 09:38:03 HTTP/2.0 GET : https://f.mffb.com.cn/a/487788.html
  2. 运行时间 : 0.108457s [ 吞吐率:9.22req/s ] 内存消耗:5,140.00kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=082c99f43fd7128b0697285a603133a5
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000580s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000759s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000362s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000356s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000540s ]
  6. SELECT * FROM `set` [ RunTime:0.000198s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000497s ]
  8. SELECT * FROM `article` WHERE `id` = 487788 LIMIT 1 [ RunTime:0.000565s ]
  9. UPDATE `article` SET `lasttime` = 1783129083 WHERE `id` = 487788 [ RunTime:0.001138s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.003990s ]
  11. SELECT * FROM `article` WHERE `id` < 487788 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000696s ]
  12. SELECT * FROM `article` WHERE `id` > 487788 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000512s ]
  13. SELECT * FROM `article` WHERE `id` < 487788 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.005571s ]
  14. SELECT * FROM `article` WHERE `id` < 487788 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.013553s ]
  15. SELECT * FROM `article` WHERE `id` < 487788 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.007289s ]
0.110025s