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

Added show function for GR and Magick backends #52

Merged
merged 30 commits into from Aug 29, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
21d2450
improved the show function for both backends and frontend
alishdipani Jul 13, 2019
0644a78
correction in testing of plot function
alishdipani Jul 14, 2019
64cbdf4
added error handling of large figures for Magick
alishdipani Jul 16, 2019
af190f4
improved frontend for plot function
alishdipani Jul 16, 2019
a0c27ce
Merge pull request #45 from alishdipani/master
alishdipani Jul 17, 2019
cc71ad0
implemented the fmt argument
alishdipani Jul 19, 2019
1b38f34
minor improvements in the plot function frontend
alishdipani Jul 19, 2019
5947c91
added bubble opacity as input for the bubble plot
alishdipani Jul 24, 2019
ca2aa73
added new method print_on_device to avoid repetition in write and show
Aug 7, 2019
a5a91cb
Added iruby integration to magick backend
Aug 15, 2019
92d4da0
Added iruby integration to show function frontend
Aug 15, 2019
640b3d7
Added inline and stop_inline functions to start and stop iruby inline
Aug 15, 2019
442a675
Corrected bug for to changing properties of canvas after declaring
Aug 15, 2019
2edeaef
stop printing output device in stop_output_device function
Aug 15, 2019
bdf5bbc
Added tutorial for Magick backend
Aug 16, 2019
bd321be
Improved the tutorial
Aug 17, 2019
7abeae6
Implemented major ticks
Aug 18, 2019
954f83f
Improved the tutorial
Aug 18, 2019
4f0dab1
Implemented minor ticks
Aug 19, 2019
d11ee83
Corrected bug - only first subplot had axes drawn in case of multiple
Aug 19, 2019
b0b21a2
Improved tick labels
Aug 20, 2019
0e8aa83
added data method for taking in x values as input for consistency
Aug 20, 2019
f101e63
Made x coordinate values compulsory for Line plot
Aug 20, 2019
e89fd2f
Made x values compulsory, added stacked option
Aug 20, 2019
9d693a2
added line_opacity to Line plot and corrected line_color attribute
Aug 21, 2019
2e34714
removed line_opacity option from line plot and plot function
Aug 21, 2019
7780962
improved the tutorial
Aug 21, 2019
3ffd94c
Added comment for point
Aug 25, 2019
8efa9d6
added blog links to the tutorial
Aug 26, 2019
3624962
added final blog link to the tutorial
Aug 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 13 additions & 2 deletions lib/rubyplot.rb
Expand Up @@ -144,12 +144,23 @@ module Rubyplot
:double_line_single_ended,
:double_line_double_ended
].freeze

class << self

class << self

attr_accessor :iruby_inline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add docs saying what exactly this does and how it can be used. BTW you were going to push some method-specific docs right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will work on writing the docs soon and will make a PR for that too.


def backend
@backend
end

def inline
@iruby_inline = true
end

def stop_inline
@iruby_inline = false
end

def set_backend b
case b
when :magick
Expand Down
42 changes: 42 additions & 0 deletions lib/rubyplot/artist/axes.rb
Expand Up @@ -256,6 +256,27 @@ def assign_x_ticks
)
end
end

@x_axis.minor_ticks = []
@x_axis.major_ticks.each_with_index do |major_tick, i|
minor_tick_value_distance = value_distance / (@x_axis.minor_ticks_count.to_f + 1)
if i < (@x_axis.major_ticks_count-1) # Skip the last tick
for j in 1..@x_axis.minor_ticks_count do
@x_axis.minor_ticks.push(major_tick.coord + j * minor_tick_value_distance)
end
end
end

unless @x_axis.minor_ticks.all? { |t| t.is_a?(Rubyplot::Artist::XTick) }
@x_axis.minor_ticks.map!.with_index do |coord, i|
Rubyplot::Artist::XTick.new(
self,
coord: coord,
label: nil,
tick_size: @x_axis.major_ticks[0].tick_size/2
)
end
end
end

def assign_y_ticks
Expand All @@ -273,6 +294,27 @@ def assign_y_ticks
)
end
end

