gerbilcharts 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -9,6 +9,7 @@ test/trafgen.rb
9
9
  test/test_noob.rb
10
10
  test/test_render_string.rb
11
11
  test/test_helper.rb
12
+ test/test_scaling.rb
12
13
  lib/gerbilcharts.rb
13
14
  lib/gerbilcharts/version.rb
14
15
  lib/gerbilcharts/models.rb
@@ -3,7 +3,7 @@ module GerbilCharts::Charts
3
3
 
4
4
  # =Area Chart
5
5
  # Draws each model in a shaded area.
6
- # We use a transparency to show hidden models. Not the best looking, but has its uses.
6
+ # We use a transparency to show hidden charts. Not the best looking, but has its uses.
7
7
  #
8
8
  class AreaChart < ChartBase
9
9
 
@@ -18,6 +18,16 @@ module GerbilCharts::Charts
18
18
  #
19
19
  # GerbilCharts uses a color scheme from a stylesheet.
20
20
  # The stylesheets contain the coloring for each model.
21
+ #
22
+ # Options common for all charts
23
+ #
24
+ # [+:width+] Width of the generated SVG chart in pixels
25
+ # [+:height+] Height of the generated SVG chart in pixels
26
+ # [+:style+] CSS Stylesheet to use for the chart (default = brushmetal.css see public gem directory)
27
+ # [+:scaling_x+] Allowed values are :auto, :auto_0, and an array [min,max] (default = :auto)
28
+ # [+:scaling_y+] Allowed values are :auto, :auto_0, and an array [min,max] (default = :auto)
29
+ # [+:circle_data_points+] Draws a tiny circle around datapoints for tooltips
30
+ #
21
31
  class ChartBase
22
32
 
23
33
 
@@ -30,7 +30,7 @@ class LineChart < ChartBase
30
30
  @thechart.add_child(GerbilCharts::Surfaces::TitlePanel.new(:orient => ORIENT_OVERLAY, :dim => 30))
31
31
  @thechart.add_child(GerbilCharts::Surfaces::LineSurface.new(:orient => ORIENT_OVERLAY),:anchor => true)
32
32
  @thechart.add_child(GerbilCharts::Surfaces::Legend.new(:orient=> ORIENT_OVERLAY, :dim => 100))
33
- @thechart.add_child(GerbilCharts::Surfaces::VerticalAxis.new(:orient => ORIENT_WEST, :dim => 30 ))
33
+ @thechart.add_child(GerbilCharts::Surfaces::VerticalAxis.new(:orient => ORIENT_WEST, :dim => 40 ))
34
34
  @thechart.add_child(GerbilCharts::Surfaces::HorizontalTimeAxis.new(:orient => ORIENT_SOUTH, :dim => 25 ))
35
35
  end
36
36
  end
@@ -82,7 +82,31 @@ class GraphModelGroup
82
82
  yield mod.userdata if mod.hasUserData?
83
83
  end
84
84
  end
85
+
86
+ # rangeoptions
87
+ # [+:auto+] automatic rounded max and min range
88
+ # [+:auto_0+] automatic rounded max and 0 min
89
+ # [+[min,max+] manual scaling
90
+ #
91
+ def effective_range_x(rangeopts=nil)
92
+ if rangeopts.nil?
93
+ return effective_round_range_x
94
+ end
95
+
96
+ if rangeopts.to_sym == :auto
97
+ return effective_round_range_x
98
+ elsif rangeopts.to_sym = :auto_0
99
+ return effective_round_range_x
100
+ elsif rangeopts.respond_to?('size') and rangeopts.size == 2
101
+ reffx = RawRange.new
102
+ reffx.update(rangeopts[0])
103
+ reffx.update(rangeopts[1])
104
+ return reffx
105
+ end
106
+ end
85
107
 
108
+ # effective round range
109
+ # rounds both x and y scales, returns two ranges
86
110
  def effective_round_range
87
111
 
88
112
  if @models.length==0
