spark_pr 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +21 -0
- data/README +55 -0
- data/Rakefile +10 -0
- data/lib/spark_pr.rb +4 -0
- data/lib/spark_pr/spark.rb +117 -0
- data/lib/spark_pr/spark_canvas.rb +115 -0
- data/lib/spark_pr/version.rb +3 -0
- data/spark_pr.gemspec +25 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2ae3c06cbc2f596478b629cbe0cb1633f69588ba
|
4
|
+
data.tar.gz: 74c01a3c6803ab55cd31525efe57ac7e698232d7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7409d7d0e046cb2a45b1396ea6339e4aaf56a231057df192a62680f0b022e399bcc73726bd3b53e992f18bc0aa069c5ebbcd3ba01000afb780325c50ba7ab43
|
7
|
+
data.tar.gz: 5085572f5d9a30797ddfb0abe294b26649403081516916379b46192e64ea88877b239e41eed635ffbc42bd3dbabe9036a5790e838fa507e0d4302828103198a9
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2005 Thomas Fuchs
|
2
|
+
http://mir.aculo.us/
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
spark_pr is a Ruby class to generate sparkline graphs with PNG or ASCII output.
|
2
|
+
|
3
|
+
It only depends on zlib and generates PNGs with pure Ruby code.
|
4
|
+
The line-graph outputs antialised lines.
|
5
|
+
|
6
|
+
Example for PNG output:
|
7
|
+
|
8
|
+
File.open( 'test.png', 'wb' ) do |png|
|
9
|
+
png << Spark.plot( [47, 43, 24, 47, 16, 28, 38, 57, 50, 76,
|
10
|
+
42, 20, 98, 34, 53, 1, 55, 74, 63, 38,
|
11
|
+
31, 98, 89],
|
12
|
+
:has_min => true, :has_max => true, 'has_last' => 'true',
|
13
|
+
'height' => '40', :step => 10, :normalize => 'logarithmic' )
|
14
|
+
end
|
15
|
+
|
16
|
+
Example ASCII output:
|
17
|
+
|
18
|
+
spark = Spark.new({:has_min => true, :has_max => true, :height => 14, :step => 4})
|
19
|
+
puts spark.smooth( [47, 43, 24, 47, 16, 28, 38, 57, 50, 76,
|
20
|
+
42, 1, 98, 34, 53, 97, 55, 74, 63, 38,
|
21
|
+
31, 98, 89] ).to_ascii
|
22
|
+
|
23
|
+
The PNG output can also be obtained in data: URI format convenient for web
|
24
|
+
use. If the Spark.data_uri is used, there is also a dependency on Base64,
|
25
|
+
which is a standard library just like Zlib
|
26
|
+
|
27
|
+
You can paste the output from:
|
28
|
+
|
29
|
+
Spark.data_uri( [47, 43, 24, 47, 16, 28, 38, 57, 50, 76,
|
30
|
+
42, 20, 98, 34, 53, 1, 55, 74, 63, 38,
|
31
|
+
31, 98, 89],
|
32
|
+
:has_min => true, :has_max => true, 'has_last' => 'true',
|
33
|
+
'height' => '40', :step => 10, :normalize => 'logarithmic' )
|
34
|
+
|
35
|
+
into your browser's address and see the PNG directly.
|
36
|
+
|
37
|
+
Class based usage:
|
38
|
+
|
39
|
+
spark = Spark.new(:has_min => true, :has_max => true, 'has_last' => 'true',
|
40
|
+
'height' => '40', :step => 10, :normalize => 'logarithmic' )
|
41
|
+
spark.smooth(data)
|
42
|
+
|
43
|
+
File.open( 'test.png', 'wb' ) do |png|
|
44
|
+
png << spark.png
|
45
|
+
end
|
46
|
+
|
47
|
+
img_src = spark.data_uri
|
48
|
+
|
49
|
+
|
50
|
+
The SparkCanvas class can also be used for other drawing operations,
|
51
|
+
it provides drawing canvas with alpha blending and some primitive graphics
|
52
|
+
operations and PNG output in just about 100 lines of Ruby code.
|
53
|
+
|
54
|
+
Pure Ruby sparklines are released under the terms of the MIT-LICENSE.
|
55
|
+
See the included MIT-LICENSE file for details.
|
data/Rakefile
ADDED
data/lib/spark_pr.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require_relative 'spark_canvas'
|
3
|
+
|
4
|
+
class Spark
|
5
|
+
attr_accessor :opts, :png, :canvas
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
# process options
|
9
|
+
o = options.inject({}) do |o, (key, value)|
|
10
|
+
o[key.to_sym] = value ; o
|
11
|
+
end
|
12
|
+
[:height, :width, :step].each do |k|
|
13
|
+
o[k] = o[k].to_i if o.has_key?(k)
|
14
|
+
end
|
15
|
+
[:has_min, :has_max, :has_last].each do |k|
|
16
|
+
o[k] = (o[k] ? true : false) if o.has_key?(k)
|
17
|
+
end
|
18
|
+
o[:normalize] ||= :linear
|
19
|
+
o[:normalize] = o[:normalize].to_sym
|
20
|
+
|
21
|
+
self.opts = o
|
22
|
+
end
|
23
|
+
|
24
|
+
# normalize arr to contain values between 0..1 inclusive
|
25
|
+
def normalize( arr, type = :linear )
|
26
|
+
arr = arr.map{|v| Math.log(v) } if type == :logarithmic
|
27
|
+
adj, fac = arr.min, arr.max-arr.min
|
28
|
+
arr.map {|v| (v-adj).quo(fac) rescue 0 }
|
29
|
+
end
|
30
|
+
|
31
|
+
def smooth( results )
|
32
|
+
o = {
|
33
|
+
:step => 2,
|
34
|
+
:height => 14,
|
35
|
+
:has_min => false,
|
36
|
+
:has_max => false
|
37
|
+
}.merge(opts)
|
38
|
+
|
39
|
+
o[:width] ||= (results.size-1)*o[:step] + 5
|
40
|
+
|
41
|
+
c = SparkCanvas.new(o[:width], o[:height])
|
42
|
+
|
43
|
+
results = normalize(results, o[:normalize])
|
44
|
+
fac = c.height-5
|
45
|
+
i = -o[:step]
|
46
|
+
coords = results.map do |r|
|
47
|
+
[(i += o[:step])+2, c.height - 3 - r*fac ]
|
48
|
+
end
|
49
|
+
|
50
|
+
c.color = opts[:line_color] || [0xB0, 0xB0, 0xB0, 0xFF]
|
51
|
+
c.polyline coords
|
52
|
+
|
53
|
+
if o[:has_min]
|
54
|
+
min_pt = coords[results.index(results.min)]
|
55
|
+
c.color = [0x80, 0x80, 0x00, 0x70]
|
56
|
+
c.rectangle(min_pt[0]-2, min_pt[1]-2, min_pt[0]+2, min_pt[1]+2)
|
57
|
+
end
|
58
|
+
|
59
|
+
if o[:has_max]
|
60
|
+
max_pt = coords[results.index(results.max)]
|
61
|
+
c.color = [0x00, 0x80, 0x00, 0x70]
|
62
|
+
c.rectangle(max_pt[0]-2, max_pt[1]-2, max_pt[0]+2, max_pt[1]+2)
|
63
|
+
end
|
64
|
+
|
65
|
+
if o[:has_last]
|
66
|
+
c.color = [0xFF, 0x00, 0x00, 0x70]
|
67
|
+
c.rectangle(coords.last[0]-2, coords.last[1]-2, coords.last[0]+2, coords.last[1]+2)
|
68
|
+
end
|
69
|
+
self.png = c.to_png
|
70
|
+
self.canvas = c
|
71
|
+
end
|
72
|
+
|
73
|
+
def discrete( results )
|
74
|
+
o = {
|
75
|
+
:height => 14,
|
76
|
+
:upper => 0.5,
|
77
|
+
:has_min => false,
|
78
|
+
:has_max => false
|
79
|
+
}.merge(opts)
|
80
|
+
|
81
|
+
o[:width] ||= results.size*2-1
|
82
|
+
|
83
|
+
c = SparkCanvas.new(o[:width], o[:height])
|
84
|
+
|
85
|
+
results = normalize(results, o[:normalize])
|
86
|
+
fac = c.height-4
|
87
|
+
|
88
|
+
i = -2
|
89
|
+
results.each do |r|
|
90
|
+
p = c.height - 4 - r*fac
|
91
|
+
c.color = r < o[:upper] ? [0x66,0x66,0x66,0xFF] : [0xFF,0x00,0x00,0xFF]
|
92
|
+
c.line(i+=2, p, i, p+3)
|
93
|
+
end
|
94
|
+
|
95
|
+
self.png = c.to_png
|
96
|
+
self.canvas = c
|
97
|
+
end
|
98
|
+
|
99
|
+
def data_uri
|
100
|
+
%{data:image/png;base64,#{Base64.encode64(png).gsub("\n",'')}}
|
101
|
+
end
|
102
|
+
|
103
|
+
# convenience methods
|
104
|
+
def self.plot( results, options = {} )
|
105
|
+
spark = Spark.new(options)
|
106
|
+
type = opts.delete(:type) || :smooth
|
107
|
+
spark.send(type, results, o).to_png
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.data_uri( results, options = {} )
|
111
|
+
spark = Spark.new(options)
|
112
|
+
type = spark.opts.delete(:type) || :smooth
|
113
|
+
spark.send(type, results )
|
114
|
+
spark.data_uri
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# pure ruby sparklines module, generates PNG or ASCII
|
2
|
+
# contact thomas@fesch.at for questions
|
3
|
+
#
|
4
|
+
# strives to be somewhat compatible with sparklines lib by
|
5
|
+
# {Dan Nugent}[mailto:nugend@gmail.com] and {Geoffrey Grosenbach}[mailto:boss@topfunky.com]
|
6
|
+
#
|
7
|
+
# png creation based on http://www.whytheluckystiff.net/bumpspark/
|
8
|
+
|
9
|
+
require 'zlib'
|
10
|
+
|
11
|
+
class SparkCanvas
|
12
|
+
|
13
|
+
attr_accessor :color
|
14
|
+
attr_reader :width, :height
|
15
|
+
|
16
|
+
def initialize(width,height)
|
17
|
+
@canvas = []
|
18
|
+
@height = height
|
19
|
+
@width = width
|
20
|
+
height.times{ @canvas << [[0xFF,0xFF,0xFF]]*width }
|
21
|
+
@color = [0,0,0,0xFF] #RGBA
|
22
|
+
end
|
23
|
+
|
24
|
+
# alpha blends two colors, using the alpha given by c2
|
25
|
+
def blend(c1, c2)
|
26
|
+
(0..2).map{ |i| (c1[i]*(0xFF-c2[3]) + c2[i]*c2[3]) >> 8 }
|
27
|
+
end
|
28
|
+
|
29
|
+
# calculate a new alpha given a 0-0xFF intensity
|
30
|
+
def intensity(c,i)
|
31
|
+
[c[0],c[1],c[2],(c[3]*i) >> 8]
|
32
|
+
end
|
33
|
+
|
34
|
+
# calculate perceptive grayscale value
|
35
|
+
def grayscale(c)
|
36
|
+
(c[0]*0.3 + c[1]*0.59 + c[2]*0.11).to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
def point(x,y,color = nil)
|
40
|
+
return if x<0 or y<0 or x>@width-1 or y>@height-1
|
41
|
+
@canvas[y][x] = blend(@canvas[y][x], color || @color)
|
42
|
+
end
|
43
|
+
|
44
|
+
def rectangle(x0, y0, x1, y1)
|
45
|
+
x0, y0, x1, y1 = x0.to_i, y0.to_i, x1.to_i, y1.to_i
|
46
|
+
x0, x1 = x1, x0 if x0 > x1
|
47
|
+
y0, y1 = y1, y0 if y0 > y1
|
48
|
+
x0.upto(x1) { |x| y0.upto(y1) { |y| point x, y } }
|
49
|
+
end
|
50
|
+
|
51
|
+
# draw an antialiased line
|
52
|
+
# google for "wu antialiasing"
|
53
|
+
def line(x0, y0, x1, y1)
|
54
|
+
# clean params
|
55
|
+
x0, y0, x1, y1 = x0.to_i, y0.to_i, x1.to_i, y1.to_i
|
56
|
+
y0, y1, x0, x1 = y1, y0, x1, x0 if y0>y1
|
57
|
+
sx = (dx = x1-x0) < 0 ? -1 : 1 ; dx *= sx ; dy = y1-y0
|
58
|
+
|
59
|
+
# special cases
|
60
|
+
x0.step(x1,sx) { |x| point x, y0 } and return if dy.zero?
|
61
|
+
y0.upto(y1) { |y| point x0, y } and return if dx.zero?
|
62
|
+
x0.step(x1,sx) { |x| point x, y0; y0 += 1 } and return if dx==dy
|
63
|
+
|
64
|
+
# main loops
|
65
|
+
point x0, y0
|
66
|
+
|
67
|
+
e_acc = 0
|
68
|
+
if dy > dx
|
69
|
+
e = (dx << 16) / dy
|
70
|
+
y0.upto(y1-1) do
|
71
|
+
e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
|
72
|
+
x0 += sx if (e_acc <= e_acc_temp)
|
73
|
+
point x0, (y0 += 1), intensity(@color,(w=0xFF-(e_acc >> 8)))
|
74
|
+
point x0+sx, y0, intensity(@color,(0xFF-w))
|
75
|
+
end
|
76
|
+
point x1, y1
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
e = (dy << 16) / dx
|
81
|
+
x0.step(x1-sx,sx) do
|
82
|
+
e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
|
83
|
+
y0 += 1 if (e_acc <= e_acc_temp)
|
84
|
+
point (x0 += sx), y0, intensity(@color,(w=0xFF-(e_acc >> 8)))
|
85
|
+
point x0, y0+1, intensity(@color,(0xFF-w))
|
86
|
+
end
|
87
|
+
point x1, y1
|
88
|
+
end
|
89
|
+
|
90
|
+
def polyline(arr)
|
91
|
+
(0...arr.size-1).each{ |i| line(arr[i][0], arr[i][1], arr[i+1][0], arr[i+1][1]) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_png
|
95
|
+
header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
|
96
|
+
raw_data = @canvas.map { |row| [0] + row }.flatten.pack("C*")
|
97
|
+
ihdr_data = [@canvas.first.length,@canvas.length,8,2,0,0,0].pack("NNCCCCC")
|
98
|
+
|
99
|
+
header +
|
100
|
+
build_png_chunk("IHDR", ihdr_data) +
|
101
|
+
build_png_chunk("tRNS", ([ 0xFF ]*6).pack("C6")) +
|
102
|
+
build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data)) +
|
103
|
+
build_png_chunk("IEND", "")
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_png_chunk(type,data)
|
107
|
+
to_check = type + data
|
108
|
+
[data.length].pack("N") + to_check + [Zlib.crc32(to_check)].pack("N")
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_ascii
|
112
|
+
chr = %w(M O # + ; - .) << ' '
|
113
|
+
@canvas.map{ |r| r.map { |pt| chr[grayscale(pt) >> 5] }.join << "\n" }.join
|
114
|
+
end
|
115
|
+
end
|
data/spark_pr.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'spark_pr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "spark_pr"
|
8
|
+
spec.version = SparkPr::VERSION
|
9
|
+
spec.authors = ["Thomas Fuchs", "Rob Biedenharn", "Lukas Eklund"]
|
10
|
+
spec.email = ["leklund@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Pure Ruby sparkline graph generator with PNG or ASCII output}
|
13
|
+
spec.description = %q{spark_pr is a Ruby class to generate sparkline graphs with PNG or ASCII output. It only depends on zlib and generates PNGs with pure Ruby code. The line-graph outputs antialised lines.}
|
14
|
+
spec.homepage = "https://github.com/leklund/spark_pr"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "minitest"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spark_pr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas Fuchs
|
8
|
+
- Rob Biedenharn
|
9
|
+
- Lukas Eklund
|
10
|
+
autorequire:
|
11
|
+
bindir: exe
|
12
|
+
cert_chain: []
|
13
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bundler
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.10'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.10'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '10.0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '10.0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: minitest
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
description: spark_pr is a Ruby class to generate sparkline graphs with PNG or ASCII
|
58
|
+
output. It only depends on zlib and generates PNGs with pure Ruby code. The line-graph
|
59
|
+
outputs antialised lines.
|
60
|
+
email:
|
61
|
+
- leklund@gmail.com
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- ".gitignore"
|
67
|
+
- Gemfile
|
68
|
+
- MIT-LICENSE
|
69
|
+
- README
|
70
|
+
- Rakefile
|
71
|
+
- lib/spark_pr.rb
|
72
|
+
- lib/spark_pr/spark.rb
|
73
|
+
- lib/spark_pr/spark_canvas.rb
|
74
|
+
- lib/spark_pr/version.rb
|
75
|
+
- spark_pr.gemspec
|
76
|
+
homepage: https://github.com/leklund/spark_pr
|
77
|
+
licenses:
|
78
|
+
- MIT
|
79
|
+
metadata: {}
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.4.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: Pure Ruby sparkline graph generator with PNG or ASCII output
|
100
|
+
test_files: []
|