227 lines
9.7 KiB
Python
227 lines
9.7 KiB
Python
from PySide6.QtWidgets import QApplication, QMainWindow, QSlider, QVBoxLayout, QComboBox, QWidget, QPushButton, QToolBar, QGridLayout, QHBoxLayout, QLabel, QRadioButton, QScrollArea, QSizePolicy, QSpacerItem
|
|
from PySide6.QtCore import Qt, QTimer, QSize, QPointF
|
|
from PySide6.QtCharts import QChart, QChartView, QLineSeries, QValueAxis
|
|
from PySide6.QtGui import QAction, QPainter, QColor, QIcon, QFont
|
|
from codes.common import clibs
|
|
import os
|
|
import pandas
|
|
|
|
|
|
class ChartWindow(QMainWindow):
|
|
curve_map = {
|
|
"周期内平均转矩": ["device_servo_trq_feedback", ],
|
|
"周期内最大速度": ["hw_joint_vel_feedback", ],
|
|
}
|
|
ylabels = {"周期内最大速度": "速度(rad/s)", "周期内平均转矩": "转矩(Nm)"}
|
|
colors = [QColor(255, 0, 0), QColor(255, 0, 0), QColor(0, 0, 255), QColor(0, 255, 0), QColor(254, 153, 0), QColor(0, 255, 255), QColor(255, 0, 255), QColor(0, 0, 0), QColor(255, 255, 255), QColor(128, 128, 128), QColor(255, 182, 193), QColor(173, 216, 230), QColor(144, 238, 144)]
|
|
|
|
def __init__(self, dir_path, procs):
|
|
super().__init__()
|
|
self.procs = procs
|
|
self.dir_path = dir_path
|
|
self.setup_ui()
|
|
self.detect_files()
|
|
|
|
# self.timer = QTimer()
|
|
# self.timer.timeout.connect(self.reset_zoom)
|
|
# self.timer.start(60000) # 60000ms 更新一次数据
|
|
|
|
def detect_files(self):
|
|
with open(f"{clibs.PREFIX}/qss/style.qss", mode="r", encoding="utf-8") as f_qss:
|
|
style_sheet = f_qss.read()
|
|
self.setStyleSheet(style_sheet)
|
|
|
|
if not os.path.exists(self.dir_path):
|
|
clibs.logger("ERROR", "curves_draw", f"数据文件夹{self.dir_path}不存在,请确认后重试......", "red")
|
|
for proc_name, is_enabled in self.procs.items():
|
|
if is_enabled:
|
|
break
|
|
else:
|
|
clibs.logger("ERROR", "curves_draw", f"需要选择至少一个功能,才能继续绘图......", "red")
|
|
|
|
_, files = clibs.traversal_files(self.dir_path)
|
|
csv_files = []
|
|
for file in files:
|
|
if file.lower().endswith(".csv"):
|
|
self.cb_func_name.addItem(file.split("/")[-1].split(".")[0])
|
|
csv_files.append(file)
|
|
|
|
if len(csv_files) == 0:
|
|
clibs.logger("ERROR", "curves_draw", "程序未开始运行,暂无数据可以展示......", "red")
|
|
|
|
self.reset_zoom()
|
|
|
|
def get_current_info(self):
|
|
self.func_name = self.cb_func_name.currentText()
|
|
self.file_name = f"{self.dir_path}/{self.func_name}.csv"
|
|
self.df = pandas.read_csv(self.file_name)
|
|
self.horizontal_slider.setRange(0, len(self.df))
|
|
|
|
def center_on_screen(self):
|
|
screen_geometry = QApplication.primaryScreen().geometry()
|
|
screen_width = screen_geometry.width()
|
|
screen_height = screen_geometry.height()
|
|
|
|
win_width = self.width()
|
|
win_height = self.height()
|
|
x = (screen_width - win_width) // 2
|
|
y = (screen_height - win_height) // 2
|
|
self.move(x, y)
|
|
|
|
def setup_ui(self):
|
|
self.setWindowTitle("曲线绘制")
|
|
self.setGeometry(100, 100, 1000, 500)
|
|
self.setWindowIcon(QIcon(f"{clibs.PREFIX}/media/icon.ico"))
|
|
self.center_on_screen()
|
|
|
|
# 窗体布局
|
|
self.centralwidget = QWidget(self)
|
|
self.centralwidget.setObjectName(u"centralwidget")
|
|
self.gridLayout = QGridLayout(self.centralwidget)
|
|
self.gridLayout.setObjectName(u"gridLayout")
|
|
|
|
# 布局spinbox 和 label coordinate
|
|
self.hl_spinbox_btn = QHBoxLayout()
|
|
self.hl_spinbox_btn.setObjectName(u"hl_spinbox_btn")
|
|
font = QFont()
|
|
font.setFamilies([u"Consolas"])
|
|
font.setPointSize(10)
|
|
self.rb_x = QRadioButton(self.centralwidget)
|
|
self.rb_x.setObjectName(u"rb_x")
|
|
self.rb_x.setText(u"仅X轴缩放")
|
|
self.rb_x.setFont(font)
|
|
self.rb_y = QRadioButton(self.centralwidget)
|
|
self.rb_y.setObjectName(u"rb_y")
|
|
self.rb_y.setText(u"仅Y轴缩放")
|
|
self.rb_y.setFont(font)
|
|
self.rb_xy = QRadioButton(self.centralwidget)
|
|
self.rb_xy.setObjectName(u"rb_xy")
|
|
self.rb_xy.setText(u"XY轴缩放")
|
|
self.rb_xy.setFont(font)
|
|
self.rb_xy.setChecked(True)
|
|
|
|
self.cb_func_name = QComboBox(self.centralwidget)
|
|
self.cb_func_name.setObjectName(u"cb_func_name")
|
|
self.cb_func_name.setMinimumSize(QSize(200, 0))
|
|
self.cb_func_name.setFont(font)
|
|
self.button_reset = QPushButton(self.centralwidget)
|
|
self.button_reset.setObjectName(u"button_reset")
|
|
self.button_reset.setFont(font)
|
|
self.button_reset.setText(u"视图重置")
|
|
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
|
self.hl_spinbox_btn.addWidget(self.rb_x)
|
|
self.hl_spinbox_btn.addWidget(self.rb_y)
|
|
self.hl_spinbox_btn.addWidget(self.rb_xy)
|
|
self.hl_spinbox_btn.addItem(self.horizontalSpacer)
|
|
self.hl_spinbox_btn.addWidget(self.cb_func_name)
|
|
self.hl_spinbox_btn.addWidget(self.button_reset)
|
|
# 连接信号
|
|
self.rb_x.clicked.connect(lambda: self.set_zoom_mode(QChartView.RubberBand.HorizontalRubberBand))
|
|
self.rb_y.clicked.connect(lambda: self.set_zoom_mode(QChartView.RubberBand.VerticalRubberBand))
|
|
self.rb_xy.clicked.connect(lambda: self.set_zoom_mode(QChartView.RubberBand.RectangleRubberBand))
|
|
self.button_reset.clicked.connect(self.reset_zoom)
|
|
self.cb_func_name.currentTextChanged.connect(self.cb_func_name_change)
|
|
|
|
# 生成曲线图
|
|
self.chart = QChart()
|
|
self.chart.setTheme(QChart.ChartTheme.ChartThemeLight) # 设置主题
|
|
self.chart.legend().setVisible(True)
|
|
self.chart.legend().setAlignment(Qt.AlignmentFlag.AlignRight) # 图例右对齐
|
|
self.chart_view = QChartView(self.chart)
|
|
self.chart_view.setRubberBand(QChartView.RubberBand.RectangleRubberBand) # 矩形缩放
|
|
self.chart_view.setRenderHint(QPainter.RenderHint.Antialiasing) # 抗锯齿
|
|
self.axisX = QValueAxis()
|
|
# self.axisX.setTitleText("X轴")
|
|
self.axisX.setRange(0, 10) # 初始显示范围
|
|
self.axisY = QValueAxis()
|
|
# self.axisY.setTitleText("Y轴")
|
|
self.axisY.setRange(-5, 5)
|
|
self.chart.addAxis(self.axisX, Qt.AlignmentFlag.AlignBottom)
|
|
self.chart.addAxis(self.axisY, Qt.AlignmentFlag.AlignLeft)
|
|
# 创建水平滚动条
|
|
self.horizontal_slider = QSlider(Qt.Orientation.Horizontal)
|
|
self.horizontal_slider.valueChanged.connect(self.update_view)
|
|
# self.horizontal_slider.setFixedHeight(200)
|
|
|
|
# 左侧布局
|
|
self.vl_central = QVBoxLayout()
|
|
self.vl_central.setObjectName(u"vl_central")
|
|
self.vl_central.addWidget(self.chart_view)
|
|
self.vl_central.addWidget(self.horizontal_slider)
|
|
self.vl_central.addLayout(self.hl_spinbox_btn)
|
|
self.vl_central.setStretch(0, 20)
|
|
self.vl_central.setStretch(1, 1)
|
|
self.vl_central.setStretch(2, 1)
|
|
|
|
self.gridLayout.addLayout(self.vl_central, 0, 0)
|
|
self.setCentralWidget(self.centralwidget)
|
|
|
|
def connect_legend_markers(self):
|
|
for marker in self.chart.legend().markers():
|
|
try:
|
|
marker.clicked.disconnect()
|
|
except:
|
|
pass
|
|
marker.clicked.connect(self.toggle_series_visibility)
|
|
self.update_legend_style(marker)
|
|
|
|
def update_legend_style(self, marker):
|
|
alpha = 255 if marker.series().isVisible() else 128
|
|
color = marker.labelBrush().color()
|
|
color.setAlpha(alpha)
|
|
marker.setLabelBrush(color)
|
|
|
|
marker_color = marker.series().color()
|
|
marker_color.setAlpha(alpha)
|
|
marker.setBrush(marker_color)
|
|
marker.setPen(marker_color.darker())
|
|
|
|
def toggle_series_visibility(self):
|
|
marker = self.sender()
|
|
if series := marker.series():
|
|
new_visibility = not series.isVisible()
|
|
series.setVisible(new_visibility)
|
|
self.update_legend_style(marker)
|
|
marker.setVisible(True)
|
|
|
|
def cb_func_name_change(self):
|
|
self.reset_zoom()
|
|
|
|
def set_zoom_mode(self, mode):
|
|
"""设置缩放模式"""
|
|
self.chart_view.setRubberBand(mode)
|
|
# 取消其他按钮的选中状态
|
|
self.rb_x.setChecked(mode == QChartView.RubberBand.HorizontalRubberBand)
|
|
self.rb_y.setChecked(mode == QChartView.RubberBand.VerticalRubberBand)
|
|
self.rb_xy.setChecked(mode == QChartView.RubberBand.RectangleRubberBand)
|
|
|
|
def reset_zoom(self):
|
|
self.chart.removeAllSeries()
|
|
self.get_current_info()
|
|
self.axisY.setTitleText(self.ylabels[self.func_name])
|
|
|
|
series_s = [QLineSeries() for _ in range(18)]
|
|
for col in range(1, len(self.df.columns)):
|
|
self.series = series_s[col]
|
|
self.chart.addSeries(self.series)
|
|
self.series.attachAxis(self.axisX)
|
|
self.series.attachAxis(self.axisY)
|
|
data = [QPointF(idx, self.df.iloc[:, col].values[idx]) for idx in range(len(self.df))]
|
|
self.series.append(data)
|
|
self.series.setColor(self.colors[col])
|
|
self.series.setName(self.df.columns[col])
|
|
|
|
self.chart.zoomReset() # 重置所有缩放
|
|
self.horizontal_slider.setValue(0)
|
|
self.axisX.setRange(0, len(self.df))
|
|
self.axisY.setRange(min(self.df.iloc[:, 1:].min())-1, max(self.df.iloc[:, 1:].max())+1)
|
|
self.connect_legend_markers()
|
|
|
|
def update_view(self):
|
|
self.connect_legend_markers()
|
|
# 自动滚动显示最新10个点
|
|
if self.horizontal_slider.value() > 10:
|
|
self.axisX.setRange(self.horizontal_slider.value() - 10, self.horizontal_slider.value())
|
|
else:
|
|
self.axisX.setRange(0, 10)
|