svg-graph-test 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt ADDED
@@ -0,0 +1,89 @@
1
+ = SVG::Graph
2
+
3
+ http://www.germane-software.com/software/SVG/SVG::Graph/
4
+
5
+ == AUTHOR
6
+
7
+ Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
8
+ Copyright 2004 Sean E. Russell
9
+ This software is available under the Ruby license[LICENSE.txt]
10
+
11
+ == DEVELOPERS
12
+
13
+ * Claudio Bustos <clbustos_AT_gmail_DOT_com
14
+ * Liehann Loots <liehhanl_AT_gmail_DOT_com
15
+ * Piergiuliano Bossi <pgbossi_AT_gmail_DOT_com
16
+
17
+ == DESCRIPTION:
18
+
19
+ This is a revision of the [SVG::Graph library](http://www.germane-software.com/software/SVG/SVG::Graph/) by Sean Russell with touch-ups to make it run on Ruby 1.9.x and be gem-installable. See History.txt for other changes
20
+
21
+ SVG:::Graph is a pure Ruby library for generating charts, which are a type of graph where the values of one axis are not scalar. SVG::Graph has a verry similar API to the Perl library SVG::TT::Graph, and the resulting charts also look the same. This isn't surprising, because SVG::Graph started as a loose port of SVG::TT::Graph, although the internal code no longer resembles the Perl original at all.
22
+
23
+ == FEATURES
24
+
25
+ * Tested for Ruby versions 1.8.6, 1.8.7 and 1.9.*
26
+
27
+ We are not sure that all the parts of the original SVG library work as expected under 1.9.x too. Please notify via github messages or on the Issues section if you find any bug.
28
+
29
+ == LICENSE:
30
+
31
+ (The Ruby Licence)
32
+
33
+ SVG::Graph is copyrighted free software by Sean Russell <ser@germane-software.com>.
34
+ You can redistribute it and/or modify it under either the terms of the GPL
35
+ (see GPL.txt file), or the conditions below:
36
+
37
+ 1. You may make and give away verbatim copies of the source form of the
38
+ software without restriction, provided that you duplicate all of the
39
+ original copyright notices and associated disclaimers.
40
+
41
+ 2. You may modify your copy of the software in any way, provided that
42
+ you do at least ONE of the following:
43
+
44
+ a) place your modifications in the Public Domain or otherwise
45
+ make them Freely Available, such as by posting said
46
+ modifications to Usenet or an equivalent medium, or by allowing
47
+ the author to include your modifications in the software.
48
+
49
+ b) use the modified software only within your corporation or
50
+ organization.
51
+
52
+ c) rename any non-standard executables so the names do not conflict
53
+ with standard executables, which must also be provided.
54
+
55
+ d) make other distribution arrangements with the author.
56
+
57
+ 3. You may distribute the software in object code or executable
58
+ form, provided that you do at least ONE of the following:
59
+
60
+ a) distribute the executables and library files of the software,
61
+ together with instructions (in the manual page or equivalent)
62
+ on where to get the original distribution.
63
+
64
+ b) accompany the distribution with the machine-readable source of
65
+ the software.
66
+
67
+ c) give non-standard executables non-standard names, with
68
+ instructions on where to get the original software distribution.
69
+
70
+ d) make other distribution arrangements with the author.
71
+
72
+ 4. You may modify and include the part of the software into any other
73
+ software (possibly commercial). But some files in the distribution
74
+ are not written by the author, so that they are not under this terms.
75
+
76
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
77
+ files under the ./missing directory. See each file for the copying
78
+ condition.
79
+
80
+ 5. The scripts and library files supplied as input to or produced as
81
+ output from the software do not automatically fall under the
82
+ copyright of the software, but belong to whomever generated them,
83
+ and may be sold commercially, and may be aggregated with this
84
+ software.
85
+
86
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
87
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
88
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
89
+ PURPOSE.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ # -*- ruby -*-
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # TODO
5
+ #
6
+ #require 'rubygems'
7
+ #require 'hoe'
8
+ #
9
+ #Hoe.plugin :git
10
+ #
11
+ #require_relative 'lib/svggraph'
12
+ #
13
+ #Hoe.spec 'svg-graph' do
14
+ # self.version=SVG::Graph::VERSION
15
+ # self.developer('Sean Russell', 'ser_AT_germane-software.com')
16
+ # self.developer('Claudio Bustos', 'clbustos_AT_gmail.com')
17
+ # self.developer('Liehann Loots','liehhanl_AT_gmail.com')
18
+ # self.developer('Piergiuliano Bossi','pgbossi_AT_gmail.com')
19
+ # self.developer('Manuel Widmer','m-widmer_AT_gmx.com')
20
+ # self.rubyforge_name = 'ruby-statsample' # if different than 'svg_graph'
21
+ # self.remote_rdoc_dir = 'svg-graph'
22
+ #end
23
+
24
+ # by default run all unit tests with 'rake test'
25
+ task default: [:test]
26
+
27
+ task :test do
28
+ [
29
+ "test/test_data_point.rb",
30
+ "test/test_plot.rb",
31
+ "test/test_svg_graph.rb",
32
+ "test/test_graph.rb",
33
+ "test/run_examples_and_percy.io.rb"
34
+ ].each do |file|
35
+ # exec all above scripts (with simplecov if env is set)
36
+ args = file
37
+ if ENV['COVERAGE']
38
+ args = '-r ./test/simplecov ' + file
39
+ end
40
+ ruby args
41
+ end
42
+ end
@@ -0,0 +1,154 @@
1
+ require 'rexml/document'
2
+ require_relative 'Graph'
3
+ require_relative 'BarBase'
4
+
5
+ module SVG
6
+ module Graph
7
+ # === Create presentation quality SVG bar graphs easily
8
+ #
9
+ # = Synopsis
10
+ #
11
+ # require 'SVG/Graph/Bar'
12
+ #
13
+ # fields = %w(Jan Feb Mar);
14
+ # data_sales_02 = [12, 45, 21]
15
+ #
16
+ # graph = SVG::Graph::Bar.new(
17
+ # :height => 500,
18
+ # :width => 300,
19
+ # :fields => fields
20
+ # )
21
+ #
22
+ # graph.add_data(
23
+ # :data => data_sales_02,
24
+ # :title => 'Sales 2002'
25
+ # )
26
+ #
27
+ # print "Content-type: image/svg+xml\r\n\r\n"
28
+ # print graph.burn
29
+ #
30
+ # = Description
31
+ #
32
+ # This object aims to allow you to easily create high quality
33
+ # SVG[http://www.w3c.org/tr/svg bar graphs. You can either use the default
34
+ # style sheet or supply your own. Either way there are many options which
35
+ # can be configured to give you control over how the graph is generated -
36
+ # with or without a key, data elements at each point, title, subtitle etc.
37
+ #
38
+ # = Notes
39
+ #
40
+ # The default stylesheet handles upto 12 data sets, if you
41
+ # use more you must create your own stylesheet and add the
42
+ # additional settings for the extra data sets. You will know
43
+ # if you go over 12 data sets as they will have no style and
44
+ # be in black.
45
+ #
46
+ # = Examples
47
+ #
48
+ # * http://germane-software.com/repositories/public/SVG/test/test.rb
49
+ #
50
+ # = See also
51
+ #
52
+ # * SVG::Graph::Graph
53
+ # * SVG::Graph::BarHorizontal
54
+ # * SVG::Graph::Line
55
+ # * SVG::Graph::Pie
56
+ # * SVG::Graph::Plot
57
+ # * SVG::Graph::TimeSeries
58
+ class Bar < BarBase
59
+ include REXML
60
+
61
+ protected
62
+
63
+ def get_x_labels
64
+ @config[:fields]
65
+ end
66
+
67
+ def get_y_labels
68
+ maxvalue = max_value
69
+ minvalue = min_value
70
+ range = maxvalue - minvalue
71
+ # add some padding on top of the graph
72
+ if range == 0
73
+ maxvalue += 10
74
+ else
75
+ maxvalue += range / 20.0
76
+ end
77
+ scale_range = maxvalue - minvalue
78
+
79
+ @y_scale_division = scale_divisions || (scale_range / 10.0)
80
+
81
+ if scale_integers
82
+ @y_scale_division = @y_scale_division < 1 ? 1 : @y_scale_division.round
83
+ end
84
+
85
+ rv = []
86
+ if maxvalue%@y_scale_division != 0
87
+ maxvalue = maxvalue + @y_scale_division
88
+ end
89
+ minvalue.step( maxvalue, @y_scale_division ) {|v| rv << v}
90
+ return rv
91
+ end
92
+
93
+ def x_label_offset( width )
94
+ width / 2.0
95
+ end
96
+
97
+ def draw_data
98
+ minvalue = min_value
99
+ fieldwidth = field_width
100
+
101
+ unit_size = field_height
102
+ bargap = bar_gap ? (fieldwidth < 10 ? fieldwidth / 2 : 10) : 0
103
+
104
+ bar_width = fieldwidth - bargap
105
+ bar_width /= @data.length if stack == :side
106
+
107
+ bottom = @graph_height
108
+
109
+ field_count = 0
110
+ @config[:fields].each_index { |i|
111
+ dataset_count = 0
112
+ for dataset in @data
113
+ total = 0
114
+ dataset[:data].each {|x|
115
+ total += x
116
+ }
117
+
118
+ # cases (assume 0 = +ve):
119
+ # value min length
120
+ # +ve +ve value - min
121
+ # +ve -ve value - 0
122
+ # -ve -ve value.abs - 0
123
+
124
+ value = dataset[:data][i] / @y_scale_division.to_f
125
+
126
+ left = (fieldwidth * field_count)
127
+
128
+ length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
129
+ # top is 0 if value is negative
130
+ top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size)
131
+ left += bar_width * dataset_count if stack == :side
132
+
133
+ @graph.add_element( "rect", {
134
+ "x" => left.to_s,
135
+ "y" => top.to_s,
136
+ "width" => bar_width.to_s,
137
+ "height" => length.to_s,
138
+ "class" => "fill#{dataset_count+1}"
139
+ })
140
+ value_string = ""
141
+ value_string += (@number_format % dataset[:data][i]) if show_actual_values
142
+ percent = 100.0 * dataset[:data][i] / total
143
+ value_string += " (" + percent.round.to_s + "%)" if show_percent
144
+ make_datapoint_text(left + bar_width/2.0, top - font_size/2, value_string)
145
+ # number format shall not apply to popup (use .to_s conversion)
146
+ add_popup(left + bar_width/2.0, top , value_string)
147
+ dataset_count += 1
148
+ end
149
+ field_count += 1
150
+ }
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,149 @@
1
+ require 'rexml/document'
2
+ require_relative 'Graph'
3
+
4
+ module SVG
5
+ module Graph
6
+ # = Synopsis
7
+ #
8
+ # A superclass for bar-style graphs. Do not attempt to instantiate
9
+ # directly; use one of the subclasses instead.
10
+ #
11
+ # = Author
12
+ #
13
+ # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
14
+ #
15
+ # Copyright 2004 Sean E. Russell
16
+ # This software is available under the Ruby license[LICENSE.txt]
17
+ #
18
+ class BarBase < SVG::Graph::Graph
19
+ # Ensures that :fields are provided in the configuration.
20
+ def initialize config
21
+ raise "fields was not supplied or is empty" unless config[:fields] &&
22
+ config[:fields].kind_of?(Array) &&
23
+ config[:fields].length > 0
24
+ super
25
+ end
26
+
27
+ # In addition to the defaults set in Graph::initialize, sets
28
+ # [bar_gap] true
29
+ # [stack] :overlap
30
+ def set_defaults
31
+ init_with( :bar_gap => true, :stack => :overlap, :show_percent => false, :show_actual_values => true)
32
+ end
33
+
34
+ # Whether to have a gap between the bars or not, default
35
+ # is true, set to false if you don't want gaps.
36
+ attr_accessor :bar_gap
37
+ # How to stack data sets. :overlap overlaps bars with
38
+ # transparent colors, :top stacks bars on top of one another,
39
+ # :side stacks the bars side-by-side. Defaults to :overlap.
40
+ attr_accessor :stack
41
+ # If true, display the percentage value of each bar. Default: false
42
+ attr_accessor :show_percent
43
+ # If true, display the actual field values in the data labels. Default: true
44
+ attr_accessor :show_actual_values
45
+ protected
46
+
47
+ # space in px between x-labels, we override the Graph version because
48
+ # we need the extra space (i.e. don't subtract 1 from get_x_labels.length)
49
+ def field_width
50
+ # don't use -1 otherwise bar is out of bounds
51
+ @graph_width.to_f / ( get_x_labels.length )
52
+ end
53
+
54
+ def max_value
55
+ @data.collect{|x| x[:data].max}.max
56
+ end
57
+
58
+ def min_value
59
+ min = 0
60
+ if min_scale_value.nil?
61
+ min = @data.collect{|x| x[:data].min}.min
62
+ # by default bar should always start from zero unless there are negative values
63
+ min = min > 0 ? 0 : min
64
+ else
65
+ min = min_scale_value
66
+ end
67
+ return min
68
+ end
69
+
70
+ def get_css
71
+ return <<EOL
72
+ /* default fill styles for multiple datasets (probably only use a single dataset on this graph though) */
73
+ .key1,.fill1{
74
+ fill: #ff0000;
75
+ fill-opacity: 0.5;
76
+ stroke: none;
77
+ stroke-width: 0.5px;
78
+ }
79
+ .key2,.fill2{
80
+ fill: #0000ff;
81
+ fill-opacity: 0.5;
82
+ stroke: none;
83
+ stroke-width: 1px;
84
+ }
85
+ .key3,.fill3{
86
+ fill: #00ff00;
87
+ fill-opacity: 0.5;
88
+ stroke: none;
89
+ stroke-width: 1px;
90
+ }
91
+ .key4,.fill4{
92
+ fill: #ffcc00;
93
+ fill-opacity: 0.5;
94
+ stroke: none;
95
+ stroke-width: 1px;
96
+ }
97
+ .key5,.fill5{
98
+ fill: #00ccff;
99
+ fill-opacity: 0.5;
100
+ stroke: none;
101
+ stroke-width: 1px;
102
+ }
103
+ .key6,.fill6{
104
+ fill: #ff00ff;
105
+ fill-opacity: 0.5;
106
+ stroke: none;
107
+ stroke-width: 1px;
108
+ }
109
+ .key7,.fill7{
110
+ fill: #00ffff;
111
+ fill-opacity: 0.5;
112
+ stroke: none;
113
+ stroke-width: 1px;
114
+ }
115
+ .key8,.fill8{
116
+ fill: #ffff00;
117
+ fill-opacity: 0.5;
118
+ stroke: none;
119
+ stroke-width: 1px;
120
+ }
121
+ .key9,.fill9{
122
+ fill: #cc6666;
123
+ fill-opacity: 0.5;
124
+ stroke: none;
125
+ stroke-width: 1px;
126
+ }
127
+ .key10,.fill10{
128
+ fill: #663399;
129
+ fill-opacity: 0.5;
130
+ stroke: none;
131
+ stroke-width: 1px;
132
+ }
133
+ .key11,.fill11{
134
+ fill: #339900;
135
+ fill-opacity: 0.5;
136
+ stroke: none;
137
+ stroke-width: 1px;
138
+ }
139
+ .key12,.fill12{
140
+ fill: #9966FF;
141
+ fill-opacity: 0.5;
142
+ stroke: none;
143
+ stroke-width: 1px;
144
+ }
145
+ EOL
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,155 @@
1
+ require 'rexml/document'
2
+ require_relative 'BarBase'
3
+
4
+ module SVG
5
+ module Graph
6
+ # === Create presentation quality SVG horitonzal bar graphs easily
7
+ #
8
+ # = Synopsis
9
+ #
10
+ # require 'SVG/Graph/BarHorizontal'
11
+ #
12
+ # fields = %w(Jan Feb Mar)
13
+ # data_sales_02 = [12, 45, 21]
14
+ #
15
+ # graph = SVG::Graph::BarHorizontal.new({
16
+ # :height => 500,
17
+ # :width => 300,
18
+ # :fields => fields,
19
+ # })
20
+ #
21
+ # graph.add_data({
22
+ # :data => data_sales_02,
23
+ # :title => 'Sales 2002',
24
+ # })
25
+ #
26
+ # print "Content-type: image/svg+xml\r\n\r\n"
27
+ # print graph.burn
28
+ #
29
+ # = Description
30
+ #
31
+ # This object aims to allow you to easily create high quality
32
+ # SVG horitonzal bar graphs. You can either use the default style sheet
33
+ # or supply your own. Either way there are many options which can
34
+ # be configured to give you control over how the graph is
35
+ # generated - with or without a key, data elements at each point,
36
+ # title, subtitle etc.
37
+ #
38
+ # = Examples
39
+ #
40
+ # * http://germane-software.com/repositories/public/SVG/test/test.rb
41
+ #
42
+ # = See also
43
+ #
44
+ # * SVG::Graph::Graph
45
+ # * SVG::Graph::Bar
46
+ # * SVG::Graph::Line
47
+ # * SVG::Graph::Pie
48
+ # * SVG::Graph::Plot
49
+ # * SVG::Graph::TimeSeries
50
+ #
51
+ # == Author
52
+ #
53
+ # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
54
+ #
55
+ # Copyright 2004 Sean E. Russell
56
+ # This software is available under the Ruby license[LICENSE.txt]
57
+ #
58
+ class BarHorizontal < BarBase
59
+ # In addition to the defaults set in BarBase::set_defaults, sets
60
+ # [rotate_y_labels] true
61
+ # [show_x_guidelines] true
62
+ # [show_y_guidelines] false
63
+ def set_defaults
64
+ super
65
+ init_with(
66
+ :rotate_y_labels => true,
67
+ :show_x_guidelines => true,
68
+ :show_y_guidelines => false
69
+ )
70
+ # self.right_align = self.right_font = 1
71
+ end
72
+
73
+ protected
74
+
75
+ def get_x_labels
76
+ maxvalue = max_value
77
+ minvalue = min_value
78
+ range = maxvalue - minvalue
79
+ top_pad = range == 0 ? 10 : range / 20.0
80
+ scale_range = (maxvalue + top_pad) - minvalue
81
+
82
+ @x_scale_division = scale_divisions || (scale_range / 10.0)
83
+
84
+ if scale_integers
85
+ @x_scale_division = @x_scale_division < 1 ? 1 : @x_scale_division.round
86
+ end
87
+
88
+ rv = []
89
+ #if maxvalue%@x_scale_division != 0
90
+ # maxvalue = maxvalue + @x_scale_division
91
+ #end
92
+ minvalue.step( maxvalue, @x_scale_division ) {|v| rv << v}
93
+ return rv
94
+ end
95
+
96
+ def get_y_labels
97
+ @config[:fields]
98
+ end
99
+
100
+ def y_label_offset( height )
101
+ height / -2.0
102
+ end
103
+
104
+ def draw_data
105
+ minvalue = min_value
106
+ fieldheight = field_height
107
+
108
+ bargap = bar_gap ? (fieldheight < 10 ? fieldheight / 2 : 10) : 0
109
+
110
+ bar_height = fieldheight - bargap
111
+ bar_height /= @data.length if stack == :side
112
+ y_mod = (bar_height / 2) + (font_size / 2)
113
+ field_count = 1
114
+
115
+ @config[:fields].each_index { |i|
116
+ dataset_count = 0
117
+ for dataset in @data
118
+ total = 0
119
+ dataset[:data].each {|x|
120
+ total += x
121
+ }
122
+ value = dataset[:data][i]
123
+
124
+ top = @graph_height - (fieldheight * field_count) + (bargap/2)
125
+ top += (bar_height * dataset_count) if stack == :side
126
+ # cases (assume 0 = +ve):
127
+ # value min length left
128
+ # +ve +ve value.abs - min minvalue.abs
129
+ # +ve -ve value.abs - 0 minvalue.abs
130
+ # -ve -ve value.abs - 0 minvalue.abs + value
131
+ length = (value.abs - (minvalue > 0 ? minvalue : 0))/@x_scale_division.to_f * field_width
132
+ left = (minvalue.abs + (value < 0 ? value : 0))/@x_scale_division.to_f * field_width
133
+
134
+ @graph.add_element( "rect", {
135
+ "x" => left.to_s,
136
+ "y" => top.to_s,
137
+ "width" => length.to_s,
138
+ "height" => bar_height.to_s,
139
+ "class" => "fill#{dataset_count+1}"
140
+ })
141
+ value_string = ""
142
+ value_string += (@number_format % dataset[:data][i]) if show_actual_values
143
+ percent = 100.0 * dataset[:data][i] / total
144
+ value_string += " (" + percent.round.to_s + "%)" if show_percent
145
+ make_datapoint_text(left+length+5, top+y_mod, value_string, "text-anchor: start; ")
146
+ # number format shall not apply to popup (use .to_s conversion)
147
+ add_popup(left+length, top+y_mod , value_string)
148
+ dataset_count += 1
149
+ end
150
+ field_count += 1
151
+ }
152
+ end
153
+ end
154
+ end
155
+ end