用处理可视化正弦波

时间:2013-01-12 11:24:16

标签: visualization processing data-visualization

我有1000多行正弦波数据随时间变化,我想用Processing语言将其可视化。我的目标是创建一个动画,它将从矩形[height / 2]的中间开始绘制正弦波。我还想只显示该波的1秒周期。我的意思是1秒后,第一个坐标应该消失,依此类推。

我怎样才能实现这一目标? 感谢

示例数据:

 TIME   X   Y
0.1333  0   0
0.2666  0.1 0.0999983333
0.3999  0.2 0.1999866669
0.5332  0.3 0.299955002
0.6665  0.4 0.3998933419
0.7998  0.5 0.4997916927
0.9331  0.6 0.5996400648
1.0664  0.7 0.6994284734

1 个答案:

答案 0 :(得分:1)

您实现这一目标的方法是将此项目拆分为任务:

  1. load&解析数据
  2. 更新时间和呈现数据
  3. 为了确保第1部分顺利进行,最好确保您的数据首先易于解析。示例数据看起来像表/电子表格,但它没有使用标准分隔符(例如逗号或制表符)进行格式化。解析时可以解决问题,但我建议首先使用干净的数据,例如,如果您打算使用space作为分隔符:

     TIME  X   Y
    0.1333 0.0 0
    0.2666 0.1 0.0999983333
    0.3999 0.2 0.1999866669
    0.5332 0.3 0.299955002
    0.6665 0.4 0.3998933419
    0.7998 0.5 0.4997916927
    0.9331 0.6 0.5996400648
    1.0664 0.7 0.6994284734
    

    完成后,您可以使用loadStrings()加载数据,使用split()将行分成3个元素,这些元素可以从字符串转换为浮点数。

    一旦你有价值可以使用,你可以存储它们。您可以创建三个数组,每个数组都包含已加载数据的字段(一个用于所有X值,一个用于所有Y值,一个用于所有时间值)或者您可以欺骗并使用{{3的单个数组对象。虽然PVector适用于3D数学/线性代数,但您有2D坐标,因此您可以将时间存储为第三个“维度”/组件。

    第二部分主要围绕基于时间的更新,这就是PVector派上用场的地方。您可以检查更新之间传递的时间量,如果它大于某个(延迟)值,则需要进行另一次更新(帧/数据行索引)。

    您需要担心的最后一部分是在屏幕上呈现数据。幸运的是,在您的样本数据中,坐标被标准化(在0.0和1.0之间),这使得易于映射到草图维度(通过使用简单的乘法)。否则,millis()功能会派上用场。

    这是一个用于说明上述内容的草图,data.csv是一个包含上述格式化样本数据的文本文件:

    PVector[] frames;//keep track of the frame data(position(x,y) and time(store in PVector's z property))
    int currentFrame = 0,totalFrames;//keep track of the current frame and total frames from the csv
    int now, delay = 1000;//keep track of time and a delay to update frames
    
    void setup(){
      //handle data
      String[] rows = loadStrings("data.csv");//load data
      totalFrames = rows.length-1;//get total number of lines (-1 = sans the header)
      frames = new PVector[totalFrames];//initialize/allocate frame data array 
      for(int i = 1 ; i <= totalFrames; i++){//start parsing data(from 1, skip header)
        String[] frame = rows[i].split(" ");//chop each row into 3 strings(time,x,y)
        frames[i-1] = new PVector(float(frame[1]),float(frame[2]),float(frame[0]));//parse each row(not i-1 to get back to 0 index) and how the PVector's initialized 1,2,0 (x,y,time)
      }
      now = millis();//initialize this to keep track of time
      //render setup, up to you
      size(400,400);smooth();fill(0);strokeWeight(15);
    }
    void draw(){
      //update
      if(millis() - now >= delay){//if the amount of time between the current millis() and the last time we updated is greater than the delay (i.e. every 'delay' ms)
        currentFrame++;//update the frame index
        if(currentFrame >= totalFrames) currentFrame = 0;//reset to 0 if we reached the end
        now = millis();//finally update our timer/stop-watch variable
      }
      PVector frame = frames[currentFrame];//get the data for the current frame
      //render
      background(255);
      point(frame.x * width,frame.y * height);//draw
      text("frame index: " + currentFrame + " data: " + frame,mouseX,mouseY);
    }
    

    需要一些额外的注意事项:

    1. 您提到1秒后移动到下一个坐标。从我在示例数据中看到的每秒有8个更新,因此1000/8可能会更好。这取决于你如何处理时间安排。
    2. 我假设你的全套包括正弦波运动的数据。我已经映射到完整坐标,但是在draw()循环的渲染部分中,您可以根据需要进行映射(例如,包括高度/ 2偏移等)。此外,如果您不熟悉正弦波,请查看以下处理资源:map()Daniel Shiffman's SineWave sample