prawn_charts 0.0.4 → 0.0.5
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/README.md +87 -17
- data/lib/prawn_charts.rb +1 -2
- data/lib/prawn_charts/core_extensions.rb +7 -0
- data/lib/prawn_charts/data_collector.rb +68 -0
- data/lib/prawn_charts/data_points.rb +16 -0
- data/lib/prawn_charts/examples/linear_example.rb +55 -0
- data/lib/prawn_charts/examples/log_example.rb +56 -133
- data/lib/prawn_charts/helpers.rb +26 -0
- data/lib/prawn_charts/linear_vertical_data_collector.rb +23 -0
- data/lib/prawn_charts/log_vertical_data_collector.rb +27 -0
- data/lib/prawn_charts/prawn_chart_renderer.rb +139 -0
- data/lib/prawn_charts/renderer_assistant.rb +146 -0
- data/lib/prawn_charts/version.rb +1 -1
- data/spec/data_collector_spec.rb +64 -0
- data/spec/linear_vertical_data_collector_spec.rb +17 -0
- data/spec/log_vertical_data_collector.rb +12 -0
- data/todo +5 -0
- metadata +18 -31
- data/lib/prawn_charts/data_collectors/container/container_data_collector.rb +0 -59
- data/lib/prawn_charts/data_collectors/container/graph_title_data_collector.rb +0 -15
- data/lib/prawn_charts/data_collectors/graph/horizontal_lines_data_collector.rb +0 -22
- data/lib/prawn_charts/data_collectors/graph/linear_y_pdf_data_collector.rb +0 -23
- data/lib/prawn_charts/data_collectors/graph/log_y_pdf_data_collector.rb +0 -21
- data/lib/prawn_charts/data_collectors/graph/pdf_data_collector.rb +0 -26
- data/lib/prawn_charts/data_collectors/graph/x_labels_data_collector.rb +0 -29
- data/lib/prawn_charts/data_collectors/graph/x_pdf_data_collector.rb +0 -16
- data/lib/prawn_charts/data_collectors/graph/y_labels_data_collector.rb +0 -35
- data/lib/prawn_charts/data_collectors/graph/y_pdf_data_collector.rb +0 -21
- data/lib/prawn_charts/examples/simple_linear_example.rb +0 -59
- data/lib/prawn_charts/examples/simple_log_example.rb +0 -59
- data/lib/prawn_charts/renderers/prawn_chart_renderer.rb +0 -31
- data/spec/data_collectors/container/container_data_collector_spec.rb +0 -59
- data/spec/data_collectors/graph/horizontal_lines_data_collector_spec.rb +0 -19
- data/spec/data_collectors/graph/linear_y_pdf_data_collector_spec.rb +0 -19
- data/spec/data_collectors/graph/log_y_pdf_data_collector_spec.rb +0 -26
- data/spec/data_collectors/graph/pdf_data_collector_spec.rb +0 -49
- data/spec/data_collectors/graph/x_labels_data_collector_spec.rb +0 -20
- data/spec/data_collectors/graph/x_pdf_data_collector_spec.rb +0 -23
- data/spec/data_collectors/graph/y_labels_data_collector_spec.rb +0 -21
data/README.md
CHANGED
@@ -10,7 +10,7 @@ charts in Prawn with no dependencies other than Prawn.
|
|
10
10
|
Clone the respository and run the following script to generate a PDF
|
11
11
|
file with a log graph on your Desktop:
|
12
12
|
```bash
|
13
|
-
$ ruby lib/examples/log_example.rb
|
13
|
+
$ ruby lib/prawn_charts/examples/log_example.rb
|
14
14
|
```
|
15
15
|
|
16
16
|
This script will generate a PDF file of a log graph that is only 6KB.
|
@@ -19,33 +19,103 @@ This script will generate a PDF file of a log graph that is only 6KB.
|
|
19
19
|
|
20
20
|
|
21
21
|
Prawn Charts can also be used to generate linear graphs. This graph
|
22
|
-
does not leverage built in features (i.e. graph title, y label, x label)
|
22
|
+
does not leverage some built in features (i.e. graph title, y label, x label)
|
23
23
|
and demonstrates that Prawn Charts is easily customizable.
|
24
24
|
|
25
25
|

