Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Lots of improvements and handy things #16

Merged
merged 2 commits into from over 1 year ago

2 participants

nitbix Cory G Watson
nitbix
  • I made it so data can have hole - this should be inclusive of the patch that epa submitted
  • Made it so that the Line renderer can plot holes properly, even when there is only one point surrounded by holes
  • Fixed a problem with Range that made it impossible to render completely flat lines
  • Added a 'fast mode' that skips unnecessary data when there are lots of points per pixel
Alan Mosca added some commits
Alan Mosca fixed tests for changes in divvy() 34a86fb
Alan Mosca data can have holes (undef values), if there are holes around data th…
…ey are visible, we can plot straight lines and there is a fast mode (Line only for now)
49acfcc
Cory G Watson gphat merged commit cdefc9f into from
Cory G Watson gphat closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

Mar 08, 2013
Alan Mosca fixed tests for changes in divvy() 34a86fb
Alan Mosca data can have holes (undef values), if there are holes around data th…
…ey are visible, we can plot straight lines and there is a fast mode (Line only for now)
49acfcc
This page is out of date. Refresh to see the latest.
13 lib/Chart/Clicker.pm
@@ -403,6 +403,19 @@ has 'format' => (
403 403 default => sub { 'PNG' }
404 404 );
405 405
  406 +=attr plot_mode
  407 +
  408 +Fast or slow plot mode. When in fast mode, data elements that are deemed to be
  409 +superfluous or invisible will not be drawn. Default is 'slow'
  410 +
  411 +=cut
  412 +
  413 +has 'plot_mode' => (
  414 + is => 'rw',
  415 + isa => 'Str',
  416 + default => sub { 'slow' }
  417 +);
  418 +
