Skip to content

Commit 2c86f52

Browse files
committed
added new line plots
1 parent ef260b9 commit 2c86f52

15 files changed

Lines changed: 197 additions & 121 deletions

File tree

lib/rubyplot/artist.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require_relative 'artist/base'
22
require_relative 'artist/legend'
3-
require_relative 'artist/line'
3+
require_relative 'artist/line2d'
44
require_relative 'artist/tick'
55
require_relative 'artist/axis'
66
require_relative 'artist/text'

lib/rubyplot/artist/axes.rb

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ def initialize figure, width, height, position
7070

7171
@x_title = ''
7272
@y_title = ''
73-
@x_range = [0, 0]
74-
@y_range = [0, 0]
73+
@x_range = [nil, nil]
74+
@y_range = [nil, nil]
7575
@x_tick_count = :default
7676
@y_tick_count = :default
7777

@@ -136,7 +136,9 @@ def bar! *args, &block
136136
end
137137

138138
def line! *args, &block
139-
add_plot "Line", *args, &block
139+
plot = Rubyplot::Artist::Plot::Line.new self
140+
yield(plot) if block_given?
141+
@plots << plot
140142
end
141143

142144
def area! *args, &block
@@ -181,9 +183,9 @@ def with_backend plot_type, *args
181183

182184
def prepare_xy_axes
183185
@x_axis = Rubyplot::Artist::XAxis.new(
184-
self, @x_title, @geometry.x_min_value, @geometry.x_max_value)
186+
self, @x_title, @x_range[0], @x_range[1])
185187
@y_axis = Rubyplot::Artist::YAxis.new(
186-
self, @y_title, @geometry.y_min_value, @geometry.y_max_value)
188+
self, @y_title, @y_range[0], @y_range[1])
187189
@x_axis.draw
188190
@y_axis.draw
189191
end
@@ -243,9 +245,9 @@ def setup_drawing
243245

244246
# Calculate spread of the data.
245247
def calculate_spread
246-
@y_spread = @geometry.y_max_value.to_f - @geometry.y_min_value.to_f
247-
unless @geometry.x_min_value.nil? && @geometry.x_max_value.nil?
248-
@x_spread = @geometry.x_max_value.to_f - @geometry.x_min_value.to_f
248+
@y_spread = @y_range[1].to_f - @y_range[0].to_f
249+
unless @x_range[0].nil? && @x_range[1].nil?
250+
@x_spread = @x_range[1].to_f - @x_range[0].to_f
249251
@x_spread = @x_spread > 0 ? @x_spread : 1
250252
end
251253
end
@@ -280,7 +282,7 @@ def setup_graph_measurements
280282
else
281283
longest_left_label_width = @backend.string_width(
282284
@font, @marker_font_size,
283-
label_string(@geometry.y_max_value.to_f, @geometry.increment))
285+
label_string(@y_range[1].to_f, @geometry.increment))
284286
end
285287

286288
# Shift graph if left line numbers are hidden
@@ -291,11 +293,14 @@ def setup_graph_measurements
291293
line_number_width +
292294
(@geometry.y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
293295
# Make space for half the width of the rightmost column label.
294-
last_label = @x_ticks.keys.max.to_i
295-
extra_room_for_long_label = last_label >= (@geometry.column_count - 1) &&
296-
@geometry.center_labels_over_point ?
297-
@backend.string_width(@marker_font_size,
298-
@x_ticks[last_label]) / 2.0 : 0
296+
# last_label = @x_ticks.keys.max.to_i
297+
# extra_room_for_long_label = last_label >= (@geometry.column_count - 1) &&
298+
# @geometry.center_labels_over_point ?
299+
# @backend.string_width(
300+
# @font,
301+
# @marker_font_size,
302+
# @x_ticks[last_label]) / 2.0 : 0
303+
extra_room_for_long_label = 0
299304
# Margins
300305
@graph_right_margin = @geometry.right_margin + extra_room_for_long_label
301306
@graph_bottom_margin = @geometry.bottom_margin + @marker_caps_height + LABEL_MARGIN

lib/rubyplot/artist/axis/base.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def initialize axes, title, min_val, max_val
1515
end
1616

1717
def draw
18-
@axes.backend.draw_line(x1: @x1, y1: @y1, x2: @x2, y2: @y2)
18+
Rubyplot::Artist::Line2D.new(
19+
self, x1: @x1, y1: @y1, x2: @x2, y2: @y2, stroke_width: 2.0)
1920
end
2021
end # class Base
2122
end # class Axis

lib/rubyplot/artist/legend.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ def draw_legend_color_indicator
4444
y1: @current_y_offset - @legend_box_size/2.0,
4545
x2: @current_x_offset + @legend_box_size,
4646
y2: @current_y_offset + @legend_box_size/2.0,
47-
fill: @color,
47+
color: @color,
4848
stroke: 'transparent'
4949
)
5050
end
5151