@@ -96,27 +120,56 @@ class GraphModelGroup
96
120
  reffy.update_r(m.yrange)
97
121
  end
98
122
 
123
+ # todo : need to convert the round_given method to a class method
99
124
  return models[0].rounderx.round_given(reffx), models[0].roundery.round_given(reffy)
100
125
 
101
126
  end
102
127
 
128
+ # round the x ranges of all models
103
129
  def effective_round_range_x
104
130
 
105
131
  reffx = RawRange.new
106
132
  @models.each do |m|
107
133
  reffx.update_r(m.xrange)
108
134
  end
109
-
110
135
  return models[0].round_given_x(reffx)
111
136
  end
112
137
 
138
+ # rangeoptions
139
+ # [+:auto+] automatic rounded max and min range
140
+ # [+:auto_0+] automatic rounded max and 0 min
141
+ # [+[min,max+] manual scaling
142
+ #
143
+ def effective_range_y(rangeopts=nil)
144
+ if rangeopts.nil?
145
+ return effective_round_range_y0
146
+ end
147
+
148
+ if rangeopts == :auto
149
+ return effective_round_range_y
150
+ elsif rangeopts == :auto_0
151
+ return effective_round_range_y0
152
+ elsif rangeopts.respond_to?('size') and rangeopts.size == 2
153
+ reffy = RawRange.new
154
+ reffy.update(rangeopts[0])
155
+ reffy.update(rangeopts[1])
156
+ return reffy
157
+ end
158
+ end
159
+
160
+ # round the y ranges of all models but minimum fixed at 0
113
161
  def effective_round_range_y0
114
162
  reffy = RawRange.new
115
163
  reffy.zeromin
116
164
  @models.each do |m|
117
165
  reffy.update_r(m.yrange)
118
166
  end
119
-
167
+ return @models[0].round_given_y(reffy)
168
+ end
169
+
170
+ def effective_round_range_y
171
+ reffy = RawRange.new
172
+ @models.each { |m| reffy.update_r(m.yrange) }
120
173
  return @models[0].round_given_y(reffy)
121
174
  end
122
175
 
@@ -124,46 +177,42 @@ class GraphModelGroup
124
177
  return @models[0].sweep_interval
125
178
  end
126
179
 
127
- # sum of model ranges
180
+ # sum of model ranges with min y being 0
128
181
  def cumulative_round_range_y0
129
182
  reffy = RawRange.new
130
183
  reffy.update(0)
131
184
  @models.each do |m|
132
185
  reffy.update(m.yrange.rmax+reffy.rmax)
133
186
  end
134
-
135
187
  return models[0].round_given_y(reffy)
136
188
  end
137
189
 
138
- # sweep for an interval with max
190
+ # sum of model ranges
191
+ def cumulative_round_range_y
192
+ reffy = RawRange.new
193
+ @models.each do |m|
194
+ reffy.update(m.yrange.rmax+reffy.rmax)
195
+ end
196
+ return models[0].round_given_y(reffy)
197
+ end
198
+
199
+
200
+
201
+ # sweep for an interval with y scale starting 0
202
+ # this is most appropriate for network traffic charts
139
203
  def cumulative_sweep_round_range_y0
140
-
141
- rx = effective_round_range_x
142
- reffy = RawRange.new
204
+ reffy=RawRange.new
143
205
  reffy.zeromin
144
-
145
- # prepare models for sweeping
146
- sweep_pos= rx.rmin
147
- sweep_to = rx.rmax
148
-
149
- @models.each do | mod|
150
- mod.begin_sweep
151
- end
152
-
153
- # perform the sweep
154
- while (sweep_pos<=sweep_to)
155
- acc_y = 0
156
- @models.each do | mod, i|
157
- acc_y += mod.sweep(sweep_pos)
158
- end
159
- sweep_pos += sweep_interval
160
- reffy.update(acc_y)
161
- end
206
+ return cumulative_sweep_round_range_y_generic(reffy)
207
+ end
208
+
209
+ # sweep for an interval with y scale
210
+ def cumulative_sweep_round_range_y0
211
+ reffy=RawRange.new
212
+ return cumulative_sweep_round_range_y_generic(reffy)
213
+ end
214
+
162
215
 
