Skip to content

Commit 7b5baff

Browse files
committed
ported code for dot graphs
1 parent 01a90bb commit 7b5baff

5 files changed

Lines changed: 182 additions & 5 deletions

File tree

lib/rubyplot/axes.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Axes
1616
#
1717
# Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008
1818
attr_accessor :x_ticks
19+
attr_accessor :y_ticks
1920

2021
# Main title for this Axes.
2122
attr_accessor :title
@@ -72,6 +73,10 @@ def bubble! *args, &block
7273
add_plot "Bubble", *args, &block
7374
end
7475

76+
def dot! *args, &block
77+
add_plot "Dot", *args, &block
78+
end
79+
7580
def write file_name
7681
@plots[0].write file_name
7782
end

lib/rubyplot/magick_wrapper/artist.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,14 @@ def setup_graph_measurements
240240

241241
@legend_caps_height = calculate_caps_height(@legend_font_size)
242242

243-
# For now, the labels feature only focuses on the dot graph so it makes sense to only have
244-
# this as an attribute for this kind of graph and not for others.
243+
# For now, the labels feature only focuses on the dot graph so it
244+
# makes sense to only have this as an attribute for this kind of
245+
# graph and not for others.
246+
# FIXME: move this out of Artist.
245247
if @geometry.has_left_labels
246248
longest_left_label_width = calculate_width(
247249
@marker_font_size,
248-
@axes.x_ticks.values.inject('') { |value, memo|
250+
@axes.y_ticks.values.inject('') { |value, memo|
249251
value.to_s.length > memo.to_s.length ? value : memo
250252
}) * 1.25
251253
else

lib/rubyplot/magick_wrapper/plot.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
require_relative 'plot/line'
44
require_relative 'plot/area'
55
require_relative 'plot/bubble'
6+
require_relative 'plot/dot'
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
module Rubyplot
2+
module MagickWrapper
3+
module Plot
4+
class Dot < Artist
5+
def draw
6+
@geometry.has_left_labels = true
7+
super
8+
return unless @geometry.has_data
9+
10+
# Setup spacing.
11+
spacing_factor = 1.0
12+
@items_width = @graph_height / @geometry.column_count.to_f
13+
@item_width = @items_width * spacing_factor / @geometry.norm_data.size
14+
@d = @d.stroke_opacity 0.0
15+
padding = (@items_width * (1 - spacing_factor)) / 2
16+
17+
@geometry.norm_data.each_with_index do |data_row, row_index|
18+
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
19+
x_pos = @graph_left + (data_point * @graph_width)
20+
y_pos = @graph_top + (@items_width * point_index) +
21+
padding + (@items_width.to_f / 2.0).round
22+
23+
if row_index == 0
24+
@d = @d.stroke(@marker_color)
25+
@d = @d.fill(@marker_color)
26+
@d = @d.stroke_width 1.0
27+
@d = @d.stroke_opacity 0.1
28+
@d = @d.fill_opacity 0.1
29+
@d = @d.line(@graph_left, y_pos, @graph_left + @graph_width, y_pos)
30+
@d = @d.fill_opacity 1
31+
end
32+
33+
@d = @d.fill @plot_colors[row_index]
34+
@d = @d.circle(x_pos, y_pos, x_pos + (@item_width.to_f / 3.0).round, y_pos)
35+
draw_label(y_pos, point_index)
36+
end
37+
end
38+
@d.draw(@base_image)
39+
end
40+
41+
# Instead of base class version, draws vertical background lines and label
42+
def draw_line_markers
43+
@d = @d.stroke_antialias false
44+
45+
# Draw horizontal line markers and annotate with numbers
46+
@d = @d.stroke(@marker_color)
47+
@d = @d.stroke_width 1
48+
if @y_axis_increment
49+
increment = @y_axis_increment
50+
number_of_lines = (@spread / @y_axis_increment).to_i
51+
else
52+
# Try to use a number of horizontal lines that will come out even.
53+
#
54+
# TODO Do the same for larger numbers...100, 75, 50, 25
55+
if @geometry.marker_count.nil?
56+
(3..7).each do |lines|
57+
if @spread % lines == 0.0
58+
@geometry.marker_count = lines
59+
break
60+
end
61+
end
62+
@geometry.marker_count ||= 5
63+
end
64+
# TODO: Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
65+
@geometry.increment = @spread > 0 && @geometry.marker_count > 0 ? significant(@spread / @geometry.marker_count) : 1
66+
67+
number_of_lines = @geometry.marker_count
68+
increment = @geometry.increment
69+
end
70+
71+
(0..number_of_lines).each do |index|
72+
marker_label = @geometry.minimum_value + index * increment
73+
x = @graph_left + (marker_label - @geometry.minimum_value) * @graph_width / @spread
74+
@d = @d.line(x, @graph_bottom, x, @graph_bottom + 0.5 * LABEL_MARGIN)
75+
76+
unless @geometry.hide_line_numbers
77+
@d.fill = @font_color
78+
@d.font = @font if @font
79+
@d.stroke = 'transparent'
80+
@d.pointsize = scale_fontsize(@marker_font_size)
81+
@d.gravity = CenterGravity
82+
# TODO: Center text over line
83+
@d = @d.scale_annotation(@base_image,
84+
0, 0, # Width of box to draw text in
85+
x, @graph_bottom + (LABEL_MARGIN * 2.0), # Coordinates of text
86+
label(marker_label, increment), @scale)
87+
end # unless
88+
@d = @d.stroke_antialias true
89+
end
90+
end
91+
92+
# Draw on the Y axis instead of the X
93+
def draw_label(y_offset, index)
94+
if !@axes.y_ticks[index].nil? && @geometry.labels_seen[index].nil?
95+
@d.fill = @font_color
96+
@d.font = @font if @font
97+
@d.stroke = 'transparent'
98+
@d.font_weight = NormalWeight
99+
@d.pointsize = scale_fontsize(@marker_font_size)
100+
@d.gravity = EastGravity
101+
@d = @d.scale_annotation(@base_image,
102+
1, 1,
103+
-@graph_left + LABEL_MARGIN * 2.0, y_offset,
104+
@axes.y_ticks[index], @scale)
105+
@geometry.labels_seen[index] = 1
106+
end
107+
end
108+
end # class Dot
109+
end # module Plot
110+
end # module MagickWrapper
111+
end # module Rubyplot

spec/axes_spec.rb

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,72 @@
1313
]
1414
end
1515