@y_axis.minor_ticks = []
@y_axis.major_ticks.each_with_index do |major_tick, i|
minor_tick_value_distance = value_distance / (@y_axis.minor_ticks_count.to_f + 1)
if i < (@y_axis.major_ticks_count-1) # Skip the last tick
for j in 1..@y_axis.minor_ticks_count do # Skip the 0th index as major tick is already present
@y_axis.minor_ticks.push(major_tick.coord + j * minor_tick_value_distance)
end
end
end

unless @y_axis.minor_ticks.all? { |t| t.is_a?(Rubyplot::Artist::YTick) }
@y_axis.minor_ticks.map!.with_index do |coord, i|
Rubyplot::Artist::XTick.new(
self,
coord: coord,
label: nil,
tick_size: @y_axis.major_ticks[0].tick_size/2
)
end
end
end

# Figure out the co-ordinates of the title text w.r.t Axes.
Expand Down
3 changes: 2 additions & 1 deletion lib/rubyplot/artist/figure.rb
Expand Up @@ -99,7 +99,8 @@ def write(file_name, device: :file)
end

def show
print_on_device(nil, :window)
Rubyplot.backend.output_device = Rubyplot.iruby_inline ? :iruby : :window
print_on_device(nil, Rubyplot.backend.output_device)
end

private
Expand Down
14 changes: 9 additions & 5 deletions lib/rubyplot/artist/plot/area.rb 100644 → 100755
Expand Up @@ -6,12 +6,16 @@ class Area < Artist::Plot::Base

def initialize(*)
super
@sort_data = false
@sort_data = true
@fill_opacity = 0.3
end

def data y_values, x_values=[]
x_values = Array.new(y_values.size) { |i| i } if x_values.empty?
y_values.sort! if @sort_data
def stacked(bool)
@fill_opacity = 1 if bool
end

def data x_values, y_values
x_values, y_values = x_values.zip(y_values).sort.transpose if @sort_data
super(x_values, y_values)
end

Expand All @@ -22,7 +26,7 @@ def draw
x: x_poly_points,
y: y_poly_points,
color: @data[:color],
fill_opacity: 0.3
fill_opacity: @fill_opacity
).draw
end
end # class Area
Expand Down
4 changes: 0 additions & 4 deletions lib/rubyplot/artist/plot/basic_plot.rb
Expand Up @@ -9,7 +9,6 @@ class BasicPlot < Artist::Plot::Base
attr_accessor :line_color
attr_accessor :line_type
attr_accessor :line_width
attr_accessor :line_opacity

