gruff 0.15.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +21 -5
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +0 -12
  5. data/CHANGELOG.md +52 -0
  6. data/README.md +14 -3
  7. data/gruff.gemspec +3 -4
  8. data/lib/gruff/accumulator_bar.rb +1 -1
  9. data/lib/gruff/area.rb +6 -4
  10. data/lib/gruff/bar.rb +53 -32
  11. data/lib/gruff/base.rb +297 -186
  12. data/lib/gruff/bezier.rb +4 -2
  13. data/lib/gruff/box.rb +180 -0
  14. data/lib/gruff/bubble.rb +99 -0
  15. data/lib/gruff/bullet.rb +5 -5
  16. data/lib/gruff/candlestick.rb +120 -0
  17. data/lib/gruff/dot.rb +11 -12
  18. data/lib/gruff/font.rb +3 -0
  19. data/lib/gruff/helper/bar_conversion.rb +6 -10
  20. data/lib/gruff/helper/bar_mixin.rb +25 -0
  21. data/lib/gruff/helper/bar_value_label.rb +24 -43
  22. data/lib/gruff/helper/stacked_mixin.rb +19 -1
  23. data/lib/gruff/histogram.rb +9 -6
  24. data/lib/gruff/line.rb +67 -43
  25. data/lib/gruff/mini/legend.rb +15 -11
  26. data/lib/gruff/net.rb +23 -18
  27. data/lib/gruff/patch/string.rb +1 -0
  28. data/lib/gruff/pie.rb +26 -12
  29. data/lib/gruff/renderer/circle.rb +3 -1
  30. data/lib/gruff/renderer/dash_line.rb +3 -2
  31. data/lib/gruff/renderer/dot.rb +28 -15
  32. data/lib/gruff/renderer/line.rb +1 -3
  33. data/lib/gruff/renderer/rectangle.rb +6 -2
  34. data/lib/gruff/renderer/renderer.rb +0 -4
  35. data/lib/gruff/renderer/text.rb +7 -1
  36. data/lib/gruff/scatter.rb +84 -81
  37. data/lib/gruff/side_bar.rb +64 -31
  38. data/lib/gruff/side_stacked_bar.rb +43 -55
  39. data/lib/gruff/spider.rb +52 -14
  40. data/lib/gruff/stacked_area.rb +18 -8
  41. data/lib/gruff/stacked_bar.rb +59 -29
  42. data/lib/gruff/store/xy_data.rb +8 -9
  43. data/lib/gruff/store/xy_pointsizes_data.rb +60 -0
  44. data/lib/gruff/version.rb +1 -1
  45. data/lib/gruff.rb +11 -12
  46. metadata +14 -11
  47. data/lib/gruff/scene.rb +0 -208
  48. data/lib/gruff/store/custom_data.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c6b8682f3d05aa7d0a91ea58fbe907aa581f9a2ed7549f28376390fc0f2101ec
4
- data.tar.gz: 31dc3d1b680b887405a66d8c1d14a2baea76b549958f4cd92bf3d2a6adae8ba3
3
+ metadata.gz: 1b7a28fa80f8c598a927ce29242c2014a38cc21b1fc1fc43a80285239b448176
4
+ data.tar.gz: 13a94cca6581eebccafd48de9d48daa1acd4c085989cd996a6054fd63bfa8f8a
5
5
  SHA512:
6
- metadata.gz: 5b5e6a29b5acf50408dd03a75f7acaa8830d96cf23bc02d6ac7a5ef9d713afcc41157fc2e94be8ab1611c624bc36398ba0e6793228f9ce75be009f59a9ac9f7c
7
- data.tar.gz: 15766e34990536075a856d716d75f5e6d940f7bcb5d4dc9074040c82a8d418f95c0e3780bdbe36821a1c2aca66a07eaeaa11ff10622da7e29faf6347cac303af
6
+ metadata.gz: 165988fc75b87fcd15f789ee9b178cbbe4ddc32cd0090f62cdcd36041806223b65c59406cd855038e0881ffb0b260df146aec74de7caff5ee0fc32df01447268
7
+ data.tar.gz: c5dcff59b2f8ab733fc99bafee1472ab0c014fbb106bec26fca167880b585cc9e61a6cc00b4e08aa02d39a2fe92d2291a7363a13ed16673a06898edcd15fb081
@@ -6,9 +6,12 @@ on:
6
6
  pull_request:
