p5.js 代码不会抛出错误,但不会在鼠标单击时加载

p5.js code doesn't throw errors, but won't load on mouse click

我正在分析总统候选人的演讲。我有一个包含以下变量的数据文件:

> names(cl.context)
[1] "id"        "category"  "statement" "nchar"     "polarity" 

statement 变量由属于三个句子中的一个 category 的句子填充。 polarity的取值范围是-1到1,反映了句子是偏向正向、中向还是偏向负向。
我在 p5 中尝试做的是当用户在 canvas 内单击鼠标时,按类别显示语句,随机放置 x,y。陈述本身根据其极性着色。
我终于到了开发者控制台不会抛出任何错误并绘制 canvas 的地步。但是当我在 canvas 中单击时,没有任何反应。没有出现任何陈述。
我是 JavaScript 的新手,因为它没有抛出错误消息,所以我无法解决问题所在。希望在这里得到一些建议。

我的 p5 代码:

var clContext;
var x;
var y;

const STATEMENTS = 118, CATEGORY = 3, QTY = STATEMENTS/CATEGORY | 0,
      POLARITY = 3,
      statements = Array(STATEMENTS), inds = Array(CATEGORY), polarity = Array(POLARITY);

      //load the table of Clinton's words and frequencies
function preload() {
        clContext = loadTable("cl_context.csv", "header");
      }

function setup() {
  createCanvas(647, 400);
  background(51);
  // Calling noStroke once here to avoid unecessary repeated function calls
  noStroke();
  // iterate over the table rows
  for(var i=0; i<clContext.getRowCount(); i++){
      //- Get data out of the relevant columns for each row -//
      var inds = clContext.get(i, "category");
      var statements = clContext.get(i, "statement");
      var polarity = clContext.get(i, "polarity")
    }

  for (let i = 0; i < statements; randomCategoryStates(i++));
  // create your Statement object and add to
  // the statements array for use later
  inds[i] = new Statement();


    console.info(inds);
}

function draw() {
  if(mouseClicked == true){
  for(var i=0; i<inds.length; i++) {
      inds[i].display();
  }
}
}

function mouseClicked() {
  if((mouseX < width) && (mouseY < height)) {
      randomCategoryStates(~~random(CATEGORY));
      redraw();
      return false;
  }

}

// Function to display statements by a random category with each mouse click
function randomCategoryStates(group) {
  let idx = inds[group], rnd;
  while ((rnd = ~~random(QTY)) == idx);
  inds[group] = rnd;
}

// Function to align statements, categories, and polarity
function Statement() {
  this.x = x;
  this.y = y;
  this.xmax = 10;
  this.ymax = 4;
  this.cat = inds;
  this.statement = statements;
  this.polarity = polarity;
  // set a random x,y position for each statement
  this.dx = (Math.random()*this.xmax) * (Math.random() < .5 ? -1 : 1);
  this.dy = (Math.random()*this.ymax) * (Math.random() < .5 ? -1 : 1);
}
// Attach pseudo-class methods to prototype;
// Maps polarity to color and x,y to random placement on canvas
Statement.prototype.display = function() {
  this.x += this.dx;
  this.y += this.dy;
  var cols = map(this.polarity == -1, 205, 38, 38);
  var cols = map(this.polarity == 0, 148, 0, 211);
  var cols = map(this.polarity == 1, 0, 145, 205);
  fill(cols);
  textSize(14);
  text(this.statement, this.x, this.y);
};  

编辑: 让我感到困惑的一件事是,我在 Processing 论坛上使用此代码获得的帮助没有包括对 mouseClicked() 函数的调用draw 函数,所以我添加了它。不完全确定我做对了或者是否有必要。

您的代码有很多问题。我将尝试完成所有内容,没有特别的顺序:

为什么需要这些变量?

var x;
var y;

我知道您认为您正在使用它们将位置传递给 Statement,但您从未设置这些变量!让我们暂时摆脱它们,因为它们什么也没做。这会导致您的代码出错,但我们会在一秒钟内修复它。

看这个for循环:

for(var i=0; i<clContext.getRowCount(); i++){
      //- Get data out of the relevant columns for each row -//
      var inds = clContext.get(i, "category");
      var statements = clContext.get(i, "statement");
      var polarity = clContext.get(i, "polarity")
    }

您在此处读取的是 CSV 文件,但您并未对这些变量执行任何操作。然后你用这个跟进:

for (let i = 0; i < statements; randomCategoryStates(i++));
  // create your Statement object and add to
  // the statements array for use later
  inds[i] = new Statement();

注意 for 循环后面的分号! 这意味着 inds[i] = new Statement() 行在 外部 循环,它不没有任何意义。我也不知道你在用 randomCategoryStates(i++) 部分做什么。

您需要将所有这些组合成一个循环:

  for (var i = 0; i < clContext.getRowCount(); i++) {
    var category = clContext.get(i, "category");
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity")
    inds[i] = new Statement();
  }

但这仍然没有任何意义, 因为您永远不会将这些变量传递给您的 Statement class。那么让我们来看看吧。

