Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Four quadrants implementation with major ticks #41

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 108 additions & 8 deletions lib/rubyplot/artist/axes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,32 @@ class Axes < Base
attr_reader :label_stagger_height
# Rubyplot::Artist::XAxis object.
attr_reader :x_axis
# Rubyplot::Artist::XDashAxis object.
attr_reader :x_dash_axis

# Rubyplot::Artist::YAxis object.
attr_reader :y_axis
# Rubyplot::Artist::YDASHAxis object.
attr_reader :y_dash_axis

# Array of X ticks.
attr_reader :x_ticks
# Array of X dash ticks.
attr_reader :x_dash_ticks
# Array of Y ticks.
attr_reader :y_ticks
# Array of Y dash ticks.
attr_reader :y_dash_ticks
# Array denoting co-ordinates in pixels of the origin of X and Y axes.
attr_reader :origin
# Number of X ticks.
attr_accessor :num_x_ticks
# Number of X dash ticks.
attr_accessor :num_x_dash_ticks
# Number of Y ticks.
attr_accessor :num_y_ticks
# Number of Y dash ticks.
attr_accessor :num_y_dash_ticks
# Position of the legend box.
attr_accessor :legend_box_position
# Set true if title is to be hidden.
Expand All @@ -41,6 +55,10 @@ class Axes < Base
attr_accessor :y_axis_margin
# Range of X axis.
attr_accessor :x_range
# Range of X dash axis.
attr_accessor :x_dash_range
# Range of Y dash axis.
attr_accessor :y_dash_range
# Range of Y axis.
attr_accessor :y_range, :grid, :bounding_box, :title_shift
# Main title for this Axes.
Expand All @@ -55,7 +73,9 @@ def initialize(figure)
@x_axis_margin = 40.0
@y_axis_margin = 40.0
@x_range = [nil, nil]
@x_dash_range = [nil, nil]
@y_range = [nil, nil]
@y_dash_range = [nil, nil]
@title = ''
@title_shift = 0
@title_margin = TITLE_MARGIN
Expand All @@ -80,11 +100,17 @@ def initialize(figure)
@origin = [nil, nil]
calculate_xy_axes_origin
@x_axis = Rubyplot::Artist::XAxis.new(self)
@x_dash_axis = Rubyplot::Artist::XDashAxis.new(self)
@y_axis = Rubyplot::Artist::YAxis.new(self)
@y_dash_axis = Rubyplot::Artist::YDashAxis.new(self)
@x_ticks = nil
@x_dash_ticks = nil
@y_ticks = nil
@y_dash_ticks = nil
@num_x_ticks = 5
@num_x_dash_ticks = 5
@num_y_ticks = 4
@num_y_dash_ticks = 4
@legend_box_position = :top
end

Expand Down Expand Up @@ -113,6 +139,8 @@ def draw
configure_title
configure_legends
assign_x_ticks
assign_x_dash_ticks
assign_y_dash_ticks
assign_y_ticks
actually_draw
end
Expand Down Expand Up @@ -185,10 +213,15 @@ def height
def x_ticks= x_ticks
@x_ticks = x_ticks
end

def x_dash_ticks= x_dash_ticks
@x_dash_ticks = x_dash_ticks
end
def y_ticks= y_ticks
@y_ticks = y_ticks
end
def y_dash_ticks= y_dash_ticks
@y_dash_ticks = y_dash_ticks
end

def x_title= x_title
@x_axis.title = x_title
Expand All @@ -210,7 +243,7 @@ def assign_default_label_colors
end

def assign_x_ticks
@inter_x_ticks_distance = @x_axis.length / (@num_x_ticks.to_f-1)
@inter_x_ticks_distance = @x_axis.length / (@num_x_ticks.to_f - 1)
unless @x_ticks
value_distance = (@x_range[1] - @x_range[0]) / (@num_x_ticks.to_f - 1)
@x_ticks = @num_x_ticks.times.map do |i|
Expand All @@ -232,6 +265,29 @@ def assign_x_ticks
end
end

def assign_x_dash_ticks
@inter_x_dash_ticks_distance = @x_dash_axis.length / (@num_x_dash_ticks.to_f - 1)
unless @x_dash_ticks
value_distance = (@x_dash_range[1] - @x_dash_range[0]) / (@num_x_dash_ticks.to_f - 1)
@x_dash_ticks = @num_x_dash_ticks.times.map do |i|
@x_dash_range[0] + i * value_distance
end
end

unless @x_dash_ticks.all? { |t| t.is_a?(Rubyplot::Artist::XDashTick) }
@x_dash_ticks.map!.with_index do |tick_label, i|
Rubyplot::Artist::XDashTick.new(
self,
abs_x: -i * @inter_x_dash_ticks_distance + @x_dash_axis.abs_x1,
abs_y: @origin[1],
label: Rubyplot::Utils.format_label(-tick_label),
length: 6,
label_distance: 10
)
end
end
end