163
- return models[0].round_given_y(reffy)
164
-
165
- end
166
-
167
216
  def cumulative_round_range
168
217
 
169
218
  if @models.length==0
@@ -234,6 +283,37 @@ class GraphModelGroup
234
283
  return "No activity" if @emptycaption.nil?
235
284
  return @emptycaption
236
285
  end
286
+
287
+
288
+ private
289
+
290
+ # :nodoc:
291
+ def cumulative_sweep_round_range_y_generic(reffy)
292
+
293
+ rx = effective_round_range_x
294
+
295
+ # prepare models for sweeping
296
+ sweep_pos= rx.rmin
297
+ sweep_to = rx.rmax
298
+
299
+ @models.each do | mod|
300
+ mod.begin_sweep
301
+ end
302
+
303
+ # perform the sweep
304
+ while (sweep_pos<=sweep_to)
305
+ acc_y = 0
306
+ @models.each do | mod, i|
307
+ acc_y += mod.sweep(sweep_pos)
308
+ end
309
+ sweep_pos += sweep_interval
310
+ reffy.update(acc_y)
311
+ end
312
+
313
+ return models[0].round_given_y(reffy)
314
+
315
+ end
316
+
237
317
  end
238
318
 
239
319
  end
@@ -15,8 +15,8 @@ protected
15
15
  [20000,5000], [50000,10000], [100000,25000], [200000,50000],
16
16
  [500000,100000],[800000,200000],
17
17
  [1000000,200000],[2000000,500000], [3000000,500000], [4000000,1000000],
18
- [5000000,1000000],[6000000, 1500000],
19
- [10000000,2500000], [20000000,4000000], [50000000, 10000000],
18
+ [5000000,1000000],[6000000, 1000000],
19
+ [8000000,2000000], [10000000,2000000], [20000000,4000000], [50000000, 10000000],
20
20
  [100000000,25000000], [500000000,100000000],
21
21
  [1000000000,250000000]
22
22
  ]
@@ -62,6 +62,39 @@ class RawRange < Presets
62
62
  return format_suffix(val)
63
63
  end
64
64
 
65
+ # provide labels for raw range
66
+ # assumes ticks = 5
67
+ # yields two items (value,string label)
68
+ #
69
+ # Usage example:
70
+ # r.each_label do |v,s|
71
+ # p "Value = #{v} Label String = #{s}"
72
+ # end
73
+ #
74
+ def each_label(ticks=4)
75
+
76
+ raise "No data points in model" if @rmax == -1
77
+
78
+ label_interval = (@rmax-@rmin)/ticks
79
+ v = @rmin
80
+ while (v<=@rmax) do
81
+ yield v, format_suffix(v)
82
+ v = v+label_interval
83
+ end
84
+ end
85
+
86
+ # provide ticks (per label interval)
87
+ # for raw range simply divide the max and min into ticks
88
+ def each_tick(ticks=4)
89
+
90
+ label_interval = (@rmax-@rmin)/ticks
91
+ v = @rmin
92
+ while (v<@rmax) do
93
+ yield v
94
+ v = v+label_interval
95
+ end
96
+ end
97
+
65
98
 
66
99
  end
67
100
 
@@ -9,8 +9,14 @@ class AreaSurface < Surface
9
9
  end
10
10
 
11
11
  def int_render(g)
12
- rx = parent.modelgroup.effective_round_range_x
13
- ry = parent.modelgroup.effective_round_range_y0
12
+
13
+
14
+ range_options_x = parent.get_global_option(:scaling_x,:auto)
15
+ range_options_y = parent.get_global_option(:scaling_y,:auto)
16
+ rx = parent.modelgroup.effective_range_x(range_options_x)
17
+ ry = parent.modelgroup.effective_range_y(range_options_y)
18
+
19
+ p "range y = #{ry}"
14
20
 