7
7
  branches: [ master ]
8
8
 
9
+ permissions:
10
+ contents: read
11
+
9
12
  jobs:
10
13
  lint:
11
- runs-on: ubuntu-18.04
14
+ runs-on: ubuntu-20.04
12
15
  timeout-minutes: 20
13
16
  name: Lint
14
17
  steps:
@@ -23,31 +26,44 @@ jobs:
23
26
  - name: Install dependencies
24
27
  run: bundle install --path=vendor/bundle --jobs 4 --retry 3
25
28
  - name: RuboCop Problem Matchers
26
- uses: r7kamura/rubocop-problem-matchers-action@v1.1.0
29
+ uses: r7kamura/rubocop-problem-matchers-action@v1
27
30
  - name: Run tests
28
31
  run: bundle exec rubocop
29
32
 
30
33
  test-ruby:
31
- runs-on: ubuntu-18.04
34
+ runs-on: ubuntu-20.04
32
35
  timeout-minutes: 20
33
36
  strategy:
34
37
  matrix:
35
38
  ruby-version: ['2.5', '2.6', '2.7', '3.0', '3.1']
39
+ imagemagick-version:
40
+ - { full: 7.1.0-39, major-minor: '7.0' }
36
41
  name: Ruby ${{ matrix.ruby-version }}
37
42
  steps:
38
43
  - uses: actions/checkout@v3
44
+ - name: Cache ImageMagick
45
+ uses: actions/cache@v3
46
+ with:
47
+ path: ./build-ImageMagick
48
+ key: v1-linux-imagemagick-${{ matrix.imagemagick-version.full }}
49
+ restore-keys: |
50
+ v1-linux-imagemagick-${{ matrix.imagemagick-version.full }}
51
+ - name: Install ImageMagick ${{ matrix.imagemagick-version.full }}
52
+ run: |
53
+ export IMAGEMAGICK_VERSION=${{ matrix.imagemagick-version.full }}
54
+ ./before_install_linux.sh
39
55
  - name: Set up Ruby
40
56
  uses: ruby/setup-ruby@master
41
57
  with:
42
58
  ruby-version: ${{ matrix.ruby-version }}
43
- bundler-cache: true
59
+ bundler-cache: false
44
60
  - name: Install dependencies
45
61
  run: bundle install --path=vendor/bundle --jobs 4 --retry 3
46
62
  - name: Run tests
47
63
  run: bundle exec rake
48
64
 
49
65
  test-jruby:
50
- runs-on: ubuntu-18.04
66
+ runs-on: ubuntu-20.04
51
67
  timeout-minutes: 20
52
68
  strategy:
53
69
  matrix:
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *~
2
2
  /.idea/
3
3
  /pkg/
4
+ /doc/
4
5
  /coverage/
5
6
  /vendor/
6
7
  /test/output/
data/.rubocop.yml CHANGED
@@ -21,9 +21,6 @@ Gemspec/RequiredRubyVersion:
21
21
  Layout/AccessModifierIndentation:
22
22
  EnforcedStyle: outdent
23
23
 
24
- Layout/ClassStructure:
25
- Enabled: false
26
-
27
24
  Layout/FirstMethodArgumentLineBreak:
28
25
  Enabled: false
29
26
 
@@ -42,9 +39,6 @@ Layout/RedundantLineBreak:
42
39
  Layout/SingleLineBlockChain:
43
40
  Enabled: false
44
41
 
