tags:

views:

274

answers:

2

I am making some plots in Perl using GD::Graph and some of the data is outside the area I would like to display, but instead of being truncated off the chart outside the graphing area, it is being drawn over the title, legend, and axis labels. Does anyone know how to stop this from happening?

+1  A: 

If you know what your bounds are, filter the data and don't include those points in the data that you send to GD::Graph.

brian d foy
A: 

To clarify: are you declaring the y_max_value height and your data is overflowing that bound? Or is GD::Graph miscalculating the correct upper limit?

If you're setting the value, you need to fix your values to that upper bound. GD::Graph is only doing what you're telling it to do. (Which is more or less what Brian said).

OTOH, I've found that GD::Graph doesn't always cope well with cumulative (stacked) graphs, and tends to overestimate the y_max_value in those circumstances. It can also produce some unattractive values on the Y axis, with floating point numbers at the tick values. Is this what you're really trying to solve?

Having had both these problems, we've found a solution using Tie::RangeHash to create 'tidy' increments that always produce 5 integer tick points.

use Tie::RangeHash ;
my $y_ranges = new Tie::RangeHash Type => Tie::RangeHash::TYPE_NUMBER;
$y_ranges->add(' -500,  -101', '-25');
$y_ranges->add(' -100,   -26', '-10');
$y_ranges->add('  -25,    -1',  '-5');
$y_ranges->add('    0,    25',   '5');
$y_ranges->add('   26,   100',  '10');
$y_ranges->add('  101,   500',  '25');
$y_ranges->add('  501,  1000', '100');
$y_ranges->add(' 1001,  5000', '250');
$y_ranges->add(' 5001, 10000','1000');
$y_ranges->add('10001, 50000','2500');
$y_ranges->add('50001,'      ,'5000');

sub set_y_axis {
    # This routine over-rides the y_max_value calculation in GD::Graph, which produces double the
    # required limit, and therefore a lot of white-space...
    return 1 unless @_ ;            #no point going any further if no arguments were provided, however result has to be
                                    #non-zero to avoid /0 errors in GD::Graph
    my @a = map { $_ || 0 } @_ ;    #array may have undefs in it. Set null to zero for calc of max
    my ($y_max) = sort { $b <=> $a } @a ; # Get largest total for y-axis
    my $y_range = $y_ranges->fetch($y_max);
    my $y_axis = ($y_max%$y_range==0) ? $y_max+$y_range : ($y_max - ($y_max%$y_range) + $y_range);
    sprintf("%d", $y_axis);
}

sub my_graph {
    my @ymax;
    # generate data... foreach loop etc
        push(@ymax, $this_y_value); # append y-value or cumulative y-value as appropriate
    # etc.
    my $graph = GD::Graph::lines->new(750, 280);
    $graph->set(
        y_max_value         => set_y_axis(@ymax),
        x_labels_vertical   => 1,
        transparent         => 1,
        # etc
    );
    # etc
}

Hope that's useful to you.

RET
I am setting the y_max_value height and the data is overflowing that bound.I think this is a bit counter intuitive that the graph area would not truncate everything outside of it, but I guess that pre filtering the data is the best I can do.
Dan Littlejohn
y_max_value is useful for ensuring a series of graphs share the same height, or to declare a business rule limit. But if you do that, you need to ensure your data points meet that rule. That's why I wrote the code provided above. The graphs just look 'right'.
RET