15
21
  # ajax if used
16
22
  if parent.usesAjax?
@@ -35,7 +35,8 @@ class BarSurface < Surface
35
35
  #p "Spacing = #{parent.anchor.element_spacing} spacing"
36
36
 
37
37
  # atleast one model is present, chhug along
38
- ry = parent.modelgroup.effective_round_range_y0
38
+ range_options_y = parent.get_global_option(:scaling_y,:auto)
39
+ ry = parent.modelgroup.effective_range_y(range_options_y)
39
40
  set_ajaxSurfaceContext(0,ry.rmax,"BAR") if parent.usesAjax?
40
41
 
41
42
  xpos = @bounds.left + @element_spacing
@@ -24,13 +24,13 @@ class Grid < GraphElement
24
24
 
25
25
  protected
26
26
 
27
- def grid_range_x
28
- return parent.modelgroup.effective_round_range_x
29
- end
27
+ def grid_range_x
28
+ return parent.modelgroup.effective_round_range_x
29
+ end
30
30
 
31
- def grid_range_y
32
- return parent.modelgroup.effective_round_range_y0
33
- end
31
+ def grid_range_y
32
+ return parent.modelgroup.effective_round_range_y0
33
+ end
34
34
 
35
35
 
36
36
  end
@@ -9,8 +9,10 @@ class ImpulseSurface < Surface
9
9
 
10
10
  def int_render(g)
11
11
 
12
- rx = parent.modelgroup.effective_round_range_x
13
- ry = parent.modelgroup.effective_round_range_y0
12
+ range_options_x = parent.get_global_option(:scaling_x,:auto)
13
+ range_options_y = parent.get_global_option(:scaling_y,:auto)
14
+ rx = parent.modelgroup.effective_range_x(range_options_x)
15
+ ry = parent.modelgroup.effective_range_y(range_options_y)
14
16
 
15
17
  impulse_width = 2
16
18
  x2 = scale_x Time.at(0),rx
@@ -7,6 +7,7 @@ module GerbilCharts::Surfaces
7
7
  # Supported global options
8
8
  #
9
9
  # [+circle_data_points+] Draw a solid circle around datapoints
10
+ # [+scaling+] :auto, :auto_y0
10
11
  #
11
12
  class LineSurface < Surface
12
13
  def initialize(opts={})
@@ -15,8 +16,10 @@ class LineSurface < Surface
15
16
 
16
17
  def int_render(g)
17
18
 
18
- rx = parent.modelgroup.effective_round_range_x
19
- ry = parent.modelgroup.effective_round_range_y0
19
+ range_options_x = parent.get_global_option(:scaling_x,:auto)
20
+ range_options_y = parent.get_global_option(:scaling_y,:auto)
21
+ rx = parent.modelgroup.effective_range_x(range_options_x)
22
+ ry = parent.modelgroup.effective_range_y(range_options_y)
20
23
 
21
24
  # ajax if used
22
25
  if parent.usesAjax?
@@ -4,6 +4,7 @@ module GerbilCharts::Surfaces
4
4
  # Base class for all surfaces (line,bar,pie,area,...)
5
5
  #
6
6
  class Surface < GraphElement
7
+
7
8
  def initialize(opts={})
8
9
  @class = "surfacepanel"
9
10
  super(opts)
@@ -21,10 +21,11 @@ class VerticalAxis < Axis
21
21
 
22
22
  return if parent.modelgroup.empty?
23
23
 
24
+ p "axis = #{parent.get_global_option(:scaling_y,false)}"
24
25
  if @use_cumulative_y
25
26
  ry = parent.modelgroup.cumulative_sweep_round_range_y0
26
27
  else
27
- ry = parent.modelgroup.effective_round_range_y0
28
+ ry = parent.modelgroup.effective_range_y(parent.get_global_option(:scaling_y,:auto))
28
29
  end
29
30
 
30
31
  ry.each_label do |val,label|
