qchart 和 qchartview 的运用的例子


qchart 存在一些问题

一般用在2000个点以下的场景,点多了,就会卡。 解决的办法就是 开启opengl加速。

但这时,对qchartview 进行transform 时, 绘制的点,并不能同时变换。原因是QT把opengl的图案是单独绘制的,要找到这个单独的view 进行变换才行。 但找不到。。。

这就不能使用的底层的函数了,只能用 qchart的setrange,变换的事情,交给qt 自己去实现。

这个例子,实现了 拖动 滚轮缩放 ,加了一个取值的限定框。

python 3.10 pyside6


import sys from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QWidget,
QVBoxLayout,
QGraphicsSceneWheelEvent,
QGraphicsSceneMouseEvent,
QLabel,
QHBoxLayout,
QFormLayout,
QPushButton,
QSlider,
)
from PySide6.QtCharts import QChartView, QChart, QScatterSeries, QValueAxis, QLineSeries
from PySide6.QtGui import QMouseEvent
from PySide6.QtCore import Qt, QPointF, Signal, QRectF, QTimer, QPoint import random
import math
import threading class zn_chart(QChart):
sg_mouse_db_click = Signal(QPointF) def __init__(self):
super().__init__()
self._left_pos = None # data series
self.se = QScatterSeries()
self.ax_x = QValueAxis()
self.ax_y = QValueAxis()
self.addSeries(self.se)
self.addAxis(self.ax_x, Qt.AlignmentFlag.AlignBottom)
self.addAxis(self.ax_y, Qt.AlignmentFlag.AlignLeft)
self.se.attachAxis(self.ax_x)
self.se.attachAxis(self.ax_y)
self.se.setBorderColor(self.se.color())
self.se.setMarkerSize(2.0)
self.ax_x.setRange(-51, 51)
self.ax_y.setRange(-51, 51)
self.setTitle("Line Chart")
self.se.setUseOpenGL(True) # data
self._data: list[QPointF] = []
self._x_min: float = None
self._x_max: float = None
self._y_min: float = None
self._y_max: float = None # limit line data self.lm_x_min: float = None
self.lm_x_max: float = None self.lm_se = QLineSeries()
self.addSeries(self.lm_se)
self.lm_se.attachAxis(self.ax_x)
self.lm_se.attachAxis(self.ax_y)
self.lm_se.setUseOpenGL(True)
self.lm_pts: list[QPointF] = []
self.lm_se.setMarkerSize(2.0)
self.lm_se.setVisible(True) # signal
self.drag_start_pos: QPointF = None
self.drag_start_range: QRectF = None
self.on_drag: bool = False # tm
self.tm: QTimer = None
self._tmp_data: list[QPointF] = []
self._tm_lock = threading.Lock() @property
def range(self) -> QRectF:
return QRectF(
self.ax_x.min(),
self.ax_y.min(),
self.ax_x.max() - self.ax_x.min(),
self.ax_y.max() - self.ax_y.min(),
) def set_range_x(self, p1: float, p2: float):
self.ax_x.setRange(p1, p2) def set_range_y(self, p1: float, p2: float):
self.ax_y.setRange(p1, p2) def setrange(self, r: QRectF):
self.ax_x.setRange(r.x(), r.x() + r.width())
self.ax_y.setRange(r.y(), r.y() + r.height()) def wheelEvent(self, event: QGraphicsSceneWheelEvent) -> None:
y = event.delta()
factor = 1
if y > 0:
factor = 1.1
elif y < 0:
factor = 1 / 1.1 if factor != 1:
f = 1 / factor
r = self.range
r_center_x = r.x() + r.width() * 0.5
r_center_y = r.y() + r.height() * 0.5
p_center = self.mapToValue(event.pos()) r_c_x2 = p_center.x() + f * (r_center_x - p_center.x())
r_c_y2 = p_center.y() + f * (r_center_y - p_center.y())
w2 = r.width() * f
h2 = r.height() * f
r2 = QRectF(r_c_x2 - w2 * 0.5, r_c_y2 - h2 * 0.5, w2, h2)
self.setrange(r2) def on_drag_enter(self, p: QPointF) -> None:
self.drag_start_pos = p
self.drag_start_range = self.range
self.on_drag = True def on_drag_exit(self) -> None:
self.on_drag = False
self.drag_start_pos = None
self.drag_start_range = None def on_drag_move(self, p: QPointF) -> None:
if self.on_drag:
vp = self.plotArea()
now_p = p
dx = -(
(now_p.x() - self.drag_start_pos.x())
/ vp.width()
* self.drag_start_range.width()
)
dy = (
(now_p.y() - self.drag_start_pos.y())
/ vp.height()
* self.drag_start_range.height()
)
r2 = QRectF(
self.drag_start_range.x() + dx,
self.drag_start_range.y() + dy,
self.drag_start_range.width(),
self.drag_start_range.height(),
)
self.setrange(r2) def mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent) -> None:
p = self.mapToValue(event.pos())
self.sg_mouse_db_click.emit(p)
print(p)
return super().mouseDoubleClickEvent(event) # data op
@property
def data(self) -> list[QPointF]:
return self._data def data_add_xy(self, x: float, y: float):
self._data.append(QPointF(x, y))
self.se.append(x, y)
if self._x_min is None or x < self._x_min:
self._x_min = x
if self._x_max is None or x > self._x_max:
self._x_max = x
if self._y_min is None or y < self._y_min:
self._y_min = y
if self._y_max is None or y > self._y_max:
self._y_max = y def data_add_p(self, d: QPointF | QPoint):
self.data_add_xy(d.x(), d.y()) def data_add_list_point(self, lp: list[QPointF | QPointF]):
for i in lp:
self.data_add_p(i)
self.se.append(lp) def data_clear(self):
self._data.clear()
self.se.clear()
self._x_min = self._x_max = self._y_min = self._y_max = None def data_load_more(self, sp: list[QPointF]):
with self._tm_lock:
if self.tm is not None:
self.tm.stop()
self.tm = None
self.data_clear() self._tmp_data.clear()
self._tmp_data += sp[:]
self.tm = QTimer()
self.tm.setInterval(15)
self.tm.timeout.connect(self._do_add)
self.tm.start() def _do_add(self):
with self._tm_lock:
if self.tm is None:
self._tmp_data.clear()
elif len(self._tmp_data) == 0:
self.tm.stop()
self.tm = None
print("over")
else:
if len(self._tmp_data) > 1000:
to_add = self._tmp_data[:1000]
self._tmp_data = self._tmp_data[1000:]
else:
to_add = self._tmp_data[:]
self._tmp_data.clear() self.data_add_list_point(to_add) # limit setting
def lm_refresh(self):
if (
self.lm_x_min is not None
and self.lm_x_max is not None
and self._y_max is not None
and self._y_min is not None
):
if self._y_max > self._y_min:
x1 = float(self.lm_x_min)
x2 = float(self.lm_x_max)
d = self._y_max - self._y_min
y1 = self._y_min - 0.2 * d
y2 = self._y_max + 0.2 * d
self.lm_pts.clear()
for i in [[x1, y1], [x1, y2], [x2, y2], [x2, y1], [x1, y1]]:
self.lm_pts.append(QPointF(*i))
self.lm_se.clear()
self.lm_se.append(self.lm_pts) def lm_set_x_min(self, x: float):
xx = float(x)
if self.lm_x_max is None or xx <= self.lm_x_max:
self.lm_x_min = xx
self.lm_refresh() def lm_set_x_max(self, x: float):
xx = float(x)
if self.lm_x_min is None or xx >= self.lm_x_min:
self.lm_x_max = xx
self.lm_refresh() def lm_set_x_min_percent(self, v: int):
f = float(v / 100)
if self._x_min is not None and self._x_max is not None:
dd = self._x_max - self._x_min
self.lm_set_x_min(dd * f + self._x_min) def lm_set_x_max_percent(self, v: int):
f = float(v / 100)
if self._x_min is not None and self._x_max is not None:
dd = self._x_max - self._x_min
self.lm_set_x_max(dd * f + self._x_min) def lm_show(self):
self.lm_se.setVisible(True) def lm_hide(self):
self.lm_se.setVisible(False) def lm_new_from_data(self):
self.lm_set_x_min(self._x_min)
self.lm_set_x_max(self._x_max) def lm_clear(self):
self.lm_se.clear()
self.lm_x_min = None
self.lm_x_max = None
self.lm_pts = [] class my_view(QChartView):
sg_drag_enter = Signal(QPointF)
sg_drag_exit = Signal()
sg_drag_move = Signal(QPointF)
on_drag: bool = False def mousePressEvent(self, event: QMouseEvent) -> None:
if event.button() == Qt.MouseButton.LeftButton:
self.sg_drag_enter.emit(event.position())
self.on_drag = True
return super().mousePressEvent(event) def mouseReleaseEvent(self, event: QMouseEvent) -> None:
self.sg_drag_exit.emit()
self.on_drag = False
return super().mouseReleaseEvent(event) def mouseMoveEvent(self, event: QMouseEvent) -> None:
if self.on_drag:
self.sg_drag_move.emit(event.position())
return super().mouseMoveEvent(event) def setChart(self, chart: QChart) -> None:
if isinstance(chart, zn_chart):
self.sg_drag_enter.connect(chart.on_drag_enter)
self.sg_drag_exit.connect(chart.on_drag_exit)
self.sg_drag_move.connect(chart.on_drag_move)
return super().setChart(chart) class zn_slider(QSlider):
def __init__(self):
super().__init__(Qt.Orientation.Horizontal)
self.setMinimum(0)
self.setMaximum(100)
self.setSingleStep(1)
self.setValue(0)
self.setTickPosition(self.TickPosition.TicksBelow) if __name__ == "__main__": class test_wg(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PySide6 QChart Example")
self.setGeometry(50, 50, 800, 600) self.central_widget = QWidget()
self.setCentralWidget(self.central_widget) self.main_layout = QVBoxLayout(self.central_widget) self.chart_view = my_view() self.main_layout.addWidget(self.chart_view) self.chart = zn_chart() self.chart_view.setChart(self.chart) ##
self.c_ly = QHBoxLayout()
self.main_layout.addLayout(self.c_ly) self.b1 = QPushButton("add data")
self.b1.clicked.connect(self.adddata)
self.c_ly.addWidget(self.b1) self.b2 = QPushButton("init limit")
self.b2.clicked.connect(self.lm_init)
self.c_ly.addWidget(self.b2) self.b3 = QPushButton("show limit")
self.b3.clicked.connect(self.chart.lm_show)
self.c_ly.addWidget(self.b3) self.b4 = QPushButton("hide limit")
self.b4.clicked.connect(self.chart.lm_hide)
self.c_ly.addWidget(self.b4)
# slider
self.f_ly = QFormLayout() self.s1 = zn_slider()
self.s1.valueChanged.connect(self.on_s1_change)
self.s1_lb = QLabel("下限")
self.s1_lb.setFixedWidth(120)
self.f_ly.addRow(self.s1_lb, self.s1) self.s2 = zn_slider()
self.s2.setValue(100)
self.s2.valueChanged.connect(self.on_s2_change)
self.s2_lb = QLabel("上限")
self.s2_lb.setFixedWidth(120)
self.f_ly.addRow(self.s2_lb, self.s2) self.main_layout.addLayout(self.f_ly)
# show
self.show() def adddata(self):
self.chart.data_clear()
dt = []
for i in range(10000):
x = random.randint(0, 10000) / 100 - 50
xx = math.pi * 2 * x / 100
y = math.sin(xx) * 50
dt.append(QPointF(x, y))
self.chart.data_load_more(dt) def lm_init(self):
self.chart.lm_set_x_min_percent(0)
self.chart.lm_set_x_max_percent(100)
self.chart.lm_show() def on_s1_change(self, v: int):
self.chart.lm_set_x_min_percent(v)
if self.chart.lm_x_min is None:
self.s1_lb.setText(f"下限")
else:
self.s1_lb.setText(f"下限 {self.chart.lm_x_min:<.3f}") def on_s2_change(self, v: int):
self.chart.lm_set_x_max_percent(v)
if self.chart.lm_x_max is None:
self.s2_lb.setText(f"上限")
else:
self.s2_lb.setText(f"上限 {self.chart.lm_x_max:<.3f}") app = QApplication(sys.argv)
window = test_wg()
app.exec()

QChart 移动 缩放 加速的更多相关文章

  1. [C1] 线性回归(Linear Regression)

    线性回归(Linear Regression with One / Multiple Variable) 定义符号(Symbol Definition) m = 数据集中训练样本的数量 n = 特征的 ...

  2. qt qchart缩放后坐标轴间隔取整

    使用qt的qchart显示数据曲线,坐标轴QValueAxis可以设置刻度间隔数量,但每个刻度的数值是根据坐标的极值除以间隔数量得到的,不一定是整数,导致曲线控件的显示刻度不适合观察. 如图: 纵坐标 ...

  3. 项目实战:流水线图像显示控件(列刷新、1ms一次、缩放、拽拖、拽拖预览、性能优化、支持OpenGL GPU加速)

      需求   流水线图像扫描采集控件(带模拟数据测试)性能需求  1.需至少满足可1ms接收一次列数据,而不丢包(接收后可不必立马显示)  2.图片刷新率可达30HZ:限制需求  1.图片高度最小只能 ...

  4. 开启gpu加速的高性能移动端相框组件!

    通过设置新的css3新属性translateX来代替传统的绝对定位改变left值的动画原理,新属性translateX会开启浏览器自带的gpu硬件加速动画性能,提高流畅度从而提高用户体验, 代码有很详 ...

  5. Minimit Anima – 硬件加速的 CSS3 动画插件

    Minimit Anima 是一个实现 CSS3 Transforms 和 Transitions 动画的 jQuery 插件.基于硬件加速的 CSS3 动画执行更快,而且它有一个类似于 jQuery ...

  6. lecture6-mini批量梯度训练及三个加速的方法

    Hinton的第6课,这一课中最后的那个rmsprop,关于它的资料,相对较少,差不多除了Hinton提出,没论文的样子,各位大大可以在这上面研究研究啊. 一.mini-批量梯度下降概述 这部分将介绍 ...

  7. Android动画及图片的缩放和旋转

    Android动画有2种,一种是Tween Animation,另一种是Frame Animation,先说说Tween动画吧. Tween动画是对视图对象中的内容进行一系列简单的转换,比如位置的移动 ...

  8. HDU 4087 三维上的平移缩放旋转矩阵变化

    题目大意: 就是根据它给的程序的要求,不断平移,缩放,旋转三维的点,最后计算出点的位置 这里主要是要列出三种转换方式的齐次矩阵描述 平移translate tx ty tz1 0 0 00 1 0 0 ...

  9. jQuery支持移动Mobile的DOM元素移动和缩放插件

    jQuery Panzoom是一款很有用的HTML DOM元素平移和缩放jQuery和CSS3插件. Panzoom利用CSS transforms 和 matrix函数来为浏览器进行硬件(GPU)加 ...

  10. TensorFlow之DNN(二):全连接神经网络的加速技巧(Xavier初始化、Adam、Batch Norm、学习率衰减与梯度截断)

    在上一篇博客<TensorFlow之DNN(一):构建“裸机版”全连接神经网络>中,我整理了一个用TensorFlow实现的简单全连接神经网络模型,没有运用加速技巧(小批量梯度下降不算哦) ...

随机推荐

  1. NSThread的isEexcuting和isFinish什么时候被设置

    NSThread的isExecuting在进入-[NSThread main]函数之前就已经被设置成YES; NSThread的isFinished在执行+[NSThread exit]后才被设置成N ...

  2. 化繁为简|AIRIOT智慧水务信息化建设解决方案

    ​ "生产自动化,管理信息化"是现代化水厂建设的目标之一,需要在水质要求.工艺.生产.管理.环境等监测方面达到精细化管理标准,这是一个高度智能化,实现化繁为简智慧进阶的工程.传统水 ...

  3. openstack报错

    1. 创建机器失败 openstack_compute_servergroup_v2.servergroup_vm-qa-cloudconfig-sidecar: Creating... 41Erro ...

  4. sql审计平台部署

    其它数据库管理平台:Orchestrator部署 包链接:https://github.com/hhyo/Archery/tree/master 部署链接:https://github.com/hhy ...

  5. vulnhub --> Web Machine: (N7)

    靶场下载地址 Web Machine: (N7) << 点我 开始打靶 ip发现: nmap扫描网段发现靶机ip:192.168.56.101 端口发现: 对靶机进行常规端口扫描 访问网站 ...

  6. EDP .Net开发框架--权限

    平台下载地址:https://gitee.com/alwaysinsist/edp 权限介绍 权限实际上就是谁有权使用或是访问什么,这里的"谁"可以视作"授权对象&quo ...

  7. sass变量的详细使用

    sass变量同javascript变量,可以用来存储一些信息,并且可以重复使用. 先来对比一下css中的变量 同css变量对比 CSS 变量是由 CSS 作者定义的,它包含的值可以在整个文档或指定的范 ...

  8. Flutter(二):编写第一个Flutter App

    Create New Flutter Project 在Android Studio添加上Flutter插件以后,通过File -> New -> New Flutter Project创 ...

  9. 阅读LXH《FFMPEG+SDL的视频播放器》总结

    一.原文地址 https://blog.csdn.net/leixiaohua1020/article/details/46889389 在此向雷霄骅致敬!!! 二.视频播放器实现思路 1)视频播放器 ...

  10. .NET开源、跨平台、使用简单的面部识别库

    前言 今天给大家分享一个.NET开源(MIT License).免费.跨平台(适用于 Windows.MacOS 和 Linux ).使用简单的面部识别库:FaceRecognitionDotNet. ...