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?


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.

  • $\begingroup$ The function $f(x)=2500\log _{10}x$ transforms a linear scale in the interval $x=1$ to $x=10000$ into a logarithmic one from $0$ to $10000$. Some values: $f(10000)=10000$, $f(5000)=9247.4$, $f(1000)=7500$, $f(500)=6747.4$, $f(100)=5000$, $f(50)=4247.4$, $f(10)=2500$, $f(1)=0$. $\endgroup$ – Américo Tavares Oct 13 '11 at 19:45
  • $\begingroup$ That's going the wrong way. $\endgroup$ – Daniel R Hicks Oct 13 '11 at 20:12

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.

  • $\begingroup$ +1, Minor typo: data ranges from 10 to 1,000,000, taking logs makes it range from 1 to 6. $\endgroup$ – Américo Tavares Oct 13 '11 at 21:07
  • $\begingroup$ @AméricoTavares: I fixed it. Thanks. $\endgroup$ – Ross Millikan Oct 13 '11 at 21:08

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


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.