45
- Lint/AmbiguousOperatorPrecedence:
46
- Enabled: false
47
-
48
42
  Lint/ConstantResolution:
49
43
  Enabled: false
50
44
 
@@ -54,9 +48,6 @@ Lint/FloatComparison:
54
48
  Lint/NumberConversion:
55
49
  Enabled: false
56
50
 
57
- Naming/MemoizedInstanceVariableName:
58
- Enabled: false
59
-
60
51
  Naming/MethodParameterName:
61
52
  Enabled: false
62
53
 
@@ -128,6 +119,3 @@ Style/StructInheritance:
128
119
 
129
120
  Performance/ChainArrayAllocation:
130
121
  Enabled: false
131
-
132
- Performance/StringReplacement:
133
- Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.18.0
4
+ - Add Gruff::Bubble (#604)
5
+ - Rename Gruff::BoxPlot to Gruff::Box (#603)
6
+ - Mark Gruff::Scatter#disable_significant_rounding_x_axis= as deprecated (#602)
7
+ - Mark Gruff::Scatter#x_label_margin= as deprecated (#601)
8
+ - Mark Gruff::Scatter#use_vertical_x_labels= as deprecated (#600)
9
+
10
+ ## 0.17.0
11
+ - Add Gruff::Base#label_rotation= method to rotate bottom label (#599)
12
+ - Mark #label_stagger_height= as deprecated (#598)
13
+ - Fixed truncation of long legends in mini graph (#597)
14
+ - Fix error when input empty data in Gruff::Bezier (#596)
15
+ - Fix error when input empty data in Gruff::StackedArea (#595)
16
+ - Fix error when input empty data in Gruff::BoxPlot (#594)
17
+ - Fix error when input empty data in Gruff::Spider (#593)
18
+ - Fix error when input empty data in Gruff::Histogram (#592)
19
+ - Fix error when input empty data in Gruff::Area (#591)
20
+ - Stop adjusting the square radius in Gruff::Line (#589)
21
+ - Add diamond dot stype in Gruff::Line (#588)
22
+ - Allow title to be set as an array (#587)
23
+ - Allow labels to be set as an array corresponding to the data values (#586)
24
+ - Fixed a bug that breaks the colors in the theme when using the add_color method (#583)
25
+ - Ensure to raise an exception if use sort feature in Candlestick
26
+ - Fix column_count in BoxPlot/Candlestick (#581)
27
+ - Fix left/right graph margin (#579)
28
+
29
+ ## 0.16.0
30
+ - Add Candlestick (#575)
31
+ - Add BoxPlot (#574)
32
+ - Raise exception if less data set was given in Gruff::Spider (#573)
33
+ - Adjust default label offset value in Gruff::Pie
34
+ - Remove has_left_labels from attribute (#571)
35
+ - Remove center_labels_over_point from attribute (#570)
36
+ - Adjust legend label / box position
37
+ - Fix right margin when truncate the label
38
+ - Adjust axis label position
39
+ - Adjust left label margin
40
+ - Fix axis label position with hide_line_markers
41
+ - Fix margin of value label in Bar/StackedBar (#568)
42
+ - Fix label position in Gruff::Spider (#567)
43
+ - Fix axis label position with legend_at_bottom
44
+ - Fix axis label position with hide_line_markers
45
+ - Refactor: Remove instance variable usage
46
+ - Remove Gruff::Scene (#566)
47
+ - Fix exception with zero value in StackBar (#565)
48
+ - Fix segment spacing in SideStackedBar (#564)
49
+ - Fix margin of value label in SideBar/SideStackedBar (#563)
50
+ - Raise exception if negative values were given in stacked graph (#562)
51
+ - Fix centering in value label position (#561)
52
+ - Fix duck typing support in Gruff::Histogram (#560)
53
+ - Fix start drawing position to top in Pie and enabled sort option by default (#559)
54
+
3
55
  ## 0.15.0
4
56
  - Fix SideStackedBar which bars overlap on the coordinate axes if data contains 0 (#558)
5
57
  - Lazy loading library to reduce memory usage (#556)
data/README.md CHANGED
@@ -126,6 +126,17 @@ In progress!
126
126
 
127
127
  ![Histogram chart](https://raw.github.com/topfunky/gruff/master/test/expected/histogram.png)
128
128
 
129
+ ### Box chart
130
+
131
+ ![Box chart](https://raw.github.com/topfunky/gruff/master/test/expected/box.png)
132
+
133
+ ### Candlestick
134
+
135
+ ![Candlestick](https://raw.github.com/topfunky/gruff/master/test/expected/candlestick.png)
136
+
137
+ ### Bubble chart
138
+
139
+ ![Bubble chart](https://raw.github.com/topfunky/gruff/master/test/expected/bubble.png)
129
140
 
130
141
  ## Documentation
131
142
 
@@ -133,7 +144,7 @@ http://www.rubydoc.info/github/topfunky/gruff/frames
133
144
 
134
145
  ## Supported Ruby Versions
135
146
 
136
- - Ruby 2.4 or later
147
+ - Ruby 2.5 or later
137
148
  - JRuby 9.2.x or later
138
149
 
139
150
  ## Development
@@ -149,13 +160,13 @@ $ ./docker-launch.sh
149
160
 
150
161
  3. Run tests
151
162
  ```sh
152
- $ rake
163
+ $ bundle exec rake
153
164
  ```
154
165
 
155
166
  If you have made changes that involve updating the expected image, you need to update the image with the following command after running tests.
156
167
 
157
168
  ```sh
158
- $ rake test:image:update
169
+ $ bundle exec rake test:image:update
159
170
  ```
160
171
 
161
172
  ## Contributing
data/gruff.gemspec CHANGED
@@ -11,12 +11,11 @@ Gem::Specification.new do |s|
11
11
  s.authors = ['Geoffrey Grosenbach', 'Uwe Kubosch']
12
12
  s.description = 'Beautiful graphs for one or multiple datasets. Can be used on websites or in documents.'
13
13
  s.email = 'boss@topfunky.com'
14
- s.files = `git ls-files`.split.grep_v(/^test|^docker|^Rakefile/i)
14
+ s.files = `git ls-files`.split.grep_v(/^test|^docker|^before_install_linux.sh|^Rakefile/i)
15
15
  s.homepage = 'https://github.com/topfunky/gruff'
16
16
  s.require_paths = %w[lib]
17
17
  s.summary = 'Beautiful graphs for one or multiple datasets.'
18
18
  s.license = 'MIT'
19
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
19
  s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
21
20
  s.specification_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
21
 
@@ -25,7 +24,7 @@ Gem::Specification.new do |s|
25
24
  s.add_dependency 'rmagick4j'
26
25
  else
27
26
  s.add_dependency 'rmagick', '>= 4.2'
28
- s.add_development_dependency 'rubocop', '~> 1.27.0'
27
+ s.add_development_dependency 'rubocop', '~> 1.28.2'
29
28
  s.add_development_dependency 'rubocop-performance', '~> 1.13.3'
30
29
  s.add_development_dependency 'rubocop-rake', '~> 0.6.0'
31
30
  end
@@ -35,7 +34,7 @@ Gem::Specification.new do |s|
35
34
  s.add_development_dependency 'rake'
36
35
  s.add_development_dependency 'minitest-reporters'
37
36
  s.add_development_dependency 'simplecov'
38
- s.add_development_dependency 'yard', '~> 0.9.25'
37
+ s.add_development_dependency 'yard', '~> 0.9.28'
39
38
 
40
39
  s.metadata['rubygems_mfa_required'] = 'true'
41
40
  end
@@ -19,7 +19,7 @@ private
19
19
  def setup_data
20
20
  raise(Gruff::IncorrectNumberOfDatasetsException) unless store.length == 1
21
21
 
22
- accum_array = store.data.first.points[0..-2].reduce([0]) { |a, v| a << a.last + v }
22
+ accum_array = store.data.first.points[0..-2].reduce([0]) { |a, v| a << (a.last + v) }
23
23
  data 'Accumulator', accum_array
24
24
  set_colors
25
25
  store.reverse!
data/lib/gruff/area.rb CHANGED
@@ -30,15 +30,17 @@ private
30
30
  end
31
31
 
32
32
  def draw_graph
33
- x_increment = @graph_width / (column_count - 1).to_f
33
+ x_increment = (@graph_width / (column_count - 1)).to_f
34
34
 
35
35
  store.norm_data.each do |data_row|
36
+ next if data_row.points.empty?
37
+
36
38
  poly_points = []
37
39
 
38
40
  data_row.points.each_with_index do |data_point, index|
39
41
  # Use incremented x and scaled y
40
42
  new_x = @graph_left + (x_increment * index)
41
- new_y = @graph_top + (@graph_height - data_point * @graph_height)
43
+ new_y = @graph_top + (@graph_height - (data_point * @graph_height))
42
44
 
43
45
  poly_points << new_x
44
46
  poly_points << new_y
@@ -48,9 +50,9 @@ private
48
50
 
49
51
  # Add closing points, draw polygon
50
52
  poly_points << @graph_right
51
- poly_points << @graph_bottom - 1
53
+ poly_points << (@graph_bottom - 1)
52
54
  poly_points << @graph_left
53
- poly_points << @graph_bottom - 1
55
+ poly_points << (@graph_bottom - 1)
54
56
 
55
57
  Gruff::Renderer::Polygon.new(renderer, color: data_row.color, width: @stroke_width, opacity: @fill_opacity).render(poly_points)
56
58
  end
data/lib/gruff/bar.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'helper/bar_mixin'
4
+
3
5
  #
4
6
  # Gruff::Bar provide a bar graph that presents categorical data
5
7
  # with rectangular bars.
@@ -16,6 +18,8 @@
16
18
  # g.write('bar.png')
17
19
  #
18
20
  class Gruff::Bar < Gruff::Base
21
+ include BarMixin
22
+
19
23
  # Spacing factor applied between bars.
20
24
  attr_writer :bar_spacing
21
25
 
@@ -33,6 +37,10 @@ class Gruff::Bar < Gruff::Base
33
37
  # Prevent drawing of column labels below a bar graph. Default is +false+.
34
38
  attr_writer :hide_labels
35
39
 
40
+ # Value to avoid completely overwriting the coordinate axis
41
+ AXIS_MARGIN = 0.5
42
+ private_constant :AXIS_MARGIN
43
+
36
44
  # Can be used to adjust the spaces between the bars.
37
45
  # Accepts values between 0.00 and 1.00 where 0.00 means no spacing at all
38
46
  # and 1 means that each bars' width is nearly 0 (so each bar is a simple
@@ -70,15 +78,26 @@ private
70
78
  end
71
79
 
72
80
  def hide_left_label_area?
73
- @hide_line_markers
81
+ @hide_line_markers && @y_axis_label.nil?
74
82
  end
75
83
 
76
84
  def hide_bottom_label_area?
77
- hide_labels?
85
+ hide_labels? && @x_axis_label.nil? && @legend_at_bottom == false
78
86
  end
79
87
 
80
- # Value to avoid completely overwriting the coordinate axis
81
- AXIS_MARGIN = 0.5
88
+ def setup_graph_measurements
89
+ super
90
+ return if @hide_line_markers
91
+
92
+ if @show_labels_for_bar_values
93
+ if maximum_value >= 0
94
+ _, metrics = Gruff::BarValueLabel.metrics(maximum_value, @label_formatting, proc_text_metrics)
95
+ @graph_top += metrics.height
96
+ end
97
+
98
+ @graph_height = @graph_bottom - @graph_top
99
+ end
100
+ end
82
101
 
83
102
  def draw_graph
84
103
  # Setup spacing.
@@ -86,8 +105,8 @@ private
86
105
  # Columns sit side-by-side.
87
106
  @bar_spacing ||= @spacing_factor # space between the bars
88
107
 
89
- bar_width = (@graph_width - calculate_spacing) / (column_count * store.length).to_f
90
- padding = (bar_width * (1 - @bar_spacing)) / 2
108
+ bar_width = (@graph_width - calculate_spacing) / (column_count * store.length)
109
+ padding = (bar_width * (1 - @bar_spacing)) / 2.0
91
110
 
92
111
  # Setup the BarConversion Object
93
112
  conversion = Gruff::BarConversion.new(
@@ -95,34 +114,32 @@ private
95
114
  minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
96
115
  )
97
116
 
98
- # iterate over all normalised data
99
- store.norm_data.each_with_index do |data_row, row_index|
100
- data_row.points.each_with_index do |data_point, point_index|
101
- group_spacing = @group_spacing * @scale * point_index
102
-
103
- # Use incremented x and scaled y
104
- # x
105
- left_x = @graph_left + (bar_width * (row_index + point_index + ((store.length - 1) * point_index))) + padding + group_spacing
106
- right_x = left_x + bar_width * @bar_spacing
107
- # y
108
- left_y, right_y = conversion.get_top_bottom_scaled(data_point)
109
-
110
- # create new bar
111
- rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
112
- rect_renderer.render(left_x, left_y - AXIS_MARGIN, right_x, right_y - AXIS_MARGIN)
113
-
114
- # Calculate center based on bar_width and current row
115
- label_center = @graph_left + group_spacing + (store.length * bar_width * point_index) + (store.length * bar_width / 2.0)
116
-
117
- # Subtract half a bar width to center left if requested
118
- draw_label(label_center, point_index)
119
- if @show_labels_for_bar_values
120
- bar_value_label = Gruff::BarValueLabel::Bar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
121
- bar_value_label.prepare_rendering(@label_formatting, bar_width) do |x, y, text|
122
- draw_value_label(x, y, text)
117
+ group_left_x = @graph_left
118
+
119
+ normalized_group_bars.each_with_index do |group_bars, group_index|
120
+ right_x = 0
121
+ group_bars.each_with_index do |bar, index|
122
+ left_x = group_left_x + (bar_width * index) + padding
123
+ right_x = left_x + (bar_width * @bar_spacing)
124
+
125
+ top_y, bottom_y = conversion.get_top_bottom_scaled(bar.point)
126
+ if bar.point != 0
127
+ rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: bar.color)
128
+ rect_renderer.render(left_x, bottom_y - AXIS_MARGIN, right_x, top_y)
129
+ end
130
+
131
+ if @show_labels_for_bar_values && bar.value
132
+ bar_value_label = Gruff::BarValueLabel::Bar.new([left_x, top_y, right_x, bottom_y], bar.value)
133
+ bar_value_label.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, _text_width, text_height|
134
+ draw_value_label(bar_width * @bar_spacing, text_height, x, y, text)
123
135
  end
124
136
  end
125
137
  end
138
+
139
+ label_center = group_left_x + ((right_x - group_left_x) / 2.0)
140
+ draw_label(label_center, group_index)
141
+
142
+ group_left_x = right_x + padding + @group_spacing
126
143
  end
127
144
 
128
145
  # Draw the last label if requested
@@ -130,6 +147,10 @@ private
130
147
  end
131
148
 
132
149
  def calculate_spacing
133
- @scale * @group_spacing * (column_count - 1)
150
+ @group_spacing * (column_count - 1)
151
+ end
152
+
153
+ def proc_text_metrics
154
+ ->(text) { text_metrics(@marker_font, text) }
134
155
  end
135
156
  end