跳转到内容
工程实践已发布

监测数据可视化与趋势分析方案

轨道交通控制保护区监测数据的可视化呈现方案与趋势分析方法,涵盖时程曲线、等值线图、三维展示、相关性分析等多种可视化技术。

复核 2026-07-09入门公开可引用RailWise 技术团队
工程实践

监测数据可视化与趋势分析方案

Section titled “监测数据可视化与趋势分析方案”

本文档适用于轨道交通控制保护区监测项目的数据可视化与趋势分析工作,涵盖时程曲线、空间分布图、相关性分析等多种可视化技术,以及变形趋势研判、异常识别等分析方法。

监测数据可视化是将抽象的数值数据转化为直观的图形图像,帮助工程师快速理解监测状态、识别异常趋势、支持决策判断。核心目标包括:

  • 状态感知:一眼掌握全部测点的当前状态
  • 趋势识别:快速发现数据变化趋势和规律
  • 异常定位:及时识别异常数据并定位异常测点
  • 关联分析:揭示多源数据之间的关联关系
  • 汇报展示:为技术汇报和管理决策提供直观素材
┌─────────────────────────────────────────────────────────┐
│ 数据可视化核心原则 │
├─────────────────────────────────────────────────────────┤
│ 准确性 ──→ 图形真实反映数据,不夸大、不缩小 │
│ 清晰性 ──→ 图表简洁明了,避免过度装饰 │
│ 一致性 ──→ 同类图表风格统一,便于对比 │
│ 完整性 ──→ 包含必要的标注、图例、单位 │
│ 可读性 ──→ 字体、颜色、线型易于辨识 │
│ 交互性 ──→ 支持缩放、筛选、详情查看(电子报告) │
└─────────────────────────────────────────────────────────┘
标准编号 相关条款 要求摘要
GB 50497-2019 第9.2节 监测数据应绘制时程曲线,分析变化规律
JGJ 8-2016 第8.2节 变形监测成果应绘制图表,进行综合分析
CJJ/T 202-2013 第7.2节 监测数据应进行趋势分析,评估安全状态

单测点时程曲线是最基础的可视化形式,展示单个测点随时间的变化趋势。

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime
import numpy as np
def plot_single_point_trend(data, point_id, save_path=None):
"""
绘制单测点时程曲线
参数:
data: DataFrame,包含datetime和displacement列
point_id: 测点编号
save_path: 保存路径(可选)
"""
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制位移曲线
ax.plot(data['datetime'], data['displacement'],
'b-', linewidth=1.5, label='累计位移')
# 绘制预警阈值线
ax.axhline(y=4.0, color='orange', linestyle='--',
linewidth=1, label='黄色预警阈值')
ax.axhline(y=6.0, color='red', linestyle='--',
linewidth=1, label='红色预警阈值')
ax.axhline(y=-4.0, color='orange', linestyle='--', linewidth=1)
ax.axhline(y=-6.0, color='red', linestyle='--', linewidth=1)
# 标注预警事件
alert_data = data[data['status'] == 'alert']
if not alert_data.empty:
ax.scatter(alert_data['datetime'], alert_data['displacement'],
color='red', s=50, zorder=5, label='预警数据')
# 设置图表属性
ax.set_xlabel('日期', fontsize=12)
ax.set_ylabel('累计位移 (mm)', fontsize=12)
ax.set_title(f'{point_id} 位移时程曲线', fontsize=14, fontweight='bold')
ax.legend(loc='upper left', fontsize=10)
ax.grid(True, alpha=0.3)
# 格式化日期轴
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
ax.xaxis.set_major_locator(mdates.DayLocator(interval=2))
plt.xticks(rotation=45)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()
# 使用示例
# plot_single_point_trend(df, 'R3G1-H-01-001', 'trend.png')

当需要同时展示多个测点或多种监测类型时,采用多子图布局:

