首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Vispy多重图

Vispy多重图
EN

Stack Overflow用户
提问于 2021-01-27 10:01:02
回答 1查看 114关注 0票数 0

我是python编程的新手,正在为Vispy库而苦苦挣扎。

基本上,我有一个树莓派连接到两个Arduinos加速计传感器。raspberry正在通过UDP将来自两个传感器的X、Y和Z值发送到我的计算机。然后我的计算机必须显示9个图表:6个用于两个传感器的x,y和z的演变,3个用于它们之间的差异(X1-X2,Y1-Y2和Z1-Z2),最后,它必须是实时的。

对于最后一点,我想使用Vispy库。在阅读了文档之后,我想出了以下代码:

代码语言:javascript
复制
#!/usr/bin/env python3

import numpy as np
from vispy import app
from vispy import gloo
import socket
from itertools import count

# init x, y arrays
x1_vals = []
time_vals = []

#UDP connection from Raspberry pi
UDP_IP = ""
UDP_PORT = 5005

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

# Initialize the index and set it to 1
index = count()
next(index)

# Initialize the Canvas c
c = app.Canvas(keys='interactive')

vertex = """
attribute vec2 a_position;
void main (void)
{
    gl_Position = vec4(a_position, 0.0, 1.0);
}
"""

fragment = """
void main()
{
    gl_FragColor = vec4(0.0, 0.0, 15.0, 10.0);
}
"""
program = gloo.Program(vertex, fragment)

@c.connect
def on_resize(event):
    gloo.set_viewport(0, 0, *event.size)

@c.connect
def on_draw(event):
    gloo.clear((1,1,1,1))
    program.draw('line_strip')


def on_timer(event):
    
    # next index
    cpt = next(index)
    
    # Get data from UDP
    recv, addr = sock.recvfrom(1024)
    data = recv.decode('UTF-8').split(';')
    
    # We want to display only 100 samples so the graph still readable.
    # So we delete the first value of the x array if there are more than 100 values
    if (cpt > 100):
        del x1_vals[0]
        time_vals = np.linspace(-1.0, +1.0, 100)      
    else:
        time_vals = np.linspace(-1.0, +1.0, cpt)

    # The values must be bound between -1.0 and 1.0
    tmp = float(data[0])*0.5
    if (tmp >= 1):
        tmp = float(0.99)
    elif (tmp <= -1):
        tmp = float(-0.99)
    
    x1_vals.append(tmp)
    
    # Then we concatenate the arrays of x and y
    program['a_position'] = np.c_[time_vals, x1_vals].astype(np.float32)
    c.update()
   
c.timer = app.Timer('auto', connect=on_timer, start=True)
    
c.show()
app.run()

因此,正如注释所描述的那样,它首先初始化UDP连接和画布,然后为接收到的每个值使用新添加的值更新画布。如果值的数量超过100,则会删除数组的第一个值,以保持采样数量不变。

当我只想显示X1加速度计传感器的演变时,它工作得很好。所以现在我选择了the code from the Vispy documentation which demonstrates how to show multiple graphs,但是代码对于我的水平来说有点太复杂了。

基本上,在我的代码中,我接收data数组中的所有感应器值。我选择了第一个值0,但完整的数据如下所示:[x1, y1, z1, dx, dy, dz, x2, y2, z2],其中dx = x1 - x2,dy = y1 - y2,dz = z1 - z2。(差值必须直接在覆盆子上计算)。

因此,我尝试修改文档中的代码,如下所示:

代码语言:javascript
复制
# Number of cols and rows in the table.
nrows = 3
ncols = 3

# Number of signals.
m = nrows*ncols

# Number of samples per signal.
n = 100

因为我想要9个图表,每个图表只有100个样本。

我忽略了索引,颜色,并删除了振幅,这在我的情况下是不需要的。基本上,我几乎保留了整个设置部分的原始代码,然后我用我的def on_timer替换了它。

现在,我正在尝试用我自己的数据提供给来自GLSL的a_position数组。但我不确定如何准备数据以使其在此代码中正常工作。我很难理解这些代码行是做什么的:

代码语言:javascript
复制
# GLSL C code
VERT_SHADER = """
    // Compute the x coordinate from the time index.
    float x = -1 + 2*a_index.z / (u_n-1);
    vec2 position = vec2(x - (1 - 1 / u_scale.x), a_position);
    // Find the affine transformation for the subplots.
    vec2 a = vec2(1./ncols, 1./nrows)*.9;
    vec2 b = vec2(-1 + 2*(a_index.x+.5) / ncols,
                  -1 + 2*(a_index.y+.5) / nrows);
    // Apply the static subplot transformation + scaling.
    gl_Position = vec4(a*u_scale*position+b, 0.0, 1.0);
"""

# Python code
def __init__(self):
    self.program['a_position'] = y.reshape(-1, 1)
    
def on_timer(self, event):
    k = 10
    y[:, :-k] = y[:, k:]
    y[:, -k:] = amplitudes * np.random.randn(m, k)

    self.program['a_position'].set_data(y.ravel().astype(np.float32))

我删除了周围的代码,我认为我正在理解。

请注意,即使我从python开始,我也知道当我在代码中使用bare对象时,他们正在使用Canvas的类定义。我了解self和其他工具的用法。

如何使realtime_signals文档中的代码适合我的情况?

EN

回答 1

Stack Overflow用户

发布于 2021-01-27 23:57:36

免责声明:总的来说,在我看来,实时信号的例子有点不靠谱。它“作弊”地生成了尽可能多的图,但最终的结果是快速的。

这段着色器代码所做的就是尝试获取一系列的线顶点,并找出它们应该进入哪个“子图”。所有线的所有顶点将作为一个数组进入着色器。着色器代码试图说“这个顶点在数组中是第23位的,这意味着它必须属于子图5,并且它是该图中的第三个点,因为我们知道每个图有5个点”(作为示例)。着色器主要通过a_index中的信息执行此操作。例如,这一位:

代码语言:javascript
复制
    // Compute the x coordinate from the time index.
    float x = -1 + 2*a_index.z / (u_n-1);
    vec2 position = vec2(x - (1 - 1 / u_scale.x), a_position);

根据点所在的子图调整x坐标(a_position)。

下一个块:

代码语言:javascript
复制
    // Find the affine transformation for the subplots.
    vec2 a = vec2(1./ncols, 1./nrows)*.9;
    vec2 b = vec2(-1 + 2*(a_index.x+.5) / ncols,
                  -1 + 2*(a_index.y+.5) / nrows);
    // Apply the static subplot transformation + scaling.
    gl_Position = vec4(a*u_scale*position+b, 0.0, 1.0);

正在尝试确定每个子图应该有多大。所以第一个块是“这个点落在哪个子图中”,这个是“这个点在那个子图中的位置”。这段代码提出了一个线性仿射变换(y = m*x + b)来将线缩放到合适的大小,以便所有的子图都是相同的大小并且不会重叠。

我不确定如果不重新遍历整个脚本并尝试理解a_index中的每个值到底是什么,我就不能深入了解更多细节。

编辑:另一个建议,从长远来看,您可能希望将UDP recv代码移动到一个单独的线程(如果使用Qt后端,则为QThread),该线程在新数据可用时发出一个信号。这样,GUI/主线程会保持响应,而不会挂起等待数据进入。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65911898

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档