gruff 0.15.0-java → 0.18.0-java

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 (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 +9 -6
  47. data/lib/gruff/scene.rb +0 -208
  48. data/lib/gruff/store/custom_data.rb +0 -36
data/lib/gruff/scene.rb DELETED
@@ -1,208 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'observer'
4
-
5
- # A scene is a non-linear graph that assembles layers together to tell a story.
6
- # Layers are folders with appropriately named files (see below). You can group
7
- # layers and control them together or just set their values individually.
8
- #
9
- # Examples:
10
- #
11
- # * A city scene that changes with the time of day and the weather conditions.
12
- # * A traffic map that shows red lines on streets that are crowded and green on free-flowing ones.
13
- #
14
- # g = Gruff::Scene.new("500x100", "path/to/city_scene_directory")
15
- #
16
- # # Define order of layers, back to front
17
- # g.layers = %w(background haze sky clouds)
18
- #
19
- # # Define groups that will be controlled by the same input
20
- # g.weather_group = %w(clouds)
21
- # g.time_group = %w(background sky)
22
- #
23
- # # Set values for the layers or groups
24
- # g.weather = "cloudy"
25
- # g.time = Time.now
26
- # g.haze = true
27
- #
28
- # # Write the final graph to disk
29
- # g.write "hazy_daytime_city_scene.png"
30
- #
31
- # There are several rules that will magically select a layer when possible.
32
- #
33
- # * Numbered files will be selected according to the closest value that is less than the input value.
34
- # * +'true.png'+ and +'false.png'+ will be used as booleans.
35
- # * Other named files will be used if the input matches the filename (without the filetype extension).
36
- # * If there is a file named +'default.png'+, it will be used unless other input values are set for the corresponding layer.
37
- class Gruff::Scene < Gruff::Base
38
- # An array listing the folder names that will be rendered, from back to front.
39
- #
40
- # @example
41
- # g.layers = %w(sky clouds buildings street people)
42
- attr_reader :layers
43
-
44
- def initialize(target_width, base_dir)
45
- @base_dir = base_dir
46
- @groups = {}
47
- @layers = []
48
- super target_width
49
- end
50
-
51
- def draw
52
- # Join all the custom paths and filter out the empty ones
53
- image_paths = @layers.map(&:path).reject(&:empty?)
54
- images = Magick::ImageList.new(*image_paths)
55
- renderer.background_image = images.flatten_images
56
- end
57
-
58
- def layers=(ordered_list)
59
- ordered_list.each do |layer_name|
60
- @layers << Gruff::Layer.new(@base_dir, layer_name)
61
- end
62
- end
63
-
64
- # Group layers to input values
65
- #
66
- # g.weather_group = ["sky", "sea", "clouds"]
67
- #
68
- # Set input values
69
- #
70
- # g.weather = "cloudy"
71
- #
72
- def method_missing(method_name, *args)
73
- case method_name.to_s
74
- when /^(\w+)_group=$/
75
- add_group Regexp.last_match(1), *args
76
- when /^(\w+)=$/
77
- set_input Regexp.last_match(1), args.first
78
- else
79
- super
80
- end
81
- end
82
-
83
- def respond_to_missing?(method_sym, include_private)
84
- case method_sym.to_s
85
- when /^(\w+)_group=$/, /^(\w+)=$/
86
- true
87
- else
88
- super
89
- end
90
- end
91
-
92
- private
93
-
94
- def add_group(input_name, layer_names)
95
- @groups[input_name] = Gruff::Group.new(input_name, @layers.select { |layer| layer_names.include?(layer.name) })
96
- end
97
-
98
- def set_input(input_name, input_value)
99
- if !@groups[input_name].nil?
100
- @groups[input_name].send_updates(input_value)
101
- elsif (chosen_layer = @layers.find { |layer| layer.name == input_name })
102
- chosen_layer.update input_value
103
- end
104
- end
105
- end
106
-
107
- # @private
108
- class Gruff::Group
109
- include Observable
110
- attr_reader :name
111
-
112
- def initialize(folder_name, layers)
113
- @name = folder_name
114
- layers.each do |layer|
115
- layer.observe self
116
- end
117
- end
118
-
119
- def send_updates(value)
120
- changed
121
- notify_observers value
122
- end
123
- end
124
-
125
- # @private
126
- class Gruff::Layer
127
- attr_reader :name
128
-
129
- def initialize(base_dir, folder_name)
130
- @base_dir = base_dir.to_s
131
- @name = folder_name.to_s
132
- @filenames = Dir.open(File.join(base_dir, folder_name)).entries.grep(/^[^.]+\.png$/).sort
133
- @selected_filename = select_default
134
- end
135
-
136
- # Register this layer so it receives updates from the group
137
- def observe(obj)
138
- obj.add_observer self
139
- end
140
-
141
- # Choose the appropriate filename for this layer, based on the input
142
- def update(value)
143
- @selected_filename = begin
144
- case value.to_s
145
- when /^(true|false)$/
146
- select_boolean value
147
- when /^(\w|\s)+$/
148
- select_string value
149
- when /^-?(\d+\.)?\d+$/
150
- select_numeric value
151
- when /(\d\d):(\d\d):\d\d/
152
- select_time "#{Regexp.last_match(1)}#{Regexp.last_match(2)}"
153
- else
154
- select_default
155
- end
156
- end
157
- # Finally, try to use 'default' if we're still blank
158
- @selected_filename ||= select_default
159
- end
160
-
161
- # Returns the full path to the selected image, or a blank string
162
- def path
163
- unless @selected_filename.nil? || @selected_filename.empty?
164
- return File.join(@base_dir, @name, @selected_filename)
165
- end
166
-
167
- ''
168
- end
169
-
170
- private
171
-
172
- # Match "true.png" or "false.png"
173
- def select_boolean(value)
174
- file_exists_or_blank value.to_s
175
- end
176
-
177
- # Match -5 to _5.png
178
- def select_numeric(value)
179
- file_exists_or_blank value.to_s.gsub('-', '_')
180
- end
181
-
182
- def select_time(value)
183
- times = @filenames.map { |filename| filename.gsub('.png', '') }
184
- times.each_with_index do |time, index|
185
- if (time > value) && (index > 0)
186
- return "#{times[index - 1]}.png"
187
- end
188
- end
189
-
190
- "#{times.last}.png"
191
- end
192
-
193
- # Match "partly cloudy" to "partly_cloudy.png"
194
- def select_string(value)
195
- file_exists_or_blank value.to_s.gsub(' ', '_')
196
- end
197
-
198
- def select_default
199
- @filenames.include?('default.png') ? 'default.png' : ''
200
- end
201
-
202
- # Returns the string "#{filename}.png", if it exists.
203
- #
204
- # Failing that, it returns default.png, or '' if that doesn't exist.
205
- def file_exists_or_blank(filename)
206
- @filenames.include?("#{filename}.png") ? "#{filename}.png" : select_default
207
- end
208
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gruff
4
- class Store
5
- # @private
6
- class CustomData < Struct.new(:label, :points, :color, :custom)
7
- def initialize(label, points, color, custom = nil)
8
- super(label.to_s, Array(points), color, custom)
9
- end
10
-
11
- def empty?
12
- points.empty?
13
- end
14
-
15
- def columns
16
- points.length
17
- end
18
-
19
- def min
20
- points.compact.min
21
- end
22
-
23
- def max
24
- points.compact.max
25
- end
26
-
27
- def normalize(minimum:, spread:)
28
- norm_points = points.map do |point|
29
- point.nil? ? nil : (point.to_f - minimum.to_f) / spread
30
- end
31
-
32
- self.class.new(label, norm_points, color, custom)
33
- end
34
- end
35
- end
36
- end