Skip to content

Commit 29e6bbe

Browse files
committed
Adding support for multiple bar plots
1 parent a3d50cf commit 29e6bbe

7 files changed

Lines changed: 114 additions & 34 deletions

File tree

lib/rubyplot/artist/axes.rb

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,9 @@ class Axes < Base
2020
attr_accessor :x_range
2121
# Range of Y axis.
2222
attr_accessor :y_range,
23-
:x_tick_count, :y_tick_count, :text_font, :grid,
23+
:text_font, :grid,
2424
:bounding_box, :x_axis_padding, :y_axis_padding, :origin,
2525
:title_shift, :title_margin
26-
27-
# A hash of names for the individual columns, where the key is the array
28-
# index for the column this label represents.
29-
#
30-
# Not all columns need to be named.
31-
#
32-
# Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008
33-
attr_accessor :x_ticks
34-
attr_accessor :y_ticks
3526
# Main title for this Axes.
3627
attr_accessor :title
3728
# Rubyplot::Figure object to which this Axes belongs.
@@ -71,8 +62,6 @@ def initialize figure
7162
@y_axis_margin = 40.0
7263
@x_range = [nil, nil]
7364
@y_range = [nil, nil]
74-
@x_tick_count = :default
75-
@y_tick_count = :default
7665

7766
@origin = [nil, nil]
7867
@title = ""
@@ -81,7 +70,6 @@ def initialize figure
8170
@text_font = :default
8271
@grid = true
8372
@bounding_box = true
84-
@x_ticks = {}
8573
@plots = []
8674

8775
@raw_rows = width * (height/width)
@@ -124,6 +112,7 @@ def legend_box_iy
124112

125113
# Write an image to a file by communicating with the backend.
126114
def draw
115+
consolidate_plots
127116
configure_title
128117
calculate_xy_axes_origin
129118
configure_xy_axes
@@ -191,6 +180,10 @@ def height
191180
(1 - (@figure.top_spacing + @figure.bottom_spacing)) * @figure.height
192181
end
193182

183+
def x_ticks= ticks_hash
184+
@x_ticks = ticks_hash
185+
end
186+
194187
private
195188

196189
def add_plot plot_type, *args, &block
@@ -300,6 +293,12 @@ def label_string(value, increment)
300293
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{THOUSAND_SEPARATOR}")
301294
parts.join('.')
302295
end
296+
297+
def consolidate_plots
298+
bars = @plots.map { |p| p.is_a?(Rubyplot::Artist::Plot::Bar) }
299+
@plots.delete_if { |p| p.is_a?(Rubyplot::Artist::Plot::Bar) }
300+
@plots << Rubyplot::Artist::Plot::MultiBars.new(self, bars)
301+
end
303302
end # class Axes
304303
end # moudle Artist
305304
end # module Rubyplot

lib/rubyplot/artist/axis/base.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class Base
77

88
attr_reader :label, :ticks, :major_ticks_count, :min_val, :max_val, :title
99
attr_reader :abs_x1, :abs_x2, :abs_y1, :abs_y2, :backend
10-
attr_reader :stroke_width
10+
attr_reader :stroke_width, :major_ticks
1111

1212
def initialize axes, title, min_val, max_val
1313
@axes = axes
@@ -16,6 +16,7 @@ def initialize axes, title, min_val, max_val
1616
@max_val = max_val
1717
@stroke_width = 1.0
1818
@backend = @axes.backend
19+
@major_ticks = []
1920
end
2021
end # class Base
2122
end # class Axis

