prawn_charts 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.md +87 -17
  2. data/lib/prawn_charts.rb +1 -2
  3. data/lib/prawn_charts/core_extensions.rb +7 -0
  4. data/lib/prawn_charts/data_collector.rb +68 -0
  5. data/lib/prawn_charts/data_points.rb +16 -0
  6. data/lib/prawn_charts/examples/linear_example.rb +55 -0
  7. data/lib/prawn_charts/examples/log_example.rb +56 -133
  8. data/lib/prawn_charts/helpers.rb +26 -0
  9. data/lib/prawn_charts/linear_vertical_data_collector.rb +23 -0
  10. data/lib/prawn_charts/log_vertical_data_collector.rb +27 -0
  11. data/lib/prawn_charts/prawn_chart_renderer.rb +139 -0
  12. data/lib/prawn_charts/renderer_assistant.rb +146 -0
  13. data/lib/prawn_charts/version.rb +1 -1
  14. data/spec/data_collector_spec.rb +64 -0
  15. data/spec/linear_vertical_data_collector_spec.rb +17 -0
  16. data/spec/log_vertical_data_collector.rb +12 -0
  17. data/todo +5 -0
  18. metadata +18 -31
  19. data/lib/prawn_charts/data_collectors/container/container_data_collector.rb +0 -59
  20. data/lib/prawn_charts/data_collectors/container/graph_title_data_collector.rb +0 -15
  21. data/lib/prawn_charts/data_collectors/graph/horizontal_lines_data_collector.rb +0 -22
  22. data/lib/prawn_charts/data_collectors/graph/linear_y_pdf_data_collector.rb +0 -23
  23. data/lib/prawn_charts/data_collectors/graph/log_y_pdf_data_collector.rb +0 -21
  24. data/lib/prawn_charts/data_collectors/graph/pdf_data_collector.rb +0 -26
  25. data/lib/prawn_charts/data_collectors/graph/x_labels_data_collector.rb +0 -29
  26. data/lib/prawn_charts/data_collectors/graph/x_pdf_data_collector.rb +0 -16
  27. data/lib/prawn_charts/data_collectors/graph/y_labels_data_collector.rb +0 -35
  28. data/lib/prawn_charts/data_collectors/graph/y_pdf_data_collector.rb +0 -21
  29. data/lib/prawn_charts/examples/simple_linear_example.rb +0 -59
  30. data/lib/prawn_charts/examples/simple_log_example.rb +0 -59
  31. data/lib/prawn_charts/renderers/prawn_chart_renderer.rb +0 -31
  32. data/spec/data_collectors/container/container_data_collector_spec.rb +0 -59
  33. data/spec/data_collectors/graph/horizontal_lines_data_collector_spec.rb +0 -19
  34. data/spec/data_collectors/graph/linear_y_pdf_data_collector_spec.rb +0 -19
  35. data/spec/data_collectors/graph/log_y_pdf_data_collector_spec.rb +0 -26
  36. data/spec/data_collectors/graph/pdf_data_collector_spec.rb +0 -49
  37. data/spec/data_collectors/graph/x_labels_data_collector_spec.rb +0 -20
  38. data/spec/data_collectors/graph/x_pdf_data_collector_spec.rb +0 -23
  39. 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
  ![alt tag](https://raw.github.com/MrPowers/prawn_charts/master/images/simple_linear_example.png)
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
- manipulating input data in a format suitable for the PrawnChartRenderer. The
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
- This example code shows how to use the PdfDataCollector to get formatted
35
- data that can be passed to the draw_chart() and draw_dots() methods:
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
- ```ruby
38
- Prawn::Document.extensions << PrawnChartRenderer
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
- pdf_data = PdfDataCollector.new(scale, input_data, graph_width_pdf, graph_height_pdf, y_labels).collect
45
- pdf.draw_chart(pdf_data)
46
- pdf.draw_dots(pdf_data, dot_radius)
47
- end
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
- There are separate methods to draw_chart(), draw_dots(), draw_labels(),
51
- draw_horizontal_lines(), and draw titles, so the charts can be customized.
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/data_collectors/**/*.rb"].each {|file| require file }
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,7 @@
1
+ class Hash
2
+ def dig(*path)
3
+ path.inject(self) do |location, key|
4
+ location.respond_to?(:keys) ? location[key] : nil
5
+ end
6
+ end
7
+ end
@@ -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 "../../prawn_charts"
2
-
3
- module PrawnCharts
4
- ##################################
5
- #Graph Data Collectors
6
- ##################################
7
- input_data = [["Apr-11", 5_000_000],
8
- ["May-11", nil],
9
- ["Jun-11", nil],
10
- ["Jul-11", nil],
11
- ["Aug-11", 1_000_000],
12
- ["Sep-11", nil],
13
- ["Oct-11", nil],
14
- ["Dec-11", 10_000],
15
- ["Jan-12", nil],
16
- ["Feb-12", nil],
17
- ["Mar-12", 150_000],
18
- ["Apr-12", nil],
19
- ["May-12", nil],
20
- ["Jun-12", 7_500_000]]
21
- scale = :log
22
- graph_height_pdf = 200
23
- graph_width_pdf = graph_height_pdf * 1.7
24
- dot_radius = 4
25
-
26
- x_label_width = 50
27
- x_label_height = 35
28
- x_label_text_box_options = { overflow: :shrink_to_fit, align: :center, rotate: 45 }
29
-
30
- y_labels = [0, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000]
31
- y_label_height = 30
32
- y_label_width = 65
33
- y_label_offset = 10
34
- y_label_text_box_options = { align: :right, valign: :center }
35
-
36
- graph_title_text = "Cool Prawn Graph"
37
- graph_title_height = 40
38
-
39
- y_title_width = 30
40
- y_title_text = "HCV Viral Load"
41
-
42
- x_title_height = 40
43
- x_title_text = "Month"
44
-
45
- pdf_data = PdfDataCollector.new(scale, input_data, graph_width_pdf, graph_height_pdf, y_labels).collect
46
- x_label_data = XLabelsDataCollector.new(input_data, graph_width_pdf, x_label_height, x_label_width).collect
47
- y_label_data = YLabelsDataCollector.new(y_labels, graph_height_pdf, y_label_width, y_label_height, y_label_offset).collect
48
- horizontal_lines_data = HorizontalLinesDataCollector.new(graph_height_pdf, graph_width_pdf, y_labels).collect
49
-
50
- ##################################
51
- #Container Data Collectors
52
- ##################################
53
-
54
- container_inputs = {
55
- container_left_padding: 0,
56
- y_label_offset: y_label_offset,
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")