优化历史趋势 光标吸附

main
zcwBit 3 months ago
parent 4796448544
commit 42ff71796c

@ -262,6 +262,8 @@ class TrendWidgets(QWidget):
self.crosshair_visible = False
self.crosshair_point = None # 交叉点圆点
self.crosshair_text = None # 坐标文本标签
self._snapped_var = None # 当前吸附的变量名
self.snap_enabled = True # 是否启用智能吸附功能
# 连接鼠标事件
self.canvas.mpl_connect('motion_notify_event', self.onMouseMove)
@ -877,10 +879,17 @@ class TrendWidgets(QWidget):
if not (xlim[0] <= x <= xlim[1] and ylim[0] <= y <= ylim[1]):
return
# 可选:吸附到最近的数据点
snap_x, snap_y = self.snapToNearestDataPoint(x, y)
if snap_x is not None and snap_y is not None:
x, y = snap_x, snap_y
# 智能吸附到最近的数据点(如果启用)
if self.snap_enabled:
snap_x, snap_y, snap_var_name = self.snapToNearestDataPoint(x, y)
if snap_x is not None and snap_y is not None:
x, y = snap_x, snap_y
# 存储吸附信息,用于显示
self._snapped_var = snap_var_name
else:
self._snapped_var = None
else:
self._snapped_var = None
# 更新垂直线位置
self.crosshair_v.set_data([x, x], [ylim[0], ylim[1]])
@ -890,8 +899,21 @@ class TrendWidgets(QWidget):
self.crosshair_h.set_data([xlim[0], xlim[1]], [y, y])
self.crosshair_h.set_visible(True)
# 更新交叉点圆点位置
# 更新交叉点圆点位置和样式
self.crosshair_point.set_offsets([[x, y]])
# 根据是否吸附到数据点改变圆点颜色
if hasattr(self, '_snapped_var') and self._snapped_var:
# 吸附状态:使用绿色表示精确定位
self.crosshair_point.set_color('#00AA00')
self.crosshair_point.set_edgecolors('white')
self.crosshair_point.set_sizes([64]) # 稍大一些
else:
# 普通状态:使用红色
self.crosshair_point.set_color('#FF4444')
self.crosshair_point.set_edgecolors('white')
self.crosshair_point.set_sizes([36]) # 正常大小
self.crosshair_point.set_visible(True)
# 更新坐标文本
@ -912,40 +934,70 @@ class TrendWidgets(QWidget):
pass
def snapToNearestDataPoint(self, x, y):
"""吸附到最近的数据点(可选功能)"""
if not self.selectedVars:
return None, None
"""智能吸附到最近的数据点 - 多变量增强版"""
if not self.selectedVars or not self.multiVarData:
return None, None, None
min_distance = float('inf')
snap_x, snap_y = None, None
snap_var_name = None
# 获取当前坐标轴范围,用于归一化距离计算
xlim = self.axMain.get_xlim()
ylim = self.axMain.get_ylim()
x_range = xlim[1] - xlim[0]
y_range = ylim[1] - ylim[0]
# 遍历所有选中的变量,找到最近的数据点
for varName in self.selectedVars:
if varName in self.multiVarData:
data = self.multiVarData[varName]
if data['x'] and data['y']:
# 找到最接近的X坐标点
closest_idx = self.findClosestPoint(data['x'], x)
if closest_idx is not None and closest_idx < len(data['y']):
data_x = data['x'][closest_idx]
data_y = data['y'][closest_idx]
# 将datetime转换为matplotlib数值
if isinstance(data_x, datetime.datetime):
data_x_num = mdates.date2num(data_x)
else:
data_x_num = data_x
# 计算距离(在屏幕坐标系中)
distance = abs(data_x_num - x)
# 只有距离足够近才吸附(避免过度吸附)
if distance < min_distance and distance < 0.01: # 可调整吸附阈值
min_distance = distance
snap_x = data_x_num
snap_y = data_y
return snap_x, snap_y
# 遍历该变量的所有数据点
for i, (data_x, data_y) in enumerate(zip(data['x'], data['y'])):
try:
# 将datetime转换为matplotlib数值
if isinstance(data_x, datetime.datetime):
data_x_num = mdates.date2num(data_x)
else:
data_x_num = data_x
# 计算归一化的欧几里得距离
# 归一化是为了让X轴时间和Y轴数值的距离具有可比性
dx_norm = (data_x_num - x) / x_range if x_range != 0 else 0
dy_norm = (data_y - y) / y_range if y_range != 0 else 0
distance = (dx_norm ** 2 + dy_norm ** 2) ** 0.5
# 使用可配置的吸附阈值
snap_threshold = getattr(self, 'snap_threshold', 0.05) # 默认5%的屏幕距离
if distance < min_distance and distance < snap_threshold:
min_distance = distance
snap_x = data_x_num
snap_y = data_y
snap_var_name = varName
except Exception as e:
# 跳过有问题的数据点
continue
return snap_x, snap_y, snap_var_name
def toggleSnapToDataPoints(self, enabled=None):
"""切换智能吸附功能"""
if enabled is None:
self.snap_enabled = not self.snap_enabled
else:
self.snap_enabled = enabled
print(f"智能吸附功能: {'启用' if self.snap_enabled else '禁用'}")
return self.snap_enabled
def setSnapThreshold(self, threshold):
"""设置吸附阈值0.01-0.2之间)"""
self.snap_threshold = max(0.01, min(0.2, threshold))
print(f"吸附阈值设置为: {self.snap_threshold:.3f}")
return self.snap_threshold
def _delayed_crosshair_draw(self):
"""延迟绘制十字标线,避免频繁更新"""
@ -958,15 +1010,17 @@ class TrendWidgets(QWidget):
pass
def formatCoordinateText(self, x, y):
"""格式化坐标文本显示"""
"""格式化坐标文本显示 - 增强版,显示吸附信息"""
try:
# 格式化时间X轴
if isinstance(x, (int, float)):
# 将matplotlib数值转换为datetime
time_obj = mdates.num2date(x)
time_str = time_obj.strftime('%H:%M:%S')
date_str = time_obj.strftime('%m-%d')
else:
time_str = str(x)
date_str = ""
# 格式化数值Y轴
if isinstance(y, (int, float)):
@ -979,7 +1033,17 @@ class TrendWidgets(QWidget):
else:
value_str = str(y)
return f"时间: {time_str}\n数值: {value_str}"
# 构建基础文本
if date_str:
coord_text = f"时间: {date_str} {time_str}\n数值: {value_str}"
else:
coord_text = f"时间: {time_str}\n数值: {value_str}"
# 如果吸附到了数据点,显示变量信息
if hasattr(self, '_snapped_var') and self._snapped_var:
coord_text += f"\n📍 {self._snapped_var}"
return coord_text
except Exception as e:
return f"X: {x:.3f}\nY: {y:.3f}"

Loading…
Cancel
Save