wxPython 绘图演示——模拟雷达信号图(2)


参考此前 wxpython 实现简易画板(1),wxPython 实现绘图有直接法和缓冲法。推荐使用缓冲法来避免屏闪。

1.1. 基本框架

下面以“雷达信号图”为例,回顾 wxPython 的绘图的基本框架:

class RadarGraph(wx.Window):

    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)

        # 自定义的数据
        # Add your codes
        
        # 设置并重绘缓冲区
        self.buffer = None # 缓冲区
        self.InitBuffer()

        # 绑定事件
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        # add other events you need

    def InitBuffer(self):
        '''设置并重绘缓冲区'''
        w, h = self.GetClientSize()
        self.buffer = wx.Bitmap(w, h)
        dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
        
        # 你的绘制内容
        self.DrawGraph(dc)
    
    def DrawGraph(self, dc:wx.BufferedPaintDC):
        pass

    # ----- 事件响应函数 -----
    def OnSize(self, event):
        """响应窗口大小改变"""

        # 每次窗口大小变换,都需要重新设置缓冲区大小,重绘窗口
        self.InitBuffer()
    
    def OnPaint(self, event):
        """响应Paint Event"""

        wx.BufferedPaintDC(self, self.buffer)

1.2. 运行结果

设置了一个定时器 wx.Timer,让数据随着时间而变化,形成一个动图效果。

运行结果

1.3. 完整代码

点击查看代码
# -*- encoding: utf-8 -*-
# Python 3.9.6 64bit
'''
@File        : a_sample_radar_graph.py
@Time        : 2022/01/04 11:02
@Author      : Wreng
@Description : 雷达信号图,参考 Python in action / Chapter 12 / example 12.2
@Other       : version - Python 3.9.6 64bit, wxPython 4.1.1
'''


import wx
import math
import random

class RadarGraph(wx.Window):

    def __init__(self, parent, title, labels):
        super().__init__(parent)

        # 窗口标题
        self.title = title
        self.titleFont = wx.Font(14, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)

        # 图中的标签
        self.labels = labels
        self.labelFont = wx.Font(10, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)

        self.data = [0.0] * len(labels)
        self.xy = None
        
        self.buffer = None # 缓冲区

        # 设置并重绘缓冲区
        self.InitBuffer()

        # 绑定事件
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
    
    def InitBuffer(self):
        '''创建缓冲区'''
        w, h = self.GetClientSize()
        self.buffer = wx.Bitmap(w, h)
        dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
        
        # 你的绘制内容
        self.DrawGraph(dc) 

    def DrawGraph(self, dc:wx.BufferedPaintDC):
        '''绘制图形'''
        spacer = 10
        scaledmax = 150.0
        
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()
        dw, dh = dc.GetSize()

        # 绘制标题
        dc.SetFont(self.titleFont)
        tw, th = dc.GetTextExtent(self.title)
        dc.DrawText(self.title, (dw-tw)/2, spacer)

        # 找到中心点
        th = th + 2*spacer
        cx = dw / 2
        cy = (dh - th)/2 + th

        # 计算比率
        mindim = min(cx, (dh - th)/2)
        scale = mindim / scaledmax

        # 绘制轴线,以25为刻度
        dc.SetPen(wx.Pen("black", 1))
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
        dc.DrawCircle(cx, cy, 25*scale)
        dc.DrawCircle(cx, cy, 50*scale)
        dc.DrawCircle(cx, cy, 75*scale)
        dc.DrawCircle(cx, cy, 100*scale)

        dc.SetPen(wx.Pen("black", 2))
        dc.DrawLine(cx-110*scale, cy, cx+110*scale, cy)
        dc.DrawLine(cx, cy-110*scale, cx, cy+110*scale)

        # 寻找了每个点的坐标,绘制标签以及最大的数据点
        dc.SetFont(self.labelFont)
        maxval = 0
        angle = 0
        polypoints = []
        for i, label in enumerate(self.labels):
            val = self.data[i]
            point = self.PolarToCartesian(val*scale, angle, cx, cy) # 将极坐标转化为直角坐标
            polypoints.append(point)
            x, y = self.PolarToCartesian(125*scale, angle, cx, cy)
            dc.DrawText(label, x, y) # 绘制标签
            if val > maxval:
                maxval = val
            angle = angle + 360 / len(self.labels)
    
        # 根据最大值确定brush的颜色, green is good; red is bad
        c = "forest green"
        if maxval > 70:
            c = "yellow"
        if maxval > 95:
            c = "red"
        dc.SetBrush(wx.Brush(c)) # 设置画刷的颜色
        dc.SetPen(wx.Pen("navy", 3))
        dc.DrawPolygon(polypoints) # 绘制采集的形状

    def PolarToCartesian(self, radius, angle, cx,cy):
        '''将极坐标转化为直角坐标'''
        x = radius * math.cos(math.radians(angle))
        y = radius * math.sin(math.radians(angle))
        return (int(cx+x+0.5), int(cy+y+0.5)) # 四舍五入转化为整数

    def GetData(self):
        return self.data
    
    def SetData(self, newData):
        assert len(newData) == len(self.data)
        self.data = newData[:]

        # 数据改变了,因此更新缓冲和窗口
        dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
        self.DrawGraph(dc)

    # ====================================================================
    # 事件响应函数
    # ====================================================================
    def OnSize(self, event):
        """响应窗口大小改变"""

        # 每次窗口大小变换,都需要重新设置缓冲区大小,重绘窗口
        self.InitBuffer()
    
    def OnPaint(self, event):
        """响应Paint Event"""

        wx.BufferedPaintDC(self, self.buffer)


