gruff 0.16.0-java → 0.17.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +19 -0
- data/gruff.gemspec +2 -3
- data/lib/gruff/area.rb +2 -0
- data/lib/gruff/bar.rb +26 -23
- data/lib/gruff/base.rb +198 -81
- data/lib/gruff/bezier.rb +2 -0
- data/lib/gruff/box_plot.rb +7 -1
- data/lib/gruff/candlestick.rb +21 -13
- data/lib/gruff/dot.rb +4 -5
- data/lib/gruff/helper/bar_conversion.rb +1 -5
- data/lib/gruff/helper/bar_mixin.rb +25 -0
- data/lib/gruff/helper/bar_value_label.rb +0 -22
- data/lib/gruff/helper/stacked_mixin.rb +16 -0
- data/lib/gruff/histogram.rb +8 -4
- data/lib/gruff/line.rb +2 -5
- data/lib/gruff/mini/legend.rb +9 -9
- data/lib/gruff/net.rb +16 -11
- data/lib/gruff/pie.rb +6 -1
- data/lib/gruff/renderer/dot.rb +25 -14
- data/lib/gruff/renderer/renderer.rb +0 -4
- data/lib/gruff/renderer/text.rb +7 -1
- data/lib/gruff/scatter.rb +20 -18
- data/lib/gruff/side_bar.rb +28 -23
- data/lib/gruff/side_stacked_bar.rb +36 -41
- data/lib/gruff/spider.rb +7 -2
- data/lib/gruff/stacked_area.rb +7 -2
- data/lib/gruff/stacked_bar.rb +46 -38
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +0 -3
- metadata +5 -4
data/lib/gruff/base.rb
CHANGED
@@ -45,14 +45,15 @@ module Gruff
|
|
45
45
|
# Blank space below the legend. Default is +20+.
|
46
46
|
attr_writer :legend_margin
|
47
47
|
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
#
|
48
|
+
# Truncates labels if longer than max specified.
|
49
|
+
attr_writer :label_max_size
|
50
|
+
|
51
|
+
# How truncated labels visually appear if they exceed {#label_max_size=}.
|
52
52
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
|
53
|
+
# - +:absolute+ - does not show trailing dots to indicate truncation. This is the default.
|
54
|
+
# - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size=}
|
55
|
+
# must be greater than 3).
|
56
|
+
attr_writer :label_truncation_style
|
56
57
|
|
57
58
|
# Set a label for the bottom of the graph.
|
58
59
|
attr_writer :x_axis_label
|
@@ -72,25 +73,9 @@ module Gruff
|
|
72
73
|
# Set increment of the horizontal marking lines.
|
73
74
|
attr_writer :y_axis_increment
|
74
75
|
|
75
|
-
# Height of staggering between labels (Bar graph only).
|
76
|
-
attr_writer :label_stagger_height
|
77
|
-
|
78
|
-
# Truncates labels if longer than max specified.
|
79
|
-
attr_writer :label_max_size
|
80
|
-
|
81
|
-
# How truncated labels visually appear if they exceed {#label_max_size=}.
|
82
|
-
#
|
83
|
-
# - +:absolute+ - does not show trailing dots to indicate truncation. This is the default.
|
84
|
-
# - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size=}
|
85
|
-
# must be greater than 3).
|
86
|
-
attr_writer :label_truncation_style
|
87
|
-
|
88
76
|
# Get or set the list of colors that will be used to draw the bars or lines.
|
89
77
|
attr_accessor :colors
|
90
78
|
|
91
|
-
# Set the large title of the graph displayed at the top.
|
92
|
-
attr_writer :title
|
93
|
-
|
94
79
|
# Prevent drawing of line markers. Default is +false+.
|
95
80
|
attr_writer :hide_line_markers
|
96
81
|
|
@@ -107,9 +92,6 @@ module Gruff
|
|
107
92
|
# to +"No Data."+.
|
108
93
|
attr_writer :no_data_message
|
109
94
|
|
110
|
-
# Display the legend under the graph. Default is +false+.
|
111
|
-
attr_writer :legend_at_bottom
|
112
|
-
|
113
95
|
# Set the color of the auxiliary lines.
|
114
96
|
attr_writer :marker_color
|
115
97
|
|
@@ -127,6 +109,9 @@ module Gruff
|
|
127
109
|
# first. This does not affect the legend. Default is +false+.
|
128
110
|
attr_writer :sorted_drawing
|
129
111
|
|
112
|
+
# Display the legend under the graph. Default is +false+.
|
113
|
+
attr_writer :legend_at_bottom
|
114
|
+
|
130
115
|
# Optionally set the size of the colored box by each item in the legend.
|
131
116
|
# Default is +20.0+.
|
132
117
|
#
|
@@ -204,9 +189,9 @@ module Gruff
|
|
204
189
|
@no_data_message = 'No Data'
|
205
190
|
|
206
191
|
@hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = false
|
207
|
-
@label_stagger_height = 0
|
208
192
|
@label_max_size = 0
|
209
193
|
@label_truncation_style = :absolute
|
194
|
+
@label_rotation = 0
|
210
195
|
|
211
196
|
@x_axis_increment = nil
|
212
197
|
@x_axis_label = @y_axis_label = nil
|
@@ -217,6 +202,67 @@ module Gruff
|
|
217
202
|
end
|
218
203
|
protected :initialize_attributes
|
219
204
|
|
205
|
+
# A hash of names for the individual columns, where the key is the array
|
206
|
+
# index for the column this label represents.
|
207
|
+
# Not all columns need to be named with hash.
|
208
|
+
#
|
209
|
+
# Or, an array corresponding to the data values.
|
210
|
+
#
|
211
|
+
# @param labels [Hash, Array] the labels.
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
# g = Gruff::Bar.new
|
215
|
+
# g.labels = { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
|
216
|
+
#
|
217
|
+
# g = Gruff::Bar.new
|
218
|
+
# g.labels = ['2005', nil, nil, '2006', nil, nil, '2007', nil, nil, '2008'] # same labels for columns
|
219
|
+
def labels=(labels)
|
220
|
+
if labels.is_a?(Array)
|
221
|
+
labels = labels.each_with_index.each_with_object({}) do |(label, index), hash|
|
222
|
+
hash[index] = label
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
@labels = labels
|
227
|
+
end
|
228
|
+
|
229
|
+
# Set a rotation for labels. You can use Default is +0+.
|
230
|
+
# You can use a rotation between +0.0+ and +45.0+, or between +0.0+ and +-45.0+.
|
231
|
+
#
|
232
|
+
# @param rotation [Numeric] the rotation.
|
233
|
+
#
|
234
|
+
def label_rotation=(rotation)
|
235
|
+
raise ArgumentError, 'rotation must be between 0.0 and 45.0 or between 0.0 and -45.0' if rotation > 45.0 || rotation < -45.0
|
236
|
+
|
237
|
+
@label_rotation = rotation.to_f
|
238
|
+
end
|
239
|
+
|
240
|
+
# Height of staggering between labels.
|
241
|
+
# @deprecated
|
242
|
+
def label_stagger_height=(_value)
|
243
|
+
warn '#label_stagger_height= is deprecated. It is no longer effective.'
|
244
|
+
end
|
245
|
+
|
246
|
+
# Set the large title of the graph displayed at the top.
|
247
|
+
# You can draw a multi-line title by putting a line break in the string
|
248
|
+
# or by setting an array as argument.
|
249
|
+
#
|
250
|
+
# @param title [String, Array] the title.
|
251
|
+
#
|
252
|
+
# @example
|
253
|
+
# g = Gruff::Bar.new
|
254
|
+
# g.title = "The graph title"
|
255
|
+
#
|
256
|
+
# g = Gruff::Bar.new
|
257
|
+
# g.title = ['The first line of title', 'The second line of title']
|
258
|
+
def title=(title)
|
259
|
+
if title.is_a?(Array)
|
260
|
+
title = title.join("\n")
|
261
|
+
end
|
262
|
+
|
263
|
+
@title = title
|
264
|
+
end
|
265
|
+
|
220
266
|
# Sets the top, bottom, left and right margins to +margin+.
|
221
267
|
#
|
222
268
|
# @param margin [Numeric] The margin size.
|
@@ -320,7 +366,8 @@ module Gruff
|
|
320
366
|
# You can set a theme manually. Assign a hash to this method before you
|
321
367
|
# send your data.
|
322
368
|
#
|
323
|
-
#
|
369
|
+
# g = Gruff::Bar.new
|
370
|
+
# g.theme = {
|
324
371
|
# colors: %w(orange purple green white red),
|
325
372
|
# marker_color: 'blue',
|
326
373
|
# background_colors: ['black', 'grey'],
|
@@ -357,7 +404,7 @@ module Gruff
|
|
357
404
|
self.marker_color = @theme_options[:marker_color]
|
358
405
|
self.font_color = @theme_options[:font_color] || @marker_color
|
359
406
|
|
360
|
-
@colors = @theme_options[:colors]
|
407
|
+
@colors = @theme_options[:colors].dup
|
361
408
|
@marker_shadow_color = @theme_options[:marker_shadow_color]
|
362
409
|
|
363
410
|
@renderer = Gruff::Renderer.new(@columns, @rows, @scale, @theme_options)
|
@@ -503,11 +550,13 @@ module Gruff
|
|
503
550
|
attr_reader :renderer
|
504
551
|
|
505
552
|
# Perform data manipulation before calculating chart measurements
|
506
|
-
def setup_data
|
553
|
+
def setup_data
|
507
554
|
if @y_axis_increment && !@hide_line_markers
|
508
555
|
self.maximum_value = [@y_axis_increment, maximum_value, (maximum_value / @y_axis_increment).round * @y_axis_increment].max
|
509
556
|
self.minimum_value = [minimum_value, (minimum_value / @y_axis_increment).round * @y_axis_increment].min
|
510
557
|
end
|
558
|
+
|
559
|
+
sort_data if @sort # Sort data with avg largest values set first (for display)
|
511
560
|
end
|
512
561
|
|
513
562
|
# Calculates size of drawable area and generates normalized data.
|
@@ -518,7 +567,6 @@ module Gruff
|
|
518
567
|
def setup_drawing
|
519
568
|
calculate_spread
|
520
569
|
calculate_increment
|
521
|
-
sort_data if @sort # Sort data with avg largest values set first (for display)
|
522
570
|
set_colors
|
523
571
|
normalize
|
524
572
|
setup_graph_measurements
|
@@ -583,8 +631,7 @@ module Gruff
|
|
583
631
|
# Calculates size of drawable area, general font dimensions, etc.
|
584
632
|
|
585
633
|
def setup_graph_measurements
|
586
|
-
|
587
|
-
@graph_right = @raw_columns - margin_on_right
|
634
|
+
@graph_right = setup_right_margin
|
588
635
|
@graph_left = setup_left_margin
|
589
636
|
@graph_top = setup_top_margin
|
590
637
|
@graph_bottom = setup_bottom_margin
|
@@ -599,7 +646,7 @@ module Gruff
|
|
599
646
|
# X Axis
|
600
647
|
# Centered vertically and horizontally by setting the
|
601
648
|
# height to 1.0 and the width to the width of the graph.
|
602
|
-
x_axis_label_y_coordinate = @graph_bottom + (LABEL_MARGIN * 2) +
|
649
|
+
x_axis_label_y_coordinate = @graph_bottom + (LABEL_MARGIN * 2) + labels_caps_height
|
603
650
|
|
604
651
|
text_renderer = Gruff::Renderer::Text.new(renderer, @x_axis_label, font: @marker_font)
|
605
652
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
|
@@ -621,9 +668,7 @@ module Gruff
|
|
621
668
|
# Draw horizontal line markers and annotate with numbers
|
622
669
|
(0..marker_count).each do |index|
|
623
670
|
y = @graph_top + @graph_height - (index * increment_scaled)
|
624
|
-
|
625
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y, @graph_right, y)
|
626
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1) if @marker_shadow_color
|
671
|
+
draw_marker_horizontal_line(y)
|
627
672
|
|
628
673
|
unless @hide_line_numbers
|
629
674
|
marker_label = (BigDecimal(index.to_s) * BigDecimal(@increment.to_s)) + BigDecimal(minimum_value.to_s)
|
@@ -634,6 +679,25 @@ module Gruff
|
|
634
679
|
end
|
635
680
|
end
|
636
681
|
|
682
|
+
def draw_marker_horizontal_line(y)
|
683
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y, @graph_right, y)
|
684
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1) if @marker_shadow_color
|
685
|
+
end
|
686
|
+
|
687
|
+
def draw_marker_vertical_line(x, tick_mark_mode: false)
|
688
|
+
if tick_mark_mode
|
689
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_bottom + 5)
|
690
|
+
if @marker_shadow_color
|
691
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_bottom + 5)
|
692
|
+
end
|
693
|
+
else
|
694
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_top)
|
695
|
+
if @marker_shadow_color
|
696
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_top)
|
697
|
+
end
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
637
701
|
# Return a calculation of center
|
638
702
|
def center(size)
|
639
703
|
(@raw_columns - size) / 2
|
@@ -651,7 +715,7 @@ module Gruff
|
|
651
715
|
|
652
716
|
current_y_offset = begin
|
653
717
|
if @legend_at_bottom
|
654
|
-
@graph_bottom + @legend_margin +
|
718
|
+
@graph_bottom + @legend_margin + labels_caps_height + LABEL_MARGIN + (@x_axis_label ? (LABEL_MARGIN * 2) + marker_caps_height : 0)
|
655
719
|
else
|
656
720
|
hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin + title_caps_height
|
657
721
|
end
|
@@ -705,11 +769,22 @@ module Gruff
|
|
705
769
|
# Draws column labels below graph, centered over x_offset
|
706
770
|
def draw_label(x_offset, index, gravity = Magick::NorthGravity, &block)
|
707
771
|
draw_unique_label(index) do
|
708
|
-
y_offset = @graph_bottom
|
709
|
-
y_offset += @label_stagger_height if index.odd?
|
772
|
+
y_offset = @graph_bottom
|
710
773
|
|
711
774
|
if x_offset >= @graph_left && x_offset <= @graph_right
|
712
|
-
|
775
|
+
width = calculate_width(@marker_font, @labels[index], rotation: @label_rotation)
|
776
|
+
height = calculate_height(@marker_font, @labels[index], rotation: @label_rotation)
|
777
|
+
case @label_rotation
|
778
|
+
when 0
|
779
|
+
x_offset
|
780
|
+
when 0..45
|
781
|
+
x_offset += (width / 2.0)
|
782
|
+
when -45..0
|
783
|
+
x_offset -= (width / 2.0)
|
784
|
+
end
|
785
|
+
y_offset += (height / 2.0) > LABEL_MARGIN ? (height / 2.0) : LABEL_MARGIN
|
786
|
+
|
787
|
+
draw_label_at(1.0, 1.0, x_offset, y_offset, @labels[index], gravity: gravity, rotation: @label_rotation)
|
713
788
|
yield if block
|
714
789
|
end
|
715
790
|
end
|
@@ -725,17 +800,17 @@ module Gruff
|
|
725
800
|
end
|
726
801
|
end
|
727
802
|
|
728
|
-
def draw_label_at(width, height, x, y, text, gravity
|
803
|
+
def draw_label_at(width, height, x, y, text, gravity: Magick::NorthGravity, rotation: 0)
|
729
804
|
label_text = truncate_label_text(text)
|
730
|
-
text_renderer = Gruff::Renderer::Text.new(renderer, label_text, font: @marker_font)
|
805
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label_text, font: @marker_font, rotation: rotation)
|
731
806
|
text_renderer.add_to_render_queue(width, height, x, y, gravity)
|
732
807
|
end
|
733
808
|
|
734
809
|
# Draws the data value over the data point in bar graphs
|
735
|
-
def draw_value_label(width, height, x_offset, y_offset, data_point, gravity
|
810
|
+
def draw_value_label(width, height, x_offset, y_offset, data_point, gravity: Magick::CenterGravity)
|
736
811
|
return if @hide_line_markers
|
737
812
|
|
738
|
-
draw_label_at(width, height, x_offset, y_offset, data_point, gravity)
|
813
|
+
draw_label_at(width, height, x_offset, y_offset, data_point, gravity: gravity)
|
739
814
|
end
|
740
815
|
|
741
816
|
# Shows an error message because you have no data.
|
@@ -756,20 +831,15 @@ module Gruff
|
|
756
831
|
@theme_options = {}
|
757
832
|
end
|
758
833
|
|
759
|
-
def scale(value)
|
834
|
+
def scale(value)
|
760
835
|
value * @scale
|
761
836
|
end
|
762
837
|
|
763
|
-
|
764
|
-
def scale_fontsize(value)
|
765
|
-
value * @scale
|
766
|
-
end
|
767
|
-
|
768
|
-
def clip_value_if_greater_than(value, max_value) # :nodoc:
|
838
|
+
def clip_value_if_greater_than(value, max_value)
|
769
839
|
value > max_value ? max_value : value
|
770
840
|
end
|
771
841
|
|
772
|
-
def significant(i)
|
842
|
+
def significant(i)
|
773
843
|
return 1.0 if i == 0 # Keep from going into infinite loop
|
774
844
|
|
775
845
|
inc = BigDecimal(i.to_s)
|
@@ -816,6 +886,10 @@ module Gruff
|
|
816
886
|
hide_bottom_label_area? ? 0 : calculate_caps_height(@marker_font)
|
817
887
|
end
|
818
888
|
|
889
|
+
def labels_caps_height
|
890
|
+
hide_bottom_label_area? ? 0 : calculate_labels_height(@marker_font)
|
891
|
+
end
|
892
|
+
|
819
893
|
def title_caps_height
|
820
894
|
hide_title? ? 0 : calculate_caps_height(@title_font) * @title.lines.to_a.size
|
821
895
|
end
|
@@ -824,21 +898,6 @@ module Gruff
|
|
824
898
|
@hide_legend ? 0 : calculate_caps_height(@legend_font)
|
825
899
|
end
|
826
900
|
|
827
|
-
def graph_right_margin
|
828
|
-
@hide_line_markers ? @right_margin : @right_margin + extra_room_for_long_label
|
829
|
-
end
|
830
|
-
|
831
|
-
def extra_room_for_long_label
|
832
|
-
# Make space for half the width of the rightmost column label.
|
833
|
-
# Might be greater than the number of columns if between-style bar markers are used.
|
834
|
-
last_label = @labels.keys.max.to_i
|
835
|
-
if last_label >= (column_count - 1) && @center_labels_over_point
|
836
|
-
calculate_width(@marker_font, truncate_label_text(@labels[last_label])) / 2.0
|
837
|
-
else
|
838
|
-
0
|
839
|
-
end
|
840
|
-
end
|
841
|
-
|
842
901
|
def setup_left_margin
|
843
902
|
return @left_margin if hide_left_label_area?
|
844
903
|
|
@@ -851,10 +910,62 @@ module Gruff
|
|
851
910
|
end
|
852
911
|
longest_left_label_width = calculate_width(@marker_font, truncate_label_text(text))
|
853
912
|
|
854
|
-
|
855
|
-
|
913
|
+
line_number_width = begin
|
914
|
+
if !@has_left_labels && (@hide_line_markers || @hide_line_numbers)
|
915
|
+
0.0
|
916
|
+
else
|
917
|
+
longest_left_label_width + LABEL_MARGIN
|
918
|
+
end
|
919
|
+
end
|
920
|
+
y_axis_label_width = @y_axis_label.nil? ? 0.0 : marker_caps_height + (LABEL_MARGIN * 2)
|
921
|
+
|
922
|
+
bottom_label_width = extra_left_room_for_long_label
|
923
|
+
|
924
|
+
margin = line_number_width + y_axis_label_width
|
925
|
+
@left_margin + (margin > bottom_label_width ? margin : bottom_label_width)
|
926
|
+
end
|
927
|
+
|
928
|
+
def setup_right_margin
|
929
|
+
@raw_columns - (@hide_line_markers ? @right_margin : @right_margin + extra_right_room_for_long_label)
|
930
|
+
end
|
931
|
+
|
932
|
+
def extra_left_room_for_long_label
|
933
|
+
if require_extra_side_margin?
|
934
|
+
width = calculate_width(@marker_font, truncate_label_text(@labels[0]), rotation: @label_rotation)
|
935
|
+
case @label_rotation
|
936
|
+
when 0
|
937
|
+
width / 2.0
|
938
|
+
when 0..45
|
939
|
+
0
|
940
|
+
when -45..0
|
941
|
+
width
|
942
|
+
end
|
943
|
+
else
|
944
|
+
0
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
def extra_right_room_for_long_label
|
949
|
+
# Make space for half the width of the rightmost column label.
|
950
|
+
# Might be greater than the number of columns if between-style bar markers are used.
|
951
|
+
last_label = @labels.keys.max.to_i
|
952
|
+
if last_label >= (column_count - 1) && require_extra_side_margin?
|
953
|
+
width = calculate_width(@marker_font, truncate_label_text(@labels[last_label]), rotation: @label_rotation)
|
954
|
+
case @label_rotation
|
955
|
+
when 0
|
956
|
+
width / 2.0
|
957
|
+
when 0..45
|
958
|
+
width
|
959
|
+
when -45..0
|
960
|
+
0
|
961
|
+
end
|
962
|
+
else
|
963
|
+
0
|
964
|
+
end
|
965
|
+
end
|
856
966
|
|
857
|
-
|
967
|
+
def require_extra_side_margin?
|
968
|
+
!hide_bottom_label_area? && @center_labels_over_point
|
858
969
|
end
|
859
970
|
|
860
971
|
def setup_top_margin
|
@@ -866,11 +977,11 @@ module Gruff
|
|
866
977
|
end
|
867
978
|
|
868
979
|
def setup_bottom_margin
|
869
|
-
graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin +
|
980
|
+
graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin + labels_caps_height + LABEL_MARGIN
|
870
981
|
graph_bottom_margin += (calculate_legend_height + @legend_margin) if @legend_at_bottom
|
871
982
|
|
872
983
|
x_axis_label_height = @x_axis_label.nil? ? 0.0 : marker_caps_height + (LABEL_MARGIN * 2)
|
873
|
-
@raw_rows - graph_bottom_margin - x_axis_label_height
|
984
|
+
@raw_rows - graph_bottom_margin - x_axis_label_height
|
874
985
|
end
|
875
986
|
|
876
987
|
def truncate_label_text(text)
|
@@ -973,32 +1084,38 @@ module Gruff
|
|
973
1084
|
calculate_height(font, 'X')
|
974
1085
|
end
|
975
1086
|
|
1087
|
+
def calculate_labels_height(font)
|
1088
|
+
@labels.values.map { |label| calculate_height(font, label, rotation: @label_rotation) }.max || marker_caps_height
|
1089
|
+
end
|
1090
|
+
|
976
1091
|
# Returns the height of a string at this point size.
|
977
1092
|
#
|
978
1093
|
# Not scaled since it deals with dimensions that the regular scaling will
|
979
1094
|
# handle.
|
980
|
-
def calculate_height(font, text)
|
1095
|
+
def calculate_height(font, text, rotation: 0)
|
981
1096
|
text = text.to_s
|
982
1097
|
return 0 if text.empty?
|
983
1098
|
|
984
|
-
metrics = text_metrics(font, text)
|
985
|
-
|
1099
|
+
metrics = text_metrics(font, text, rotation: rotation)
|
1100
|
+
# Calculate manually because it does not return the height after rotation.
|
1101
|
+
(metrics.width * Math.sin(deg2rad(rotation))).abs + (metrics.height * Math.cos(deg2rad(rotation))).abs
|
986
1102
|
end
|
987
1103
|
|
988
1104
|
# Returns the width of a string at this point size.
|
989
1105
|
#
|
990
1106
|
# Not scaled since it deals with dimensions that the regular
|
991
1107
|
# scaling will handle.
|
992
|
-
def calculate_width(font, text)
|
1108
|
+
def calculate_width(font, text, rotation: 0)
|
993
1109
|
text = text.to_s
|
994
1110
|
return 0 if text.empty?
|
995
1111
|
|
996
|
-
metrics = text_metrics(font, text)
|
997
|
-
|
1112
|
+
metrics = text_metrics(font, text, rotation: rotation)
|
1113
|
+
# Calculate manually because it does not return the width after rotation.
|
1114
|
+
(metrics.width * Math.cos(deg2rad(rotation))).abs - (metrics.height * Math.sin(deg2rad(rotation))).abs
|
998
1115
|
end
|
999
1116
|
|
1000
|
-
def text_metrics(font, text)
|
1001
|
-
Gruff::Renderer::Text.new(renderer, text, font: font).metrics
|
1117
|
+
def text_metrics(font, text, rotation: 0)
|
1118
|
+
Gruff::Renderer::Text.new(renderer, text, font: font, rotation: rotation).metrics
|
1002
1119
|
end
|
1003
1120
|
|
1004
1121
|
def calculate_increment
|
data/lib/gruff/bezier.rb
CHANGED
data/lib/gruff/box_plot.rb
CHANGED
@@ -44,11 +44,13 @@ private
|
|
44
44
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
45
45
|
)
|
46
46
|
|
47
|
-
width = (@graph_width - calculate_spacing) /
|
47
|
+
width = (@graph_width - calculate_spacing) / column_count
|
48
48
|
bar_width = width * @spacing_factor
|
49
49
|
padding = width - bar_width
|
50
50
|
|
51
51
|
normalized_boxes.each_with_index do |box, index|
|
52
|
+
next if box.points.empty?
|
53
|
+
|
52
54
|
left_x = @graph_left + (width * index) + (padding / 2.0)
|
53
55
|
right_x = left_x + bar_width
|
54
56
|
center_x = (left_x + right_x) / 2.0
|
@@ -91,6 +93,10 @@ private
|
|
91
93
|
@normalized_boxes ||= store.norm_data.map { |data| Gruff::BoxPlot::BoxData.new(data.label, data.points, data.color) }
|
92
94
|
end
|
93
95
|
|
96
|
+
def column_count
|
97
|
+
normalized_boxes.size
|
98
|
+
end
|
99
|
+
|
94
100
|
def calculate_spacing
|
95
101
|
@scale * (column_count - 1)
|
96
102
|
end
|
data/lib/gruff/candlestick.rb
CHANGED
@@ -38,6 +38,16 @@ class Gruff::Candlestick < Gruff::Base
|
|
38
38
|
@spacing_factor = (1 - space_percent)
|
39
39
|
end
|
40
40
|
|
41
|
+
# The sort feature is not supported in this graph.
|
42
|
+
def sort=(_value)
|
43
|
+
raise 'Not support #sort= in Gruff::Candlestick'
|
44
|
+
end
|
45
|
+
|
46
|
+
# The sort feature is not supported in this graph.
|
47
|
+
def sorted_drawing=(_value)
|
48
|
+
raise 'Not support #sorted_drawing= in Gruff::Candlestick'
|
49
|
+
end
|
50
|
+
|
41
51
|
def data(low:, high:, open:, close:)
|
42
52
|
super('', [low, high, open, close])
|
43
53
|
end
|
@@ -53,7 +63,6 @@ private
|
|
53
63
|
@up_color = '#579773'
|
54
64
|
@down_color = '#eb5242'
|
55
65
|
|
56
|
-
@sort = false
|
57
66
|
@hide_legend = true
|
58
67
|
end
|
59
68
|
|
@@ -64,7 +73,7 @@ private
|
|
64
73
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
65
74
|
)
|
66
75
|
|
67
|
-
width = (@graph_width - calculate_spacing) /
|
76
|
+
width = (@graph_width - calculate_spacing) / column_count
|
68
77
|
bar_width = width * @spacing_factor
|
69
78
|
padding = width - bar_width
|
70
79
|
|
@@ -74,16 +83,7 @@ private
|
|
74
83
|
center_x = (left_x + right_x) / 2.0
|
75
84
|
color = candlestick.close >= candlestick.open ? @up_color : @down_color
|
76
85
|
|
77
|
-
draw_label(center_x, index)
|
78
|
-
break if @hide_line_markers
|
79
|
-
break unless @show_vertical_markers
|
80
|
-
|
81
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(center_x, @graph_bottom, center_x, @graph_top)
|
82
|
-
if @marker_shadow_color
|
83
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color)
|
84
|
-
.render(center_x + 1, @graph_bottom, center_x + 1, @graph_top)
|
85
|
-
end
|
86
|
-
end
|
86
|
+
draw_label(center_x, index) { draw_marker_vertical_line(center_x) if show_marker_vertical_line? }
|
87
87
|
|
88
88
|
open_y, = conversion.get_top_bottom_scaled(candlestick.open)
|
89
89
|
close_y, = conversion.get_top_bottom_scaled(candlestick.close)
|
@@ -99,13 +99,21 @@ private
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def normalized_candlesticks
|
102
|
-
@
|
102
|
+
@normalized_candlesticks ||= store.norm_data.map { |data| Gruff::Candlestick::CandlestickData.new(*data.points) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def column_count
|
106
|
+
normalized_candlesticks.size
|
103
107
|
end
|
104
108
|
|
105
109
|
def calculate_spacing
|
106
110
|
@scale * (column_count - 1)
|
107
111
|
end
|
108
112
|
|
113
|
+
def show_marker_vertical_line?
|
114
|
+
!@hide_line_markers && @show_vertical_markers
|
115
|
+
end
|
116
|
+
|
109
117
|
# @private
|
110
118
|
class CandlestickData < Struct.new(:low, :high, :open, :close)
|
111
119
|
end
|
data/lib/gruff/dot.rb
CHANGED
@@ -17,6 +17,7 @@ class Gruff::Dot < Gruff::Base
|
|
17
17
|
def initialize(*)
|
18
18
|
super
|
19
19
|
@has_left_labels = true
|
20
|
+
@dot_style = 'circle'
|
20
21
|
end
|
21
22
|
|
22
23
|
private
|
@@ -39,7 +40,7 @@ private
|
|
39
40
|
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y_pos, @graph_left + @graph_width, y_pos)
|
40
41
|
end
|
41
42
|
|
42
|
-
Gruff::Renderer::
|
43
|
+
Gruff::Renderer::Dot.new(renderer, @dot_style, color: data_row.color).render(x_pos, y_pos, item_width / 3.0)
|
43
44
|
|
44
45
|
draw_label(y_pos, point_index)
|
45
46
|
end
|
@@ -53,9 +54,7 @@ private
|
|
53
54
|
(0..marker_count).each do |index|
|
54
55
|
marker_label = (BigDecimal(index.to_s) * BigDecimal(@increment.to_s)) + BigDecimal(minimum_value.to_s)
|
55
56
|
x = @graph_left + ((marker_label - minimum_value) * @graph_width / @spread)
|
56
|
-
|
57
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_bottom + 5)
|
58
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x, @graph_bottom + 1, x, @graph_bottom + 6) if @marker_shadow_color
|
57
|
+
draw_marker_vertical_line(x, tick_mark_mode: true)
|
59
58
|
|
60
59
|
unless @hide_line_numbers
|
61
60
|
label = y_axis_label(marker_label, @increment)
|
@@ -70,7 +69,7 @@ private
|
|
70
69
|
|
71
70
|
def draw_label(y_offset, index)
|
72
71
|
draw_unique_label(index) do
|
73
|
-
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
|
72
|
+
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], gravity: Magick::EastGravity)
|
74
73
|
end
|
75
74
|
end
|
76
75
|
end
|
@@ -13,8 +13,6 @@
|
|
13
13
|
#
|
14
14
|
# @private
|
15
15
|
class Gruff::BarConversion
|
16
|
-
attr_writer :mode
|
17
|
-
|
18
16
|
def initialize(top:, bottom:, minimum_value:, maximum_value:, spread:)
|
19
17
|
@graph_top = top
|
20
18
|
@graph_height = bottom - top
|
@@ -36,6 +34,7 @@ class Gruff::BarConversion
|
|
36
34
|
end
|
37
35
|
|
38
36
|
def get_top_bottom_scaled(data_point)
|
37
|
+
data_point = data_point.to_f
|
39
38
|
result = []
|
40
39
|
|
41
40
|
case @mode
|
@@ -52,9 +51,6 @@ class Gruff::BarConversion
|
|
52
51
|
val = data_point - (@minimum_value / @spread)
|
53
52
|
result[0] = @graph_top + (@graph_height * (1 - (val - @zero)))
|
54
53
|
result[1] = @graph_top + (@graph_height * (1 - @zero))
|
55
|
-
else
|
56
|
-
result[0] = 0.0
|
57
|
-
result[1] = 0.0
|
58
54
|
end
|
59
55
|
|
60
56
|
result
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @private
|
4
|
+
module Gruff::Base::BarMixin
|
5
|
+
def normalized_group_bars
|
6
|
+
@normalized_group_bars ||= begin
|
7
|
+
group_bars = Array.new(column_count) { [] }
|
8
|
+
store.norm_data.each_with_index do |data_row, row_index|
|
9
|
+
data_row.points.each_with_index do |data_point, point_index|
|
10
|
+
group_bars[point_index] << BarData.new(data_point, store.data[row_index].points[point_index], data_row.color)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Adjust the number of each group with empty bar
|
14
|
+
(data_row.points.size..(column_count - 1)).each do |index|
|
15
|
+
group_bars[index] << BarData.new(0, nil, data_row.color)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
group_bars
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
class BarData < Struct.new(:point, :value, :color)
|
24
|
+
end
|
25
|
+
end
|