[Math] How to scale data for a log graph

graphing-functionslogarithms

I'm writing a program to "printer plot" some data (printing "*" characters), and I'd like to scale the data on the vertical axis logarithmically (ie, semi-log chart). I have data values ranging from zero to about 10000, and I'd like to scale the data to fit on 30-40 lines.

For a linear plot it's fairly simple — divide 10000 by 30 (number of lines) and then, for each row being printed, calculate row# * (10000/30) and (row# + 1) * (10000/30), then print a "*" if the value in the data vector is between those two values.

How do I do the same conceptual thing with log scaling? (I realize that on a log chart you never really have zero, but let's say I want to plot the data on a 2 decade chart spread over the 30 lines.)

I've got the following C code:

float max = 10000;
int xDim = 200;
int yDim = 30;
for (int yIndex = yDim - 1; yIndex >= 0; yIndex--) {

    --<clear "buffer">--    

    float top = exp((float) yDim);
    float upper = exp((float) yIndex + 1);
    float lower = exp((float) yIndex);
    float topThresh = (max / top) * upper;
    float bottomThresh = (max / top) * lower;

    for (int xIndex = 0; xIndex < xDim; xIndex++) {
        if (data[xIndex] > bottomThresh && data[xIndex] <= topThresh) {
            buffer[xIndex] = '*';
        }
    }

    --<print "buffer">--
}

This does print something resembling a semi-log chart, but all the data (five decades, more or less) is compressed into the top 12 or so lines (out of 30), and obviously I've not factored in the number of decades I want to display (since I can't figure out how to do that).

So how do I scale to plot two decades?

Update

I've discovered that if I divide the arguments to the three exp calls with a value of about 6.5 (or multiply by about 0.15), I get close to two decades on the graph. But I have no idea how to compute this value. It kind of made sense to do log(pow(10,2)) (ie, natural log of 10 raised to the number of decades desired), but that yields a value near 4 (and it's moving in the wrong direction). How should I compute the value?

Update #2

If I multiply the arguments to the exp calls times the value (log(10) * decades)/yDim I get the right result.

Best Answer

If you take the log of all your values, you can then treat it just like a linear scale. Using base 10 logs, if your data ranges from 10 to 100,000, taking logs makes it range from 1 to 5. Then scale that as you have before, presumably giving 10 lines to each unit to make 40 lines in your plot. Then plot you * where the log of the value belongs, so if you have a value of 2,000, the log of that is 3.3 and you would plot it on the 24th line.

Related Question