New Upstream Release - ruby-unicode-plot
Ready changes
Summary
Merged new upstream version: 0.0.5 (was: 0.0.4).
Resulting package
Built on 2022-03-14T11:01 (took 2m1s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases ruby-unicode-plot
Lintian Result
Diff
diff --git a/Gemfile b/Gemfile
index 07483b2..8ba4877 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,6 @@
source "https://rubygems.org/"
gemspec
+
+# Temporary use this for module_function decorator support
+gem "yard", github: "mrkn/yard", branch: "module_function_decorator"
diff --git a/README.md b/README.md
index 8976cbe..e28ad4f 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,10 @@
UnicodePlot provides the feature to make charts with Unicode characters.
+## Documentation
+
+https://red-data-tools.github.io/unicode_plot.rb/
+
## Install
```console
@@ -18,8 +22,7 @@ y_sin = x.map {|xi| Math.sin(xi) }
y_cos = x.map {|xi| Math.cos(xi) }
plot = UnicodePlot.lineplot(x, y_sin, name: "sin(x)", width: 40, height: 10)
UnicodePlot.lineplot!(plot, x, y_cos, name: "cos(x)")
-plot.render($stdout)
-puts
+plot.render
```
You can get the results below by running the above script:
@@ -31,8 +34,7 @@ You can get the results below by running the above script:
### barplot
```ruby
-plot = UnicodePlot.barplot(data: {'foo': 20, 'bar': 50}, title: "Bar")
-plot.render($stdout)
+UnicodePlot.barplot(data: {'foo': 20, 'bar': 50}, title: "Bar").render
```
<img src="img/barplot.png" width="50%" />
@@ -40,8 +42,7 @@ plot.render($stdout)
### boxplot
```ruby
-plot = UnicodePlot.boxplot(data: {foo: [1, 3, 5], bar: [3, 5, 7]}, title: "Box")
-plot.render($stdout)
+UnicodePlot.boxplot(data: {foo: [1, 3, 5], bar: [3, 5, 7]}, title: "Box").render
```
<img src="img/boxplot.png" width="50%" />
@@ -51,8 +52,7 @@ plot.render($stdout)
```ruby
x = Array.new(500) { 20*rand - 10 } + Array.new(500) { 6*rand - 3 }
y = Array.new(1000) { 30*rand - 10 }
-plot = UnicodePlot.densityplot(x, y, title: "Density")
-plot.render($stdout)
+UnicodePlot.densityplot(x, y, title: "Density").render
```
<img src="img/densityplot.png" width="50%" />
@@ -61,8 +61,7 @@ plot.render($stdout)
```ruby
x = Array.new(100) { rand(10) } + Array.new(100) { rand(30) + 10 }
-plot = UnicodePlot.histogram(x, title: "Histogram")
-plot.render($stdout)
+UnicodePlot.histogram(x, title: "Histogram").render
```
<img src="img/histogram.png" width="50%" />
@@ -76,8 +75,7 @@ See [Usage](#usage) section above.
```ruby
x = Array.new(50) { rand(20) - 10 }
y = x.map {|xx| xx*rand(30) - 10 }
-plot = UnicodePlot.scatterplot(x, y, title: "Scatter")
-plot.render($stdout)
+UnicodePlot.scatterplot(x, y, title: "Scatter").render
```
<img src="img/scatterplot.png" width="50%" />
diff --git a/Rakefile b/Rakefile
index 6de7fbb..53c7e96 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,9 +1,9 @@
require "bundler/gem_helper"
+require "yard"
base_dir = File.expand_path("..", __FILE__)
helper = Bundler::GemHelper.new(base_dir)
helper.install
-spec = helper.gemspec
desc "Run test"
task :test do
@@ -11,3 +11,6 @@ task :test do
end
task default: :test
+
+YARD::Rake::YardocTask.new do |task|
+end
diff --git a/debian/changelog b/debian/changelog
index ff3333c..cf1f2ed 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,12 +1,13 @@
-ruby-unicode-plot (0.0.4-3) UNRELEASED; urgency=low
+ruby-unicode-plot (0.0.5-1) UNRELEASED; urgency=low
* Set field Upstream-Contact in debian/copyright.
* Remove obsolete fields Contact, Name from debian/upstream/metadata (already
present in machine-readable debian/copyright).
* Bump debhelper from old 12 to 13.
* Update standards version to 4.5.1, no changes needed.
+ * New upstream release.
- -- Debian Janitor <janitor@jelmer.uk> Fri, 04 Sep 2020 03:18:24 -0000
+ -- Debian Janitor <janitor@jelmer.uk> Mon, 14 Mar 2022 10:59:26 -0000
ruby-unicode-plot (0.0.4-2) unstable; urgency=medium
diff --git a/lib/unicode_plot.rb b/lib/unicode_plot.rb
index 77887e2..8a0ba57 100644
--- a/lib/unicode_plot.rb
+++ b/lib/unicode_plot.rb
@@ -2,17 +2,13 @@ require 'stringio'
require 'unicode_plot/version'
+require 'unicode_plot/io_context'
require 'unicode_plot/utils'
require 'unicode_plot/styled_printer'
require 'unicode_plot/value_transformer'
require 'unicode_plot/renderer'
require 'unicode_plot/canvas'
-require 'unicode_plot/braille_canvas'
-require 'unicode_plot/density_canvas'
-require 'unicode_plot/lookup_canvas'
-require 'unicode_plot/ascii_canvas'
-require 'unicode_plot/dot_canvas'
require 'unicode_plot/plot'
require 'unicode_plot/grid_plot'
@@ -23,3 +19,5 @@ require 'unicode_plot/densityplot'
require 'unicode_plot/lineplot'
require 'unicode_plot/histogram'
require 'unicode_plot/scatterplot'
+require 'unicode_plot/stairs'
+require 'unicode_plot/stemplot'
diff --git a/lib/unicode_plot/barplot.rb b/lib/unicode_plot/barplot.rb
index f2b561e..2a25762 100644
--- a/lib/unicode_plot/barplot.rb
+++ b/lib/unicode_plot/barplot.rb
@@ -69,6 +69,57 @@ module UnicodePlot
end
end
+ # @overload barplot(text, heights, xscale: nil, title: nil, xlabel: nil, ylabel: nil, labels: true, border: :barplot, margin: Plot::DEFAULT_MARGIN, padding: Plot::DEFAULT_PADDING, color: Barplot::DEFAULT_COLOR, width: Plot::DEFAULT_WIDTH, symbol: Barplot::DEFAULT_SYMBOL)
+ #
+ # Draws a horizontal barplot.
+ #
+ # @param text [Array<String>] The lables / captions of the bars.
+ # @param heights [Array<Numeric>] The values / heights of the bars.
+ # @param xscale [nil,:log,:ln,:log10,:lg,:log2,:lb,callable]
+ # A function name symbol or callable object to transform the bar
+ # length before plotting. This effectively scales the x-axis
+ # without influencing the captions of the individual bars.
+ # e.g. use `xscale: :log10` for logscale.
+ # @param title
+ # @param xlabel
+ # @param ylabel
+ # @param labels
+ # @param border
+ # @param margin
+ # @param padding
+ # @param color
+ # @param width
+ # @param symbol [String] Specifies the character that should be used
+ # to render the bars.
+ #
+ # @return [Barplot] A plot object.
+ #
+ # @example Example usage of barplot on IRB:
+ #
+ # >> UnicodePlot.barplot(["Paris", "New York", "Moskau", "Madrid"],
+ # [2.244, 8.406, 11.92, 3.165],
+ # xlabel: "population [in mil]").render
+ # ┌ ┐
+ # Paris ┤■■■■■■ 2.244
+ # New York ┤■■■■■■■■■■■■■■■■■■■■■■■ 8.406
+ # Moskau ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 11.92
+ # Madrid ┤■■■■■■■■■ 3.165
+ # └ ┘
+ # population [in mil]
+ # => nil
+ #
+ # @see Plot
+ # @see histogram
+ # @see Barplot
+ #
+ # @overload barplot(data, **kwargs)
+ #
+ # The different variation of barplot described above.
+ #
+ # @param data [Hash] A hash in which the keys will be used as `text` and
+ # the values will be utilized as `heights`.
+ # @param kwargs Optional keyword arguments same as ones described above.
+ # @return [Barplot] A plot object.
module_function def barplot(*args,
width: Plot::DEFAULT_WIDTH,
color: Barplot::DEFAULT_COLOR,
@@ -108,10 +159,24 @@ module UnicodePlot
plot
end
+ # @overload barplot!(plot, text, heights)
+ #
+ # Draw additional bars on the given existing plot.
+ #
+ # @param plot [Barplot] the existing plot.
+ # @return [Barplot] A plot object.
+ #
+ # @see barplot
+ #
+ # @overload barplot!(plot, data)
+ #
+ # The different variation of `barplot!` that takes the plotting data in a hash.
+ #
+ # @param plot [Barplot] the existing plot.
+ # @return [Barplot] A plot object.
module_function def barplot!(plot,
*args,
- data: nil,
- **kw)
+ data: nil)
case args.length
when 0
data = Hash(data)
diff --git a/lib/unicode_plot/canvas.rb b/lib/unicode_plot/canvas.rb
index 3905cb7..324b063 100644
--- a/lib/unicode_plot/canvas.rb
+++ b/lib/unicode_plot/canvas.rb
@@ -2,16 +2,13 @@ module UnicodePlot
class Canvas
include BorderPrinter
+ CANVAS_CLASS_MAP = {}
+
def self.create(canvas_type, width, height, **kw)
- case canvas_type
- when :ascii
- AsciiCanvas.new(width, height, **kw)
- when :braille
- BrailleCanvas.new(width, height, **kw)
- when :density
- DensityCanvas.new(width, height, **kw)
- when :dot
- DotCanvas.new(width, height, **kw)
+ canvas_class = CANVAS_CLASS_MAP[canvas_type]
+ case canvas_class
+ when Class
+ canvas_class.new(width, height, **kw)
else
raise ArgumentError, "unknown canvas type: #{canvas_type}"
end
@@ -166,4 +163,16 @@ module UnicodePlot
raise ArgumentError, "#{name} has to be positive"
end
end
+
+ def self.canvas_types
+ Canvas::CANVAS_CLASS_MAP.keys
+ end
end
+
+require_relative 'canvas/ascii_canvas'
+require_relative 'canvas/block_canvas'
+require_relative 'canvas/braille_canvas'
+require_relative 'canvas/density_canvas'
+require_relative 'canvas/dot_canvas'
+
+UnicodePlot::Canvas::CANVAS_CLASS_MAP.freeze
diff --git a/lib/unicode_plot/ascii_canvas.rb b/lib/unicode_plot/canvas/ascii_canvas.rb
similarity index 97%
rename from lib/unicode_plot/ascii_canvas.rb
rename to lib/unicode_plot/canvas/ascii_canvas.rb
index c625b22..1b8c81e 100644
--- a/lib/unicode_plot/ascii_canvas.rb
+++ b/lib/unicode_plot/canvas/ascii_canvas.rb
@@ -1,5 +1,9 @@
+require_relative 'lookup_canvas'
+
module UnicodePlot
class AsciiCanvas < LookupCanvas
+ Canvas::CANVAS_CLASS_MAP[:ascii] = self
+
ASCII_SIGNS = [
[ 0b100_000_000, 0b000_100_000, 0b000_000_100 ].freeze,
[ 0b010_000_000, 0b000_010_000, 0b000_000_010 ].freeze,
diff --git a/lib/unicode_plot/canvas/block_canvas.rb b/lib/unicode_plot/canvas/block_canvas.rb
new file mode 100644
index 0000000..942b995
--- /dev/null
+++ b/lib/unicode_plot/canvas/block_canvas.rb
@@ -0,0 +1,38 @@
+module UnicodePlot
+ # The `BlockCanvas` is also Unicode-based.
+ # It has half the resolution of the `BrailleCanvas`.
+ # In contrast to BrailleCanvas, the pixels don't
+ # have visible spacing between them.
+ # This canvas effectively turns every character
+ # into 4 pixels that can individually be manipulated
+ # using binary operations.
+ class BlockCanvas < LookupCanvas
+ Canvas::CANVAS_CLASS_MAP[:block] = self
+
+ X_PIXEL_PER_CHAR = 2
+ Y_PIXEL_PER_CHAR = 2
+
+ def initialize(width, height, fill_char=0, **kw)
+ super(width, height,
+ X_PIXEL_PER_CHAR,
+ Y_PIXEL_PER_CHAR,
+ fill_char,
+ **kw)
+ end
+
+ BLOCK_SIGNS = [
+ [0b1000, 0b0010].freeze,
+ [0b0100, 0b0001].freeze
+ ].freeze
+
+ BLOCK_DECODE = [
+ -' ', -'▗', -'▖', -'▄',
+ -'▝', -'▐', -'▞', -'▟',
+ -'▘', -'▚', -'▌', -'▙',
+ -'▀', -'▜', -'▛', -'█'
+ ].freeze
+
+ def lookup_encode(x,y) ; BLOCK_SIGNS[x][y] ; end
+ def lookup_decode(x) ; BLOCK_DECODE[x] ; end
+ end
+end
diff --git a/lib/unicode_plot/braille_canvas.rb b/lib/unicode_plot/canvas/braille_canvas.rb
similarity index 93%
rename from lib/unicode_plot/braille_canvas.rb
rename to lib/unicode_plot/canvas/braille_canvas.rb
index b509745..58c88b6 100644
--- a/lib/unicode_plot/braille_canvas.rb
+++ b/lib/unicode_plot/canvas/braille_canvas.rb
@@ -1,5 +1,7 @@
module UnicodePlot
class BrailleCanvas < Canvas
+ Canvas::CANVAS_CLASS_MAP[:braille] = self
+
X_PIXEL_PER_CHAR = 2
Y_PIXEL_PER_CHAR = 4
@@ -40,8 +42,8 @@ module UnicodePlot
char_x_off = pixel_x % X_PIXEL_PER_CHAR + 1
char_x += 1 if char_x < tx.round + 1 && char_x_off == 1
- char_y = (pixel_y.fdiv(pixel_height) * height).floor + 1
char_y_off = pixel_y % Y_PIXEL_PER_CHAR + 1
+ char_y = ((pixel_y - (char_y_off - 1)) / Y_PIXEL_PER_CHAR) + 1
index = index_at(char_x - 1, char_y - 1)
if index
diff --git a/lib/unicode_plot/density_canvas.rb b/lib/unicode_plot/canvas/density_canvas.rb
similarity index 97%
rename from lib/unicode_plot/density_canvas.rb
rename to lib/unicode_plot/canvas/density_canvas.rb
index 6d6a212..4d9c5b3 100644
--- a/lib/unicode_plot/density_canvas.rb
+++ b/lib/unicode_plot/canvas/density_canvas.rb
@@ -1,5 +1,7 @@
module UnicodePlot
class DensityCanvas < Canvas
+ Canvas::CANVAS_CLASS_MAP[:density] = self
+
DENSITY_SIGNS = [" ", "░", "▒", "▓", "█"].freeze
MIN_WIDTH = 5
diff --git a/lib/unicode_plot/dot_canvas.rb b/lib/unicode_plot/canvas/dot_canvas.rb
similarity index 93%
rename from lib/unicode_plot/dot_canvas.rb
rename to lib/unicode_plot/canvas/dot_canvas.rb
index a54ef82..8d6b39f 100644
--- a/lib/unicode_plot/dot_canvas.rb
+++ b/lib/unicode_plot/canvas/dot_canvas.rb
@@ -1,5 +1,7 @@
module UnicodePlot
class DotCanvas < LookupCanvas
+ Canvas::CANVAS_CLASS_MAP[:dot] = self
+
DOT_SIGNS = [
[
0b10,
diff --git a/lib/unicode_plot/lookup_canvas.rb b/lib/unicode_plot/canvas/lookup_canvas.rb
similarity index 95%
rename from lib/unicode_plot/lookup_canvas.rb
rename to lib/unicode_plot/canvas/lookup_canvas.rb
index 01eb768..99a25d5 100644
--- a/lib/unicode_plot/lookup_canvas.rb
+++ b/lib/unicode_plot/canvas/lookup_canvas.rb
@@ -23,8 +23,8 @@ module UnicodePlot
char_x_off = pixel_x % x_pixel_per_char + 1
char_x += 1 if char_x < tx.round + 1 && char_x_off == 1
- char_y = (pixel_y.fdiv(pixel_height) * height).floor + 1
char_y_off = pixel_y % y_pixel_per_char + 1
+ char_y = ((pixel_y - (char_y_off - 1)) / y_pixel_per_char) + 1
index = index_at(char_x - 1, char_y - 1)
if index
diff --git a/lib/unicode_plot/io_context.rb b/lib/unicode_plot/io_context.rb
new file mode 100644
index 0000000..4070739
--- /dev/null
+++ b/lib/unicode_plot/io_context.rb
@@ -0,0 +1,32 @@
+require "forwardable"
+
+module UnicodePlot
+ class IOContext
+ extend Forwardable
+
+ def initialize(io, color: :auto)
+ @io = io
+ @color = check_color(color)
+ end
+
+ def_delegators :@io, :print, :puts
+
+ def color?
+ case @color
+ when :auto
+ @io.respond_to?(:tty?) ? @io.tty? : false
+ else
+ @color
+ end
+ end
+
+ private def check_color(color)
+ case color
+ when true, false, :auto
+ color
+ else
+ raise ArgumentError, "color must be either true, false, :auto"
+ end
+ end
+ end
+end
diff --git a/lib/unicode_plot/layout.rb b/lib/unicode_plot/layout.rb
deleted file mode 100644
index 9fb1b0f..0000000
--- a/lib/unicode_plot/layout.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-module UnicodePlot
- class GridLayout
- DEFAULT_WIDTH = 80
-
- def initialize(n_rows, n_columns, width: Layout::DEFAULT_WIDTH)
- @n_rows = n_rows
- @n_columns = n_columns
- @width = width
- end
-
- def [](i, j)
- @plots[i * n_cols + j]
- end
-
- def []=(i, j, plot)
- @plots[i * n_cols + j] = plot
- end
-
- def <<(plot)
- @plots << plot
- end
-
- def render(out)
- buffers = []
- (0 ... n_rows).each do |i|
- (0 ... n_columns).each do |j|
- StringIO.open do |sio|
- def sio.tty?; true; end
- render_cell(sio, i, j)
- sio.close
- buffers << sio.string
- end
- end
- end
- end
-
- def render_cell(out, i, j)
- plot = self[i, j]
- return unless plot
- plot.width = cell_width
- end
- end
-
- module_function def grid_layout(n_rows, n_cols, *plots, **kw)
- grid = GridLayout.new(n_rows, n_cols, **kw)
- plots.each do |plot|
- grid << plot
- end
- grid
- end
-end
diff --git a/lib/unicode_plot/lineplot.rb b/lib/unicode_plot/lineplot.rb
index 7ec7b0f..acc687b 100644
--- a/lib/unicode_plot/lineplot.rb
+++ b/lib/unicode_plot/lineplot.rb
@@ -4,6 +4,32 @@ module UnicodePlot
class Lineplot < GridPlot
end
+ # @overload lineplot([x], y, name: "", canvas: :braille, title: "", xlabel: "", ylabel: "", labels: true, border: :solid, margin: Plot::DEFAULT_MARGIN, padding: Plot::DEFAULT_PADDING, color: :auto, width: Plot::DEFAULT_WIDTH, height: GridPlot::DEFAULT_HEIGHT, xlim: [0, 0], ylim: [0, 0], canvas: :braille, grid: true)
+ #
+ # Draws a path through the given points on a new canvas.
+ #
+ # The first (optional) array `x` should contain the horizontal positions for all the points along the path.
+ # The second array `y` should then contain the corresponding vertical positions respectively.
+ # This means that the two vectors must be of the same length and ordering.
+ #
+ # @param x [Array<Numeric>] Optional. The horizontal position for each point. If omitted, the axes of `y` will be used as `x`.
+ # @param y [Array<Numeric>] The vertical position for each point.
+ # @param name [String] Annotation of the current drawing to be displayed on the right.
+ # @param title
+ # @param xlabel
+ # @param ylabel
+ # @param labels
+ # @param border
+ # @param margin
+ # @param padding
+ # @param color
+ # @param width
+ # @param height
+ # @param xlim
+ # @param ylim
+ # @param canvas [Symbol] The type of canvas that should be used for drawing.
+ # @param grid [true,false] If `true`, draws grid-lines at the origin.
+ # @return [Lineplot] A plot object.
module_function def lineplot(*args,
canvas: :braille,
color: :auto,
@@ -41,6 +67,16 @@ module UnicodePlot
end
end
+ # @overload lineplot!(plot, [x], y, name: "", color: :auto)
+ #
+ # Draws a path through the given points on the given canvas.
+ #
+ # @param plot [Lineplot] The plot object.
+ # @param x [Array<Numeric>] Optional. The horizontal position for each point. If omitted, the axes of `y` will be used as `x`.
+ # @param y [Array<Numeric>] The vertical position for each point.
+ # @param name [String] Annotation of the current drawing to be displayed on the right.
+ # @param color
+ # @return [Lineplot] The plot object same as the `plot` parameter.
module_function def lineplot!(plot,
*args,
color: :auto,
diff --git a/lib/unicode_plot/plot.rb b/lib/unicode_plot/plot.rb
index e931144..728ce20 100644
--- a/lib/unicode_plot/plot.rb
+++ b/lib/unicode_plot/plot.rb
@@ -17,7 +17,7 @@ module UnicodePlot
@title = title
@xlabel = xlabel
@ylabel = ylabel
- @border = border
+ @border = check_border(border)
@margin = check_margin(margin)
@padding = padding
@labels_left = {}
@@ -103,8 +103,8 @@ module UnicodePlot
end
end
- def render(out=$stdout, newline: true)
- Renderer.render(out, self, newline)
+ def render(out=$stdout, newline: true, color: :auto)
+ Renderer.render(IOContext.new(out, color: color), self, newline)
end
COLOR_CYCLE = [
@@ -142,5 +142,10 @@ module UnicodePlot
raise ArgumentError, "row_index out of bounds"
end
end
+
+ private def check_border(border)
+ return border if BORDER_MAP.key?(border)
+ raise ArgumentError, "unknown border type: #{border}"
+ end
end
end
diff --git a/lib/unicode_plot/renderer.rb b/lib/unicode_plot/renderer.rb
index 7ec4aa4..7d3d417 100644
--- a/lib/unicode_plot/renderer.rb
+++ b/lib/unicode_plot/renderer.rb
@@ -40,6 +40,10 @@ module UnicodePlot
barplot: BorderMaps::BORDER_BARPLOT,
}.freeze
+ def self.border_types
+ BORDER_MAP.keys
+ end
+
module BorderPrinter
include StyledPrinter
@@ -128,7 +132,7 @@ module UnicodePlot
left_len = nocolor_string(left_str).length
right_len = nocolor_string(right_str).length
- unless color?(out)
+ unless out.color?
left_str = nocolor_string(left_str)
right_str = nocolor_string(right_str)
end
diff --git a/lib/unicode_plot/stairs.rb b/lib/unicode_plot/stairs.rb
new file mode 100644
index 0000000..8161167
--- /dev/null
+++ b/lib/unicode_plot/stairs.rb
@@ -0,0 +1,88 @@
+# coding: utf-8
+module UnicodePlot
+ # @overload stairs(x, y, style: :post, name: "", title: "", xlabel: "", ylabel: "", labels: true, border: :solid, margin: 3, padding: 1, color: :auto, width: 40, height: 15, xlim: [0, 0], ylim: [0, 0], canvas: :braille, grid: true)
+ #
+ # Draws a staircase plot on a new canvas.
+ #
+ # The first vector `x` should contain the horizontal
+ # positions for all the points. The second vector `y` should then
+ # contain the corresponding vertical positions respectively. This
+ # means that the two vectors must be of the same length and
+ # ordering.
+ #
+ # @param x [Array<Numeric>] The horizontal position for each point.
+ # @param y [Array<Numeric>] The vertical position for each point.
+ # @param style [Symbol] Specifies where the transition of the stair takes place. Can be either `:pre` or `:post`.
+ # @param name [String] Annotation of the current drawing to be displayed on the right.
+ # @param height [Integer] Number of character rows that should be used for plotting.
+ # @param xlim [Array<Numeric>] Plotting range for the x axis. `[0, 0]` stands for automatic.
+ # @param ylim [Array<Numeric>] Plotting range for the y axis. `[0, 0]` stands for automatic.
+ # @param canvas [Symbol] The type of canvas that should be used for drawing.
+ # @param grid [Boolean] If `true`, draws grid-lines at the origin.
+ #
+ # @return [Plot] A plot object.
+ #
+ # @example Example usage of stairs on IRB:
+ #
+ # >> UnicodePlot.stairs([1, 2, 4, 7, 8], [1, 3, 4, 2, 7], style: :post, title: "My Staircase Plot").render
+ # My Staircase Plot
+ # ┌────────────────────────────────────────┐
+ # 7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡄⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⢸⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
+ # │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠧⠤⠤⠤⠤⠼│
+ # │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
+ # 1 │⣀⣀⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
+ # └────────────────────────────────────────┘
+ # 1 8
+ # => nil
+ #
+ # @see Plot
+ # @see scatterplot
+ # @see lineplot
+ module_function def stairs(xvec, yvec, style: :post, **kw)
+ x_vex, y_vex = compute_stair_lines(xvec, yvec, style: style)
+ lineplot(x_vex, y_vex, **kw)
+ end
+
+ # Similar to stairs, but takes an existing plot object as a first argument.
+ module_function def stairs!(plot, xvec, yvec, style: :post, **kw)
+ x_vex, y_vex = compute_stair_lines(xvec, yvec, style: style)
+ lineplot!(plot, x_vex, y_vex, **kw)
+ end
+
+ module_function def compute_stair_lines(x, y, style: :post)
+ x_vex = Array.new(x.length * 2 - 1, 0)
+ y_vex = Array.new(x.length * 2 - 1, 0)
+ x_vex[0] = x[0]
+ y_vex[0] = y[0]
+ o = 0
+ if style == :post
+ (1 ... x.length).each do |i|
+ x_vex[i + o] = x[i]
+ x_vex[i + o + 1] = x[i]
+ y_vex[i + o] = y[i-1]
+ y_vex[i + o + 1] = y[i]
+ o += 1
+ end
+ elsif style == :pre
+ (1 ... x.length).each do |i|
+ x_vex[i + o] = x[i-1]
+ x_vex[i + o + 1] = x[i]
+ y_vex[i + o] = y[i]
+ y_vex[i + o + 1] = y[i]
+ o += 1
+ end
+ end
+ return [x_vex, y_vex]
+ end
+end
diff --git a/lib/unicode_plot/stemplot.rb b/lib/unicode_plot/stemplot.rb
new file mode 100644
index 0000000..9a37779
--- /dev/null
+++ b/lib/unicode_plot/stemplot.rb
@@ -0,0 +1,344 @@
+# coding: utf-8
+
+module UnicodePlot
+
+ # ## Description
+ #
+ # Draw a stem-leaf plot of the given vector +vec+.
+ #
+ # ```
+ # stemplot(vec, **kwargs)
+ # ```
+ #
+ # Draw a back-to-back stem-leaf plot of the given vectors +vec1+ and +vec2+.
+ #
+ # ```
+ # stemplot(vec1, vec2, **kwargs)
+ # ```
+ #
+ # The vectors can be any object that converts to an Array, e.g. an Array, Range, etc.
+ # If all elements of the vector are Numeric, the stem-leaf plot is classified as a
+ # {NumericStemplot}, otherwise it is classified as a {StringStemplot}. Back-to-back
+ # stem-leaf plots must be the same type, i.e. String and Numeric stem-leaf plots cannot
+ # be mixed in a back-to-back plot.
+ #
+ # ## Usage
+ #
+ # stemplot(vec, [vec2], scale:, divider:, padchar:, trim: )
+ #
+ # ## Arguments
+ #
+ # - +vec+: Vector for which the stem leaf plot should be computed.
+ # - +vec2+: Optional secondary vector, will be used to create a back-to-back stem-leaf plot.
+ # - +scale+: Set scale of plot. Default = 10. Scale is changed via orders of magnitude. Common values are 0.1, 1, and 10. For String stems, the default value of 10 is a one character stem, 100 is a two character stem.
+ # - +divider+: Character for break between stem and leaf. Default = "|"
+ # - +padchar+: Character(s) to separate stems, leaves and dividers. Default = " "
+ # - +trim+: Trims the stem labels when there are no leaves. This can be useful if your data is sparse. Default = +false+
+ # - +string_padchar+: Character used to replace missing position for input strings shorter than the stem-size. Default = "_"
+ #
+ # ## Result
+ # A plot of object type is sent to <tt>$stdout</tt>
+ #
+ # @example Examples using Numbers
+ # # Generate some numbers
+ # fifty_floats = 50.times.map { rand(-1000..1000)/350.0 }
+ # eighty_ints = 80.times.map { rand(1..100) }
+ # another_eighty_ints = 80.times.map { rand(1..100) }
+ # three_hundred_ints = 300.times.map { rand(-100..100) }
+ #
+ # # Single sided stem-plot
+ # UnicodePlot.stemplot(eighty_ints)
+ #
+ # # Single sided stem-plot with positive and negative values
+ # UnicodePlot.stemplot(three_hundred_ints)
+ #
+ # # Single sided stem-plot using floating point values, scaled
+ # UnicodePlot.stemplot(fifty_floats, scale: 1)
+ #
+ # # Single sided stem-plot using floating point values, scaled with new divider
+ # UnicodePlot.stemplot(fifty_floats, scale: 1, divider: "😄")
+ #
+ # # Back to back stem-plot
+ # UnicodePlot.stemplot(eighty_ints, another_eighty_ints)
+ #
+ # @example Examples using Strings
+ # # Generate some strings
+ # words_1 = %w[apple junk ant age bee bar baz dog egg a]
+ # words_2 = %w[ape flan can cat juice elf gnome child fruit]
+ #
+ # # Single sided stem-plot
+ # UnicodePlot.stemplot(words_1)
+ #
+ # # Back to back stem-plot
+ # UnicodePlot.stemplot(words_1, words_2)
+ #
+ # # Scaled stem plot using scale=100 (two letters for the stem) and trimmed stems
+ # UnicodePlot.stemplot(words_1, scale: 100, trim: true)
+ #
+ # # Above, but changing the string_padchar
+ # UnicodePlot.stemplot(words_1, scale: 100, trim: true, string_padchar: '?')
+
+ class Stemplot
+
+ # Use {factory} method -- should not be directly called.
+ def initialize(*_args, **_kw)
+ @stemleafs = {}
+ end
+
+ # Factory method to create a Stemplot, creates either a NumericStemplot
+ # or StringStemplot depending on input.
+ #
+ # @param vector [Array] An array of elements to stem-leaf plot
+ # @return [NumericStemplot] If all elements are Numeric
+ # @return [StringStemplot] If any elements are not Numeric
+ def self.factory(vector, **kw)
+ vec = Array(vector)
+ if vec.all? { |item| item.is_a?(Numeric) }
+ NumericStemplot.new(vec, **kw)
+ else
+ StringStemplot.new(vec, **kw)
+ end
+ end
+
+ # Insert a stem and leaf
+ def insert(stem, leaf)
+ @stemleafs[stem] ||= []
+ @stemleafs[stem] << leaf
+ end
+
+ # Returns an unsorted list of stems
+ # @return [Array] Unsorted list of stems
+ def raw_stems
+ @stemleafs.keys
+ end
+
+ # Returns a list of leaves for a given stem
+ # @param stem [Object] The stem
+ # @return [Array] Unsorted list of leaves
+ def leaves(stem)
+ @stemleafs[stem] || []
+ end
+
+ # Determines largest length of any stem
+ # @return [Integer] Length value
+ def max_stem_length
+ @stemleafs.values.map(&:length).max
+ end
+
+ # Returns a sorted list of stems
+ # @param all [Boolean] Return all stems if true, otherwise only return stems if a leaf exists for a stem
+ # @return [Array] Sorted list of stems
+ def stems(all: true)
+ self.class.sorted_stem_list(raw_stems, all: all)
+ end
+
+ end
+
+ class NumericStemplot < Stemplot
+ def initialize(vector, scale: 10, **kw)
+ super
+ Array(vector).each do |value|
+ fvalue = value.to_f.fdiv(scale/10.0)
+ stemnum = (fvalue/10).to_i
+ leafnum = (fvalue - (stemnum*10)).to_i
+ stemsign = value.negative? ? "-" : ''
+ stem = stemsign + stemnum.abs.to_s
+ leaf = leafnum.abs.to_s
+ self.insert(stem, leaf)
+ end
+ end
+
+ # Print key to STDOUT
+ # @param scale [Integer] Scale, should be a power of 10
+ # @param divider [String] Divider character between stem and leaf
+ def print_key(scale, divider)
+ # First print the key
+ puts "Key: 1#{divider}0 = #{scale}"
+ # Description of where the decimal is
+ trunclog = Math.log10(scale).truncate
+ ndigits = trunclog.abs
+ right_or_left = (trunclog < 0) ? "left" : "right"
+ puts "The decimal is #{ndigits} digit(s) to the #{right_or_left} of #{divider}"
+ end
+
+ # Used when we have stems from a back-to-back stemplot and a combined list of stems is given
+ # @param stems [Array] Concatenated list of stems from two plots
+ # @param all [Boolean] Return all stems if true, otherwise only return stems if a leaf exists for a stem
+ # @return [Array] Sorted list of stems
+ def self.sorted_stem_list(stems, all: true)
+ negkeys, poskeys = stems.partition { |str| str[0] == '-'}
+ if all
+ negmin, negmax = negkeys.map(&:to_i).map(&:abs).minmax
+ posmin, posmax = poskeys.map(&:to_i).minmax
+ negrange = negmin ? (negmin..negmax).to_a.reverse.map { |s| "-"+s.to_s } : []
+ posrange = posmin ? (posmin..posmax).to_a.map(&:to_s) : []
+ return negrange + posrange
+ else
+ negkeys.sort! { |a,b| a.to_i <=> b.to_i }
+ poskeys.sort! { |a,b| a.to_i <=> b.to_i }
+ return negkeys + poskeys
+ end
+ end
+ end
+
+ class StringStemplot < Stemplot
+
+ def initialize(vector, scale: 10, string_padchar: '_', **_kw)
+ super
+ stem_places = Math.log10(scale).floor
+ raise ArgumentError, "Cannot take fewer than 1 place from stem. Scale parameter should be greater than or equal to 10." if stem_places < 1
+ vector.each do |value|
+ # Strings may be shorter than the number of places we desire,
+ # so we will pad them with a string-pad-character.
+ padded_value = value.ljust(stem_places+1, string_padchar)
+ stem = padded_value[0...stem_places]
+ leaf = padded_value[stem_places]
+ self.insert(stem, leaf)
+ end
+ end
+
+ # Function prototype to provide same interface as {NumericStemplot}.
+ # This function does not do anything.
+ # @return [false]
+ def print_key(_scale, _divider)
+ # intentionally empty
+ return false
+ end
+
+ # Used when we have stems from a back-to-back stemplot and a combined list of stems is given
+ # @param stems [Array] Concatenated list of stems from two plots
+ # @param all [Boolean] Return all stems if true, otherwise only return stems if a leaf exists for a stem
+ # @return [Array] Sorted list of stems
+ def self.sorted_stem_list(stems, all: true)
+ if all
+ rmin, rmax = stems.minmax
+ return (rmin .. rmax).to_a
+ else
+ stems.sort
+ end
+ end
+
+ end
+
+ # Print a Single-Vector stemplot to STDOUT.
+ #
+ # - Stem data is printed on the left.
+ # - Leaf data is printed on the right.
+ # - Key is printed at the bottom.
+ # @param plt [Stemplot] Stemplot object
+ # @param scale [Integer] Scale, should be a power of 10
+ # @param divider [String] Divider character between stem and leaf
+ # @param padchar [String] Padding character
+ # @param trim [Boolean] Trim missing stems from the plot
+ def stemplot1!(plt,
+ scale: 10,
+ divider: "|",
+ padchar: " ",
+ trim: false,
+ **_kw
+ )
+
+ stem_labels = plt.stems(all: !trim)
+ label_len = stem_labels.map(&:length).max
+ column_len = label_len + 1
+
+ stem_labels.each do |stem|
+ leaves = plt.leaves(stem).sort
+ stemlbl = stem.rjust(label_len, padchar).ljust(column_len, padchar)
+ puts stemlbl + divider + padchar + leaves.join
+ end
+ plt.print_key(scale, divider)
+ end
+
+ # Print a Back-to-Back Stemplot to STDOUT
+ #
+ # - +plt1+ Leaf data is printed on the left.
+ # - Common stem data is printed in the center.
+ # - +plt2+ Leaf data is printed on the right.
+ # - Key is printed at the bottom.
+ # @param plt1 [Stemplot] Stemplot object for the left side
+ # @param plt2 [Stemplot] Stemplot object for the right side
+ # @param scale [Integer] Scale, should be a power of 10
+ # @param divider [String] Divider character between stem and leaf
+ # @param padchar [String] Padding character
+ # @param trim [Boolean] Trim missing stems from the plot
+ def stemplot2!(plt1, plt2,
+ scale: 10,
+ divider: "|",
+ padchar: " ",
+ trim: false,
+ **_kw
+ )
+ stem_labels = plt1.class.sorted_stem_list( (plt1.raw_stems + plt2.raw_stems).uniq, all: !trim )
+ label_len = stem_labels.map(&:length).max
+ column_len = label_len + 1
+
+ leftleaf_len = plt1.max_stem_length
+
+ stem_labels.each do |stem|
+ left_leaves = plt1.leaves(stem).sort.join('')
+ right_leaves = plt2.leaves(stem).sort.join('')
+ left_leaves_just = left_leaves.reverse.rjust(leftleaf_len, padchar)
+ stem = stem.rjust(column_len, padchar).ljust(column_len+1, padchar)
+ puts left_leaves_just + padchar + divider + stem + divider + padchar + right_leaves
+ end
+
+ plt1.print_key(scale, divider)
+
+ end
+
+ # Generates one or more {Stemplot} objects from the input data
+ # and prints a Single or Double stemplot using {stemplot1!} or {stemplot2!}
+ # @see Stemplot
+ # @example Single sided stemplot
+ # >> UnicodePlot.stemplot(eighty_ints)
+ # 0 | 257
+ # 1 | 00335679
+ # 2 | 034455899
+ # 3 | 145588
+ # 4 | 0022223
+ # 5 | 0223399
+ # 6 | 012345568889
+ # 7 | 01133334466777888
+ # 8 | 013689
+ # 9 | 22667
+ # Key: 1|0 = 10
+ # The decimal is 1 digit(s) to the right of |
+ #
+ # @example Back-to-back stemplot
+ # >> UnicodePlot.stemplot(eighty_ints, another_eighty_ints)
+ # 752 | 0 | 1244457899
+ # 97653300 | 1 | 4799
+ # 998554430 | 2 | 015668
+ # 885541 | 3 | 0144557888899
+ # 3222200 | 4 | 00268
+ # 9933220 | 5 | 0234778
+ # 988865543210 | 6 | 122222357889
+ # 88877766443333110 | 7 | 134556689
+ # 986310 | 8 | 24589
+ # 76622 | 9 | 022234468
+ # Key: 1|0 = 10
+ # The decimal is 1 digit(s) to the right of |
+ #
+ def stemplot(*args, scale: 10, **kw)
+ case args.length
+ when 1
+ # Stemplot object
+ plt = Stemplot.factory(args[0], scale: scale, **kw)
+ # Dispatch to plot routine
+ stemplot1!(plt, scale: scale, **kw)
+ when 2
+ # Stemplot object
+ plt1 = Stemplot.factory(args[0], scale: scale)
+ plt2 = Stemplot.factory(args[1], scale: scale)
+ raise ArgumentError, "Plot types must be the same for back-to-back stemplot " +
+ "#{plt1.class} != #{plt2.class}" unless plt1.class == plt2.class
+ # Dispatch to plot routine
+ stemplot2!(plt1, plt2, scale: scale, **kw)
+ else
+ raise ArgumentError, "Expecting one or two arguments"
+ end
+ end
+
+ module_function :stemplot, :stemplot1!, :stemplot2!
+end
diff --git a/lib/unicode_plot/styled_printer.rb b/lib/unicode_plot/styled_printer.rb
index b3ad81c..1a6c660 100644
--- a/lib/unicode_plot/styled_printer.rb
+++ b/lib/unicode_plot/styled_printer.rb
@@ -58,7 +58,7 @@ module UnicodePlot
COLOR_DECODE = COLOR_ENCODE.map {|k, v| [v, k] }.to_h.freeze
def print_styled(out, *args, bold: false, color: :normal)
- return out.print(*args) unless color?(out)
+ return out.print(*args) unless out.color?
str = StringIO.open {|sio| sio.print(*args); sio.close; sio.string }
color = :nothing if bold && color == :bold
@@ -83,9 +83,5 @@ module UnicodePlot
color = COLOR_DECODE[color]
print_styled(out, *args, color: color)
end
-
- def color?(out)
- out&.tty? || false
- end
end
end
diff --git a/lib/unicode_plot/version.rb b/lib/unicode_plot/version.rb
index 4a461e5..7f2e07e 100644
--- a/lib/unicode_plot/version.rb
+++ b/lib/unicode_plot/version.rb
@@ -1,5 +1,5 @@
module UnicodePlot
- VERSION = "0.0.4"
+ VERSION = "0.0.5"
module Version
numbers, TAG = VERSION.split("-", 2)
diff --git a/test/helper/with_term.rb b/test/helper/with_term.rb
index 6620037..4aae79d 100644
--- a/test/helper/with_term.rb
+++ b/test/helper/with_term.rb
@@ -2,22 +2,28 @@ require 'stringio'
module Helper
module WithTerm
- def with_term(tty=true)
+ def with_sio(tty: true)
sio = StringIO.new
def sio.tty?; true; end if tty
- orig_stdout, $stdout = $stdout, sio
- orig_env = ENV.to_h.dup
- ENV['TERM'] = 'xterm-256color'
-
- result = yield
+ result = yield(sio)
sio.close
[result, sio.string]
- ensure
- $stdout.close
- $stdout = orig_stdout
- ENV.replace(orig_env) if orig_env
+ end
+
+ def with_term(tty=true)
+ with_sio(tty: tty) do |sio|
+ begin
+ orig_stdout, $stdout = $stdout, sio
+ orig_env = ENV.to_h.dup
+ ENV['TERM'] = 'xterm-256color'
+ yield
+ ensure
+ $stdout = orig_stdout
+ ENV.replace(orig_env) if orig_env
+ end
+ end
end
end
end
diff --git a/test/test-barplot.rb b/test/test-barplot.rb
index dddbff9..c3bba4a 100644
--- a/test/test-barplot.rb
+++ b/test/test-barplot.rb
@@ -12,6 +12,14 @@ class BarplotTest < Test::Unit::TestCase
end
end
+ sub_test_case("with invalid arguments") do
+ test("unknown border type") do
+ assert_raise(ArgumentError.new("unknown border type: invalid_border_name")) do
+ UnicodePlot.barplot(data: {bar: 23, foo: 37}, border: :invalid_border_name)
+ end
+ end
+ end
+
test("colored") do
data = { bar: 23, foo: 37 }
plot = UnicodePlot.barplot(data: data)
diff --git a/test/test-boxplot.rb b/test/test-boxplot.rb
index 89874fc..db6bdf7 100644
--- a/test/test-boxplot.rb
+++ b/test/test-boxplot.rb
@@ -3,6 +3,14 @@ class BoxplotTest < Test::Unit::TestCase
include Helper::WithTerm
sub_test_case("UnicodePlot.boxplot") do
+ sub_test_case("with invalid arguments") do
+ test("unknown border type") do
+ assert_raise(ArgumentError.new("unknown border type: invalid_border_name")) do
+ UnicodePlot.boxplot([1, 2, 3, 4, 5], border: :invalid_border_name)
+ end
+ end
+ end
+
sub_test_case("print to tty") do
test("without name") do
plot = UnicodePlot.boxplot([1, 2, 3, 4, 5])
diff --git a/test/test-canvas.rb b/test/test-canvas.rb
index 59cd75e..971759b 100644
--- a/test/test-canvas.rb
+++ b/test/test-canvas.rb
@@ -6,7 +6,8 @@ module CanvasTestCases
ascii: UnicodePlot::AsciiCanvas,
braille: UnicodePlot::BrailleCanvas,
density: UnicodePlot::DensityCanvas,
- dot: UnicodePlot::DotCanvas
+ dot: UnicodePlot::DotCanvas,
+ block: UnicodePlot::BlockCanvas
}.freeze
def self.included(mod)
@@ -54,11 +55,11 @@ module CanvasTestCases
test("empty") do
if self.class::CANVAS_NAME == :braille
- _, output = with_term { @canvas.show($stdout) }
+ _, output = with_term { @canvas.show(UnicodePlot::IOContext.new($stdout)) }
assert_equal(fixture_path("canvas/empty_braille_show.txt").read,
output)
else
- _, output = with_term { @canvas.show($stdout) }
+ _, output = with_term { @canvas.show(UnicodePlot::IOContext.new($stdout)) }
assert_equal(fixture_path("canvas/empty_show.txt").read,
output)
end
@@ -80,31 +81,31 @@ module CanvasTestCases
end
test("print_row") do
- _, output = with_term { @canvas.print_row($stdout, 2) }
+ _, output = with_term { @canvas.print_row(UnicodePlot::IOContext.new($stdout), 2) }
assert_equal(fixture_path("canvas/#{self.class::CANVAS_NAME}_printrow.txt").read,
output)
end
test("print") do
- _, output = with_term { @canvas.print($stdout) }
+ _, output = with_term { @canvas.print(UnicodePlot::IOContext.new($stdout)) }
assert_equal(fixture_path("canvas/#{self.class::CANVAS_NAME}_print.txt").read,
output)
end
test("print_nocolor") do
- _, output = with_term(false) { @canvas.print($stdout) }
+ _, output = with_term(false) { @canvas.print(UnicodePlot::IOContext.new($stdout)) }
assert_equal(fixture_path("canvas/#{self.class::CANVAS_NAME}_print_nocolor.txt").read,
output)
end
test("sow") do
- _, output = with_term { @canvas.show($stdout) }
+ _, output = with_term { @canvas.show(UnicodePlot::IOContext.new($stdout)) }
assert_equal(fixture_path("canvas/#{self.class::CANVAS_NAME}_show.txt").read,
output)
end
test("show_nocolor") do
- _, output = with_term(false) { @canvas.show($stdout) }
+ _, output = with_term(false) { @canvas.show(UnicodePlot::IOContext.new($stdout)) }
assert_equal(fixture_path("canvas/#{self.class::CANVAS_NAME}_show_nocolor.txt").read,
output)
end
@@ -136,3 +137,9 @@ class DotCanvasTest < Test::Unit::TestCase
include CanvasTestCases
end
+
+class BlockCanvasTest < Test::Unit::TestCase
+ CANVAS_NAME = :block
+
+ include CanvasTestCases
+end
diff --git a/test/test-densityplot.rb b/test/test-densityplot.rb
index fa3f92e..9a85873 100644
--- a/test/test-densityplot.rb
+++ b/test/test-densityplot.rb
@@ -10,6 +10,14 @@ class DensityplotTest < Test::Unit::TestCase
assert_equal(1000, @dy.length)
end
+ sub_test_case("with invalid arguments") do
+ test("unknown border type") do
+ assert_raise(ArgumentError.new("unknown border type: invalid_border_name")) do
+ UnicodePlot.densityplot(@dx, @dy, border: :invalid_border_name)
+ end
+ end
+ end
+
test("default") do
plot = UnicodePlot.densityplot(@dx, @dy)
dx2 = @dx.map {|x| x + 2 }
diff --git a/test/test-histogram.rb b/test/test-histogram.rb
index 284e315..31c9178 100644
--- a/test/test-histogram.rb
+++ b/test/test-histogram.rb
@@ -7,6 +7,14 @@ class HistogramTest < Test::Unit::TestCase
@x = fixture_path("randn.txt").read.lines.map(&:to_f)
end
+ sub_test_case("with invalid arguments") do
+ test("unknown border type") do
+ assert_raise(ArgumentError.new("unknown border type: invalid_border_name")) do
+ UnicodePlot.histogram(@x, border: :invalid_border_name)
+ end
+ end
+ end
+
test("default") do
plot = UnicodePlot.histogram(@x)
_, output = with_term { plot.render($stdout) }
diff --git a/test/test-lineplot.rb b/test/test-lineplot.rb
index a6b43f0..cb13823 100644
--- a/test/test-lineplot.rb
+++ b/test/test-lineplot.rb
@@ -23,6 +23,14 @@ class LineplotTest < Test::Unit::TestCase
assert_raise(ArgumentError) { UnicodePlot.lineplot(1..3, 1..2) }
end
+ sub_test_case("with invalid arguments") do
+ test("unknown border type") do
+ assert_raise(ArgumentError.new("unknown border type: invalid_border_name")) do
+ UnicodePlot.lineplot(@x, @y, border: :invalid_border_name)
+ end
+ end
+ end
+
sub_test_case("with numeric array") do
test("default") do
plot = UnicodePlot.lineplot(@x, @y)
@@ -192,8 +200,84 @@ class LineplotTest < Test::Unit::TestCase
output)
end
+ test("fixed line y-interpolation bug (issue 32)") do
+ ys = [261, 272, 277, 283, 289, 294, 298, 305, 309, 314, 319, 320, 322, 323, 324]
+ xs = ys.size.times.to_a
+ plot = UnicodePlot.lineplot(xs, ys, height: 26, ylim: [0, 700])
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/issue32_fix.txt").read,
+ output)
+ end
+
# TODO: functions
- # TODO: stairs
+ sub_test_case("stairs") do
+ def setup
+ @sx = [1, 2, 4, 7, 8]
+ @sy = [1, 3, 4, 2, 7]
+ end
+
+ test("pre") do
+ plot = UnicodePlot.stairs(@sx, @sy, style: :pre)
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/stairs_pre.txt").read, output)
+ end
+
+ test("post") do
+ # inferred post
+ plot = UnicodePlot.stairs(@sx, @sy)
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/stairs_post.txt").read, output)
+ # explicit post
+ plot = UnicodePlot.stairs(@sx, @sy, style: :post)
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/stairs_post.txt").read, output)
+ end
+
+ test("with parameters") do
+ plot = UnicodePlot.stairs(@sx, @sy, title: "Foo", color: :red, xlabel: "x", name: "1")
+ sx2 = @sx.map { |val| val - 0.2 }
+ sy2 = @sy.map { |val| val + 1.5 }
+ plot2 = UnicodePlot.stairs!(plot, sx2, sy2, name: "2")
+ assert_equal(plot.class, plot2.class)
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/stairs_parameters.txt").read, output)
+
+ # add a 3rd staircase and check again
+ plot3 = UnicodePlot.stairs!(plot, @sx, @sy, name: "3", style: :pre)
+ assert_equal(plot.class, plot3.class)
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/stairs_parameters2.txt").read, output)
+
+ # check with color disabled
+ output = StringIO.open do |sio|
+ plot.render(sio)
+ sio.close
+ sio.string
+ end
+ assert_equal("\n", output[-1])
+ assert_equal(fixture_path("lineplot/stairs_parameters2_nocolor.txt").read,
+ output.chomp)
+ end
+
+ test("special weird case") do
+ plot = UnicodePlot.stairs(@sx, [1, 3, 4, 2, 7000])
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/stairs_edgecase.txt").read, output)
+ end
+
+ test("annotations") do
+ plot = UnicodePlot.stairs(@sx, @sy, width: 10, padding: 3)
+ plot.annotate!(:tl, "Hello")
+ plot.annotate!(:t, "how are")
+ plot.annotate!(:tr, "you?")
+ plot.annotate!(:bl, "Hello")
+ plot.annotate!(:b, "how are")
+ plot.annotate!(:br, "you?")
+ UnicodePlot.lineplot!(plot, 1, 0.5)
+ _, output = with_term { plot.render($stdout, newline: false) }
+ assert_equal(fixture_path("lineplot/squeeze_annotations.txt").read, output)
+ end
+ end
end
end
diff --git a/test/test-plot.rb b/test/test-plot.rb
index 6888cbe..6702df4 100644
--- a/test/test-plot.rb
+++ b/test/test-plot.rb
@@ -1,6 +1,8 @@
require 'stringio'
class TestPlot < Test::Unit::TestCase
+ include Helper::WithTerm
+
sub_test_case("#render") do
test("render to $stdout when no arguments") do
sio = StringIO.new
@@ -16,5 +18,19 @@ class TestPlot < Test::Unit::TestCase
$stdout = save_stdout
end
end
+
+ test("color: true") do
+ _, tty_output = with_sio(tty: true) {|sio| UnicodePlot.barplot(data: {a: 23, b: 37}).render(sio) }
+ _, notty_output = with_sio(tty: false) {|sio| UnicodePlot.barplot(data: {a: 23, b: 37}).render(sio, color: true) }
+
+ assert_equal(tty_output, notty_output)
+ end
+
+ test("color: false") do
+ _, tty_output = with_sio(tty: true) {|sio| UnicodePlot.barplot(data: {a: 23, b: 37}).render(sio, color: false) }
+ _, notty_output = with_sio(tty: false) {|sio| UnicodePlot.barplot(data: {a: 23, b: 37}).render(sio) }
+
+ assert_equal(tty_output, notty_output)
+ end
end
end
diff --git a/test/test-result.rb b/test/test-result.rb
deleted file mode 100644
index e69de29..0000000
diff --git a/test/test-scatterplot.rb b/test/test-scatterplot.rb
index 9634239..1334c7e 100644
--- a/test/test-scatterplot.rb
+++ b/test/test-scatterplot.rb
@@ -22,6 +22,14 @@ class ScatterplotTest < Test::Unit::TestCase
end
end
+ sub_test_case("with invalid arguments") do
+ test("unknown border type") do
+ assert_raise(ArgumentError.new("unknown border type: invalid_border_name")) do
+ UnicodePlot.scatterplot(@x, @y, border: :invalid_border_name)
+ end
+ end
+ end
+
test("default") do
plot = UnicodePlot.scatterplot(@x, @y)
_, output = with_term { plot.render($stdout, newline: false) }
diff --git a/test/test-stemplot.rb b/test/test-stemplot.rb
new file mode 100644
index 0000000..6dc518f
--- /dev/null
+++ b/test/test-stemplot.rb
@@ -0,0 +1,95 @@
+# coding: utf-8
+class HistogramTest < Test::Unit::TestCase
+ include Helper::Fixture
+ include Helper::WithTerm
+
+ sub_test_case("UnicodePlot.stemplot") do
+ def setup
+ @randoms = fixture_path("randn.txt").read.lines.take(50).map(&:to_f)
+
+ @int80a = [40, 53, 33, 8, 30, 78, 68, 63, 80, 75, 73, 75, 61, 24, 84, 84, 51, 31, 94, 63, 72, 9, 80, 1, 84, 1, 13, 55, 46, 41, 99, 100, 39, 41, 10, 70, 67, 21, 50, 41, 49, 24, 32, 42, 32, 37, 44, 10, 48, 64, 41, 46, 94, 15, 15, 5, 6, 97, 48, 14, 2, 92, 10, 2, 91, 89, 20, 98, 19, 66, 43, 95, 90, 34, 71, 42, 31, 92, 95, 30]
+
+ @int80b = [23, 24, 70, 61, 26, 57, 28, 18, 69, 53, 92, 11, 33, 38, 85, 58, 38, 27, 14, 62, 57, 38, 91, 11, 66, 23, 63, 28, 98, 9, 53, 26, 1, 93, 96, 49, 8, 89, 19, 18, 68, 51, 4, 57, 79, 90, 72, 99, 41, 57, 100, 94, 5, 13, 24, 76, 5, 60, 26, 41, 89, 99, 22, 81, 41, 48, 65, 67, 38, 53, 96, 85, 75, 89, 35, 75, 88, 50, 14, 33]
+
+ @int300 = [-30, -7, 37, -42, -15, 8, 62, 22, -3, -32, -35, -48, -29, 8, -75, 27, 84, 81, -21, 9, 23, 86, -30, 29, 47, 89, -3, 38, 22, 31, 49, 84, -5, -28, -26, -66, 68, 59, -92, -3, -23, 100, -73, 19, -37, 89, -21, 23, 71, 14, -98, 49, -3, -1, -8, 67, -55, -30, -55, 93, 69, -20, -79, -91, -23, -46, 84, -49, -12, 35, -74, -2, -84, -34, -28, 98, -70, -72, 71, 86, 24, 64, -99, -76, -37, 54, 53, 72, -31, -53, 85, 10, -17, -8, -35, -16, -3, 26, 68, -92, 20, -70, 87, -78, 95, -88, -85, -7, 67, -47, -46, 0, -24, -48, 53, -53, -26, 79, -51, -40, -95, -37, 44, 77, -66, 85, 14, 5, -25, -85, -54, -17, -94, -52, -75, -79, 79, -53, -16, -27, -43, -94, -66, -56, -47, -56, -21, 7, 73, -19, 87, -64, -46, -81, 19, -13, -44, -87, -22, 18, 54, -9, 84, 50, 85, 62, 8, 99, -94, -65, 59, 93, 84, 16, 82, -16, 77, 55, -63, -13, -34, -77, 55, 87, -99, -82, 9, 73, 75, -94, -6, 9, 89, 27, 70, 56, -38, -67, -46, 59, 91, -26, 30, -81, -6, -29, -66, 25, 17, -25, -9, -90, 20, -71, 1, -47, -76, 39, -29, -19, -45, 91, -92, -6, -59, 34, 51, -61, -41, -90, 77, 83, -83, -25, -29, -64, 16, -91, -14, 7, -71, -57, -71, 76, -9, -43, -89, 86, 56, 56, 27, 3, -5, 13, -99, 13, -97, -68, 94, -15, 6, -8, -28, -52, 38, -96, -54, 13, -36, 78, -24, 32, 96, -57, -56, -27, -79, -73, -18, 44, -48, -65, -4, 80, -69, -26, -38, 66, 62, 65, -83, -100, -37, 1, -99, 75, 33, 19, 0, -70]
+
+ @words_1 = %w[apple junk ant age bee bar baz dog egg a]
+ @words_2 = %w[ape flan can cat juice elf gnome child fruit]
+
+ end
+
+ test("range input") do
+ _, output = with_term { UnicodePlot.stemplot(-100..100) }
+ assert_equal(fixture_path("stemplot/range.txt").read, output)
+ end
+
+ test("positive integers") do
+ _, output = with_term { UnicodePlot.stemplot(@int80a) }
+ assert_equal(fixture_path("stemplot/pos_ints.txt").read, output)
+ end
+
+ test("with happy divider") do
+ _, output = with_term { UnicodePlot.stemplot(@int80a, divider: "😄") }
+ assert_equal(fixture_path("stemplot/ints_divider.txt").read, output)
+ end
+
+ test("positive and negative integers") do
+ _, output = with_term { UnicodePlot.stemplot(@int300) }
+ assert_equal(fixture_path("stemplot/posneg_ints.txt").read, output)
+ end
+
+ test("floats") do
+ x10 = @randoms.map {|a| a * 10 }
+ #p x10.sort
+ #UnicodePlot.stemplot(x10)
+ _, output = with_term { UnicodePlot.stemplot(x10) }
+ assert_equal(fixture_path("stemplot/float.txt").read, output)
+ end
+
+
+ test("floats, scale=1") do
+ floats = (-8..8).to_a.map { |a| a / 2.0 }
+ _, output = with_term { UnicodePlot.stemplot(floats, scale: 1) }
+ assert_equal(fixture_path("stemplot/float_scale1.txt").read, output)
+ end
+
+
+ test("back-to-back stemplot with integers") do
+ _, output = with_term { UnicodePlot.stemplot(@int80a, @int80b) }
+ assert_equal(fixture_path("stemplot/b2b_integers.txt").read, output)
+ end
+
+ test("stemplot with strings") do
+ _, output = with_term { UnicodePlot.stemplot(@words_1) }
+ assert_equal(fixture_path("stemplot/strings.txt").read, output)
+ end
+
+ test("back-to-back stemplot with strings") do
+ _, output = with_term { UnicodePlot.stemplot(@words_1, @words_2) }
+ assert_equal(fixture_path("stemplot/b2b_strings.txt").read, output)
+ end
+
+ test("stemplot with strings, two-char scale") do
+ _, output = with_term { UnicodePlot.stemplot(@words_1, scale: 100, trim: true) }
+ assert_equal(fixture_path("stemplot/strings_2c.txt").read, output)
+ end
+
+ test("stemplot with strings, two-char scale, string_padchar") do
+ _, output = with_term { UnicodePlot.stemplot(@words_1, string_padchar: '?') }
+ assert_equal(fixture_path("stemplot/strings_pad.txt").read, output)
+ end
+
+ test("string stemplot cannot take scale less than 10") do
+ assert_raise(ArgumentError) do
+ UnicodePlot.stemplot(@words_1, scale: 9)
+ end
+ end
+
+ test("cannot mix string/number in back to back stemplot") do
+ assert_raise(ArgumentError) do
+ UnicodePlot.stemplot(@words_1, @int80a)
+ end
+ end
+
+ end
+end
diff --git a/test/test-utils.rb b/test/test-utils.rb
new file mode 100644
index 0000000..796f9cb
--- /dev/null
+++ b/test/test-utils.rb
@@ -0,0 +1,13 @@
+class UnicodePlotTest < Test::Unit::TestCase
+ test("UnicodePlot.canvas_types") do
+ available_canvas_types = [:ascii, :block, :braille, :density, :dot]
+ assert_equal(available_canvas_types.sort,
+ UnicodePlot.canvas_types.sort)
+ end
+
+ test("UnicodePlot.border_types") do
+ available_border_types = [:solid, :corners, :barplot]
+ assert_equal(available_border_types.sort,
+ UnicodePlot.border_types.sort)
+ end
+end
diff --git a/unicode_plot.gemspec b/unicode_plot.gemspec
index a8dfd78..bb4bf62 100644
--- a/unicode_plot.gemspec
+++ b/unicode_plot.gemspec
@@ -19,6 +19,9 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/red-data-tools/unicode_plot.rb"
spec.license = "MIT"
+ spec.metadata ||= {}
+ spec.metadata["documentation_uri"] = "https://red-data-tools.github.io/unicode_plot.rb/#{spec.version}/"
+
spec.files = ["README.md", "Rakefile", "Gemfile", "#{spec.name}.gemspec"]
spec.files << "LICENSE.txt"
spec.files.concat Dir.glob("lib/**/*.rb")
@@ -34,4 +37,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "bundler", ">= 1.17"
spec.add_development_dependency "rake"
spec.add_development_dependency "test-unit"
+ spec.add_development_dependency "yard"
end
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/barplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/boxplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas/ascii_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas/block_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas/braille_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas/density_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas/dot_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/canvas/lookup_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/densityplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/grid_plot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/histogram.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/io_context.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/lineplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/plot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/renderer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/scatterplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/stairs.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/stemplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/styled_printer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/utils.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/value_transformer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.5/lib/unicode_plot/version.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/specifications/unicode_plot-0.0.5.gemspec
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/ascii_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/barplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/boxplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/braille_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/density_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/densityplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/dot_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/grid_plot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/histogram.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/layout.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/lineplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/lookup_canvas.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/plot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/renderer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/scatterplot.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/styled_printer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/utils.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/value_transformer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/unicode_plot-0.0.4/lib/unicode_plot/version.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/specifications/unicode_plot-0.0.4.gemspec
Control files: lines which differ (wdiff format)
Ruby-Versions: all