How to incorporate exponential curve with a specified limit?

Hello!
I’m playing with randomGaussians, and gradual transitions, trying to understand the concept, and I’ve hit a bit of a snag.
I’m hoping someone can help with the math involved.

I’m drawing simple squares in a grid pattern. I’d like the left side of the grid to be… “normal.”
All the squares are drawn as they should be, in a simple grid.
But as we get to the right side of the grid, I’d like square placement to become more “crazy.”

So this is what I’ve got so far.

size(800, 400);
int scale = 10;
background(0);
noStroke();
rectMode(CENTER);

for (int x = 0; x <= width; x += scale) {
  for (int y = 0; y <= height; y += scale) {

    float pDistribution = map(x, 0, width, 0, 15);

    float xDrift = randomGaussian() * pDistribution;
    float yDrift = randomGaussian() * pDistribution;

    fill(200);
    push();
    translate(x, y);
    rect(xDrift, yDrift, scale, scale);
    pop();
  }
}

I’m proud of getting this far, because it’s doing essentially what I want.
The only thing is, I’d like the Gaussian Distribution to have a more exponential curve.
Hopefully, I’m using the correct terminology here.
Basically, I’d like the squares to be in their more “correct” spots a bit longer longer as we travel across x.
The squares on the far left and far right are exactly where I want them, but I’d like the middle to chill out a bit.

Because of the word “exponential”, I thought maybe exp() should go in there somewhere, but I don’t really understand how it would fit.

If I need to rephrase or clarify what I’m asking, please let me know!
Any advice would be greatly appreciated!

you can oppress this

    float pDistribution;
    if (x<300) pDistribution = 0; 
       else pDistribution = map(x, 300, width, 0, 15);  // OR  map(x, 0, width, 0, 15);

Hello leatherbird,

Cool project!

You are on the right track.
The problem with exp() is that it diverges wayyyyy too fast.

For example, exp(10) is a bit more than 22000.
Now let’s consider that randomGaussian() gives you a value between -3 and 3 to simplify things.
Then it means that when you are at your second square (so x = 10) your drifts value are between - 3 * 22000 and + 3 * 22000.
That’s quite a lot of pixels and that’s why you don’t get any squares on your screen.

So what you want is a function that behaves in the same way as you an exp() but with the max value when x = width being the 15 that you have in your linear mapping in your code.

A good way to think of it is to trace the function along the x axis on top of your graph. The Higher the value, the higher they will drift.

Here is an example with a sin():

void setup() {

  size(800, 400);
  int scale = 10;
  background(0);
  noStroke();
  rectMode(CENTER);

  for (int x = 0; x <= width; x += scale) {
    float sinVal = 7.5 * (sin(0.03 * x) + 1);

    for (int y = 0; y <= height; y += scale) {

      float xDrift = randomGaussian() * sinVal;
      float yDrift = randomGaussian() * sinVal;

      fill(200);
      push();
      translate(x, y);
      rect(xDrift, yDrift, scale, scale);
      pop();
    }
  }

  // Plot the sin
  for (int x = 0; x <= width; x++) {
    float sinVal = 7.5 * (sin(0.03 * x) + 1);
    float yCoord = map(sinVal, 0, 15, height, 0);
    fill(255, 0, 0);
    noStroke();
    ellipse(x, yCoord, 5, 5);
  }
}

Now for your function. You know that exp(log(15)) = 15. And you want you value to be 15 when x = width. So you can have exp(log(15) * x / width) being your function. Now it doesn’t start at 0 but at exp(0). So to compensate for that you can use exp(log(15 + exp(0)) * x / width) - exp(0). So at the end you get:

void setup() {

  size(800, 400);
  int scale = 10;
  background(0);
  noStroke();
  rectMode(CENTER);

  for (int x = 0; x <= width; x += scale) {
    float expVal = exp(log(15 + exp(0)) * x / width) - exp(0);

    for (int y = 0; y <= height; y += scale) {

      float xDrift = randomGaussian() * expVal;
      float yDrift = randomGaussian() * expVal;

      fill(200);
      push();
      translate(x, y);
      rect(xDrift, yDrift, scale, scale);
      pop();
    }
  }

  // Plot the exp
  for (int x = 0; x <= width; x++) {
    float expVal = exp(log(15 + exp(0)) * x / width) - exp(0);
    float yCoord = map(expVal, 0, 15, height, 0);
    fill(255, 0, 0);
    noStroke();
    ellipse(x, yCoord, 5, 5);
  }
}

5 Likes

Thank you! This is exactly what I was attempting.
I guess I don’t fully understand what log() or exp() are doing.
I will have to research these further before I comprehend them well enough to control them.

But now I know what I need to study!
I’m grateful to you for pointing me in the right direction!
Thank you so much!

2 Likes

By the way, with your help I was able to get the look I wanted!
I’m so excited to keep playing with it!

6 Likes

Great write up @jb4x! I love the curve overlays.

1 Like