52-
# FIXME: should work for multiple legends.
52+
# FIXME: should work for multiple legeuidends.
5353
def calculate_offsets
5454
@current_x_offset = (@axes.geometry.raw_columns -
5555
@label_widths.first.inject(:+))/2

lib/rubyplot/artist/line.rb

Lines changed: 0 additions & 20 deletions
This file was deleted.

lib/rubyplot/artist/line2d.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Rubyplot
2+
module Artist
3+
class Line2D
4+
def initialize(owner,x1:,y1:,x2:,y2:,color: '#000000',
5+
stroke_opacity: 1.0, stroke_width:)
6+
@owner = owner
7+
@x1 = x1
8+
@y1 = y1
9+
@x2 = x2
10+
@y2 = y2
11+
@color = color
12+
@backend = @owner.backend
13+
end
14+
15+
def draw
16+
@backend.draw_line(x1: @x1, y1: @y1, x2: @x2, y2: @y2, color: @color)
17+
end
18+
end # class Line2D
19+
end # class Artist
20+
end # module Rubyplot

lib/rubyplot/artist/plot.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
require_relative 'plot/base'
22
require_relative 'plot/scatter'
3+
require_relative 'plot/line'

lib/rubyplot/artist/plot/base.rb

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Artist
33
module Plot
44
class Base < Artist::Base
55
attr_reader :axes, :data
6+
attr_writer :stroke_width, :stroke_opacity
67

78
def initialize axes
89
@axes = axes
@@ -11,29 +12,52 @@ def initialize axes
1112
label: :default,
1213
color: :default
1314
}
15+
@normalized_data = {
16+
:y_values => nil,
17+
:x_values => nil
18+
}
19+
@stroke_width = 4.0
20+
@stroke_opacity = 1.0
21+
end
22+
23+
def label= label
24+
@data[:label] = label
1425
end
1526

16-
def data y_values
27+
def color= color
28+
@data[:color] = Rubyplot::Color::COLOR_INDEX[color]
29+
end
30+
31+
def data x_values, y_values
32+
@data[:x_values] = x_values
1733
@data[:y_values] = y_values
1834
# Set column count if this is larger than previous column counts
1935
@axes.geometry.column_count = y_values.length > @axes.geometry.column_count ?
2036
y_values.length : @axes.geometry.column_count
37+
if @axes.y_range[0].nil? && @axes.y_range[1].nil?
38+
@axes.y_range[0] = y_values.min
39+
@axes.y_range[1] = y_values.max
40+
end
41+
if @axes.x_range[1].nil? && @axes.x_range[0].nil?
42+
@axes.x_range[0] = x_values.min
43+
@axes.x_range[1] = x_values.max
44+
end
45+
@axes.geometry.has_data = true
46+
end
2147

22-
# FIXME: move this to XAxis and YAxis later.
23-
# Pre-normalize => Set the max and min values of the data.
24-
y_values.each do |val|
25-
# Initialize the maximum and minimum values so that the spread starts
26-
# at the lowest points in the data and then changes as iteration.
27-
if @axes.geometry.y_max_value.nil? && @axes.geometry.y_min_value.nil?
28-
@axes.geometry.y_max_value = @axes.geometry.y_min_value = val
29-
end
30-
@axes.geometry.y_max_value = val > @axes.geometry.y_max_value ?
31-
val : @axes.geometry.y_max_value
32-
@axes.geometry.y_min_value = val < @axes.geometry.y_min_value ?
33-
val : @axes.geometry.y_min_value
34-
@axes.geometry.has_data = true
48+
# Normalize original data between the spread of the data.
49+
def normalize x_spread, y_spread
50+
@normalized_data[:x_values] = @data[:x_values].map do |x|
51+
(x.to_f - @axes.x_range[0]) / x_spread
52+
end
53+
@normalized_data[:y_values] = @data[:y_values].map do |y|
54+
(y.to_f - @axes.y_range[0]) / y_spread
3555
end
3656
end
57+
58+
def create_legend
59+
Rubyplot::Artist::Legend.new(@axes, @data[:label], @data[:color])
60+
end
3761
end # class Base
3862
end # module Plot
3963
end # module Artist