@@ -2,7 +2,7 @@ module GerbilCharts
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 4
5
+ TINY = 6
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/test/test_noob.rb CHANGED
@@ -55,7 +55,8 @@ class TestChartsNoob < Test::Unit::TestCase
55
55
  mychart.render('/tmp/n_daily_traffic.svg')
56
56
 
57
57
  # demo resuses the model in a different view (an area chart this time)
58
- myareachart = GerbilCharts::Charts::AreaChart.new( :width => 450, :height => 200, :style => 'brushmetal.css')
58
+ myareachart = GerbilCharts::Charts::AreaChart.new( :width => 450, :height => 200, :style => 'brushmetal.css',
59
+ :scaling_y => :auto )
59
60
  myareachart.modelgroup=modelgroup
60
61
  myareachart.render('/tmp/n_daily_traffic_area.svg')
61
62
 
@@ -0,0 +1,57 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ require 'trafgen'
4
+
5
+ # Test scaling options :auto, :auto_0, [min,max]
6
+
7
+ class TestChartsScaling < Test::Unit::TestCase
8
+
9
+
10
+ # test scaling
11
+ def test_scale_1
12
+
13
+ tend = Time.now
14
+ tbegin = tend - 3600*24
15
+
16
+ # random between 2M and 6M
17
+ model1 = GerbilCharts::Models::BucketizedTimeSeriesGraphModel.new( "eth0", 3600 )
18
+ TimeSeriesDataGenerator.new(tbegin,tend,300,2000000, 6000000).each_tuple do |t,v|
19
+ model1.add(t,v)
20
+ end
21
+
22
+ # random between 4M and 10M
23
+ model2 = GerbilCharts::Models::BucketizedTimeSeriesGraphModel.new( "wan1", 3600 )
24
+ TimeSeriesDataGenerator.new(tbegin,tend,300,4000000, 10000000).each_tuple do |t,v|
25
+ model2.add(t,v)
26
+ end
27
+
28
+ modelgroup = GerbilCharts::Models::GraphModelGroup.new( "External Traffic")
29
+ modelgroup.add model2
30
+ modelgroup.add model1
31
+
32
+
33
+ # area chart with auto scaling
34
+ myareachart = GerbilCharts::Charts::AreaChart.new( :width => 450, :height => 200, :style => 'brushmetal.css',
35
+ :scaling_y => :auto )
36
+ myareachart.modelgroup=modelgroup
37
+ myareachart.render('/tmp/n_scale_auto.svg')
38
+
39
+ # line chart with auto_0 scaling
40
+ myareachart = GerbilCharts::Charts::LineChart.new( :width => 450, :height => 200, :style => 'brushmetal.css',
41
+ :scaling_y => :auto_0 )
42
+ myareachart.modelgroup=modelgroup
43
+ myareachart.render('/tmp/n_scale_auto_0.svg')
44
+
45
+ # impulse chart with manual scaling
46
+ myareachart = GerbilCharts::Charts::ImpulseChart.new( :width => 450, :height => 200, :style => 'brushmetal.css',
47
+ :scaling_y => [2000000,8000000] )
48
+ myareachart.modelgroup=modelgroup
49
+ myareachart.render('/tmp/n_scale_manual.svg')
50
+
51
+ end
52
+
53
+
54
+
55
+ end
56
+
57
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gerbilcharts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vivek Rajagopalan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-06 00:00:00 +05:30
12
+ date: 2009-06-09 00:00:00 +05:30
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -47,6 +47,7 @@ files:
47
47
  - test/test_noob.rb
48
48
  - test/test_render_string.rb
49
49
  - test/test_helper.rb
50
+ - test/test_scaling.rb
50
51
  - lib/gerbilcharts.rb
51
52
  - lib/gerbilcharts/version.rb
52
53
  - lib/gerbilcharts/models.rb
@@ -152,4 +153,5 @@ test_files:
152
153
  - test/test_render_string.rb
153
154
  - test/test_models.rb
154
155
  - test/test_charts.rb
156
+ - test/test_scaling.rb
155
157
  - test/test_Scratch.rb