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.
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
- # A hash of names for the individual columns, where the key is the array
49
- # index for the column this label represents.
50
- #
51
- # Not all columns need to be named.
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
- # @example
54
- # { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
55
- attr_writer :labels
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
- # graph.theme = {
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 # :nodoc:
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
- margin_on_right = graph_right_margin
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) + marker_caps_height
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 + legend_caps_height + LABEL_MARGIN + (@x_axis_label ? (LABEL_MARGIN * 2) + marker_caps_height : 0)
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 + LABEL_MARGIN
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
- draw_label_at(1.0, 1.0, x_offset, y_offset, @labels[index], gravity)
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 = Magick::NorthGravity)
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 = Magick::CenterGravity)
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) # :nodoc:
834
+ def scale(value)
760
835
  value * @scale
761
836
  end
762
837
 
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:
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) # :nodoc:
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
- # Shift graph if left line numbers are hidden
855
- line_number_width = !@has_left_labels && (@hide_line_markers || @hide_line_numbers) ? 0.0 : (longest_left_label_width + LABEL_MARGIN)
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
- @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : marker_caps_height + (LABEL_MARGIN * 2))
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 + marker_caps_height + LABEL_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 - @label_stagger_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
- metrics.height
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
- metrics.width
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
@@ -25,6 +25,8 @@ private
25
25
  x_increment = @graph_width / (column_count - 1)
26
26
 
27
27
  store.norm_data.each do |data_row|
28
+ next if data_row[1].empty?
29
+
28
30
  poly_points = []
29
31
 
30
32
  data_row[1].each_with_index do |data_point, index|
@@ -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) / normalized_boxes.size
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
@@ -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) / normalized_candlesticks.size
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) do
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
- @candlesticks ||= store.norm_data.map { |data| Gruff::Candlestick::CandlestickData.new(*data.points) }
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::Circle.new(renderer, color: data_row.color).render(x_pos, y_pos, x_pos + (item_width / 3.0), y_pos)
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