class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="Double Buffered Drawing", size=(480, 480))
        self.plot = RadarGraph(self, "Sample Radar Plot", ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])

        data = []
        for d in self.plot.GetData():
            data.append(random.randint(0, 75))
        self.plot.SetData(data)

        # 设置一个定时器,使数据随时间随机变化
        self.timer = wx.Timer(self)
        self.timer.Start(500) # 每 500ms 触发一次 EVT_TIMER

        self.Bind(wx.EVT_TIMER, self.OnTimeout)

    def OnTimeout(self, event):
        data = []
        for d in self.plot.GetData():
            val = d + random.uniform(-5, 5)
            if val < 0:
                val = 0
            if val > 110:
                val = 110
            data.append(val)
        self.plot.SetData(data)

if __name__ == '__main__':
    app = wx.App()
    frm = TestFrame()
    frm.Show()
    app.MainLoop()

1.4. 相关参考

推荐这些文章:

多校省选模拟1

RT
A. 序列
考虑如果直接算,很容易算重,于是正难则反,算有不多彩的序列包含的 \(a\) 的个数。
于是对序列 \(a\) 进行分类讨论。
(1)若 \(a\) 已经是多彩的序列,那么其他位置选什么都不重要,不存在不多彩的序列包含 \(a\),答案就是 \((n - m + 1) * k^{n - m}\) 。
(2)若 \(a\) 中含有重复的元素,则一定不存在跨过 \(a\) 的多彩子序列,于是从 \(a\) 的左右两边分别进行 \(dp\) 。
左右两边的 \(dp\) 基本一样,这里只介绍从 \(a\) 的右边开始 \(dp\)。
设 \(f_{i, j}\) 表示在 \(a\...

PyQt5基础学习-多个信号对应多个槽

这里主要是有两种情况:
1.一个信号连接多个槽函数
2.多个信号连接一个槽函数

"""
信号槽N对N连接与断开连接
"""
from PyQt5.QtCore import *

class NNSignal(QObject):
signal1 = pyqtSignal()
signal2 = pyqtSignal(int)
signal3 = pyqtSignal()
def __init__(self):
super(NNSignal, self).__init__()

# 一个信号连接多个槽函数
sel...

python-以圆类为基础设计三维图形体系

【题目描述】设计三维图形类体系,要求如下:设计三维图形功能接口,接口包含周长、面积、体积计算方法;基于以上接口,首先定义点类,应包含x,y坐标数据成员,坐标获取及设置方法、显示方法等;以点类为基类派生圆类,增加表示半径的数据成员,半径获取及设置方法,重载显示函数,并可计算周长和面积等;以圆类为基础派生球类、圆柱类、圆锥类;要求派生类球、圆柱、圆锥中都含有输入和输出显示方法;并可计算面积、周长。程序中定义各种类的对象,并完成测试。【练习要求】请给出源代码程序和运行测试结果,源代码程序要求添加必要的注释。
 
代码:

import math
class Shape:
def ...

pyQt5基础学习-重载多种输入的槽函数 1.pyqtSignal([int, str], [str])(构造两种输出参数的信号)

当槽函数会有多种类型的函数输入时,需要进行重载,这里对信号构成进行重载,在绑定槽函数时,做指定操作
MultiSignal.py

"""
为类添加多个信号
"""
from PyQt5.QtCore import *

class MultiSignal(QObject):

signal1 = pyqtSignal()

signal2 = pyqtSignal(int)

signal3 = pyqtSignal(int, str)

signal4 = pyqtSignal(list)

signal5 = pyqtSignal(dict)
...

PyQt5基础学习-QPushButton().clicked.connect(信号和槽) 1.QPushButton().setStyleSheet("设置风格的执行函数")

通过对按钮绑定函数来生成信号和槽,即信号是按钮点击时发送的信号, 槽为对应绑定的函数
SignalSlotDemo.py 

"""
信号(Signal) 与槽(Slot)
"""
from PyQt5.QtWidgets import *
import sys

class SigalSlotDemo(QWidget):
def __init__(self):
super(SigalSlotDemo, self).__init__()
self.initUI()

def onClick(self):
self.bt...

PyQt5基础学习-QThread(线程) 1.pyqtSignal(信号发射器) 2.pyqtSignal().emit(发送信号) 3.QLCDNumber(计数时间框) 4.QLCDNumber().display(显示计数)

构造线程的信息函数,定时发送信号, 将时间信息器绑定函数,实现定时执行的操作
Counter.py 

"""
使用线程类(QThread)编写计数器

QThread

def run(self):
while True:
self.sleep(1)
if sec == 5:
break;
QLCDNumber

WorkThread(QThread)
用到自定义信号
"""
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimer, QDateTim...

PyQt5基础学习-绘图应用 1.QPixmap(构造画板) 2.QPainter().drawLine(在画板上画出直线) 3.mousePressEvent(鼠标的按下事件) 4.mouseMoveEvent(鼠标移动事件) 5.mouseReleaseEvent(鼠标释放事件)

通过鼠标的点击,来获得直线的初始化位置, 通过鼠标的移动事件,获得当前的位置,获得完位置后进行绘图,同时再更新初始化的位置
Drawing.py 

"""
项目实战: 实现绘图应用

需要解决3个核心内容
1.如何绘图
2.在哪里绘图
3.如果通过鼠标进行绘图
"""

import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtCore import Qt, QPoint

class Drawing(QWi...

PyQt5基础学习-信号和槽的自动连接 1.@QtCore.pyqtSlot(定义为槽函数) 2.QpushButton().setObjectName("设置需要绑定的函数名")

@QtCore.pyqtSlot 定义为需要自动连接的槽函数, on_对象名_信号名字
AutoSignalSlot.py 

"""
信号与槽自动连接

on_对象名_signalname

"""
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton
import sys

class AutoSignalSlot(QWidget):
def __init__(self):
super(AutoSignalS...

super的用法举例

class A:
def __init__(self):
self.n = 2
def add(self, m):
# 第四步
# 来自 D.add 中的 super
# self == d, self.n == d.n == 5
print('self is {0} @A.add'.format(self))
self.n += m
# d.n == 7
class B(A):
def __init__(self):
self.n = 3...

如何在模型中引入可学习参数(Pytorch)

错误实例:
def init(self):
self.w1 = torch.nn.Parameter(torch.FloatTensor(1),requires_grad=True).cuda()
self.w2 = torch.nn.Parameter(torch.FloatTensor(1),requires_grad=True).cuda()
self.w1.data.fill_(0.3)
self.w2.data.fill_(0.3)
def forward(self, x):
out = self.w1 * out1 + self.w2 * out2
out = sel...

文章标题:wxPython 绘图演示——模拟雷达信号图(2)
文章链接:https://www.dianjilingqu.com/4694.html
本文章来源于网络,版权归原作者所有,如果本站文章侵犯了您的权益,请联系我们删除,联系邮箱:saisai#email.cn,感谢支持理解。
THE END
< <上一篇
下一篇>>