Basic graphing calculator makes strange lines inconsistently

Hi all,

So I made this really basic graphing calculator that draws the form of whatever equation you give it (ex. it can draw a cubic function with axis lines). It almost works perfectly and exactly how I wanted, except for the fact that, for certain x values (and these vary with whatever the “step” variable is set to), the line will randomly jump to the origin and back, making an extremely ugly streak across the graph:


Parabola. (The annoying lines are in purple)

I have literally zero clue why this happens. All I’ve been able to deduce is that they only happen in the positive X side of the graph. Other than that, I have literally no clue.

As for the code, it uses a kind of confusing method that ensures that the screen is always encompassing the graph, so it is a bit long and I would need to include all of it (~100 lines). I can reply with it upon request, but I feel like that would be a gray area with the pasting code rule of this forum. I will however give the part that actually draws the line:

for (int i = 0; i < data.length - 1; i++) {
line(data[i][0] * pixelSizeX, 
     height - data[i][1] * pixelSizeY, 
     data[i + 1][0] * pixelSizeX, 
     height - data[i + 1][1] * pixelSizeY);

}

where data is the 2d array with all the points, and pixelSizeX & pixelSizeY are the relative amount of units that each pixel is worth in their respective axes. (so for example with a pixelSizeX of 2, each pixel is worth 2 units in the X axis) Also, index 0 of the 2nd array in the 2d array is the X, and index 1 is the Y.

Any insight as to how this would happen? Again, I can give you the full code if needed.

P.S. I already added a bit that prints every point on the graph, none of them are a random (0, 0) so these lines shouldn’t realistically appear, as they aren’t in the dataset that is generated; meaning that this must happen in the piece of code above when actually drawing them. I also understand and am sorry that this is sloppy and/or not the ideal way of doing it.

1 Like

The only thing I notice, is that line segments are missing in the curve, at the spots where the purple lines begin. I don’t know the step size, but I’m guessing the gaps represent one X step?

What are data[][] and pixelSizeX -Y’s type? (int, float, double…?).

The code you posted is not really enough to say what’s wrong as it looks like it should work. Something has to happen somewhere else. So I’m guessing you have to supply a more complete example. Probably (preferably) not the whole thing, maybe just a scaled-down or minimum runnable example that produces some curve with that error.

I noticed that too, that where it jumps to the origin there were gaps.

Data[][] and the pixelSize variables are all floats. I thought it might be something with the quirkiness of the accuracy of floating point variables, but I don’t really see that as being possible.

Also, the bug must be within the code I posted, because it just uses the array that I manipulated prior to draw the graph line. Like I said, I looked through that whole array of numbers and never saw an abrupt (0, 0) anywhere. Regardless, I’m going to share more since I might be wrong about that:

float min = -10;
float max = 10;
float step = 0.1;

data = new float[int((max - min) / step) + 1][2];
  
  for (float i = min; i <= max; i += step) {
   
       try {
         //y
         data[int((i - min) / step)][0] = i;
       
         //x                            > enter equation after = sign, use i as x (ex. [y = x/2] is [i / 2])
         data[int((i - min) / step)][1] = i * i;
         //note: it doesn't handle 1/x funcs well
       
       } catch (Exception e) {
         //in case it tries to divide by 0
         System.out.println(e);
         
       }
    
  }

This code makes the array and is inside setup(). The strange instantiation of the array is due to the fact that you can’t add values to an array like an arrayList; I might clean this up in the future. Some other values are then calculated (mainly to find the pixel sizes) in the following code snippet, as well as the array being manipulated:

for (int i = 0; i < data.length; i++) {
   
    if (data[i][0] > largestX) {
     
      largestX = data[i][0];
      
    } else if (data[i][0] < smallestX) {
     
      smallestX = data[i][0];
      
    }
    
    if (data[i][1] > largestY) {
     
      largestY = data[i][1];
      
    } else if (data[i][1] < smallestY) {
     
      smallestY = data[i][1];
      
    }
    
  }
  
  
  //make so negative values are also shown on screen
  for (int i = 0; i < data.length; i++) {
   
    data[i][0] -= smallestX;
    data[i][1] -= smallestY;
    
  }
  
  largestX -= smallestX;
  largestY -= smallestY;
    
  float pixelSizeX = width / largestX;
  float pixelSizeY = height / largestY;
  
  stroke(0, 0, 255);
  line(-1 * smallestX * pixelSizeX, -1 * (largestY - smallestY) * pixelSizeY, -1 * smallestX * pixelSizeX, largestY * pixelSizeY);
   
  stroke(255, 0, 0);
  line(-1 * (largestX - smallestX) * pixelSizeX, height - (-1 * smallestY * pixelSizeY), largestX * pixelSizeX, height - (-1 * smallestY * pixelSizeY));
  
  stroke(255);

