svg-graph 1.0.5 → 2.0.1
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.
- checksums.yaml +7 -0
- data/History.txt +18 -0
- data/README.markdown +90 -6
- data/Rakefile +26 -14
- data/lib/SVG/Graph/Bar.rb +2 -2
- data/lib/SVG/Graph/BarBase.rb +25 -24
- data/lib/SVG/Graph/BarHorizontal.rb +1 -1
- data/lib/SVG/Graph/ErrBar.rb +189 -0
- data/lib/SVG/Graph/Graph.rb +141 -64
- data/lib/SVG/Graph/Line.rb +1 -1
- data/lib/SVG/Graph/Pie.rb +76 -49
- data/lib/SVG/Graph/Plot.rb +2 -2
- data/lib/SVG/Graph/Schedule.rb +18 -19
- data/lib/SVG/Graph/TimeSeries.rb +26 -22
- data/lib/svggraph.rb +12 -10
- data/test/test_svg_graph.rb +48 -6
- metadata +41 -136
- data.tar.gz.sig +0 -2
- data/Manifest.txt +0 -56
- data/build.xml +0 -143
- data/dist.xml.in +0 -46
- data/images/bar.png +0 -0
- data/images/bar.svg +0 -76
- data/images/bar.svgz +0 -0
- data/images/barhorizontal.png +0 -0
- data/images/barhorizontal.svg +0 -76
- data/images/barhorizontal.svgz +0 -0
- data/images/line.png +0 -0
- data/images/line.svg +0 -80
- data/images/line.svgz +0 -0
- data/images/pie.png +0 -0
- data/images/pie.svg +0 -70
- data/images/pie.svgz +0 -0
- data/images/plot.png +0 -0
- data/images/plot.svg +0 -131
- data/images/plot.svgz +0 -0
- data/images/schedule.png +0 -0
- data/images/schedule.svg +0 -67
- data/images/timeseries.png +0 -0
- data/images/timeseries.svg +0 -179
- data/images/timeseries.svgz +0 -0
- data/index.xml +0 -281
- data/install.rb +0 -161
- data/screenshots.xml +0 -148
- data/style/common.xsl +0 -37
- data/style/release_html.xsl +0 -169
- data/style/release_txt.xsl +0 -25
- data/svg-graph.gemspec +0 -58
- data/test/data.txt +0 -4
- data/test/plot.rb +0 -51
- data/test/schedule.rb +0 -43
- data/test/single.rb +0 -33
- data/test/test.rb +0 -54
- data/test/test_data_point.rb +0 -67
- data/test/test_plot.rb +0 -282
- data/test/timeseries.rb +0 -58
- metadata.gz.sig +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a0a6c4dcff26a2412d42bb11f392ca6292afde8d
|
4
|
+
data.tar.gz: b91765dbbf54900ffeba3f665af1b17429e72d05
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d63ea323203f76843f1ba2b07b1db9522b7619a871467064b7f06e87e9e4d55f94404a263d513c1d295e38f2377cec4beaba53549c30f4d8142a91cc6ef26550
|
7
|
+
data.tar.gz: e682a1ee1c37dfdad7f95a52942334ba3f0eee7a001779cf0fd696745f3a7cdb5a54f265312351365992a7602d984e1b003297e1987d4cae170b8c0c096f8032
|
data/History.txt
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
TODO
|
2
|
+
* fix axis titles positioning for timeseries and schedule graphs
|
3
|
+
|
4
|
+
=== 2.0.0 / 2016-08-09
|
5
|
+
* dropped support for ruby 1.8.7 [lumean]
|
6
|
+
* Merge ErrBar graph from https://github.com/mondhs/svg-graph
|
7
|
+
* Merge number formatting to have more readable floats from https://github.com/mondhs/svg-graph
|
8
|
+
* fix warnings [lumean]
|
9
|
+
* make TimeSeries and Schedule work with ruby >2.0 and the Date/DateTime stdlib [lumean]
|
10
|
+
* dropped support for 'parsedate', instead TimeSeries and Schedule now accept a template to parse the date or time representation [lumean]
|
11
|
+
* all ruby files in the test directory now run on ruby >2.0 and write output to files [lumean]
|
12
|
+
* changed from autoload to static loading due to issues with unit-testing when the gem is not installed [lumean]
|
13
|
+
* begin transition to minitest for tests [lumean]
|
14
|
+
* merged fix for 100% pie graphs from https://github.com/endersstocker/svg-graph
|
15
|
+
* fix wrong margins for labels after merge of number formatting [lumean]
|
16
|
+
* Add new option for locations for the axis titles (at the end of the axis instead of below / left from it) [lumean]
|
17
|
+
* improved x-axis label location when x-axis marks are vertical and long [lumean]
|
18
|
+
|
1
19
|
=== 1.0.5 / 2011-09-03
|
2
20
|
* enabled all svg_graph tests[liehann]
|
3
21
|
|
data/README.markdown
CHANGED
@@ -1,14 +1,98 @@
|
|
1
|
-
SVG::
|
1
|
+
SVG::Graph
|
2
2
|
============
|
3
3
|
|
4
4
|
Description
|
5
5
|
-----------
|
6
|
-
This is
|
6
|
+
This is an effort to revive the [SVG::Graph library](http://www.germane-software.com/software/SVG/SVG::Graph/) by Sean Russell. I'd also like to thank Claudio Bustos for giving me permissions to continue publishing the gem under it's original name: [svg-graph](https://rubygems.org/gems/svg-graph)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
I'm
|
8
|
+
[Changelog](../master/History.txt)
|
9
|
+
|
10
|
+
I'm maintaing in my free time, so I can't promise on any deadlines. Please notify me (via github messages or on the Issues section) if you find any bug.
|
11
|
+
|
12
|
+
Contribute
|
13
|
+
-----
|
14
|
+
Pull requests are very welcome :-)
|
11
15
|
|
12
16
|
Usage
|
13
17
|
-----
|
14
|
-
|
18
|
+
|
19
|
+
For a complete list of configuration options please have a look at the source - most important [Graph.rb](../master/lib/SVG/Graph/Graph.rb), also checkout the subclasses (Pie, Bar, etc.) as they might provide additional options.
|
20
|
+
|
21
|
+
You can require everything at once
|
22
|
+
```ruby
|
23
|
+
require 'svggraph'
|
24
|
+
```
|
25
|
+
or only the individual parts you need
|
26
|
+
```ruby
|
27
|
+
require 'SVG/Graph/Bar'
|
28
|
+
require 'SVG/Graph/Line'
|
29
|
+
...
|
30
|
+
```
|
31
|
+
|
32
|
+
In the following some examples to get you up to speed.
|
33
|
+
|
34
|
+
### Bar
|
35
|
+
```ruby
|
36
|
+
require 'SVG/Graph/Bar'
|
37
|
+
|
38
|
+
x_axis = ['1-10', '10-30', '30-50', '50-70', 'older']
|
39
|
+
|
40
|
+
options = {
|
41
|
+
:width => 640,
|
42
|
+
:height => 300,
|
43
|
+
:stack => :side, # the stack option is valid for Bar graphs only
|
44
|
+
:fields => x_axis,
|
45
|
+
:graph_title => "kg per head and year chocolate consumption",
|
46
|
+
:show_graph_title => true,
|
47
|
+
:show_x_title => true,
|
48
|
+
:x_title => 'Age in years',
|
49
|
+
:show_y_title => true,
|
50
|
+
:y_title => 'kg/year',
|
51
|
+
:y_title_location => :end,
|
52
|
+
:no_css => true
|
53
|
+
}
|
54
|
+
|
55
|
+
male_data = [2, 4, 6, 4, 2]
|
56
|
+
female_data = [1, 5, 4, 5, 2.7]
|
57
|
+
|
58
|
+
g = SVG::Graph::Bar.new(options)
|
59
|
+
|
60
|
+
g.add_data( {
|
61
|
+
:data => female_data,
|
62
|
+
:title => "Female"
|
63
|
+
})
|
64
|
+
g.add_data( {
|
65
|
+
:data => male_data,
|
66
|
+
:title => "Male"
|
67
|
+
})
|
68
|
+
|
69
|
+
# graph.burn # this returns a full valid xml document containing the graph
|
70
|
+
# graph.burn_svg_only # this only returns the <svg>...</svg> node
|
71
|
+
File.open('bar.svg', 'w') {|f| f.write(g.burn_svg_only)}
|
72
|
+
```
|
73
|
+