def assign_y_ticks
unless @y_ticks
val_distance = (@y_range[1] - @y_range[0]).abs / @num_y_ticks.to_f
Expand All @@ -252,6 +308,26 @@ def assign_y_ticks
end
end

def assign_y_dash_ticks
unless @y_dash_ticks
val_distance = (@y_dash_range[1] - @y_dash_range[0]).abs / @num_y_dash_ticks.to_f
@y_dash_ticks = (@y_dash_range[0]..@y_dash_range[1]).step(val_distance).map { |i| i }
end
unless @y_dash_ticks.all? { |t| t.is_a?(Rubyplot::Artist::YDashTick) }
inter_ticks_distance = @y_dash_axis.length / (@num_y_dash_ticks - 1)
@y_dash_ticks.map!.with_index do |tick_label, i|
Rubyplot::Artist::YDashTick.new(
self,
abs_x: @origin[0],
abs_y: @y_dash_axis.abs_y1 - (-i * inter_ticks_distance),
label: Rubyplot::Utils.format_label(-tick_label),
length: 6,
label_distance: 50
)
end
end
end

def add_plot plot_type, *args, &block
plot = with_backend plot_type, *args
yield(plot) if block_given?
Expand Down Expand Up @@ -279,8 +355,8 @@ def configure_title
end

def calculate_xy_axes_origin
@origin[0] = abs_x + @x_axis_margin
@origin[1] = abs_y + height - @y_axis_margin
@origin[0] = abs_x + width/2
@origin[1] = abs_y + height/2
end

# Figure out co-ordinates of the legends
Expand All @@ -302,8 +378,12 @@ def normalize_plotting_data
def actually_draw
@x_axis.draw
@x_ticks.each(&:draw)
@y_axis.draw
@y_ticks.each(&:draw)
@y_axis.draw
@x_dash_axis.draw
@x_dash_ticks.each(&:draw)
@y_dash_axis.draw
@y_dash_ticks.each(&:draw)
@texts.each(&:draw)
@legend_box.draw
@plots.each(&:draw)
Expand All @@ -327,25 +407,45 @@ def consolidate_plots
def set_axes_ranges
set_xrange
set_yrange
set_xdashrange
set_ydashrange
end

def set_xrange
if @x_range[0].nil? && @x_range[1].nil?
@x_range[0] = @plots.map(&:x_min).min
@x_range[0] = 0
@x_range[1] = @plots.map(&:x_max).max
end
@x_axis.min_val = @x_range[0]
@x_axis.max_val = @x_range[1]
end


def set_xdashrange
if @x_dash_range[0].nil? && @x_dash_range[1].nil?
@x_dash_range[0] = 0
@x_dash_range[1] = @plots.map(&:x_max).max
end
@x_dash_axis.min_val = @x_dash_range[1]
@x_dash_axis.max_val = @x_dash_range[0]
end

def set_yrange
if @y_range[0].nil? && @y_range[1].nil?
@y_range[0] = @plots.map { |p| p.y_min }.min
@y_range[0] = 0
@y_range[1] = @plots.map { |p| p.y_max }.max
end
@y_axis.min_val = @y_range[0]
@y_axis.max_val = @y_range[1]
end

def set_ydashrange
if @y_dash_range[0].nil? && @y_dash_range[1].nil?
@y_dash_range[0] = 0
@y_dash_range[1] = @plots.map { |p| p.y_max }.max
end
@y_dash_axis.min_val = @y_dash_range[0]
@y_dash_axis.max_val = @y_dash_range[1]
end
end # class Axes
end # moudle Artist
end # module Rubyplot
2 changes: 2 additions & 0 deletions lib/rubyplot/artist/axis.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require_relative 'axis/base'
require_relative 'axis/x_axis'
require_relative 'axis/x_dash_axis'
require_relative 'axis/y_axis'
require_relative 'axis/y_dash_axis'
2 changes: 1 addition & 1 deletion lib/rubyplot/artist/axis/x_axis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class XAxis < Axis::Base
def initialize axes
super
@abs_x1 = @axes.origin[0]
@abs_x2 = @axes.abs_x + @axes.width - @axes.y_axis_margin
@abs_x2 = @axes.origin[0] + @axes.width/2 - @axes.y_axis_margin
@major_ticks_distance = (@abs_x2 - @abs_x1) / @major_ticks_count
@length = (@abs_x2 - @abs_x1).abs
configure_axis_line
Expand Down
35 changes: 35 additions & 0 deletions lib/rubyplot/artist/axis/x_dash_axis.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require_relative 'base'