def plot_multi_point_trends(data_dict, layout=(2, 3), save_path=None):
"""
绘制多测点时程曲线(子图布局)
参数:
data_dict: 字典,key为测点编号,value为DataFrame
layout: 子图布局 (行, 列)
save_path: 保存路径
"""
rows, cols = layout
fig, axes = plt.subplots(rows, cols, figsize=(cols*6, rows*4))
axes = axes.flatten() if rows * cols > 1 else [axes]
for idx, (point_id, data) in enumerate(data_dict.items()):
if idx >= len(axes):
break
ax = axes[idx]
ax.plot(data['datetime'], data['displacement'],
'b-', linewidth=1.2)
ax.axhline(y=4.0, color='orange', linestyle='--', linewidth=0.8)
ax.axhline(y=-4.0, color='orange', linestyle='--', linewidth=0.8)
ax.set_title(point_id, fontsize=11)
ax.set_ylabel('位移 (mm)', fontsize=9)
ax.grid(True, alpha=0.3)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
# 隐藏多余的子图
for idx in range(len(data_dict), len(axes)):
axes[idx].set_visible(False)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

将多个相关测点绘制在同一图表中,便于对比分析:

def plot_multi_point_comparison(data_dict, save_path=None):
"""
绘制多测点对比曲线
参数:
data_dict: 字典,key为测点编号,value为DataFrame
save_path: 保存路径
"""
fig, ax = plt.subplots(figsize=(14, 7))
colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd']
for idx, (point_id, data) in enumerate(data_dict.items()):
color = colors[idx % len(colors)]
ax.plot(data['datetime'], data['displacement'],
color=color, linewidth=1.5, label=point_id, marker='o',
markersize=3, markevery=5)
# 预警阈值
ax.axhline(y=4.0, color='orange', linestyle='--',
linewidth=1, alpha=0.7, label='黄色预警')
ax.axhline(y=-4.0, color='orange', linestyle='--', linewidth=1, alpha=0.7)
ax.set_xlabel('日期', fontsize=12)
ax.set_ylabel('累计位移 (mm)', fontsize=12)
ax.set_title('多测点位移对比曲线', fontsize=14, fontweight='bold')
ax.legend(loc='upper left', fontsize=10, ncol=2)
ax.grid(True, alpha=0.3)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
plt.xticks(rotation=45)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

展示位移速率的变化趋势,用于判断变形是否加速:

def plot_displacement_rate(data, window=5, save_path=None):
"""
绘制位移速率变化曲线
参数:
data: DataFrame,包含datetime和displacement列
window: 速率计算窗口(数据点数)
save_path: 保存路径
"""
# 计算速率
data['rate'] = data['displacement'].diff(window) / window
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8),
gridspec_kw={'height_ratios': [2, 1]})
# 位移曲线
ax1.plot(data['datetime'], data['displacement'],
'b-', linewidth=1.5, label='累计位移')
ax1.set_ylabel('累计位移 (mm)', fontsize=11)
ax1.set_title('位移与速率变化曲线', fontsize=13, fontweight='bold')
ax1.legend(loc='upper left')
ax1.grid(True, alpha=0.3)
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
# 速率曲线
ax2.plot(data['datetime'], data['rate'],
'r-', linewidth=1.5, label='位移速率')
ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.8)
ax2.axhline(y=2.0, color='orange', linestyle='--',
linewidth=1, label='速率预警')
ax2.axhline(y=-2.0, color='orange', linestyle='--', linewidth=1)
ax2.set_xlabel('日期', fontsize=11)
ax2.set_ylabel('速率 (mm/期)', fontsize=11)
ax2.legend(loc='upper left')
ax2.grid(True, alpha=0.3)
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

展示全部测点的当前状态,用颜色区分正常、关注、预警状态:

def plot_point_status_map(points_df, save_path=None):
"""
绘制测点状态分布图
参数:
points_df: DataFrame,包含x, y, status, displacement列
save_path: 保存路径
"""
fig, ax = plt.subplots(figsize=(12, 10))
# 状态颜色映射
status_colors = {
'normal': '#2ca02c', # 绿色
'attention': '#ffcc00', # 黄色
'yellow_alert': '#ff7f0e', # 橙色
'red_alert': '#d62728' # 红色
}
# 按状态分组绘制
for status, color in status_colors.items():
subset = points_df[points_df['status'] == status]
if not subset.empty:
ax.scatter(subset['x'], subset['y'],
c=color, s=100, alpha=0.8,
edgecolors='black', linewidth=0.5,
label=status)
# 标注测点编号
for _, row in subset.iterrows():
ax.annotate(row['point_id'],
(row['x'], row['y']),
textcoords="offset points",
xytext=(0, 10), ha='center',
fontsize=8)
ax.set_xlabel('X 坐标 (m)', fontsize=12)
ax.set_ylabel('Y 坐标 (m)', fontsize=12)
ax.set_title('测点状态分布图', fontsize=14, fontweight='bold')
ax.legend(loc='upper right', fontsize=10)
ax.grid(True, alpha=0.3)
ax.set_aspect('equal')
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