lib/rubyplot/artist/plot/line.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
module Rubyplot
2+
module Artist
3+
module Plot
4+
class Line < Artist::Plot::Base
5+
# Set true if you want to see only the vertices of the line plot.
6+
attr_writer :hide_lines
7+
8+
def initialize(*)
9+
super
10+
@hide_lines = false
11+
12+
end
13+
14+
def data x_values, y_values=[]
15+
y_values = Array.new(x_values.size) { |i| i } if y_values.empty?
16+
super x_values, y_values
17+
end
18+
19+
def draw
20+
return unless @axes.geometry.has_data
21+
if @normalized_data[:x_values].size == 1
22+
draw_single_point
23+
else
24+
draw_lines
25+
end
26+
end
27+
28+
private
29+
30+
# FIXME: make this edge case happen.
31+
def draw_single_point
32+
# Rubyplot::Artist::Circle.new()
33+
end
34+
35+
def draw_lines
36+
@normalized_data[:x_values].each_with_index do |ix, idx_ix|
37+
prev_x = prev_y = nil
38+
iy = @normalized_data[:y_values][idx_ix]
39+
new_x = ix * @axes.graph_width + @axes.graph_left
40+
new_y = @axes.graph_top + (@axes.graph_height - iy * @axes.graph_height)
41+
unless prev_x.nil? && prev_y.nil?
42+
Rubyplot::Artist::Line2D.new(
43+
x1: prev_x,
44+
y1: prev_y,
45+
x2: new_x,
46+
y2: new_y,
47+
stroke_opacity: @stroke_opacity,
48+
stroke_width: @stroke_width
49+
).draw
50+
end
51+
prev_x = new_x
52+
prev_y = new_y
53+
end
54+
end
55+
end # class Line
56+
end # module Plot
57+
end # module Artist
58+
end # module Rubyplot
59+

lib/rubyplot/artist/plot/scatter.rb

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,12 @@ module Rubyplot
22
module Artist
33
module Plot
44
class Scatter < Artist::Plot::Base
5-
attr_writer :stroke_width, :stroke_opacity, :circle_radius
5+
attr_writer :circle_radius
66

77
def initialize(*)
88
super
9-
@normalized_data = {
10-
:y_values => nil,
11-
:x_values => nil
12-
}
13-
@points = []
14-
@stroke_width = 4.0
15-
@stroke_opacity = 1.0
169
@circle_radius = 4.0
1710
end
18-
19-
def data x_values, y_values
20-
super y_values
21-
@data[:x_values] = x_values
22-
if @axes.geometry.x_max_value.nil? && @axes.geometry.x_min_value.nil?
23-
@axes.geometry.x_max_value = @axes.geometry.x_min_value = x_values.first
24-
end
25-
@axes.geometry.x_max_value = x_values.max > @axes.geometry.x_max_value ?
26-
x_values.max : @axes.geometry.x_max_value
27-
@axes.geometry.x_min_value = x_values.min < @axes.geometry.x_min_value ?
28-
x_values.min : @axes.geometry.x_min_value
29-
end
30-
31-
# Normalize original data between the spread of the data.
32-
def normalize x_spread, y_spread
33-
@normalized_data[:x_values] = @data[:x_values].map do |x|
34-
(x.to_f - @axes.geometry.x_min_value) / x_spread
35-
end
36-
@normalized_data[:y_values] = @data[:y_values].map do |y|
37-
(y.to_f - @axes.geometry.y_min_value) / y_spread
38-
end
39-
end
40-
41-
def create_legend
42-
Rubyplot::Artist::Legend.new(@axes, @data[:label], @data[:color])
43-
end
44-
45-
def label= label
46-
@data[:label] = label
47-
end
48-
49-
def color= color
50-
@data[:color] = Rubyplot::Color::COLOR_INDEX[color]
51-
end
5211

5312
def draw
5413
@x_increment = if @axes.geometry.column_count > 1

0 commit comments

Comments
 (0)