gerbilcharts 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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