/usr/local/CPAN/CGIGraph/CGI/Graph/Plot/bars/numerical.pm


package CGI::Graph::Plot::bars::numerical;

use CGI::Graph::Plot::bars;

@ISA = ("CGI::Graph::Plot::bars");

%default = (
	label_size => 5,
	bins => 10
);

#
# calls parent class to initialize values. Selection values are changed, if 
# necessary.
#

sub new {
        my ($pkg, $vars) = @_;
        my $class = ref($pkg) || $pkg;
        my $self=$class->SUPER::new($vars);

        if ($self->{rand}) {
		return bless $self,$class;
        }

	$self->graphBounds;

        if ($self->{select} || $self->{select_list} eq 'Visible' || $self->{unselect_list} eq 'Visible') {
		my @selected = split("",$self->{selected});
		my @row = $self->{table}->col('_row');
                my ($Xref) = $self->valuesInRange();
                my @X = @$Xref;
		my ($X1,$X2);

		# obtain range for selected X bar(s)
		if ($self->{select}) {
                	($X1,$X2) = $X[$self->{select}-1] =~ /^(.*)->(.*)$/;
		}
		unless ($self->{select}) {
			($X1) = $X[0] =~ /^(.*)->/;
			($X2) = $X[-1] =~ /->(.*)$/;
		}

		# update selection values for selected elements
                foreach (0..$self->{table}->nofRow()-1) {
			last if ($self->{table}->elm($_,$self->{X}) > $X2);

                        if ($self->{table}->elm($_,$self->{X}) >= $X1) {
				if ($self->{select}) {
					$selected[$row[$_]-1] = 
					($self->{select_type} eq'select')?1:0;
				}
				else {
					$selected[$row[$_]-1] =
                                        ($self->{select_list} eq 'Visible')?1:0;
				}
                        }
                }

	        $self->{selected} = join("",@selected);
		$self->write_selected();
        }

        return bless $self, $class;
}

#
# returns X and Y values for a histogram
#

sub count {
	my $self = shift;
	my $drawPartial = shift if @_;

	my @selected = split("",$self->{selected});

        my @S = $self->{table}->col($self->{X}); 
	my @row = $self->{table}->col('_row');

        my $bins = $default{bins};
	my ($start,$end);

	# determine start and end values depending on 
	# what portion of the graph is to be drawn

	if ($drawPartial) {
	        my $delta = $S[-1]-$S[0];
	        $start = $self->{x_min}*$delta+$S[0];
	        $end = $self->{x_max}*$delta+$S[0];
	}

	else {
	        $start = $S[0];
	        $end = $S[-1];
	}

        my $int = $self->{X}=~/^[i]_/;
        my $size = ($int)?($end-$start+1)/$bins:($end-$start)/$bins;

	# if using integer values, do not allow more bins than needed
        while ($int) {
                $size = ($end-$start+1)/$bins;
                last if ($size >= 1);
                $bins-- if ($size < 1);
        }

	# put range values into X array
        my @X;
        my $range;
        foreach (0..$bins-1) {
                $range = ($int) ? 
			int($_*$size+$start).'->'.int(($_+1)*$size+$start-1)
	                :($_*$size+$start).'->'.(($_+1)*$size+$start);
                push @X, $range;
        }

	# count values in each X range and store results in Y
	# also note how many selected elements are in each range
        my @Y;
	my @selectDraw;
        foreach (0..$#X) {
                push @Y,0;
                $X[$_] =~ /(.*)->(.*)/;

		foreach $count (0..$#S) {
			if (($S[$count] >= $1) && ($S[$count] <= $2)) {
				$selectDraw[$_]++ if ($selected[$row[$count]-1]
					== 1);				
                	        $Y[$_]++;
			}
		}
        }

        return (\@X,\@Y,\@selectDraw);
}

#
# depending on what type of histogram is used, returns X and Y values.
#

sub valuesInRange {
        my $self = shift;

	my (@dataX,@drawX,@dataY,@selectDraw);

	# bar graph style, zooms in without re-calculating histogram
	if ($self->{histogram_type} eq "fixed") {
	        my ($Xref,$Yref,$Sref) = $self->count();
	        my @X = @$Xref;
	        my @Y = @$Yref;
		my @S = @$Sref;

	        for ($i=0; $i<=$#X; $i++) {
	                if ( (($i+1)/($#X+2) >= $self->{x_min}) && 
			(($i+1)/($#X+2) <= $self->{x_max}) ) {
	                        push (@dataX, $X[$i]);
	                        push (@dataY, $Y[$i]);
				push (@selectDraw, $S[$i]);
	                }
	        }
	}

	# "variable" graph, re-calculates histogram when zooming in
	else {
	        my ($Xref,$Yref,$Sref) = $self->count(1);
	        @dataX = @$Xref;
	        @dataY = @$Yref;
		@selectDraw = @$Sref;
	}

	# shorten labels
        foreach (0..$#dataX) {
		$dataX[$_] =~ /(.*)->(.*)/;
                $drawX[$_] = sprintf("%.$default{label_size}g->%".
		".$default{label_size}g", $1,$2);
	}
	return (\@dataX,\@drawX,\@dataY,\@selectDraw);
}