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 +1 -0
- data/lib/gerbilcharts/charts/area_chart.rb +1 -1
- data/lib/gerbilcharts/charts/chart_base.rb +10 -0
- data/lib/gerbilcharts/charts/line_chart.rb +1 -1
- data/lib/gerbilcharts/models/graph_model_group.rb +110 -30
- data/lib/gerbilcharts/models/presets.rb +2 -2
- data/lib/gerbilcharts/models/raw_range.rb +33 -0
- data/lib/gerbilcharts/surfaces/area_surface.rb +8 -2
- data/lib/gerbilcharts/surfaces/bar_surface.rb +2 -1
- data/lib/gerbilcharts/surfaces/grid.rb +6 -6
- data/lib/gerbilcharts/surfaces/impulse_surface.rb +4 -2
- data/lib/gerbilcharts/surfaces/line_surface.rb +5 -2
- data/lib/gerbilcharts/surfaces/surface.rb +1 -0
- data/lib/gerbilcharts/surfaces/vertical_axis.rb +2 -1
- data/lib/gerbilcharts/version.rb +1 -1
- data/test/test_noob.rb +2 -1
- data/test/test_scaling.rb +57 -0
- metadata +4 -2
data/Manifest.txt
CHANGED
@@ -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
|
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 =>
|
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
|
-
#
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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,
|
19
|
-
|
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
|
-
|
13
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def grid_range_x
|
28
|
+
return parent.modelgroup.effective_round_range_x
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
13
|
-
|
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
|
-
|
19
|
-
|
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?
|
@@ -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.
|
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|
|
data/lib/gerbilcharts/version.rb
CHANGED
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
|
+
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-
|
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
|