module Rubyplot
module Artist
class XDashAxis < Axis::Base
def initialize axes
super
@abs_x1 = @axes.origin[0]
@abs_x2 = @axes.abs_x + @axes.y_axis_margin
@major_ticks_distance = (@abs_x2 - @abs_x1) / @major_ticks_count
@length = (@abs_x2 - @abs_x1).abs
configure_axis_line
end

private

def configure_axis_line
@lines << Rubyplot::Artist::Line2D.new(
self, abs_x1: @abs_x1, abs_y1: @axes.origin[1], abs_x2: @abs_x2, abs_y2: @axes.origin[1],
stroke_width: @stroke_width
)
end

def configure_title
@texts << Rubyplot::Artist::Text.new(
@title,
self,
pointsize: @axes.marker_font_size,
abs_y: @axes.origin[1] + 20,
abs_x: @axes.origin[0] + (@abs_x2 - @abs_x1)/2
)
end
end # class XAxis
end # class Artist
end # module Rubyplot
2 changes: 1 addition & 1 deletion lib/rubyplot/artist/axis/y_axis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def initialize(*)
@abs_x1 = @axes.origin[0]
@abs_y1 = @axes.origin[1]
@abs_x2 = @axes.origin[0]
@abs_y2 = @axes.origin[1] - (@axes.height - @axes.x_axis_margin)
@abs_y2 = @axes.origin[1] - (@axes.height/2 - @axes.x_axis_margin)
@y_ticks = []
@length = (@abs_y1 - @abs_y2).abs
configure_axis_line
Expand Down
40 changes: 40 additions & 0 deletions lib/rubyplot/artist/axis/y_dash_axis.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Rubyplot
module Artist
class YDashAxis < Axis::Base
def initialize(*)
super
@abs_x1 = @axes.origin[0]
@abs_y1 = @axes.origin[1]
@abs_x2 = @axes.origin[0]
@abs_y2 = @axes.origin[1] + (@axes.height/2 - @axes.x_axis_margin)
@y_ticks = []
@length = (@abs_y1 - @abs_y2).abs
configure_axis_line
end

private

def configure_axis_line
@lines << Rubyplot::Artist::Line2D.new(
self,
abs_x1: @abs_x1,
abs_y1: @abs_y1,
abs_x2: @abs_x2,
abs_y2: @abs_y2,
stroke_width: @stroke_width
)
end

def configure_title
@texts << Rubyplot::Artist::Text.new(
@title,
self,
rotation: -90.0,
abs_x: @axes.origin[0] - 10,
abs_y: (@abs_y1 - @abs_y2) / 2,
pointsize: @axes.marker_font_size
)
end
end # class YDashAxis
end # class Artist
end # module Rubyplot
5 changes: 2 additions & 3 deletions lib/rubyplot/artist/plot/line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ def draw_lines
iy = @normalized_data[:y_values][idx_ix]
next if ix.nil? || iy.nil?

new_x = ix * (@axes.x_axis.abs_x2 - @axes.x_axis.abs_x1).abs + @axes.abs_x +
@axes.y_axis_margin
new_y = (@axes.y_axis.length - iy * @axes.y_axis.length) + @axes.abs_y
new_x = ix * (@axes.x_axis.length) + @axes.origin[0]
new_y = @axes.origin[1] - iy * @axes.y_axis.length

unless prev_x.nil? && prev_y.nil?
Rubyplot::Artist::Line2D.new(
Expand Down
4 changes: 2 additions & 2 deletions lib/rubyplot/artist/plot/multi_bars.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def configure_x_ticks
@axes.x_ticks = labels.map.with_index do |label, i|
Rubyplot::Artist::XTick.new(
@axes,
abs_x: @axes.abs_x + @axes.y_axis_margin + i * @max_slot_width + @max_slot_width / 2,
abs_x: @axes.abs_x + @axes.y_axis_margin*9 + i * @max_slot_width + @max_slot_width / 2,
abs_y: @axes.origin[1],
label: label,
length: 6,
Expand All @@ -64,7 +64,7 @@ def configure_x_ticks
def set_bar_dims bar_plot, index
bar_plot.bar_width = @max_bars_width / @bars_per_slot
@num_max_slots.times do |i|
bar_plot.abs_x_left[i] = @axes.abs_x + @axes.y_axis_margin +
bar_plot.abs_x_left[i] = @axes.abs_x + @axes.y_axis_margin*9 +
i * @max_slot_width + @padding / 2 + index * bar_plot.bar_width
bar_plot.abs_y_left[i] = @axes.origin[1] - @axes.x_axis.stroke_width
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rubyplot/artist/tick.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require_relative 'tick/base'
require_relative 'tick/x_tick'
require_relative 'tick/x_dash_tick'
require_relative 'tick/y_tick'
require_relative 'tick/y_dash_tick'
Loading