Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Wednesday September 03, 2008
09:49 AM

Heatmap Ranges

[ #37337 ]

I'd like to take a series of values and convert them to numbers between 0 and 255, but on a logarithmic scale. My math studies were a long time ago and for the life of me I can't remember how to do this. I'm hoping to take a 2D table of values and project them onto an HTML table in a 'heatmap' fashion.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Maybe I'm misunderstanding, but I think you want to first scale logarithmically: log($val) if it's log base 'e'. Then linearly: so find the max value in the logged sequence, then multiply each value by 255 and divide by the max. Here's a kind of generic script, if I got it right:

    #!/usr/bin/perl
    # convert @VALS to a log scale base $LOG_BASE
    # and scaled linearly to $SCALE_MAX

    use strict;
    use warnings;
    use List::Util qw(max);

    my $SCALE_MAX = 1000;
    my $LOG_BASE = 10;
    my @VALS = (1, 10, 100, 1000);

    main();

    sub main

    • Need to scale linearly first in the case the minimum value is less than 1 before taking logs. (Also, $SCALE_MAX should be 255)

      Instead, if you simplify the mathematics (and you know the minimum and maximum values), calculate the logarithmic 'scaling factor'

      $scale = log( $maximum ) / 255;

      Then apply logarithmic scaling to each data element

      map { int( log( $_ - $minimum + 1 ) / $scale ) } @VALS;

      So that the minimum value scales to zero, maximum value scales to 255. Adjust the linear scale in the log calculatio

  • i think both of the prior comments are on target.

    If you have such quantities of data that scaling and calling log repeatedly is a problem - and only if - there are old integer bitbang routines for log2 that could be done with XS or Inline::C or PDL.

    Or you could (ab)use Perl 5.10 pack() to grab the floating point representation's exponent

    Note that 256 buckets is a lot, hi res, for loglinear data unless it already was floating point or Math::BigFloat - as log2(MAXLONG) - log2(1) 256 or 8 bits -- it'

    --
    Bill
    # I had a sig when sigs were cool
    use Sig;