406 419 =attr grid_over
407 420
408 421 Flag controlling if the grid is rendered B<over> the data. Defaults to 0.
8 lib/Chart/Clicker/Axis.pm
@@ -466,7 +466,12 @@ override('prepare', sub {
466 466
467 467 my $label = $val;
468 468 if(defined($self->tick_labels)) {
469   - $label = $self->tick_labels->[$i];
  469 + if (defined $self->tick_labels->[$i]) {
  470 + $label = $self->tick_labels->[$i];
  471 + }
  472 + else {
  473 + $label = "";
  474 + }
470 475 } else {
471 476 $label = $self->format_value($val);
472 477 }
@@ -562,6 +567,7 @@ Given a span and a value, returns it's pixel position on this Axis.
562 567 sub mark {
563 568 my ($self, $span, $value) = @_;
564 569
  570 + return undef if not defined $value;
565 571 if($self->has_skip_range) {
566 572 # We must completely ignore values that fall inside the skip range,
567 573 # so we return an undef.
54 lib/Chart/Clicker/Data/Range.pm
... ... @@ -1,5 +1,8 @@
1 1 package Chart::Clicker::Data::Range;
2 2 use Moose;
  3 +use Moose::Util::TypeConstraints;
  4 +
  5 +use constant EPSILON => 0.0001;
3 6
4 7 # ABSTRACT: A range of Data
5 8
@@ -22,7 +25,15 @@ Set/Get the lower bound for this Range
22 25
23 26 =cut
24 27
25   -has 'lower' => ( is => 'rw', isa => 'Num' );
  28 +subtype 'Lower'
  29 + => as 'Num|Undef'
  30 + => where { defined($_) };
  31 +
  32 +coerce 'Lower'
  33 + => from 'Undef'
  34 + => via { - EPSILON };
  35 +
  36 +has 'lower' => ( is => 'rw', isa => 'Lower', coerce => 1);
26 37
27 38 =attr max
28 39
@@ -48,7 +59,16 @@ Set/Get the upper bound for this Range
48 59
49 60 =cut
50 61
51   -has 'upper' => ( is => 'rw', isa => 'Num' );
  62 +subtype 'Upper'
  63 + => as 'Num|Undef'
  64 + => where { defined($_) };
  65 +
  66 +coerce 'Upper'
  67 + => from 'Num|Undef'
  68 + => via { EPSILON };
  69 +
  70 +has 'upper' => ( is => 'rw', isa => 'Upper', coerce => 1);
  71 +
52 72
53 73 =attr ticks
54 74
@@ -65,6 +85,15 @@ after 'lower' => sub {
65 85 if(defined($self->{'min'})) {
66 86 $self->{'lower'} = $self->{'min'};
67 87 }
  88 +
  89 + $self->{'lower'} = $self->{'min'} unless (defined($self->{'lower'}));
  90 + $self->{'upper'} = $self->{'max'} unless (defined($self->{'upper'}));
  91 +
  92 + if(defined($self->{'lower'}) && defined($self->{'upper'}) && $self->{'lower'} == $self->{'upper'}) {
  93 + $self->{'lower'} = $self->{'lower'} - EPSILON;
  94 + $self->{'lower'} = $self->{'lower'} + EPSILON;
  95 + }
  96 +
68 97 };
69 98
70 99 after 'upper' => sub {
@@ -73,6 +102,15 @@ after 'upper' => sub {
73 102 if(defined($self->{'max'})) {
74 103 $self->{'upper'} = $self->{'max'};
75 104 }
  105 +
  106 + $self->{'lower'} = $self->{'min'} unless (defined($self->{'lower'}));
  107 + $self->{'upper'} = $self->{'max'} unless (defined($self->{'upper'}));
  108 +
  109 + if(defined($self->{'lower'}) && defined($self->{'upper'}) && $self->{'lower'} == $self->{'upper'}) {
  110 + $self->{'upper'} = $self->{'upper'} - EPSILON;
  111 + $self->{'upper'} = $self->{'upper'} + EPSILON;
  112 + }
  113 +
76 114 };
77 115
78 116 after 'min' => sub {
@@ -161,11 +199,19 @@ Returns the span of this range, or UPPER - LOWER.
161 199 sub span {
162 200 my ($self) = @_;
163 201
164   - return $self->upper - $self->lower;
  202 + my $span = $self->upper - $self->lower;
  203 +
  204 + #we still want to be able to see flat lines!
  205 + if ($span <= EPSILON) {
  206 + $self->upper($self->upper() + EPSILON);
  207 + $self->lower($self->lower() - EPSILON);
  208 + $span = $self->upper - $self->lower;
  209 + }
  210 + return $span;
165 211 }
166 212
167 213 __PACKAGE__->meta->make_immutable;
168 214
169 215 no Moose;
170 216
171   -1;
  217 +1;
5 lib/Chart/Clicker/Data/Series.pm
@@ -110,7 +110,7 @@ Get the count of values in this series.
110 110 has 'values' => (
111 111 traits => [ 'Array' ],
112 112 is => 'rw',
113   - isa => 'ArrayRef[Num]',
  113 + isa => 'ArrayRef[Num|Undef]',
114 114 default => sub { [] },
115 115 handles => {
116 116 'add_to_values' => 'push',
@@ -127,7 +127,8 @@ sub _build_range {
127 127 unless scalar(@{ $values });
128 128
129 129 return Chart::Clicker::Data::Range->new(
130   - lower => min(@{ $values }), upper => max(@{ $values})
  130 + lower => min(grep { defined } @{ $values }),
  131 + upper => max(grep { defined } @{ $values })
131 132 );
132 133 }
133 134
5 lib/Chart/Clicker/Decoration/Legend.pm
@@ -86,6 +86,9 @@ override('prepare', sub {
86 86 my $font = $self->font;
87 87
88 88 my $ii = $self->item_padding;
  89 +
  90 + #this makes sure that wrapping works
  91 + $self->width($self->clicker->width);
89 92
90 93 if($self->is_vertical) {
91 94 # This assumes you aren't changing the layout manager...
@@ -122,4 +125,4 @@ __PACKAGE__->meta->make_immutable;
122 125
123 126 no Moose;
124 127
125   -1;
  128 +1;
59 lib/Chart/Clicker/Renderer/Line.pm
@@ -8,6 +8,12 @@ extends 'Chart::Clicker::Renderer';
8 8 use Geometry::Primitive::Point;
9 9 use Graphics::Primitive::Brush;
10 10 use Graphics::Primitive::Operation::Stroke;
  11 +use Geometry::Primitive::Circle;
  12 +
  13 +#number of defined points we must have around another point
  14 +#to render a line instead of a scatter
  15 +#
  16 +use constant MIN_DEFINED_SURROUNDING_POINTS => 5;
11 17
12 18 =head1 DESCRIPTION
13 19
@@ -108,12 +114,18 @@ sub finalize {
108 114
109 115 my $kcount = $series->key_count - 1;
110 116
  117 + my $skip = 0;
  118 + my $previous_x = -1;
  119 + my $previous_y = -1;
  120 + my $min_y_delta_on_same_x = $height / 100;
  121 +
111 122 for(0..$kcount) {
112 123
113 124 my $key = $keys[$_];
114 125
115 126 my $x = $domain->mark($width, $key);
116 127 next unless defined($x);
  128 + $skip = 1 unless defined $vals[$_];
117 129 my $ymark = $range->mark($height, $vals[$_]);
118 130 next unless defined($ymark);
119 131
@@ -127,12 +139,49 @@ sub finalize {
127 139 }
128 140
129 141 my $y = $height - $ymark;
130   -
131   - if($_ == 0) {
  142 + if( $_ == 0 || $skip ) {
  143 + my $lineop = Graphics::Primitive::Operation::Stroke->new(
  144 + brush => $self->brush->clone
  145 + );
  146 + $lineop->brush->color($color);
  147 + $self->do($lineop);
132 148 $self->move_to($x, $y);
133   - } else {
134   - $self->line_to($x, $y);
  149 + my $start_new_line = 1;
  150 + foreach my $i ($_..($_ + MIN_DEFINED_SURROUNDING_POINTS)) {
  151 + if ($i > 0 && $i < @vals && !defined($vals[$i])) {
  152 + $start_new_line = 0;
  153 + }
  154 + }
  155 + if ($start_new_line){
  156 + $skip = 0;
  157 + }
  158 + else {
  159 + my $shape = Geometry::Primitive::Circle->new(radius => 3);
  160 + $shape->origin(Geometry::Primitive::Point->new(x => $x, y => $y));
  161 + $self->path->add_primitive($shape);
  162 + my $fill = Graphics::Primitive::Operation::Fill->new(
  163 + paint => Graphics::Primitive::Paint::Solid->new(
  164 + color => $color
  165 + )
  166 + );
  167 + $self->do($fill);
  168 + }
135 169 }
  170 + else {
  171 + # when in fast mode, we plot only if we moved by more than
  172 + # 1 of a pixel on the X axis or we moved by more than 1%
  173 + # of the size of the Y axis.
  174 + if( $clicker->plot_mode ne 'fast' ||
  175 + $x - $previous_x > 1 ||
  176 + abs($y - $previous_y) > $min_y_delta_on_same_x
  177 + )
  178 + {
  179 + $self->line_to($x, $y);
  180 + $previous_x = $x;
  181 + $previous_y = $y;
  182 + }
  183 + }
  184 +
136 185 }
137 186 my $op = Graphics::Primitive::Operation::Stroke->new;
138 187 $op->brush($self->brush->clone);
@@ -203,4 +252,4 @@ __PACKAGE__->meta->make_immutable;
203 252
204 253 no Moose;
205 254
206   -1;
  255 +1;
15 t/axis-division-rounded.t
@@ -19,7 +19,7 @@ my $label = 'Foo';
19 19 $axis->range->lower(3);
20 20 $axis->range->upper(105);
21 21 is( $axis->ticks, '5', 'Default number of ticks' );
22   - is_deeply( $axis->divvy(), [ 25, 50, 75, 100 ], 'Nicely rounded tick values - medium scale' );
  22 + is_deeply( $axis->divvy(), [ 20, 40, 60, 80, 100 ], 'Nicely rounded tick values - medium scale' );
23 23 }
24 24
25 25 # Larger Range
@@ -34,7 +34,9 @@ my $label = 'Foo';
34 34 $axis->range->upper(999123421);
35 35 is_deeply(
36 36 $axis->divvy(),
37   - [ 0, 200000000, 400000000, 600000000, 800000000, 1000000000 ],
  37 + [ 0, 100000000, 200000000, 300000000, 400000000, 500000000,
  38 + 600000000, 700000000, 800000000, 900000000, 1000000000],
  39 +
38 40 'Nicely rounded tick values - large scale 5 ticks'
39 41 );
40 42 }
@@ -50,7 +52,8 @@ my $label = 'Foo';
50 52 $axis->range->lower(1);
51 53 $axis->range->upper(999123421);
52 54 $axis->ticks(3);
53   - is_deeply( $axis->divvy(), [ 0, 400000000, 800000000 ], 'Nicely rounded tick values - large scale 3 ticks' );
  55 + is_deeply( $axis->divvy(), [ 0, 250000000, 500000000, 750000000, 1000000000 ],
  56 + 'Nicely rounded tick values - large scale 3 ticks' );
54 57 }
55 58
56 59 # Very small range below 1
@@ -64,7 +67,8 @@ my $label = 'Foo';
64 67 $axis->range->lower(0.0072);
65 68 $axis->range->upper(0.0078);
66 69 $axis->ticks(3);
67   - is_deeply( $axis->divvy(), [ 0.00725, 0.00750, 0.00775 ], 'Nicely rounded tick values - large scale 3 ticks' );
  70 + is_deeply( $axis->divvy(), [ 0.0072, 0.0073, 0.0074, 0.0075, 0.0076, 0.0077, 0.0078 ],
  71 + 'Nicely rounded tick values - large scale 3 ticks' );
68 72 }
69 73
70 74 # Very small range above 1
@@ -78,7 +82,8 @@ my $label = 'Foo';
78 82 $axis->range->lower(1.5672);
79 83 $axis->range->upper(1.5679);
80 84 $axis->ticks(4);
81   - is_deeply( $axis->divvy(), [ 1.5672, 1.5674, 1.5676, 1.5678 ], 'Nicely rounded tick values - large scale 3 ticks' );
  85 + is_deeply( $axis->divvy(), [ 1.5672, 1.5673, 1.5674, 1.5675, 1.5676, 1.5677, 1.5678, 1.5679 ],
  86 + 'Nicely rounded tick values - large scale 3 ticks' );
82 87 }
83 88
84 89 done_testing;

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.