Right after this snippet comes the one I posted in the OP. I apologize for the lack of comments, I can explain parts if necessary. Hopefully this adds more context.

You can print this array

Obviously some values in it are 0,0

This causes the graphical exceptions

The reason is where you fill the array with values not where you display it

Something is wrong with your formula or with the way you use it

1 Like

Huh.

I printed the original array and found this (among others):

4.6, 21.16
4.7999997, 23.039997
0.0, 0.0 //??????
4.8999996, 24.009996
5.0999994, 26.009995

I must admit that I’m confused, as not only did I not see this before, but I also couldn’t imagine why there would be random values tossed in like this. My best guess is that the formula to determine the amount of points adds extra, unused spaces. Somewhere in the floating point numbers and rounding, it must skip a few, which may be why there are extra (0, 0)s in there.

I might try making this an arrayList, so as to eliminate these gaps. I still don’t 100% know what the problem with my current program is, though.

3 Likes

Excuse me, could you please post your code where you fill the array with values?

You could check if a value is 0,0 and has a big difference to the previous values and then skip it

I actually just switched the 2d array out with an arrayList of “Point” objects that I made and it works now. Thanks for the input!

2 Likes

Nice that you fixed it.

I had a look earlier but didn’t figure out why. Fixed now. I changed your array filling loop use an integer index instead of float (EDIT: instead of calculated from floats), and that basically fixed it (Chrisir was on the track).

I’m posting it here anyway so you can have a look.

As a side comment, you don’t really need to store the X values though (unless you plan on doing X-Y scatter plots).

float min = -10;
float max = 10;
float step = .1;

float largestX  = max;
float smallestX = min;
float largestY  = -800;// Should probably use another method to find initial value...
float smallestY = 800; // Just height of display

float data[][] = new float[int((max - min) / step) + 1][2];


void setup() {  

  size(800,800,P2D);
  background(0);

  for (int i = 0; i < data.length; i ++) {
  
       try {
       
         float X = min + (i * step);
         
         // X
         data[i][0] = X;
       
         // Y = f(X)
         data[i][1] = X * X;
         //note: it doesn't handle 1/x funcs well
       
       } catch (Exception e) {
         //in case it tries to divide by 0
         System.out.println(e);

       }
  }
  
  
  for (int i = 0; i < data.length; i++) {
   
   // We already know the X range
/**
     if (data[i][0] > largestX) {
      largestX = data[i][0];
    } else if (data[i][0] < smallestX) {
      smallestX = data[i][0];
    }
*/

    if (data[i][1] > largestY) {
      largestY = data[i][1];
    } else if (data[i][1] < smallestY) {
      smallestY = data[i][1];
    }
    
  }


  //make so negative values are also shown on screen
  for (int i = 0; i < data.length; i++) {
    data[i][0] -= smallestX;
    data[i][1] -= smallestY;
  }
  largestX -= smallestX;
  largestY -= smallestY;
    
  float pixelSizeX = width / largestX;
  float pixelSizeY = height / largestY;
  
  stroke(0, 0, 255);
  line(-1 * smallestX * pixelSizeX, -1 * (largestY - smallestY) * pixelSizeY, -1 * smallestX * pixelSizeX, largestY * pixelSizeY);
   
  stroke(255, 0, 0);
  line(-1 * (largestX - smallestX) * pixelSizeX, height - (-1 * smallestY * pixelSizeY), largestX * pixelSizeX, height - (-1 * smallestY * pixelSizeY));
  
  stroke(255);

  for (int i = 0; i < data.length - 1; i++) {
    line(data[i][0] * pixelSizeX, 
         height - data[i][1] * pixelSizeY, 
         data[i + 1][0] * pixelSizeX, 
         height - data[i + 1][1] * pixelSizeY);
  }
}