|
74
|
+
|
75
|
+
### BarHorizontal
|
76
|
+
|
77
|
+
### ErrBar
|
78
|
+
|
79
|
+
### Line
|
80
|
+
|
81
|
+
### Pie
|
82
|
+
|
83
|
+
### Plot
|
84
|
+
|
85
|
+
### Schedule
|
86
|
+
|
87
|
+
### TimeSeries
|
88
|
+
|
89
|
+
|
90
|
+
Also have a look at the original [SVG::Graph web page](http://www.germane-software.com/software/SVG/SVG::Graph/), but note that this repository has already added some additional functionality, not available with the original.
|
91
|
+
|
92
|
+
Build
|
93
|
+
-----
|
94
|
+
|
95
|
+
* Build gem:
|
96
|
+
* gem build svg-graph.gemspec
|
97
|
+
* Install:
|
98
|
+
* gem install svg-graph-\<version>.gem
|
data/Rakefile
CHANGED
@@ -1,19 +1,31 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
# -*- coding: utf-8 -*-
|
3
|
-
$:.unshift(File.dirname(__FILE__)+"/lib/")
|
4
3
|
|
5
|
-
|
6
|
-
|
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
|
7
23
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
self.developer("Liehann Loots","liehhanl_AT_gmail.com")
|
16
|
-
self.developer("Piergiuliano Bossi","pgbossi_AT_gmail.com")
|
17
|
-
self.rubyforge_name = 'ruby-statsample' # if different than 'svg_graph'
|
18
|
-
self.remote_rdoc_dir = 'svg-graph'
|
24
|
+
# run all unit tests with 'rake test'
|
25
|
+
task default: %w[test]
|
26
|
+
|
27
|
+
task :test do
|
28
|
+
ruby "test/test_data_point.rb"
|
29
|
+
ruby "test/test_plot.rb"
|
30
|
+
ruby "test/test_svg_graph.rb"
|
19
31
|
end
|
data/lib/SVG/Graph/Bar.rb
CHANGED
data/lib/SVG/Graph/BarBase.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rexml/document'
|
2
|
-
|
2
|
+
require_relative 'Graph'
|
3
3
|
|
4
4
|
module SVG
|
5
5
|
module Graph
|
@@ -17,37 +17,38 @@ module SVG
|
|
17
17
|
#
|
18
18
|
class BarBase < SVG::Graph::Graph
|
19
19
|
# Ensures that :fields are provided in the configuration.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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 )
|
32
|
+
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
+
protected
|
42
|
+
|
43
|
+
def max_value
|
44
44
|
@data.collect{|x| x[:data].max}.max
|
45
|
-
|
45
|
+
end
|
46
46
|
|
47
47
|
def min_value
|
48
48
|
min = 0
|
49
49
|
if min_scale_value.nil?
|
50
50
|
min = @data.collect{|x| x[:data].min}.min
|
51
|
+
# by default bar should always start from zero unless there are negative values
|
51
52
|
min = min > 0 ? 0 : min
|
52
53
|
else
|
53
54
|
min = min_scale_value
|
@@ -0,0 +1,189 @@
|
|
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 ErrBar < BarBase
|
59
|
+
include REXML
|
60
|
+
|
61
|
+
def initialize config
|
62
|
+
raise "fields was not supplied or is empty" unless config[:errorBars] &&
|
63
|
+
config[:errorBars].kind_of?(Array) &&
|
64
|
+
config[:errorBars].length > 0
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# See Graph::initialize and BarBase::set_defaults
|
70
|
+
def set_defaults
|
71
|
+
super
|
72
|
+
self.top_align = self.top_font = 1
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def get_x_labels
|
78
|
+
@config[:fields]
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_y_labels
|
82
|
+
maxvalue = max_value
|
83
|
+
minvalue = min_value
|
84
|
+
range = maxvalue - minvalue
|
85
|
+
|
86
|
+
top_pad = range == 0 ? 10 : range / 20.0
|
87
|
+
scale_range = (maxvalue + top_pad) - minvalue
|
88
|
+
|
89
|
+
scale_division = scale_divisions || (scale_range / 10.0)
|
90
|
+
|
91
|
+
if scale_integers
|
92
|
+
scale_division = scale_division < 1 ? 1 : scale_division.round
|
93
|
+
end
|
94
|
+
|
95
|
+
rv = []
|
96
|
+
maxvalue = maxvalue%scale_division == 0 ?
|
97
|
+
maxvalue : maxvalue + scale_division
|
98
|
+
minvalue.step( maxvalue, scale_division ) {|v| rv << v}
|
99
|
+
return rv
|
100
|
+
end
|
101
|
+
|
102
|
+
def x_label_offset( width )
|
103
|
+
width / 2.0
|
104
|
+
end
|
105
|
+
|
106
|
+
def draw_data
|
107
|
+
minvalue = min_value
|
108
|
+
fieldwidth = field_width
|
109
|
+
|
110
|
+
unit_size = (@graph_height.to_f - font_size*2*top_font) /
|
111
|
+
(get_y_labels.max - get_y_labels.min)
|
112
|
+
bargap = bar_gap ? (fieldwidth < 10 ? fieldwidth / 2 : 10) : 0
|
113
|
+
|
114
|
+
bar_width = fieldwidth - (bargap *2)
|
115
|
+
bar_width /= @data.length if stack == :side
|
116
|
+
#x_mod = (@graph_width-bargap)/2 - (stack==:side ? bar_width/2 : 0)
|
117
|
+
|
118
|
+
bottom = @graph_height
|
119
|
+
|
120
|
+
field_count = 0
|
121
|
+
@config[:fields].each_index { |i|
|
122
|
+
dataset_count = 0
|
123
|
+
for dataset in @data
|
124
|
+
|
125
|
+
# cases (assume 0 = +ve):
|
126
|
+
# value min length
|
127
|
+
# +ve +ve value - min
|
128
|
+
# +ve -ve value - 0
|
129
|
+
# -ve -ve value.abs - 0
|
130
|
+
|
131
|
+
value = dataset[:data][i]
|
132
|
+
|
133
|
+
left = (fieldwidth * field_count)
|
134
|
+
left += bargap
|
135
|
+
|
136
|
+
|
137
|
+
length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
|
138
|
+
# top is 0 if value is negative
|
139
|
+
top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size)
|
140
|
+
left += bar_width * dataset_count if stack == :side
|
141
|
+
|
142
|
+
@graph.add_element( "rect", {
|
143
|
+
"x" => left.to_s,
|
144
|
+
"y" => top.to_s,
|
145
|
+
"width" => bar_width.to_s,
|
146
|
+
"height" => length.to_s,
|
147
|
+
"class" => "fill#{dataset_count+1}"
|
148
|
+
})
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
threshold = @config[:errorBars][i] * unit_size
|
153
|
+
middlePointErr = left+bar_width/2
|
154
|
+
upperErr = top+threshold
|
155
|
+
bottomErr = top-threshold
|
156
|
+
withthErr = bar_width/4
|
157
|
+
|
158
|
+
@graph.add_element( "line", {
|
159
|
+
"x1" => middlePointErr.to_s,
|
160
|
+
"y1" => upperErr.to_s,
|
161
|
+
"x2" => middlePointErr.to_s,
|
162
|
+
"y2" => bottomErr.to_s,
|
163
|
+
"style" => "stroke:rgb(0,0,0);stroke-width:1"
|
164
|
+
})
|
165
|
+
|
166
|
+
@graph.add_element( "line", {
|
167
|
+
"x1" => (middlePointErr-withthErr).to_s,
|
168
|
+
"y1" => upperErr.to_s,
|
169
|
+
"x2" => (middlePointErr+withthErr).to_s,
|
170
|
+
"y2" => upperErr.to_s,
|
171
|
+
"style" => "stroke:rgb(0,0,0);stroke-width:1"
|
172
|
+
})
|
173
|
+
@graph.add_element( "line", {
|
174
|
+
"x1" => (middlePointErr-withthErr).to_s,
|
175
|
+
"y1" => bottomErr.to_s,
|
176
|
+
"x2" => (middlePointErr+withthErr).to_s,
|
177
|
+
"y2" => bottomErr.to_s,
|
178
|
+
"style" => "stroke:rgb(0,0,0);stroke-width:1"
|
179
|
+
})
|
180
|
+
|
181
|
+
make_datapoint_text(left + bar_width/2.0, top - 6, value.to_s)
|
182
|
+
dataset_count += 1
|
183
|
+
end
|
184
|
+
field_count += 1
|
185
|
+
}
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|