COLOR_TYPES_FMT = {
'b' => :blue,
Expand Down Expand Up @@ -65,7 +64,6 @@ def initialize(*)
@line_color = :default
@line_type = nil
@line_width = 1.0
@line_opacity = 1.0
end

def color
Expand Down Expand Up @@ -111,9 +109,7 @@ def draw
x: @data[:x_values],
y: @data[:y_values],
type: @line_type,
# type: line_style[1].to_sym,
color: @line_color,
opacity: @line_opacity,
width: @line_width
).draw if @line_type
Rubyplot.backend.draw_markers(
Expand Down
8 changes: 6 additions & 2 deletions lib/rubyplot/artist/plot/histogram.rb
Expand Up @@ -8,9 +8,13 @@ class Histogram < Artist::Plot::Base
attr_accessor :bins
# Width of each bar.
attr_accessor :bar_width

def initialize(*)
super
super
end

def data x_values
@x = x_values
end

def process_data
Expand Down
11 changes: 6 additions & 5 deletions lib/rubyplot/artist/plot/line.rb
Expand Up @@ -6,8 +6,11 @@ class Line < Artist::Plot::Base
attr_writer :line_type
# The number of times that you want the width to be of the graphic device. Default 1.0.
attr_writer :line_width
# Color of the line. Default black.
attr_writer :line_color

def line_color=(color)
@line_color = color
@data[:color] = color
end

def initialize(*)
super
Expand All @@ -16,8 +19,7 @@ def initialize(*)
@line_color = :black
end

def data(y_values, x_values=[])
x_values = Array.new(y_values.size) { |i| i } if x_values.empty?
def data(x_values, y_values)
super x_values, y_values
end

Expand All @@ -34,4 +36,3 @@ def draw
end # module Plot
end # module Artist
end # module Rubyplot

2 changes: 1 addition & 1 deletion lib/rubyplot/backend/base.rb
Expand Up @@ -5,7 +5,7 @@ class Base
# Total height and width of the canvas in pixels.
attr_accessor :canvas_height, :canvas_width

attr_accessor :active_axes, :figure
attr_accessor :active_axes, :figure, :output_device

# Write text anywhere on the canvas. abs_x and abs_y should be specified in terms
# of Rubyplot Artist Co-ordinates.
Expand Down
82 changes: 66 additions & 16 deletions lib/rubyplot/backend/magick_wrapper.rb
Expand Up @@ -14,6 +14,12 @@ class MagickWrapper < Base

NOMINAL_FACTOR_MARKERS = 15
NOMINAL_FACTOR_CIRCLE = 27.5
TICK_FONT_SIZE = 33.5
AXES_WIDTH_MULTIPLIER = 5
TICK_SIZE_MULTIPLIER = 20
TICK_LABEL_COORD_X_MULTIPLIER = 3.5
TICK_LABEL_COORD_Y_MULTIPLIER = 5.25
TICK_LABEL_FONT_WEIGHT = 800

GRAVITY_MEASURE = {
nil => Magick::ForgetGravity,
Expand All @@ -27,7 +33,8 @@ class MagickWrapper < Base
PIXEL_MULTIPLIERS = {
inch: 96,
cm: 39.7953,
pixel: 1
pixel: 1,
point: 4/3 # Point is the unit if measurement for the size of font in ImageMagick
}.freeze

MARKER_TYPES = {
Expand Down Expand Up @@ -344,13 +351,11 @@ class MagickWrapper < Base
LINE_TYPES = {
# Default type is solid
default: ->(draw, x1, y1, x2, y2, width, color, opacity) {
draw.fill_opacity opacity
draw.stroke_width width
draw.fill Rubyplot::Color::COLOR_INDEX[color]
draw.line x1, y1, x2, y2
},
solid: ->(draw, x1, y1, x2, y2, width, color, opacity) {
draw.fill_opacity opacity
draw.stroke_width width
draw.fill Rubyplot::Color::COLOR_INDEX[color]
draw.line x1, y1, x2, y2
Expand Down Expand Up @@ -585,14 +590,14 @@ def draw_arrow(x1:, y1:, x2:, y2:, size:, style:)

def write
@draw.draw(@base_image)
@text.draw(@base_image)
draw_axes
@text.draw(@base_image)
end

def show
@draw.draw(@base_image)
@text.draw(@base_image)
draw_axes
@text.draw(@base_image)
end

# Refresh this backend and remove all previously set data.
Expand All @@ -606,28 +611,33 @@ def init_output_device file_name = nil, device: :file
@draw = Magick::Draw.new
@axes = Magick::Draw.new
@text = Magick::Draw.new
if @base_image.nil?
top_color = Rubyplot::Color::COLOR_INDEX[@figure.theme_options[:background_colors][0]]
bottom_color = Rubyplot::Color::COLOR_INDEX[@figure.theme_options[:background_colors][1]]
direction = @figure.theme_options[:background_direction]

@base_image = render_gradient top_color, bottom_color, @canvas_width, @canvas_height, direction
else
@base_image.erase!
end
top_color = Rubyplot::Color::COLOR_INDEX[@figure.theme_options[:background_colors][0]]
bottom_color = Rubyplot::Color::COLOR_INDEX[@figure.theme_options[:background_colors][1]]
direction = @figure.theme_options[:background_direction]

@base_image = render_gradient top_color, bottom_color, @canvas_width, @canvas_height, direction
# Initialize base_image again even if it exists as there may be a change in properties

@output_device = device
@file_name = file_name if @output_device == :file
end

def stop_output_device
@canvas_width, @canvas_height = unscale_figure(@canvas_width, @canvas_height)
case @output_device
when :file
@base_image.write(@file_name)
flush
when :window
flush
@base_image.display
# return nil so that image is not printed on iruby
nil
when :iruby
flush
@base_image
end
@canvas_width, @canvas_height = unscale_figure(@canvas_width, @canvas_height)
flush
end

private
Expand Down Expand Up @@ -699,14 +709,54 @@ def draw_axes
@active_axes = axes
within_window do
@axes.stroke Rubyplot::Color::COLOR_INDEX[:black]
@axes.stroke_width 5
@axes.stroke_width AXES_WIDTH_MULTIPLIER
# Drawing the X and Y axes lines
if axes.square_axes
@axes.fill_opacity 0
@axes.rectangle(transform_x(x: v[:x_origin]),transform_y(y: v[:y_origin]), transform_x(x: axes.x_range[1]),transform_y(y: axes.y_range[1]))
else
@axes.line(transform_x(x: v[:x_origin]),transform_y(y: v[:y_origin]), transform_x(x: axes.x_range[1]),transform_y(y: v[:y_origin]))
@axes.line(transform_x(x: v[:x_origin]),transform_y(y: v[:y_origin]), transform_x(x: v[:x_origin]),transform_y(y: axes.y_range[1]))
end
# Drawing ticks
# X major ticks
axes.x_axis.major_ticks.each do |x_major_tick|
# @axes.stroke_width x_major_tick.tick_width*AXES_WIDTH_MULTIPLIER
# @axes.opacity x_major_tick.tick_opacity
@axes.line(transform_x(x: x_major_tick.coord),transform_y(y: v[:y_origin]), transform_x(x: x_major_tick.coord),(transform_y(y: v[:y_origin]) + x_major_tick.tick_size*TICK_SIZE_MULTIPLIER))
@text.pointsize TICK_FONT_SIZE
@text.font_weight TICK_LABEL_FONT_WEIGHT
# Changed X and Y coordinates of label for better appearance
@text.text((transform_x(x: x_major_tick.coord) - TICK_FONT_SIZE*PIXEL_MULTIPLIERS[:point]),(transform_y(y: v[:y_origin]) + TICK_LABEL_COORD_X_MULTIPLIER*TICK_SIZE_MULTIPLIER*x_major_tick.tick_size), x_major_tick.label)
@text.font_weight NormalWeight
# @axes.opacity 1
end
# X minor ticks
axes.x_axis.minor_ticks.each do |x_minor_tick|
# @axes.stroke_width x_minor_tick.tick_width*AXES_WIDTH_MULTIPLIER
# @axes.opacity x_minor_tick.tick_opacity
@axes.line(transform_x(x: x_minor_tick.coord),transform_y(y: v[:y_origin]), transform_x(x: x_minor_tick.coord),(transform_y(y: v[:y_origin]) + x_minor_tick.tick_size*TICK_SIZE_MULTIPLIER))
# @axes.opacity 1
end
# Y major ticks
axes.y_axis.major_ticks.each do |y_major_tick|
# @axes.stroke_width y_major_tick.tick_width*AXES_WIDTH_MULTIPLIER
# @axes.opacity y_major_tick.tick_opacity
@axes.line((transform_x(x: v[:x_origin]) - y_major_tick.tick_size*TICK_SIZE_MULTIPLIER),transform_y(y: y_major_tick.coord), transform_x(x: v[:x_origin]),transform_y(y: y_major_tick.coord))
@text.pointsize TICK_FONT_SIZE
@text.font_weight TICK_LABEL_FONT_WEIGHT
# Changed X and Y coordinates of label for better appearance
@text.text((transform_x(x: v[:x_origin]) - TICK_LABEL_COORD_Y_MULTIPLIER*TICK_SIZE_MULTIPLIER*y_major_tick.tick_size),(transform_y(y: y_major_tick.coord) + TICK_FONT_SIZE/3*PIXEL_MULTIPLIERS[:point]), y_major_tick.label)
@text.font_weight NormalWeight
# @axes.opacity 1
end
# Y minor ticks
axes.y_axis.minor_ticks.each do |y_minor_tick|
# @axes.stroke_width y_minor_tick.tick_width*AXES_WIDTH_MULTIPLIER
# @axes.opacity y_minor_tick.tick_opacity
@axes.line((transform_x(x: v[:x_origin]) - y_minor_tick.tick_size*TICK_SIZE_MULTIPLIER),transform_y(y: y_minor_tick.coord), transform_x(x: v[:x_origin]),transform_y(y: y_minor_tick.coord))
# @axes.opacity 1
end
end
end
@axes.draw(@base_image)
Expand Down