|
26
26
|
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
Please send pull requests - they will be merged :)
|
30
|
+
|
27
31
|
## Code Organization
|
28
32
|
|
29
33
|
The DataCollectors (located in lib/data_collectors) are responsible for
|
30
|
-
|
31
|
-
PrawnChartRenderer module should be mixed in to Prawn::Document, so the
|
32
|
-
renderer methods can be called directly on the Prawn::Document object.
|
34
|
+
converting input data to pdf_points, so it can be graphed.
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
The RenderingAssistant is responsible for parsing the input hash and
|
37
|
+
combining user specified data with smart defaults. The graph is fully
|
38
|
+
customizable, but smart defaults allow for rapid prototyping.
|
36
39
|
|
37
|
-
|
38
|
-
Prawn::Document.
|
40
|
+
The PrawnChartRenderer module should be mixed in to Prawn::Document, so the
|
41
|
+
draw_graph method can be called directly on the Prawn::Document object.
|
42
|
+
See the lib/prawn_charts/examples/ directory for examples on how to use
|
43
|
+
this gem.
|
44
|
+
|
45
|
+
## Example Input
|
46
|
+
|
47
|
+
The entire log example is included in this README for easy reference:
|
39
48
|
|
49
|
+
```ruby
|
50
|
+
Prawn::Document.extensions << PrawnCharts::PrawnChartRenderer
|
40
51
|
pdf = Prawn::Document.new
|
41
|
-
pdf.bounding_box([50, pdf.cursor], :width => graph_width_pdf, :height => graph_height_pdf) do
|
42
|
-
pdf.stroke_bounds
|
43
52
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
53
|
+
data = [
|
54
|
+
{x_label: "Apr-11", y: 1_000},
|
55
|
+
{x_label: "May-11", y: nil},
|
56
|
+
{x_label: "Jun-11", y: nil},
|
57
|
+
{x_label: "Jul-11", y: nil},
|
58
|
+
{x_label: "Aug-11", y: 300_000},
|
59
|
+
{x_label: "Sep-11", y: nil},
|
60
|
+
{x_label: "Oct-11", y: nil},
|
61
|
+
{x_label: "Dec-11", y: 17},
|
62
|
+
{x_label: "Jan-12", y: nil},
|
63
|
+
{x_label: "Feb-12", y: nil},
|
64
|
+
{x_label: "Mar-12", y: 10},
|
65
|
+
{x_label: "Apr-12", y: nil},
|
66
|
+
{x_label: "May-12", y: nil},
|
67
|
+
{x_label: "Jun-12", y: 1_000_000}
|
68
|
+
]
|
69
|
+
|
70
|
+
orange = "D95D2E"
|
71
|
+
green = "62C545"
|
72
|
+
white = "FFFFFF"
|
73
|
+
|
74
|
+
colors = {
|
75
|
+
:rectangle_fill => white,
|
76
|
+
:line => green,
|
77
|
+
:dots => orange
|
78
|
+
}
|
79
|
+
|
80
|
+
input = {
|
81
|
+
:graph => {
|
82
|
+
:starting_point => [100, 400],
|
83
|
+
:width => 300,
|
84
|
+
:height => 200,
|
85
|
+
:data => data,
|
86
|
+
:y_labels => ["1", "10", "100", "1,000", "10,000", "100,000", "1,000,000"],
|
87
|
+
:scale => :log
|
88
|
+
},
|
89
|
+
:dots => {},
|
90
|
+
:y_labels => {
|
91
|
+
:offset => -62,
|
92
|
+
:text_box_options => {:width => 55, :align => :right}
|
93
|
+
},
|
94
|
+
:x_labels => {},
|
95
|
+
:horizontal_lines => true,
|
96
|
+
:graph_title => { :title => "cool graph" },
|
97
|
+
:x_title => { :title => "x title" },
|
98
|
+
:y_title => { :title => "y title", :offset => -60 },
|
99
|
+
}
|
100
|
+
|
101
|
+
pdf.draw_graph(input, colors)
|
102
|
+
|
103
|
+
pdf.render_file(Dir.home + "/desktop/log_prawn_graph.pdf")
|
48
104
|
```
|
49
105
|
|
50
|
-
|
51
|
-
|
106
|
+
The following code illustrates most of the inputs that can be set to
|
107
|
+
configure the graph:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
data = [{y: 5, x_label: "Jan 11"}, {y: 17, x_label: "Feb 11"}, {y: 14, x_label: "Mar 11"}]
|
111
|
+
input = {
|
112
|
+
:graph => {:starting_point => [100, 200], :width => 300, :height => 200, :data => data, :y_labels => [0, 5, 10, 15, 20]},
|
113
|
+
:dots => { :radius => 4 },
|
114
|
+
:horizontal_lines => true,
|
115
|
+
:graph_title => { :title => "cool graph", :offset => 50, :text_box_options => {} },
|
116
|
+
:x_title => { :title => "x title", :offset => -60, :text_box_options => {} },
|
117
|
+
:y_title => { :title => "y title", :offset => -50, :text_box_options => {} },
|
118
|
+
:x_labels => { :offset => -50, :text_box_options => { :width => 100, :height => 20, align: :center, rotate: 45 } },
|
119
|
+
:y_labels => { :offset => -40, :text_box_options => { :height => 40, valign: :center } }
|
120
|
+
}
|
121
|
+
```
|
data/lib/prawn_charts.rb
CHANGED
@@ -5,5 +5,4 @@ module PrawnCharts
|
|
5
5
|
end
|
6
6
|
|
7
7
|
lib_path = File.expand_path(File.dirname(__FILE__))
|
8
|
-
Dir["#{lib_path}/prawn_charts
|
9
|
-
Dir["#{lib_path}/prawn_charts/renderers/**/*.rb"].each {|file| require file }
|
8
|
+
Dir["#{lib_path}/prawn_charts/*.rb"].each {|file| require file }
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module PrawnCharts
|
2
|
+
class DataCollector
|
3
|
+
# Arranges graph data in an easy format for Prawn to process
|
4
|
+
attr_reader :height, :width, :data, :y_labels_units, :scale
|
5
|
+
def initialize(input)
|
6
|
+
@height = input.fetch(:height)
|
7
|
+
@width = input.fetch(:width)
|
8
|
+
@data = input.fetch(:data)
|
9
|
+
@y_labels_units = input.fetch(:y_labels)
|
10
|
+
@scale = input.fetch(:scale, :linear)
|
11
|
+
end
|
12
|
+
|
13
|
+
def y_labels
|
14
|
+
y_labels_units.inject([]) do |memo, label|
|
15
|
+
memo << { label: label.to_s, y: y_convert_to_pdf(label) }
|
16
|
+
memo
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def horizontal_lines
|
21
|
+
y_labels_units.map do |y|
|
22
|
+
y_pdf = y_convert_to_pdf(y)
|
23
|
+
[[0, y_pdf], [width, y_pdf]]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def data_points
|
28
|
+
@data_points ||= data.map.with_index do |data, index|
|
29
|
+
DataPoint.new(
|
30
|
+
x_units: index,
|
31
|
+
y_units: data[:y],
|
32
|
+
x_pdf: index * pdf_points_per_x_unit,
|
33
|
+
y_pdf: (y_convert_to_pdf(data[:y]) if data[:y]),
|
34
|
+
x_label: data[:x_label]
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def graph_points
|
40
|
+
data_points.select { |data_point| data_point.y_pdf }
|
41
|
+
end
|
42
|
+
|
43
|
+
def y_convert_to_pdf(n)
|
44
|
+
vertical_data_collector.convert_to_pdf(to_float(n))
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def to_float(object)
|
50
|
+
return object.gsub(",", "").to_f if object.instance_of? String
|
51
|
+
object.to_f
|
52
|
+
end
|
53
|
+
|
54
|
+
def vertical_data_collector
|
55
|
+
return LinearVerticalDataCollector.new(height, y_labels_units) if scale == :linear
|
56
|
+
LogVerticalDataCollector.new(height, y_labels_units)
|
57
|
+
end
|
58
|
+
|
59
|
+
# x methods
|
60
|
+
def max_x_units
|
61
|
+
data.length - 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def pdf_points_per_x_unit
|
65
|
+
width / max_x_units.to_f
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module PrawnCharts
|
2
|
+
class DataPoint
|
3
|
+
attr_reader :x_units, :y_units, :x_pdf, :y_pdf, :x_label
|
4
|
+
def initialize(input)
|
5
|
+
@x_units = input.fetch :x_units
|
6
|
+
@y_units = input.fetch :y_units
|
7
|
+
@x_pdf = input.fetch :x_pdf
|
8
|
+
@y_pdf = input.fetch :y_pdf
|
9
|
+
@x_label = input.fetch :x_label
|
10
|
+
end
|
11
|
+
|
12
|
+
def coordinate
|
13
|
+
[x_pdf, y_pdf]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative "./../../prawn_charts"
|
2
|
+
|
3
|
+
Prawn::Document.extensions << PrawnCharts::PrawnChartRenderer
|
4
|
+
pdf = Prawn::Document.new
|
5
|
+
|
6
|
+
data = [
|
7
|
+
{x_label: "Apr-11", y: 10},
|
8
|
+
{x_label: "May-11", y: nil},
|
9
|
+
{x_label: "Jun-11", y: nil},
|
10
|
+
{x_label: "Jul-11", y: nil},
|
11
|
+
{x_label: "Aug-11", y: 3},
|
12
|
+
{x_label: "Sep-11", y: nil},
|
13
|
+
{x_label: "Oct-11", y: nil},
|
14
|
+
{x_label: "Dec-11", y: 17},
|
15
|
+
{x_label: "Jan-12", y: nil},
|
16
|
+
{x_label: "Feb-12", y: nil},
|
17
|
+
{x_label: "Mar-12", y: 14},
|
18
|
+
{x_label: "Apr-12", y: nil},
|
19
|
+
{x_label: "May-12", y: nil},
|
20
|
+
{x_label: "Jun-12", y: 16}
|
21
|
+
]
|
22
|
+
|
23
|
+
orange = "D95D2E"
|
24
|
+
green = "62C545"
|
25
|
+
light_blue = "EDF1F7"
|
26
|
+
white = "FFFFFF"
|
27
|
+
black = "000000"
|
28
|
+
|
29
|
+
colors = {
|
30
|
+
:rectangle_border => black,
|
31
|
+
:rectangle_fill => white,
|
32
|
+
:line => green,
|
33
|
+
:dots => orange,
|
34
|
+
:x_labels => black,
|
35
|
+
:y_labels => black,
|
36
|
+
:horizontal_lines => black,
|
37
|
+
:graph_title => black,
|
38
|
+
:x_title => black,
|
39
|
+
:y_title => black
|
40
|
+
}
|
41
|
+
|
42
|
+
input = {
|
43
|
+
:graph => {:starting_point => [100, 400], :width => 300, :height => 200, :data => data, :y_labels => [0, 5, 10, 15, 20]},
|
44
|
+
:dots => {},
|
45
|
+
:y_labels => {},
|
46
|
+
:x_labels => {},
|
47
|
+
:horizontal_lines => true,
|
48
|
+
:graph_title => { :title => "cool graph" },
|
49
|
+
:x_title => { :title => "x title" },
|
50
|
+
:y_title => { :title => "y title" },
|
51
|
+
}
|
52
|
+
|
53
|
+
pdf.draw_graph(input, colors)
|
54
|
+
|
55
|
+
pdf.render_file(Dir.home + "/desktop/linear_prawn_graph.pdf")
|
@@ -1,133 +1,56 @@
|
|
1
|
-
require_relative "
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
y_label_width: y_label_width,
|
58
|
-
y_title_width: y_title_width,
|
59
|
-
container_right_padding: 20,
|
60
|
-
container_top_padding: 20,
|
61
|
-
graph_title_height: graph_title_height,
|
62
|
-
container_bottom_padding: 0,
|
63
|
-
x_label_height: x_label_height,
|
64
|
-
x_title_height: x_title_height,
|
65
|
-
graph_height: graph_height_pdf,
|
66
|
-
graph_width: graph_width_pdf
|
67
|
-
}
|
68
|
-
|
69
|
-
container_data_collector = ContainerDataCollector.new(container_inputs)
|
70
|
-
|
71
|
-
graph_title_position = container_data_collector.graph_title_top_left
|
72
|
-
graph_title_options = { align: :center, valign: :center}
|
73
|
-
graph_title_data = GraphTitleDataCollector.new(graph_title_text, graph_title_position, graph_title_height, graph_width_pdf).collect
|
74
|
-
|
75
|
-
y_title_position = container_data_collector.y_title_top_left
|
76
|
-
# specifying width is a temp hack solution because of a Prawn bug: https://github.com/prawnpdf/prawn/pull/505
|
77
|
-
y_title_options = { align: :center, valign: :center, rotate: 90, rotate_around: :center, width: 65 }
|
78
|
-
y_title_data = GraphTitleDataCollector.new(y_title_text, y_title_position, graph_height_pdf, y_title_width).collect
|
79
|
-
|
80
|
-
x_title_position = container_data_collector.x_title_top_left
|
81
|
-
x_title_options = { align: :center, valign: :center }
|
82
|
-
x_title_data = GraphTitleDataCollector.new(x_title_text, x_title_position, x_title_height, graph_width_pdf).collect
|
83
|
-
|
84
|
-
graph_top_left = container_data_collector.graph_top_left
|
85
|
-
|
86
|
-
##################################
|
87
|
-
#Colors
|
88
|
-
##################################
|
89
|
-
|
90
|
-
orange = "D95D2E"
|
91
|
-
green = "62C545"
|
92
|
-
light_blue = "EDF1F7"
|
93
|
-
white = "FFFFFF"
|
94
|
-
black = "000000"
|
95
|
-
|
96
|
-
##################################
|
97
|
-
#Create PDF
|
98
|
-
##################################
|
99
|
-
|
100
|
-
Prawn::Document.extensions << PrawnChartRenderer
|
101
|
-
|
102
|
-
pdf = Prawn::Document.new
|
103
|
-
pdf.bounding_box([0, pdf.cursor], :width => container_data_collector.width, :height => container_data_collector.height) do
|
104
|
-
pdf.stroke_bounds
|
105
|
-
pdf.fill_color = light_blue
|
106
|
-
pdf.fill_rectangle([0, pdf.cursor], container_data_collector.width, container_data_collector.height)
|
107
|
-
pdf.fill_color = black
|
108
|
-
|
109
|
-
pdf.draw_title(graph_title_data, graph_title_options)
|
110
|
-
pdf.draw_title(y_title_data, y_title_options)
|
111
|
-
pdf.draw_title(x_title_data, x_title_options)
|
112
|
-
|
113
|
-
pdf.bounding_box(container_data_collector.graph_top_left, :width => graph_width_pdf, :height => graph_height_pdf) do
|
114
|
-
pdf.stroke_bounds
|
115
|
-
pdf.fill_color = white
|
116
|
-
pdf.fill_rectangle([0, pdf.cursor], graph_width_pdf, graph_height_pdf)
|
117
|
-
|
118
|
-
pdf.stroke_color = green
|
119
|
-
pdf.draw_chart(pdf_data)
|
120
|
-
pdf.fill_color = orange
|
121
|
-
pdf.draw_dots(pdf_data, dot_radius)
|
122
|
-
|
123
|
-
pdf.fill_color = black
|
124
|
-
pdf.draw_labels(x_label_data, x_label_width, x_label_height, x_label_text_box_options)
|
125
|
-
|
126
|
-
pdf.draw_labels(y_label_data, y_label_width, y_label_height, y_label_text_box_options)
|
127
|
-
|
128
|
-
pdf.stroke_color = black
|
129
|
-
pdf.draw_horizontal_lines(horizontal_lines_data)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
pdf.render_file(Dir.home + "/desktop/log_prawn_graph.pdf")
|
133
|
-
end
|
1
|
+
require_relative "./../../prawn_charts"
|
2
|
+
|
3
|
+
Prawn::Document.extensions << PrawnCharts::PrawnChartRenderer
|
4
|
+
pdf = Prawn::Document.new
|
5
|
+
|
6
|
+
data = [
|
7
|
+
{x_label: "Apr-11", y: 1_000},
|
8
|
+
{x_label: "May-11", y: nil},
|
9
|
+
{x_label: "Jun-11", y: nil},
|
10
|
+
{x_label: "Jul-11", y: nil},
|
11
|
+
{x_label: "Aug-11", y: 300_000},
|
12
|
+
{x_label: "Sep-11", y: nil},
|
13
|
+
{x_label: "Oct-11", y: nil},
|
14
|
+
{x_label: "Dec-11", y: 17},
|
15
|
+
{x_label: "Jan-12", y: nil},
|
16
|
+
{x_label: "Feb-12", y: nil},
|
17
|
+
{x_label: "Mar-12", y: 10},
|
18
|
+
{x_label: "Apr-12", y: nil},
|
19
|
+
{x_label: "May-12", y: nil},
|
20
|
+
{x_label: "Jun-12", y: 1_000_000}
|
21
|
+
]
|
22
|
+
|
23
|
+
orange = "D95D2E"
|
24
|
+
green = "62C545"
|
25
|
+
white = "FFFFFF"
|
26
|
+
|
27
|
+
colors = {
|
28
|
+
:rectangle_fill => white,
|
29
|
+
:line => green,
|
30
|
+
:dots => orange
|
31
|
+
}
|
32
|
+
|
33
|
+
input = {
|
34
|
+
:graph => {
|
35
|
+
:starting_point => [100, 400],
|
36
|
+
:width => 300,
|
37
|
+
:height => 200,
|
38
|
+
:data => data,
|
39
|
+
:y_labels => ["1", "10", "100", "1,000", "10,000", "100,000", "1,000,000"],
|
40
|
+
:scale => :log
|
41
|
+
},
|
42
|
+
:dots => {},
|
43
|
+
:y_labels => {
|
44
|
+
:offset => -62,
|
45
|
+
:text_box_options => {:width => 55, :align => :right}
|
46
|
+
},
|
47
|
+
:x_labels => {},
|
48
|
+
:horizontal_lines => true,
|
49
|
+
:graph_title => { :title => "cool graph" },
|
50
|
+
:x_title => { :title => "x title" },
|
51
|
+
:y_title => { :title => "y title", :offset => -60 },
|
52
|
+
}
|
53
|
+
|
54
|
+
pdf.draw_graph(input, colors)
|
55
|
+
|
56
|
+
pdf.render_file(Dir.home + "/desktop/log_prawn_graph.pdf")
|