展示位移的空间分布规律:

import numpy as np
from scipy.interpolate import griddata
def plot_displacement_contour(points_df, grid_size=100, save_path=None):
"""
绘制累计位移等值线图
参数:
points_df: DataFrame,包含x, y, displacement列
grid_size: 插值网格大小
save_path: 保存路径
"""
# 创建插值网格
x_min, x_max = points_df['x'].min(), points_df['x'].max()
y_min, y_max = points_df['y'].min(), points_df['y'].max()
xi = np.linspace(x_min, x_max, grid_size)
yi = np.linspace(y_min, y_max, grid_size)
Xi, Yi = np.meshgrid(xi, yi)
# 插值
Zi = griddata(
(points_df['x'], points_df['y']),
points_df['displacement'],
(Xi, Yi),
method='cubic'
)
fig, ax = plt.subplots(figsize=(12, 10))
# 绘制等值线
contour = ax.contour(Xi, Yi, Zi, levels=15, colors='black', linewidths=0.5)
ax.clabel(contour, inline=True, fontsize=8, fmt='%.1f')
# 填充等值面
contourf = ax.contourf(Xi, Yi, Zi, levels=15, cmap='RdYlBu_r', alpha=0.7)
# 标注测点
ax.scatter(points_df['x'], points_df['y'],
c='black', s=50, zorder=5)
# 颜色条
cbar = plt.colorbar(contourf, ax=ax)
cbar.set_label('累计位移 (mm)', fontsize=11)
ax.set_xlabel('X 坐标 (m)', fontsize=12)
ax.set_ylabel('Y 坐标 (m)', fontsize=12)
ax.set_title('累计位移等值线图', fontsize=14, fontweight='bold')
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

分析施工参数(土压、掘进速度等)与监测数据的相关性:

import seaborn as sns
def plot_correlation_analysis(monitoring_data, construction_data, save_path=None):
"""
绘制施工参数与监测数据相关性分析图
参数:
monitoring_data: DataFrame,监测数据
construction_data: DataFrame,施工参数数据
save_path: 保存路径
"""
# 合并数据
merged_data = pd.merge(monitoring_data, construction_data,
on='datetime', how='inner')
# 选择分析变量
variables = ['displacement', 'earth_pressure', 'advance_speed',
'cutter_speed', 'grout_volume']
# 计算相关系数矩阵
corr_matrix = merged_data[variables].corr()
fig, ax = plt.subplots(figsize=(10, 8))
# 热力图
sns.heatmap(corr_matrix, annot=True, fmt='.2f',
cmap='RdBu_r', center=0, vmin=-1, vmax=1,
square=True, ax=ax,
xticklabels=['位移', '土压', '掘进速度', '刀盘转速', '注浆量'],
yticklabels=['位移', '土压', '掘进速度', '刀盘转速', '注浆量'])
ax.set_title('施工参数与监测数据相关性矩阵', fontsize=14, fontweight='bold')
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

展示两个变量之间的线性关系:

def plot_scatter_regression(x_data, y_data, x_label, y_label, save_path=None):
"""
绘制散点图与回归线
参数:
x_data: X轴数据
y_data: Y轴数据
x_label: X轴标签
y_label: Y轴标签
save_path: 保存路径
"""
fig, ax = plt.subplots(figsize=(10, 8))
# 散点图
ax.scatter(x_data, y_data, alpha=0.6, s=50, c='#1f77b4')
# 线性回归
z = np.polyfit(x_data, y_data, 1)
p = np.poly1d(z)
x_line = np.linspace(x_data.min(), x_data.max(), 100)
ax.plot(x_line, p(x_line), 'r--', linewidth=2,
label=f'回归线: y={z[0]:.3f}x+{z[1]:.3f}')
# 计算R²
correlation = np.corrcoef(x_data, y_data)[0, 1]
r_squared = correlation ** 2
# 标注R²
ax.text(0.05, 0.95, f'R² = {r_squared:.3f}\nr = {correlation:.3f}',
transform=ax.transAxes, fontsize=12,
verticalalignment='top',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
ax.set_xlabel(x_label, fontsize=12)
ax.set_ylabel(y_label, fontsize=12)
ax.set_title(f'{x_label}{y_label}关系分析', fontsize=14, fontweight='bold')
ax.legend(loc='upper left', fontsize=10)
ax.grid(True, alpha=0.3)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

判断数据是否存在线性增长或下降趋势:

from scipy import stats
def linear_trend_analysis(data, alpha=0.05):
"""
线性趋势分析
参数:
data: Series或数组,时间序列数据
alpha: 显著性水平
返回:
趋势分析结果字典
"""
x = np.arange(len(data))
y = data.values
# 线性回归
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
# 判断趋势
if p_value < alpha:
if slope > 0:
trend = '上升'
trend_type = 'increasing'
else:
trend = '下降'
trend_type = 'decreasing'
significant = True
else:
trend = '平稳'
trend_type = 'stable'
significant = False
return {
'trend': trend,
'trend_type': trend_type,
'significant': significant,
'slope': slope,
'r_squared': r_value ** 2,
'p_value': p_value,
'std_err': std_err
}

消除数据波动,识别长期趋势:

def moving_average_analysis(data, window=7):
"""
移动平均趋势分析
参数:
data: DataFrame,包含datetime和displacement列
window: 移动平均窗口大小
返回:
包含移动平均和趋势的DataFrame
"""
result = data.copy()
# 计算移动平均
result['ma'] = result['displacement'].rolling(window=window).mean()
# 计算移动标准差
result['std'] = result['displacement'].rolling(window=window).std()
# 计算上下包络线
result['upper'] = result['ma'] + 2 * result['std']
result['lower'] = result['ma'] - 2 * result['std']
return result
def plot_moving_average(data, window=7, save_path=None):
"""
绘制移动平均趋势图
"""
ma_data = moving_average_analysis(data, window)
fig, ax = plt.subplots(figsize=(12, 6))
# 原始数据
ax.plot(ma_data['datetime'], ma_data['displacement'],
'b-', alpha=0.3, linewidth=1, label='原始数据')
# 移动平均
ax.plot(ma_data['datetime'], ma_data['ma'],
'r-', linewidth=2, label=f'{window}期移动平均')
# 包络线
ax.fill_between(ma_data['datetime'],
ma_data['upper'], ma_data['lower'],
alpha=0.2, color='gray', label='±2σ包络')
ax.set_xlabel('日期', fontsize=12)
ax.set_ylabel('累计位移 (mm)', fontsize=12)
ax.set_title('移动平均趋势分析', fontsize=14, fontweight='bold')
ax.legend(loc='upper left', fontsize=10)
ax.grid(True, alpha=0.3)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
plt.xticks(rotation=45)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

基于统计方法识别异常数据:

def detect_anomalies(data, method='iqr', threshold=1.5):
"""
异常数据检测
参数:
data: Series,时间序列数据
method: 检测方法 ('iqr'或'zscore')
threshold: 阈值
返回:
异常数据索引列表
"""
if method == 'iqr':
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - threshold * IQR
upper = Q3 + threshold * IQR
anomalies = data[(data < lower) | (data > upper)].index
elif method == 'zscore':
z_scores = np.abs(stats.zscore(data))
anomalies = data[z_scores > threshold].index
return anomalies
def plot_anomaly_detection(data, method='iqr', threshold=1.5, save_path=None):
"""
绘制异常检测结果
"""
anomalies = detect_anomalies(data['displacement'], method, threshold)
fig, ax = plt.subplots(figsize=(12, 6))
# 正常数据
normal_data = data.drop(anomalies)
ax.plot(normal_data['datetime'], normal_data['displacement'],
'b-', linewidth=1, label='正常数据')
# 异常数据
if len(anomalies) > 0:
anomaly_data = data.loc[anomalies]
ax.scatter(anomaly_data['datetime'], anomaly_data['displacement'],
color='red', s=80, zorder=5, label='异常数据')
ax.set_xlabel('日期', fontsize=12)
ax.set_ylabel('累计位移 (mm)', fontsize=12)
ax.set_title('异常数据检测', fontsize=14, fontweight='bold')
ax.legend(loc='upper left', fontsize=10)
ax.grid(True, alpha=0.3)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
plt.xticks(rotation=45)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.show()

设计综合监测数据仪表盘,集成多种可视化组件:

┌─────────────────────────────────────────────────────────────┐
│ 监测数据综合仪表盘 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 测点总数 │ │ 正常测点 │ │ 预警测点 │ │
│ │ 70 │ │ 65 │ │ 5 │ │
│ │ │ │ 92.9% │ │ 7.1% │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ 关键测点时程曲线 │ │ 测点状态分布图 │ │
│ │ │ │ │ │
│ │ [时程曲线图表区域] │ │ [状态分布图表区域] │ │
│ │ │ │ │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ 位移速率排行 │ │ 预警事件列表 │ │
│ │ │ │ │ │
│ │ [速率排行表格] │ │ [预警事件表格] │ │
│ │ │ │ │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 累计位移等值线图 │ │
│ │ │ │
│ │ [等值线图表区域] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
def generate_monitoring_dashboard(project_code, save_path=None):
"""
生成监测数据综合仪表盘
参数:
project_code: 项目代码
save_path: 保存路径
"""
fig = plt.figure(figsize=(20, 16))
# 创建子图布局
gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
# 1. 关键指标卡片(顶部3个)
ax1 = fig.add_subplot(gs[0, 0])
ax1.text(0.5, 0.5, '测点总数\n\n70', ha='center', va='center',
fontsize=24, fontweight='bold')
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
ax1.axis('off')
ax2 = fig.add_subplot(gs[0, 1])
ax2.text(0.5, 0.5, '正常测点\n\n65\n(92.9%)', ha='center', va='center',
fontsize=24, fontweight='bold', color='green')
ax2.set_xlim(0, 1)
ax2.set_ylim(0, 1)
ax2.axis('off')
ax3 = fig.add_subplot(gs[0, 2])
ax3.text(0.5, 0.5, '预警测点\n\n5\n(7.1%)', ha='center', va='center',
fontsize=24, fontweight='bold', color='orange')
ax3.set_xlim(0, 1)
ax3.set_ylim(0, 1)
ax3.axis('off')
# 2. 时程曲线
ax4 = fig.add_subplot(gs[1, :2])
# 绘制时程曲线代码...
ax4.set_title('关键测点时程曲线', fontsize=12, fontweight='bold')
# 3. 状态分布
ax5 = fig.add_subplot(gs[1, 2])
# 绘制状态分布代码...
ax5.set_title('测点状态分布', fontsize=12, fontweight='bold')
# 4. 等值线图
ax6 = fig.add_subplot(gs[2, :])
# 绘制等值线图代码...
ax6.set_title('累计位移等值线', fontsize=12, fontweight='bold')
fig.suptitle('监测数据综合仪表盘', fontsize=16, fontweight='bold', y=0.98)
if save_path:
plt.savefig(save_path, dpi=200, bbox_inches='tight')
plt.show()
  • 图表标题清晰,包含测点编号和监测类型
  • 坐标轴标注完整,包含单位和刻度
  • 图例位置合理,不遮挡数据
  • 预警阈值线已标注
  • 异常数据已高亮显示
  • 颜色搭配协调,符合色盲友好原则
  • 字体大小适中,打印后清晰可读
  • 图表分辨率满足打印要求(≥300dpi)

Q1: 数据量很大时,时程曲线如何优化?

A: 大数据量时可采用以下策略:

  1. 数据降采样:保留关键节点数据,减少数据点数量
  2. 分段展示:按时间分段绘制,避免单图过于密集
  3. 交互式图表:使用Web图表库支持缩放和筛选

Q2: 多测点颜色如何区分?

A: 建议使用以下配色方案:

  • 正常测点:蓝色系(#1f77b4, #4a90d9, #7ab8e8)
  • 关注测点:黄色系(#ffcc00, #ffdd55)
  • 预警测点:橙/红色系(#ff7f0e, #d62728)
  • 避免使用红绿色组合(色盲友好)

Q3: 等值线插值方法如何选择?

A: 常用插值方法对比:

方法 适用场景 优点 缺点
线性 数据分布均匀 计算快,不易过拟合 不够平滑
三次样条 数据分布较密 平滑,连续可导 可能产生伪极值
Kriging 数据分布稀疏 考虑空间相关性 计算复杂

元数据标签: #数据可视化 #趋势分析 #时程曲线 #等值线图 #相关性分析 #三维展示 #数据图表 #监测分析 #轨道交通 #工程监测

引用与复核把知识带回真实工程判断

引用时保留页面与来源线索;涉及标准条文、阈值、频率和项目结论,请回到现行依据与责任人复核。

查看 Agent 使用规则