16-
context "#bubble!", focus: true do
16+
context "#dot!", focus: true do
17+
before do
18+
@temp_dir = SPEC_ROOT + "temp/dot"
19+
@fix_dir = SPEC_ROOT + "fixtures/dot"
20+
FileUtils.mkdir_p @temp_dir
21+
end
22+
23+
it "plots a single dot plot" do
24+
fig = Rubyplot::Figure.new
25+
axes = fig.add_subplot 0,0
26+
axes.dot! do |p|
27+
p.data [0,5,8,15]
28+
p.label = "Car"
29+
p.color = :maroon
30+
p.minimum_value = 0 # FIXME: change this!
31+
end
32+
axes.y_ticks = {
33+
0 => '5/6',
34+
1 => '5/15',
35+
2 => '5/24',
36+
3 => '5/30'
37+
}
38+
39+
file = "/#{Rubyplot.backend}_simple_dot.png"
40+
fig.write(@temp_dir + file)
41+
42+
#expect("temp/dot" + file).to eq_image("fixtures/dot" + file)
43+
end
44+
45+
it "plots multiple dot plots" do
46+
fig = Rubyplot::Figure.new
47+
axes = fig.add_subplot 0,0
48+
[
49+
[[0, 5, 8, 15], "cars", :maroon],
50+
[[10, 3, 2, 8], "buses", :grey],
51+
[[2, 15, 8, 11],"science", :yellow]
52+
].each do |data, label, color|
53+
axes.dot! do |p|
54+
p.data data
55+
p.label = label
56+
p.color = color
57+
p.minimum_value = 0
58+
end
59+
end
60+
axes.y_ticks = {
61+
0 => '5/6',
62+
1 => '5/15',
63+
2 => '5/24',
64+
3 => '5/30'
65+
}
66+
67+
file = "/#{Rubyplot.backend}_simple_dot.png"
68+
fig.write(@temp_dir + file)
69+
70+
#expect("temp/dot" + file).to eq_image("fixtures/dot" + file)
71+
end
72+
end
73+
74+
context "#bubble!" do
1775
before do
1876
@temp_dir = SPEC_ROOT + "temp/bubble"
1977
@fix_dir = SPEC_ROOT + "fixtures/bubble"
2078
FileUtils.mkdir_p @temp_dir
2179
end
2280

23-
it "plots a single bubble plot", focus: true do
81+
it "plots a single bubble plot" do
2482
fig = Rubyplot::Figure.new
2583
axes = fig.add_subplot 0,0
2684
axes.bubble! do |p|

0 commit comments

Comments
 (0)