我将添加一些评论:

function Statement() {
  this.x = x; //when do you ever set the value of x?
  this.y = y; //when do you ever set the value of y?
  this.cat = inds; //cat is the array that holds all statements? What??
  this.statement = statements; //statement is the statements array, but nothing is ever added to that array?
  this.polarity = polarity; //when do you ever set the value of polarity?

如您所见,您在这里所做的事情没有多大意义。您需要更改此构造函数,使其接受 参数 ,然后您需要将这些参数传入。类似这样的内容:

function Statement(category, polarity, statement) {
  this.category = category;
  this.statement = statement;
  this.polarity = polarity;
}

现在我们已经有了,我们可以将 for 循环中的行更改为:

inds[i] = new Statement(category, statement, polarity);

但这仍然没有意义。为什么你有单独的数组用于语句、类别和极性?难道你不想要一个包含所有这些的数组,使用 Statement class 的实例吗?所以让我们去掉 indspolarity 变量,因为它们没有任何用途。

然后我们将该行更改为:

statements[i] = new Statement(category, polarity, statement);

我们还必须更改仍在使用 inds 变量的其他所有地方,但我们在这样做时遇到了其他问题。

让我们从您的 draw() 函数开始:

function draw() {
  if (mouseClicked == true) {
    for (var i = 0; i < statements.length; i++) {
      statements[i].display();
    }
  }
}

所以我猜你只想在按下鼠标时显示任何内容,而不是在未按下鼠标时不显示任何内容?我不确定这是否有意义,但没关系。即便如此,这段代码也没有意义,因为mouseClicked是函数,不是变量。判断鼠标是否按下,需要用到mouseIsPressed 变量,你不需要 == true 部分。

if (mouseIsPressed) {

我不知道这两个函数应该做什么:

function mouseClicked() {
  if ((mouseX < width) && (mouseY < height)) {
    randomCategoryStates(~~random(CATEGORY));
    redraw();
    return false;
  }
}

// Function to display statements by a random category with each mouse click
function randomCategoryStates(group) {
  let idx = statements[group],
    rnd;
  while ((rnd = ~~random(QTY)) == idx);
  statements[group] = rnd;
}

有更简单的方法来获取随机数据。我现在要删除它们,因为它们带来的麻烦超过了它们的价值。我们可以稍后返回并添加随机逻辑。

现在,让我们看看 Statement class:

中的 display() 函数
Statement.prototype.display = function() {
  this.x += this.dx;
  this.y += this.dy;
  var cols = map(this.polarity == -1, 205, 38, 38);
  var cols = map(this.polarity == 0, 148, 0, 211);
  var cols = map(this.polarity == 1, 0, 145, 205);
  fill(cols);
  textSize(14);
  text(this.statement, this.x, this.y);
};

我们实际上从未声明过 xydxdy 变量,所以让我们将它们添加到构造函数中:

  this.x = random(width);
  this.y = random(height);
  this.dx = random(-5, 5);
  this.dy = random(-5, 5);

回到display()函数,这些行没有任何意义:

  var cols = map(this.polarity == -1, 205, 38, 38);
  var cols = map(this.polarity == 0, 148, 0, 211);
  var cols = map(this.polarity == 1, 0, 145, 205);

为什么要声明同一个变量 3 次?为什么要尝试将布尔值映射到数字值?这没有任何意义。现在,让我们摆脱这些行并简化您的逻辑:

  if(this.polarity == -1){
    fill(255, 0, 0);
  }
  else if(this.polarity == 1){
    fill(0, 255, 0);
  }
  else{
    fill(0, 0, 255);
  }

这将使负极性红色、正极性绿色和中性极性蓝色。

现在我们有了这个,我们实际上可以 运行 代码了。当您按住鼠标时,您会看到您的报表随机显示和移动。但是,它们会很快填满您的屏幕,因为您从未清除过旧框架。 只要你想清除旧帧,就需要调用 background() 函数。 我们可以在 draw() 函数的开头,或者就在if(mouseIsPressed) 语句,for 循环之前。

  if (mouseIsPressed) {
    background(51);
    for (var i = 0; i < statements.length; i++) {

如果您进行了所有这些更改,您将拥有一个工作程序。 我敢打赌它仍然不能完全按照您的要求进行。 您将不得不从更简单的开始。您的代码有点乱,这是尝试一次编写整个程序而不是测试小块的结果一次。 这就是我们要求 MCVE, 的原因,因为像这样调试整个过程非常痛苦。您需要开始将目标缩小为更小的部分。

例如,如果您现在想要一次只显示一个语句,从一个更简单的示例草图重新开始,它只显示一个硬编码语句。 在尝试将其集成到您的主程序中之前,请使其完美运行。如果您希望语句按类别排序,那么从一个更简单的示例草图开始,它只显示基于类别的语句,没有任何额外的逻辑。这样一来,如果您对某些特定问题有疑问,您可以 post 那个小代码,它会更容易帮助您。

祝你好运。