1

I'm taking data from a plot of a 2D line drawing and trying to plot it on a piece of paper of a given size. (The paper size can change) To make the line drawings fit on the paper, I need to scale it. Unfortunately, some of the legs on this plot are very short, and some are extremely long, so a simply linear scale results in areas too small to see with a single line often taking up half the paper. I'm trying to use logarithmic scaling to compensate for this, so the entire drawing is on the piece of paper and the longest lengths are attenuated more than the shortest lengths. I just can't seem to wrap my head around the math here. If I can understand the math, I can translate that into the C++ code I need.

I've looked here: Convert Linear scale to Logarithmic
And here: https://math.stackexchange.com/questions/970094/convert-a-linear-scale-to-a-logarithmic-scale

The basics:
I need to convert linear x,y values into logarithmic values ranging from 1-paperWidth and from 1-paperHeight.
My x and y values will always be positive and will range from x-min to x-max, and y-min to y-max.

Can someone dumb down this math for me?
I would REALLY appreciate it!

Sgt AJ
  • 790
  • 5
  • 12

1 Answers1

4

Let you have range xmin..xmax and want to map it logaritmically onto canvas coordinates X0..X1. Equation is:

X = a + b * ln (x)

You can use decimal logarithm log10 if you want (this change just scales b coefficient)

Substitute start and end points:

X0 = a + b * ln(xmin)
X1 = a + b * ln(xmax)

To find a and b parameters, you need to solve equation system above. Subtract the first equation from the second one

X1 - X0 = b *(ln(xmax) - ln(xmin))  = b * ln(xmax / xmin) 
so
b = (X1 - X0) / ln(xmax / xmin)

Now put this b value in the first equation to get a

a = X0 - b * ln(xmin)

Example:

xmin = 0.01
xmax = 100
X0 = 20
X1 = 800
b = (X1 - X0) / ln(xmax / xmin) = 780/9.21 = 84.7
a = 20 - 84.7 * (-4.6)= 410

So transformation is:

X = 410 + 84.7 * ln(x)

Check for some intermediate points (should be evenly spaced in logaritmic space):

x = 0.01 => X = 20
x = 0.1 =>  X = 215
x = 1  =>   X = 410    (OK, this is (20+800)/2)
x = 10 =>   X = 605
x = 100 =>  X = 800

Concerning question in comments:

Logarithmic function y=ln(x) transforms range x1..x2 (length x2-x1) into range of length ln(x2)-ln(x1).
But if we want to have specific result range length (for example, canvas size for drawing), we should introduce scale coefficient b.
If we want that result range starts from specific value (for example, canvas coordinates start from 0), we should introduce shift coefficient a.

So we make linear transformation of result into needed range.

MBo
  • 77,366
  • 5
  • 53
  • 86
  • 1
    I really appreciate it, and I'm sort of following the math here, but where do a and b come from? That's what I didn't understand from some other answers I found online. I've tried googling log functions, but I feel like I'm missing some equations here. – Sgt AJ Apr 08 '21 at 00:05
  • 2
    I added some description into my answer – MBo Apr 08 '21 at 03:56
  • Thank you!! Your formula is working and I will accept it as the answer, but I wanted to understand it, and for some reason, this particular math problem was just not making sense to me. – Sgt AJ Apr 08 '21 at 17:37
  • Linear transform is not specific to logarithmic function - it is used everywhere when we have to map one range onto another (when you look at google maps, scale and shift map at the screen - you apply some alike transformation). – MBo Apr 09 '21 at 05:01
  • How do I deal with the case when `xmin` is zero, since `ln(0)` is `NaN`? – MiffTheFox Mar 18 '23 at 20:02
  • @MiffTheFox There is no good general way to treat "zero problem". Zero x might be excluded from plotting at all, one might add small constant like 0.01 to values, if main range is >1, then just assign xmin=1... – MBo Mar 19 '23 at 02:54