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.
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")