views:

67

answers:

2

I have an array with a few elements:

MSN = 34.3433423432434%

Chrome = 12.4343434353534%

Gtalk = 32.23233543543532% ...

And I'm passing this array as y-axis labels to use with a module called GD::Graph. The problem I am facing right now, is that the number are so big on the graph that they overlap with the adjacent entry and make it unreadable.

Is there a way where I can round off ALL the elements in an array to just 2 decimal places? And make it xx.xx%?

Also, anyone familar with using GD::Graph, do you know how can I increase the text-size on the graph? I can increase Title / Legend size fine, but the actual text as in 'Gtalk' or '32.23233543543532%' is really small and I've tried a lot of the commands from http://search.cpan.org/dist/GDGraph/Graph.pm, but they don't seem to work for me!

+4  A: 
#!/usr/bin/perl

use strict; use warnings;
use YAML;

my %x = (
    MSN => '34.3433423432434%',
    Chrome => '12.4343434353534%',
    Gtalk => '32.23233543543532%',
);

for my $x ( values %x ) {
    $x =~ s/^(\d+\.\d+)%\z/ sprintf '%.2f%%', $1/e;
}

print Dump \%x;

Output:

Chrome: 12.43%
Gtalk: 32.23%
MSN: 34.34%

If you want to extract values in a specific order, use a hash slice:

print "@x{ qw( MSN Chrome Gtalk ) }\n";

or, if you just want keys and values to line up in the plot call:

my $gd = $graph->plot([
    [ keys %x ],
    [ @x{ keys %x } ],
]) or die $graph->error;

Note: To increase the text size on a GD::Graph, use a larger font for the element. See Methods for charts with axes.

Using GD::Graph, you really should not have to modify the values yourself. Just provide the string '.2f%%' as the argument to y_number_format.

Sinan Ünür
Sinan, thanks for the reply, but I just don't want to print the decimal with a certain precision. I want to change the values of the numbers in the array to xx.xx. Reason being, I pass the entire array to the GD element. Am I clear? Or would you like me to explain better ... if I'm confusing? :)
c0d3rs
@c0d3rs What exactly is in the array? Note that the `for` loop modifies the elements of the array. I just printed each element for illustration.
Sinan Ünür
There are 2 arrays, one that has { MSN, Chrome, GTalk .. }, the other has the corresponding y-values {34.3433423432434, 12.4343434353534,32.232335435435}. I did test your code, but it doesn't modify the element of the array.
c0d3rs
When you have keys in one array and values in a parallel array, you know you should have used a hash.
Sinan Ünür
@c0d3rs I don't know how you tested the code, but *oh, yes, it does*.
Sinan Ünür
Sinan, I do have a hash, but they way GD::Graph works, is that I need to pass two seperate arrays in for the x and y axis. Thus I've passed hash-> keys as the x-axis and hash->values as the y-axis.I don't know what I'm doing wrong, but the code doesn't seem to modify the y-axis array for me at all, its the same output (I get the array by saying @y_axis = values %hash_array
c0d3rs
So, your using a hash in your code example, I'm doing this:>#y_axis = values %hash_array>for my $y_axis ( @y_axis ) {> $y_axis =~ s/^(\d+\.\d+)%\z/ sprintf '%.2f%%', $1/e;>}>print Dumper (\@y_axis);
c0d3rs
Ah, got it to work! I just needed to remove the % sign from the regex, since my array only had the decimal numbers and not the % appended to them. I should have been more clear. Thanks for the help though Sinan!
c0d3rs
+9  A: 

From perlfaq4's answer to Does Perl have a round() function? What about ceil() and floor()? Trig functions? :


Remember that int() merely truncates toward 0. For rounding to a certain number of digits, sprintf() or printf() is usually the easiest route.

printf("%.3f", 3.1415926535);   # prints 3.142

The POSIX module (part of the standard Perl distribution) implements ceil(), floor(), and a number of other mathematical and trigonometric functions.

use POSIX;
$ceil   = ceil(3.5);   # 4
$floor  = floor(3.5);  # 3

In 5.000 to 5.003 perls, trigonometry was done in the Math::Complex module. With 5.004, the Math::Trig module (part of the standard Perl distribution) implements the trigonometric functions. Internally it uses the Math::Complex module and some functions can break out from the real axis into the complex plane, for example the inverse sine of 2.

Rounding in financial applications can have serious implications, and the rounding method used should be specified precisely. In these cases, it probably pays not to trust whichever system rounding is being used by Perl, but to instead implement the rounding function you need yourself.

To see why, notice how you'll still have an issue on half-way-point alternation:

for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i}

0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7
0.8 0.8 0.9 0.9 1.0 1.0

Don't blame Perl. It's the same as in C. IEEE says we have to do this. Perl numbers whose absolute values are integers under 2**31 (on 32 bit machines) will work pretty much like mathematical integers. Other numbers are not guaranteed.

brian d foy
Thanks Brian, but Sinan's reply did the trick!
c0d3rs