File Coverage

blib/lib/Chart/Clicker/Axis/DivisionType/LinearRounded.pm
Criterion Covered Total %
statement 41 41 100.0
branch 11 12 91.6
condition n/a
subroutine 4 4 100.0
pod 1 1 100.0
total 57 58 98.2


line stmt bran cond sub pod time code
1             package Chart::Clicker::Axis::DivisionType::LinearRounded;
2             $Chart::Clicker::Axis::DivisionType::LinearRounded::VERSION = '2.89';
3 1     1   774 use Moose::Role;
  1         1  
  1         10  
4             with qw{Chart::Clicker::Axis::DivisionType};
5              
6             # Positive only
7             has 'tick_slop' => (
8             is => 'rw',
9             isa => 'Num',
10             default => 0.1,
11             documentation =>
12             q{Percent of a tick unit above or below graphed which we allow inserting an additional tick. Whitespace allowance above or below.}
13             );
14              
15             # Take the rough tick size which is the smallest possible 'round' scale
16             # and use other sub-divisors to aim for the number of ticks specified.
17             sub best_tick_size {
18 5     5 1 9 my ($self) = @_;
19              
20 5         154 my $minimum_target_ticks = $self->ticks;
21 5 50       18 $minimum_target_ticks = 1 if ( $minimum_target_ticks < 1 );
22              
23 5         150 my $equal_tick_size = $self->range->span / ($minimum_target_ticks);
24              
25             # Provide a nice round divisor which is within an order of
26             # magnitude of the actual wanted tick size. We adjust
27             # this value using hand specified sub-divider values
28             #
29             # Small ranges (below 1) require an additional digit
30 5         56 my $digits = int( log( abs($equal_tick_size) ) / log(10) );
31 5 100       169 $digits-- if ( abs( $self->range->span ) < 1 );
32 5         42 my $scale_size = 10**$digits;
33              
34             # Take the largest divider (smallest number of ticks) which will provide
35             # a nice looking result. The below dividers were selected arbitrarily to
36             # create visually pleasing numbers for an axis.
37             #
38             # The number of ticks will be equal to or larger than the requested number
39             # of ticks. Never smaller. The worst case is the 1 to 2 range which may
40             # provide nearly double (2N - 1) the number of requested ticks.
41             ADJUSTSCALE:
42 5         18 for my $scale_divider ( 25, 20, 10, 5, 4, 2.5, 2, 1 ) {
43 38         53 my $test_scale = $scale_divider * $scale_size;
44              
45 38 100       1141 if ( $self->range->span / $test_scale >= $minimum_target_ticks ) {
46 5         7 $scale_size = $test_scale;
47 5         20 last ADJUSTSCALE;
48             }
49             }
50              
51 5         12 return $scale_size;
52             }
53              
54             sub _real_divvy {
55 5     5   9 my ($self) = @_;
56              
57 5         19 my $tickSize = $self->best_tick_size;
58 5         140 my $range = $self->range;
59              
60             # If the lowest value is nearby to the first tick below it (gap
61             # at front of graph would be low) then use that as the starting
62             # value; otherwise choose the first tick value above the lowest.
63 5         36 my $lowestTick = int( $range->lower() / $tickSize ) * $tickSize;
64 5         43 my $lowestValue = $range->lower();
65 5         28 my $lowTickDifference = $lowestValue - $lowestTick;
66              
67 5 100       192 if ( $lowTickDifference > $self->tick_slop * $tickSize ) {
68 1         3 $lowestTick = $lowestTick + $tickSize;
69             }
70 5 100       15 if ( $lowestTick < $lowestValue ) {
71 2         7 $lowestValue = $lowestTick;
72             }
73 5         13 $range->lower($lowestValue);
74 5         22 my @vals;
75 5         13 push( @vals, $lowestTick );
76              
77             # Loop until upper from the starting point
78 5         7 my $lastTick = $lowestTick;
79 5         15 while ( $range->upper - $tickSize > $lastTick ) {
80 32         181 $lastTick = $lastTick + $tickSize;
81              
82 32         70 push( @vals, $lastTick );
83             }
84              
85             # If the upper value is nearby to the last tick above it
86             # (gap at end of graph would be low) then use that as the
87             # ending value; otherwise use the tick value immediately before
88             # the upper value.
89 5         36 my $potentialUpperTick = $lastTick + $tickSize;
90 5 100       16 if ( $potentialUpperTick - $range->upper < $self->tick_slop * $tickSize ) {
91 4         13 $range->upper($potentialUpperTick);
92 4         19 push( @vals, $potentialUpperTick );
93             }
94              
95 5         59 return \@vals;
96             }
97              
98 1     1   5099 no Moose;
  1         2  
  1         8  
99             1;
100              
101             __END__
102              
103             =pod
104              
105             =head1 NAME
106              
107             Chart::Clicker::Axis::DivisionType::LinearRounded
108              
109             =head1 VERSION
110              
111             version 2.89
112              
113             =head1 SYNOPSIS
114              
115             use Chart::Clicker::Axis;
116              
117             my $axis = Chart::Clicker::Axis->new({
118             tick_division_type => 'LinearRounded'
119             });
120              
121             =head1 DESCRIPTION
122              
123             Role describing how to divide data for Chart::Clicker::Axis.
124              
125             =head1 NAME
126              
127             Chart::Clicker::Axis::DivisionType::LinearRounded - Nicely rounded segments on a linear scale.
128              
129             =head1 ATTRIBUTES
130              
131             =head2 tick_slop
132              
133             This setting determines whether to add a tick outside of the data. If the tick would be
134             within the percentage of a ticks size specified here as a decimal (10% would be 0.1), then
135             the tick will be added expanding the graph.
136              
137             =head1 METHODS
138              
139             =head2 best_tick_size
140              
141             The tick division considered best for the approximate number of ticks requested
142             and data within the range.
143              
144             =head2 divvy
145              
146             Divides the range up into nicely rounded chunks for L<Chart::Clicker::Axis>.
147              
148             =head1 AUTHOR
149              
150             Rod Taylor <chartclicker@rbt.ca>
151              
152             =head1 SEE ALSO
153              
154             perl(1)
155              
156             =head1 LICENSE
157              
158             You can redistribute and/or modify this code under the same terms as Perl
159             itself.
160              
161             =head1 AUTHOR
162              
163             Cory G Watson <gphat@cpan.org>
164              
165             =head1 COPYRIGHT AND LICENSE
166              
167             This software is copyright (c) 2016 by Cory G Watson.
168              
169             This is free software; you can redistribute it and/or modify it under
170             the same terms as the Perl 5 programming language system itself.
171              
172             =cut