Quicksilver has asked for the wisdom of the Perl Monks concerning the following question:

Thanks to help from here, I've finally got most of my tag cloud working as I want it to. I've been trying to use a log function to make the font sizes readable but I've come a little awry on it. I'm trying to set up the values for $maxTagCnt and $minTagCnt to run the log against later in DetermineFontSize but I've not been able to initialize the value correctly and would value some help in achieving this:
use strict; use warnings; use DBI; my $dbh = DBI->connect('dbi:mysql:milton:localhost', 'user', 'pword'); my $sth = $dbh->prepare ('SELECT word, occurrences FROM statistic ORDE +R BY occurrences DESC LIMIT 200'); my %tag; my ($word, $count); #load in tag file - do this from db $sth->execute; while (my($word, $count) = $sth->fetchrow_array) { $tag{$word} = $count; } $sth->finish; $dbh->disconnect(); my $useLogCurve = 1; my $minFontSize = 10; my $maxFontSize = 36; my $fontRange = $maxFontSize - $minFontSize; #determining the count my $maxTagCnt = 0; my $minTagCnt = 1000000; foreach $word (%tag) { $maxTagCnt = $tag{word} if $tag{word} lt $maxTagCnt; $minTagCnt = $tag{word} if $tag{word} gt $minTagCnt; } my $minLog = log($minTagCnt); my $maxLog = log($maxTagCnt); my $logRange = $maxLog - $minLog; $logRange = 1 if ($maxLog == $minLog); sub DetermineFontSize ($) { my ($tagCnt) = @_; my $cntRatio; if ($useLogCurve) { $cntRatio = (log($tagCnt) - $minLog)/$logRange; } my $fsize = $minFontSize + $fontRange * $cntRatio; return $fsize; } #output tag cloud print "Content-type: text/html\n"; print<<EOT; <html> <head> <link href="../../css/tagcloud.css" rel="stylesheet" type="text/css" +> </head> <body> <div class=\"cdiv\"> <p class=\"cbox\"> EOT #output the keys #still needs to have on onclick event to get the bigrams or to search foreach $word (sort keys %tag) { my $fsize = DetermineFontSize($tag{$word}); printf "<div name=\"$word\" style=\"font-size:%dpx;\">%s", $fsize, $ +word, "</div>"; } #output end of tag file print <<EOT; </p> </div> </body> </html> EOT __END__

Replies are listed 'Best First'.
Re: Setting up a log to determine font size
by moritz (Cardinal) on May 22, 2008 at 09:22 UTC
    So what is the current output? What would you like the output to be? What does DetermineFontSize return?
    sub DetermineFontSize ($) { my ($tagCnt) = @_; my $cntRatio; if ($useLogCurve) { $cntRatio = (log($tagCnt) - $minLog)/$logRange; } my $fsize = $minFontSize + $fontRange * $cntRatio; return $fsize; }

    So what do you expect to happen if $useLogCurve isn't set? Currently the sub will always return $minFontSize in that case (and emit a warning that $cntRatio is uninitialized).

      The current output (without the sub) is that each tag is printed out but the font size is determined by the count so I end up with font sizes of 100+ pixels in places. What I'm trying to do is to output the values within the font range (currently 10 to 36).
      If I set useLogCurve to 0, then all the results are printed in out a uniformly small print size. Actually, having commented out the first foreach loop, it is outputting the results within a range 23 to 27 pixels (not surprising as the values are fairly similar) although the results are being printed right across the screen without wrapping (but that's an markup and CSS issue). Thanks.
        What you tried to do (and failed) is to calculate the minimum and maximum number of occurrences.
        foreach $word (%tag) { $maxTagCnt = $tag{word} if $tag{word} lt $maxTagCnt; $minTagCnt = $tag{word} if $tag{word} gt $minTagCnt; }
        There are two mistakes here. The first is that you iterate over all elements of %tag, not just the keys. Use foreach $word (keys %tag) {...} instead, or use each. The second mistake is that you try to compare numbers with lt and gt. Those two compare strings, but "2" gt "10" isn't what you want. Use < and > instead.

        You can make that even easier:

        use List::Util qw(min max); my $maxTagCount = max values %tag; my $minTagCount = min values %tag;