gruff 0.16.0-java → 0.19.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/.devcontainer/devcontainer.json +26 -0
- data/.github/workflows/ci.yml +9 -6
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +32 -0
- data/README.md +7 -3
- data/gruff.gemspec +2 -4
- data/lib/gruff/area.rb +3 -1
- data/lib/gruff/bar.rb +26 -24
- data/lib/gruff/base.rb +214 -93
- data/lib/gruff/bezier.rb +7 -8
- data/lib/gruff/{box_plot.rb → box.rb} +12 -6
- data/lib/gruff/bubble.rb +99 -0
- data/lib/gruff/candlestick.rb +22 -14
- data/lib/gruff/dot.rb +5 -6
- 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 -5
- data/lib/gruff/line.rb +47 -27
- data/lib/gruff/mini/bar.rb +1 -1
- data/lib/gruff/mini/legend.rb +13 -9
- data/lib/gruff/mini/pie.rb +2 -2
- data/lib/gruff/net.rb +26 -13
- data/lib/gruff/pie.rb +7 -2
- data/lib/gruff/renderer/bezier.rb +1 -1
- data/lib/gruff/renderer/circle.rb +5 -3
- data/lib/gruff/renderer/dash_line.rb +1 -1
- data/lib/gruff/renderer/dot.rb +26 -15
- data/lib/gruff/renderer/line.rb +1 -1
- data/lib/gruff/renderer/polygon.rb +1 -1
- data/lib/gruff/renderer/polyline.rb +4 -2
- data/lib/gruff/renderer/renderer.rb +0 -4
- data/lib/gruff/renderer/text.rb +7 -1
- data/lib/gruff/scatter.rb +52 -55
- data/lib/gruff/side_bar.rb +28 -24
- data/lib/gruff/side_stacked_bar.rb +36 -41
- data/lib/gruff/spider.rb +7 -2
- data/lib/gruff/stacked_area.rb +8 -3
- data/lib/gruff/stacked_bar.rb +48 -40
- data/lib/gruff/store/xy_data.rb +8 -9
- data/lib/gruff/store/xy_pointsizes_data.rb +60 -0
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +3 -4
- metadata +9 -5
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)
|
@@ -422,7 +469,8 @@ module Gruff
|
|
422
469
|
#
|
423
470
|
# Set it after you have given all your data to the graph object.
|
424
471
|
def minimum_value
|
425
|
-
|
472
|
+
min = [0.0, store.min.to_f].min
|
473
|
+
(@minimum_value || min).to_f
|
426
474
|
end
|
427
475
|
attr_writer :minimum_value
|
428
476
|
|
@@ -503,11 +551,13 @@ module Gruff
|
|
503
551
|
attr_reader :renderer
|
504
552
|
|
505
553
|
# Perform data manipulation before calculating chart measurements
|
506
|
-
def setup_data
|
554
|
+
def setup_data
|
507
555
|
if @y_axis_increment && !@hide_line_markers
|
508
556
|
self.maximum_value = [@y_axis_increment, maximum_value, (maximum_value / @y_axis_increment).round * @y_axis_increment].max
|
509
557
|
self.minimum_value = [minimum_value, (minimum_value / @y_axis_increment).round * @y_axis_increment].min
|
510
558
|
end
|
559
|
+
|
560
|
+
sort_data if @sort # Sort data with avg largest values set first (for display)
|
511
561
|
end
|
512
562
|
|
513
563
|
# Calculates size of drawable area and generates normalized data.
|
@@ -518,7 +568,6 @@ module Gruff
|
|
518
568
|
def setup_drawing
|
519
569
|
calculate_spread
|
520
570
|
calculate_increment
|
521
|
-
sort_data if @sort # Sort data with avg largest values set first (for display)
|
522
571
|
set_colors
|
523
572
|
normalize
|
524
573
|
setup_graph_measurements
|
@@ -559,8 +608,8 @@ module Gruff
|
|
559
608
|
end
|
560
609
|
|
561
610
|
def calculate_spread
|
562
|
-
@spread = maximum_value - minimum_value
|
563
|
-
@spread = @spread > 0 ? @spread : 1
|
611
|
+
@spread = maximum_value.to_f - minimum_value.to_f
|
612
|
+
@spread = @spread > 0 ? @spread : 1.0
|
564
613
|
end
|
565
614
|
|
566
615
|
def hide_title?
|
@@ -583,8 +632,7 @@ module Gruff
|
|
583
632
|
# Calculates size of drawable area, general font dimensions, etc.
|
584
633
|
|
585
634
|
def setup_graph_measurements
|
586
|
-
|
587
|
-
@graph_right = @raw_columns - margin_on_right
|
635
|
+
@graph_right = setup_right_margin
|
588
636
|
@graph_left = setup_left_margin
|
589
637
|
@graph_top = setup_top_margin
|
590
638
|
@graph_bottom = setup_bottom_margin
|
@@ -599,7 +647,7 @@ module Gruff
|
|
599
647
|
# X Axis
|
600
648
|
# Centered vertically and horizontally by setting the
|
601
649
|
# height to 1.0 and the width to the width of the graph.
|
602
|
-
x_axis_label_y_coordinate = @graph_bottom + (LABEL_MARGIN * 2) +
|
650
|
+
x_axis_label_y_coordinate = @graph_bottom + (LABEL_MARGIN * 2) + labels_caps_height
|
603
651
|
|
604
652
|
text_renderer = Gruff::Renderer::Text.new(renderer, @x_axis_label, font: @marker_font)
|
605
653
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
|
@@ -616,14 +664,12 @@ module Gruff
|
|
616
664
|
def draw_line_markers
|
617
665
|
return if @hide_line_markers
|
618
666
|
|
619
|
-
increment_scaled = @graph_height / (@spread / @increment)
|
667
|
+
increment_scaled = (@graph_height / (@spread / @increment)).to_f
|
620
668
|
|
621
669
|
# Draw horizontal line markers and annotate with numbers
|
622
670
|
(0..marker_count).each do |index|
|
623
671
|
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
|
672
|
+
draw_marker_horizontal_line(y)
|
627
673
|
|
628
674
|
unless @hide_line_numbers
|
629
675
|
marker_label = (BigDecimal(index.to_s) * BigDecimal(@increment.to_s)) + BigDecimal(minimum_value.to_s)
|
@@ -634,6 +680,25 @@ module Gruff
|
|
634
680
|
end
|
635
681
|
end
|
636
682
|
|
683
|
+
def draw_marker_horizontal_line(y)
|
684
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y, @graph_right, y)
|
685
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1) if @marker_shadow_color
|
686
|
+
end
|
687
|
+
|
688
|
+
def draw_marker_vertical_line(x, tick_mark_mode: false)
|
689
|
+
if tick_mark_mode
|
690
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_bottom + 5)
|
691
|
+
if @marker_shadow_color
|
692
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_bottom + 5)
|
693
|
+
end
|
694
|
+
else
|
695
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_top)
|
696
|
+
if @marker_shadow_color
|
697
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_top)
|
698
|
+
end
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
637
702
|
# Return a calculation of center
|
638
703
|
def center(size)
|
639
704
|
(@raw_columns - size) / 2
|
@@ -651,7 +716,7 @@ module Gruff
|
|
651
716
|
|
652
717
|
current_y_offset = begin
|
653
718
|
if @legend_at_bottom
|
654
|
-
@graph_bottom + @legend_margin +
|
719
|
+
@graph_bottom + @legend_margin + labels_caps_height + LABEL_MARGIN + (@x_axis_label ? (LABEL_MARGIN * 2) + marker_caps_height : 0)
|
655
720
|
else
|
656
721
|
hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin + title_caps_height
|
657
722
|
end
|
@@ -702,14 +767,14 @@ module Gruff
|
|
702
767
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, 0, @top_margin)
|
703
768
|
end
|
704
769
|
|
705
|
-
# Draws column labels below graph, centered over
|
706
|
-
def draw_label(
|
770
|
+
# Draws column labels below graph, centered over x
|
771
|
+
def draw_label(x, index, gravity = Magick::NorthGravity, &block)
|
707
772
|
draw_unique_label(index) do
|
708
|
-
|
709
|
-
|
773
|
+
if x >= @graph_left && x <= @graph_right
|
774
|
+
y = @graph_bottom
|
775
|
+
x_offset, y_offset = calculate_label_offset(@marker_font, @labels[index], LABEL_MARGIN, @label_rotation)
|
710
776
|
|
711
|
-
|
712
|
-
draw_label_at(1.0, 1.0, x_offset, y_offset, @labels[index], gravity)
|
777
|
+
draw_label_at(1.0, 1.0, x + x_offset, y + y_offset, @labels[index], gravity: gravity, rotation: @label_rotation)
|
713
778
|
yield if block
|
714
779
|
end
|
715
780
|
end
|
@@ -725,17 +790,17 @@ module Gruff
|
|
725
790
|
end
|
726
791
|
end
|
727
792
|
|
728
|
-
def draw_label_at(width, height, x, y, text, gravity
|
793
|
+
def draw_label_at(width, height, x, y, text, gravity: Magick::NorthGravity, rotation: 0)
|
729
794
|
label_text = truncate_label_text(text)
|
730
|
-
text_renderer = Gruff::Renderer::Text.new(renderer, label_text, font: @marker_font)
|
795
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label_text, font: @marker_font, rotation: rotation)
|
731
796
|
text_renderer.add_to_render_queue(width, height, x, y, gravity)
|
732
797
|
end
|
733
798
|
|
734
799
|
# 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
|
800
|
+
def draw_value_label(width, height, x_offset, y_offset, data_point, gravity: Magick::CenterGravity)
|
736
801
|
return if @hide_line_markers
|
737
802
|
|
738
|
-
draw_label_at(width, height, x_offset, y_offset, data_point, gravity)
|
803
|
+
draw_label_at(width, height, x_offset, y_offset, data_point, gravity: gravity)
|
739
804
|
end
|
740
805
|
|
741
806
|
# Shows an error message because you have no data.
|
@@ -756,20 +821,11 @@ module Gruff
|
|
756
821
|
@theme_options = {}
|
757
822
|
end
|
758
823
|
|
759
|
-
def
|
760
|
-
value * @scale
|
761
|
-
end
|
762
|
-
|
763
|
-
# Return a comparable fontsize for the current graph.
|
764
|
-
def scale_fontsize(value)
|
765
|
-
value * @scale
|
766
|
-
end
|
767
|
-
|
768
|
-
def clip_value_if_greater_than(value, max_value) # :nodoc:
|
824
|
+
def clip_value_if_greater_than(value, max_value)
|
769
825
|
value > max_value ? max_value : value
|
770
826
|
end
|
771
827
|
|
772
|
-
def significant(i)
|
828
|
+
def significant(i)
|
773
829
|
return 1.0 if i == 0 # Keep from going into infinite loop
|
774
830
|
|
775
831
|
inc = BigDecimal(i.to_s)
|
@@ -816,6 +872,10 @@ module Gruff
|
|
816
872
|
hide_bottom_label_area? ? 0 : calculate_caps_height(@marker_font)
|
817
873
|
end
|
818
874
|
|
875
|
+
def labels_caps_height
|
876
|
+
hide_bottom_label_area? ? 0 : calculate_labels_height(@marker_font)
|
877
|
+
end
|
878
|
+
|
819
879
|
def title_caps_height
|
820
880
|
hide_title? ? 0 : calculate_caps_height(@title_font) * @title.lines.to_a.size
|
821
881
|
end
|
@@ -824,21 +884,6 @@ module Gruff
|
|
824
884
|
@hide_legend ? 0 : calculate_caps_height(@legend_font)
|
825
885
|
end
|
826
886
|
|
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
887
|
def setup_left_margin
|
843
888
|
return @left_margin if hide_left_label_area?
|
844
889
|
|
@@ -851,10 +896,62 @@ module Gruff
|
|
851
896
|
end
|
852
897
|
longest_left_label_width = calculate_width(@marker_font, truncate_label_text(text))
|
853
898
|
|
854
|
-
|
855
|
-
|
899
|
+
line_number_width = begin
|
900
|
+
if !@has_left_labels && (@hide_line_markers || @hide_line_numbers)
|
901
|
+
0.0
|
902
|
+
else
|
903
|
+
longest_left_label_width + LABEL_MARGIN
|
904
|
+
end
|
905
|
+
end
|
906
|
+
y_axis_label_width = @y_axis_label.nil? ? 0.0 : marker_caps_height + (LABEL_MARGIN * 2)
|
907
|
+
|
908
|
+
bottom_label_width = extra_left_room_for_long_label
|
909
|
+
|
910
|
+
margin = line_number_width + y_axis_label_width
|
911
|
+
@left_margin + (margin > bottom_label_width ? margin : bottom_label_width)
|
912
|
+
end
|
856
913
|
|
857
|
-
|
914
|
+
def setup_right_margin
|
915
|
+
@raw_columns - (@hide_line_markers ? @right_margin : @right_margin + extra_right_room_for_long_label)
|
916
|
+
end
|
917
|
+
|
918
|
+
def extra_left_room_for_long_label
|
919
|
+
if require_extra_side_margin?
|
920
|
+
width = calculate_width(@marker_font, truncate_label_text(@labels[0]), rotation: @label_rotation)
|
921
|
+
case @label_rotation
|
922
|
+
when 0
|
923
|
+
width / 2.0
|
924
|
+
when 0..45
|
925
|
+
0
|
926
|
+
when -45..0
|
927
|
+
width
|
928
|
+
end
|
929
|
+
else
|
930
|
+
0
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
def extra_right_room_for_long_label
|
935
|
+
# Make space for half the width of the rightmost column label.
|
936
|
+
# Might be greater than the number of columns if between-style bar markers are used.
|
937
|
+
last_label = @labels.keys.max.to_i
|
938
|
+
if last_label >= (column_count - 1) && require_extra_side_margin?
|
939
|
+
width = calculate_width(@marker_font, truncate_label_text(@labels[last_label]), rotation: @label_rotation)
|
940
|
+
case @label_rotation
|
941
|
+
when 0
|
942
|
+
width / 2.0
|
943
|
+
when 0..45
|
944
|
+
width
|
945
|
+
when -45..0
|
946
|
+
0
|
947
|
+
end
|
948
|
+
else
|
949
|
+
0
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
def require_extra_side_margin?
|
954
|
+
!hide_bottom_label_area? && @center_labels_over_point
|
858
955
|
end
|
859
956
|
|
860
957
|
def setup_top_margin
|
@@ -866,11 +963,11 @@ module Gruff
|
|
866
963
|
end
|
867
964
|
|
868
965
|
def setup_bottom_margin
|
869
|
-
graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin +
|
966
|
+
graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin + labels_caps_height + LABEL_MARGIN
|
870
967
|
graph_bottom_margin += (calculate_legend_height + @legend_margin) if @legend_at_bottom
|
871
968
|
|
872
969
|
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
|
970
|
+
@raw_rows - graph_bottom_margin - x_axis_label_height
|
874
971
|
end
|
875
972
|
|
876
973
|
def truncate_label_text(text)
|
@@ -973,32 +1070,38 @@ module Gruff
|
|
973
1070
|
calculate_height(font, 'X')
|
974
1071
|
end
|
975
1072
|
|
1073
|
+
def calculate_labels_height(font)
|
1074
|
+
@labels.values.map { |label| calculate_height(font, label, rotation: @label_rotation) }.max || marker_caps_height
|
1075
|
+
end
|
1076
|
+
|
976
1077
|
# Returns the height of a string at this point size.
|
977
1078
|
#
|
978
1079
|
# Not scaled since it deals with dimensions that the regular scaling will
|
979
1080
|
# handle.
|
980
|
-
def calculate_height(font, text)
|
1081
|
+
def calculate_height(font, text, rotation: 0)
|
981
1082
|
text = text.to_s
|
982
1083
|
return 0 if text.empty?
|
983
1084
|
|
984
|
-
metrics = text_metrics(font, text)
|
985
|
-
|
1085
|
+
metrics = text_metrics(font, text, rotation: rotation)
|
1086
|
+
# Calculate manually because it does not return the height after rotation.
|
1087
|
+
(metrics.width * Math.sin(deg2rad(rotation))).abs + (metrics.height * Math.cos(deg2rad(rotation))).abs
|
986
1088
|
end
|
987
1089
|
|
988
1090
|
# Returns the width of a string at this point size.
|
989
1091
|
#
|
990
1092
|
# Not scaled since it deals with dimensions that the regular
|
991
1093
|
# scaling will handle.
|
992
|
-
def calculate_width(font, text)
|
1094
|
+
def calculate_width(font, text, rotation: 0)
|
993
1095
|
text = text.to_s
|
994
1096
|
return 0 if text.empty?
|
995
1097
|
|
996
|
-
metrics = text_metrics(font, text)
|
997
|
-
|
1098
|
+
metrics = text_metrics(font, text, rotation: rotation)
|
1099
|
+
# Calculate manually because it does not return the width after rotation.
|
1100
|
+
(metrics.width * Math.cos(deg2rad(rotation))).abs - (metrics.height * Math.sin(deg2rad(rotation))).abs
|
998
1101
|
end
|
999
1102
|
|
1000
|
-
def text_metrics(font, text)
|
1001
|
-
Gruff::Renderer::Text.new(renderer, text, font: font).metrics
|
1103
|
+
def text_metrics(font, text, rotation: 0)
|
1104
|
+
Gruff::Renderer::Text.new(renderer, text, font: font, rotation: rotation).metrics
|
1002
1105
|
end
|
1003
1106
|
|
1004
1107
|
def calculate_increment
|
@@ -1006,14 +1109,32 @@ module Gruff
|
|
1006
1109
|
# Try to use a number of horizontal lines that will come out even.
|
1007
1110
|
#
|
1008
1111
|
# TODO Do the same for larger numbers...100, 75, 50, 25
|
1009
|
-
@increment = @spread > 0 && marker_count > 0 ? significant(@spread / marker_count) : 1
|
1112
|
+
@increment = @spread > 0 && marker_count > 0 ? significant(@spread / marker_count) : 1.0
|
1010
1113
|
else
|
1011
1114
|
# TODO: Make this work for negative values
|
1012
1115
|
self.marker_count = (@spread / @y_axis_increment).to_i
|
1013
|
-
@increment = @y_axis_increment
|
1116
|
+
@increment = @y_axis_increment.to_f
|
1014
1117
|
end
|
1015
1118
|
end
|
1016
1119
|
|
1120
|
+
def calculate_label_offset(font, label, margin, rotation)
|
1121
|
+
width = calculate_width(font, label, rotation: rotation)
|
1122
|
+
height = calculate_height(font, label, rotation: rotation)
|
1123
|
+
x_offset = begin
|
1124
|
+
case rotation
|
1125
|
+
when 0
|
1126
|
+
0
|
1127
|
+
when 0..45
|
1128
|
+
width / 2.0
|
1129
|
+
when -45..0
|
1130
|
+
-(width / 2.0)
|
1131
|
+
end
|
1132
|
+
end
|
1133
|
+
y_offset = (height / 2.0) > margin ? (height / 2.0) : margin
|
1134
|
+
|
1135
|
+
[x_offset, y_offset]
|
1136
|
+
end
|
1137
|
+
|
1017
1138
|
# Used for degree <=> radian conversions
|
1018
1139
|
def deg2rad(angle)
|
1019
1140
|
(angle * Math::PI) / 180.0
|
data/lib/gruff/bezier.rb
CHANGED
@@ -22,9 +22,14 @@ class Gruff::Bezier < Gruff::Base
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def draw_graph
|
25
|
-
x_increment = @graph_width / (column_count - 1)
|
25
|
+
x_increment = (@graph_width / (column_count - 1)).to_f
|
26
|
+
|
27
|
+
renderer_class = RUBY_PLATFORM == 'java' ? Gruff::Renderer::Polyline : Gruff::Renderer::Bezier
|
28
|
+
stroke_width = clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4.0), 5.0)
|
26
29
|
|
27
30
|
store.norm_data.each do |data_row|
|
31
|
+
next if data_row[1].empty?
|
32
|
+
|
28
33
|
poly_points = []
|
29
34
|
|
30
35
|
data_row[1].each_with_index do |data_point, index|
|
@@ -43,13 +48,7 @@ private
|
|
43
48
|
draw_label(new_x, index)
|
44
49
|
end
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
if RUBY_PLATFORM == 'java'
|
49
|
-
Gruff::Renderer::Polyline.new(renderer, color: data_row.color, width: stroke_width).render(poly_points)
|
50
|
-
else
|
51
|
-
Gruff::Renderer::Bezier.new(renderer, color: data_row.color, width: stroke_width).render(poly_points)
|
52
|
-
end
|
51
|
+
renderer_class.new(renderer, color: data_row.color, width: stroke_width).render(poly_points)
|
53
52
|
end
|
54
53
|
end
|
55
54
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Here's how to set up a Gruff::
|
4
|
+
# Here's how to set up a Gruff::Box.
|
5
5
|
#
|
6
|
-
# g = Gruff::
|
6
|
+
# g = Gruff::Box.new
|
7
7
|
# g.data "A", [2, 3, 5, 6, 8, 10, 11, 15, 17, 20, 28, 29, 33, 34, 45, 46, 49, 61]
|
8
8
|
# g.data "B", [3, 4, 34, 35, 38, 39, 45, 60, 61, 69, 80, 130]
|
9
9
|
# g.data "C", [4, 40, 41, 46, 57, 64, 77, 76, 79, 78, 99, 153]
|
10
10
|
# g.write("box_plot.png")
|
11
11
|
#
|
12
|
-
class Gruff::
|
12
|
+
class Gruff::Box < Gruff::Base
|
13
13
|
# Specifies the filling opacity in area graph. Default is +0.2+.
|
14
14
|
attr_writer :fill_opacity
|
15
15
|
|
@@ -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
|
@@ -88,11 +90,15 @@ private
|
|
88
90
|
end
|
89
91
|
|
90
92
|
def normalized_boxes
|
91
|
-
@normalized_boxes ||= store.norm_data.map { |data| Gruff::
|
93
|
+
@normalized_boxes ||= store.norm_data.map { |data| Gruff::Box::BoxData.new(data.label, data.points, data.color) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def column_count
|
97
|
+
normalized_boxes.size
|
92
98
|
end
|
93
99
|
|
94
100
|
def calculate_spacing
|
95
|
-
|
101
|
+
column_count - 1
|
96
102
|
end
|
97
103
|
|
98
104
|
# @private
|