lib/rubyplot/artist/axis/x_axis.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ def initialize(*)
1111
@abs_y2 = @axes.origin[1]
1212
@major_ticks_count = 5
1313
@major_ticks_distance = (@abs_x2 - @abs_x1) / @major_ticks_count
14-
@x_ticks = []
1514
configure_axis_line
1615
populate_major_x_ticks
1716
configure_title
@@ -35,7 +34,7 @@ def populate_major_x_ticks
3534
value_distance = (@max_val) / @major_ticks_count.to_f
3635
@major_ticks_count.times do |count|
3736
count += 1
38-
@x_ticks << Rubyplot::Artist::XTick.new(
37+
@major_ticks << Rubyplot::Artist::XTick.new(
3938
@axes,
4039
abs_x: count * @major_ticks_distance + @abs_x1,
4140
abs_y: @abs_y1,

lib/rubyplot/artist/plot/bar.rb

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,52 @@ module Plot
44
class Bar < Artist::Plot::Base
55
# Space between the columns.
66
attr_accessor :bar_spacing
7+
# Width of each bar.
8+
attr_accessor :bar_width
79
# Number between 0 and 1.0 denoting spacing between the bars.
810
# 0.0 means no spacing at all 1.0 means that each bars' width
911
# is nearly 0 (so each bar is a simple line with no X dimension).
10-
attr_reader :spacing_factor
12+
attr_reader :spacing_ratio
1113
def initialize(*)
1214
super
13-
@spacing_factor = 0.9
15+
@spacing_ratio = 0.1
1416
end
1517

1618
# Set the spacing factor for this bar plot.
17-
def spacing_factor= sf
18-
raise ValueError, '@spacing_factor must be between 0.00 and 1.00' unless
19+
def spacing_ratio= sf
20+
raise ValueError, '@spacing_ratio must be between 0.00 and 1.00' unless
1921
(sf >= 0) && (sf <= 1)
20-
@spacing_factor = sf
22+
@spacing_ratio = sf
2123
end
22-
24+
25+
# Set Bar plot data.
26+
def data y_values
27+
@data[:y_values] = y_values
28+
set_yrange
29+
end
30+
31+
# Number of bars in this Bar plot
32+
def num_bars
33+
@data[:y_values].size
34+
end
35+
2336
def draw
2437
super
2538
return unless @axes.geometry.has_data
39+
configure_bars
40+
end
41+
42+
private
43+
44+
# FIXME: handle positive and negative bars.
45+
def configure_bars
46+
x_axis_length = @axes.x_axis.abs_x2 - @axes.x_axis.abs_x1
47+
@bar_width = coords_width / @data[:y_values].to_f
48+
padding = @bar_width * @spacing_ratio / 2
49+
@normalized_data[:y_values].each_with_index do |iy, index|
50+
ix = @normalized_data[:x_values][index]
51+
left_x = ix * x_axis_length
52+
end
2653
end
2754
end # class Bar
2855
end # module Plot

lib/rubyplot/artist/plot/base.rb

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,8 @@ def data x_values, y_values
4242
# Set column count if this is larger than previous column counts
4343
@axes.geometry.column_count = y_values.length > @axes.geometry.column_count ?
4444
y_values.length : @axes.geometry.column_count
45-
if @axes.y_range[0].nil? && @axes.y_range[1].nil?
46-
@axes.y_range[0] = y_values.min
47-
@axes.y_range[1] = y_values.max
48-
end
49-
if @axes.x_range[1].nil? && @axes.x_range[0].nil?
50-
@axes.x_range[0] = x_values.min
51-
@axes.x_range[1] = x_values.max
52-
end
45+
set_yrange
46+
set_xrange
5347
@axes.geometry.has_data = true
5448
end
5549

@@ -61,9 +55,25 @@ def normalize
6155
y_spread = @axes.y_range[1] - y_min
6256
@normalized_data[:x_values] = @data[:x_values].map do |x|
6357
(x.to_f - x_min) / x_spread
64-
end
58+
end if @data[:x_values]
6559
@normalized_data[:y_values] = @data[:y_values].map do |y|
6660
(y.to_f - y_min) / y_spread
61+
end if @data[:y_values]
62+
end
63+
64+
protected
65+
66+
def set_xrange
67+
if @axes.x_range[1].nil? && @axes.x_range[0].nil?
68+
@axes.x_range[0] = @data[:x_values].min
69+
@axes.x_range[1] = @data[:x_values].max
70+
end
71+
end
72+
73+
def set_yrange
74+
if @axes.y_range[0].nil? && @axes.y_range[1].nil?
75+
@axes.y_range[0] = @data[:y_values].min
76+
@axes.y_range[1] = @data[:y_values].max
6777
end
6878
end
6979
end # class Base
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
module Rubyplot
2+
module Artist
3+
module Plot
4+
# Class for holding multiple Bar plot objects.
5+
class MultiBars < Artist::Plot::Base
6+
# The max. width that each bar can occupy.
7+
attr_reader :max_bar_width
8+
9+
def initialize(*, bar_plots:)
10+
super
11+
@bar_plots = bar_plots
12+
end
13+
14+
def draw
15+
configure_plot_geometry_data
16+
configure_x_ticks
17+
broadcast_to_bar_plots
18+
@bar_plots.each(&:draw)
19+
end
20+
21+
private
22+
23+
def configure_plot_geometry_data
24+
max_bars = @bar_plots.map { |bar| bar.num_bars }.max
25+
@max_bar_width = (@axes.x_axis.abs_x2 - @axes.x_axis.abs_x1).abs
26+
@bar_plots.each do |bar|
27+
set_bar_coords bar
28+
end
29+
end
30+
31+
def configure_x_ticks
32+
if @axes.x_ticks # user supplied ticks
33+
34+
else # default ticks
35+
36+
end
37+
end
38+
39+
def set_bar_coords bar_plot
40+
41+
end
42+
end # class MultiBars
43+
end # module Plot
44+
end # module Artist
45+
end # module Rubyplot

spec/axes_spec.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,11 +449,10 @@
449449
# FileUtils.rm_rf SPEC_ROOT + "temp/bar"
450450
end
451451

452-
it "adds a simple bar plot" do
452+
it "adds a simple bar plot", focus: true do
453453
fig = Rubyplot::Figure.new
454454
axes = fig.add_subplot 0,0
455455
axes.bar!(600) do |p|
456-
p.marker_count = 8
457456
p.data [5,12,9,6,7]
458457
p.label = "data"
459458
p.color = :yellow
@@ -523,7 +522,7 @@
523522
# expect(@temp_dir + file).to eq_image(@fix_dir + file)
524523
end
525524

526-
skip "adds multiple bar plots for wide graph" do
525+
skip "adds multiple bar plots for wide graph", focus: true do
527526
fig = Rubyplot::Figure.new
528527
axes = fig.add_subplot 0,0
529528
data.each do |name, nums|

0 commit comments

Comments
 (0)