basis-processing 0.5.9 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -4,13 +4,15 @@ Please send bug reports to (avishek.sen.gupta at gmail.com)
4
4
 
5
5
  **Basis** provides a set of classes for easily plotting and transforming arbitrary 2D coordinate systems by specifying their basis vectors. Originally developed to work with Ruby-Processing, it now supports any class which supports Processing-like semantics.
6
6
 
7
- UPDATE: Starting from version 0.5.9, you can turn grid lines on or off.
7
+ **UPDATE:** Starting from version 0.6.0, Basis allows you to specify axis labels. Additionally, you can specify arrays of points instead of plotting points one at a time. When you do this, you can also specify a corresponding legend string, which will show up in a legend guide. See below for more details.
8
8
 
9
- UPDATE: Starting from version 0.5.8, you can customise axis labels, draw arbitrary shapes/text/plot custom graphics at any point in your coordinate system. See below for more details.
9
+ **UPDATE:** Starting from version 0.5.9, you can turn grid lines on or off. Additionally, the matrix operations implementation has been ported to use the Matrix class in Ruby's stdlib.
10
10
 
11
- UPDATE: With version 0.5.7, experimental support has been added for drawing objects which aren’t points. Interactions with such objects is currently not supported. Additional support for drawing markers/highlighting in custom bases is now in.
11
+ **UPDATE:** Starting from version 0.5.8, you can customise axis labels, draw arbitrary shapes/text/plot custom graphics at any point in your coordinate system. See below for more details.
12
12
 
13
- UPDATE: Starting from version 0.5.1, Basis has been ported to Ruby 1.9.2, because of the kd-tree library dependency. Currently, there are no plans of maintaining Basis compatibility with Ruby 1.8.x. As an aside, I personally recommend using RVM to manage the mess of Ruby/JRuby installations that you’re likely to have on your machine.
13
+ **UPDATE:** With version 0.5.7, experimental support has been added for drawing objects which aren’t points. Interactions with such objects is currently not supported. Additional support for drawing markers/highlighting in custom bases is now in.
14
+
15
+ **UPDATE:** Starting from version 0.5.1, Basis has been ported to Ruby 1.9.2, because of the kd-tree library dependency. Currently, there are no plans of maintaining Basis compatibility with Ruby 1.8.x. As an aside, I personally recommend using RVM to manage the mess of Ruby/JRuby installations that you’re likely to have on your machine.
14
16
 
15
17
  UPDATE: Basis has hit version 0.5.0 with experimental support for mouseover interactivity. More work is incoming, but the demo code below is up-to-date, for now. Starting from version 0.5.0, experimental support has been added for mouseover interactivity without (too much) extra effort on your part. This is still a work in progress, though.
16
18
 
@@ -96,6 +98,18 @@ Here's some example code, which plots random points.
96
98
  Demo.send :include, Interactive
97
99
  Demo.new(:title => "My Sketch", :width => w, :height => h)
98
100
 
101
+ You may choose to plot each point individually, as in the example above. However, you could have achieved the same thing by writing the following directly.
102
+
103
+ @screen.plot(points, :legend => 'Some Distribution', :track => true) do |original, mapped, s|
104
+ s.in_basis do
105
+ rect(original[:x], original[:y], 3, 3)
106
+ end
107
+ end
108
+
109
+ If you choose this route, you can specify a legend, as shown above. This will show up in a legend guide at a default position. You can customise the positioning of the legend box, while creating the Screen object, like so:
110
+
111
+ @screen = Screen.new(screen_transform, self, @basis, LegendBox.new(self, {:x => 1300, :y => 30}))
112
+
99
113
  You have a few options when plotting a point. If you specify ':bar => true', like the line below:
100
114
 
101
115
  screen.plot(p, basis, :bar => true) {|p| rect(p[:x], p[:y], 5, 5)}
@@ -217,8 +231,8 @@ Consider the following code:
217
231
  background(0,0,0)
218
232
  color_mode(HSB, 1.0)
219
233
  box = {:minimum => 20, :maximum => 70, :q1 => 30, :q2 => 40, :q3 => 50}
220
- @x_unit_vector = {:x => 1.0, :y => 0.0}
221
- @y_unit_vector = {:x => 0.0, :y => 1.0}
234
+ @x_unit_vector = {:x => 1.0, :y => 0.15, :legend => 'x-axis'}
235
+ @y_unit_vector = {:x => 0.2, :y => 1.0, :legend => 'y-axis'}
222
236
  @screen_transform = Transform.new({:x => 5.0, :y => -5.0}, {:x => @width/2, :y => @screen_height})
223
237
  x_range = ContinuousRange.new({:minimum => 0.0, :maximum => 80.0})
224
238
  y_range = ContinuousRange.new({:minimum => 0.0, :maximum => box[:maximum]})
@@ -252,8 +266,10 @@ The first interesting thing in the code above is that the box hash does not have
252
266
 
253
267
  The other interesting thing about the above code will become evident if we specify a different set of basis vectors like so:
254
268
 
255
- @x_unit_vector = {:x => 1.0, :y => 0.15}
256
- @y_unit_vector = {:x => 0.2, :y => 1.0}
269
+ @x_unit_vector = {:x => 1.0, :y => 0.15, :label => 'x-axis'}
270
+ @y_unit_vector = {:x => 0.2, :y => 1.0, :label => 'y-axis'}
271
+
272
+ Specifying the :label key is optional, Basis will generate its own legends if you don't specify anything.
257
273
 
258
274
  The box plot in this modified basis acquires the properties of skewness, rotation, etc. of the host coordinate system. This lets you get on with drawing the object without really worrying about the specific properties of the coordinate space you are plotting in.
259
275
 
@@ -263,6 +279,17 @@ The other variation you can use is the at() method of a Screen object. at() beha
263
279
 
264
280
  ## Axis drawing options
265
281
 
282
+ Starting from version 0.6.0, you can specify the axis labels. There are two ways to do this. If you're explicitly specifying your own basis vectors, you can specify the labels there, like so:
283
+
284
+ @x_unit_vector = {:x => 1.0, :y => 0.15, :label => 'x-axis'}
285
+ @y_unit_vector = {:x => 0.2, :y => 1.0, :label => 'y-axis'}
286
+
287
+ If you're using the convenience method to initialise the standard CoordinateSystem, you can specify the labels like so:
288
+
289
+ @c = CoordinateSystem.standard(x_range, y_range, self, {:x => 'Score', :y => 'Probability P(score)'})
290
+
291
+ In the code above, :x maps to 'Score' for the x-axis, and :y maps to 'Probability P(score)' for the y-axis.
292
+
266
293
  Starting from version 0.5.8, you can customise labels, if you pass two blocks to the draw_axes() method, one for the x-axis, the other for the y-axis. For example, in the fragment below, we're not outputting anything for the x-axis labels (returning an empty string), and converting the y-axis value to an integer.
267
294
 
268
295
  @screen.draw_axes(10, 10, :x => ->(p){''}, :y => ->(p){p.to_i})
@@ -271,7 +298,7 @@ Grid lines are drawn by default. To turn them off, set the :gridlines key to fal
271
298
 
272
299
  @screen.draw_axes(10, 10, :x => ->(p){''}, :y => ->(p){p.to_i}, :gridlines => false)
273
300
 
274
- ## Convenience method for setting up default CoordinateSystem
301
+ ## The default CoordinateSystem
275
302
 
276
303
  If you're doing a simple plot, with standard basis vectors with no transformations, you can use the convenience method in CoordinateSystem to set up a default system.
277
304
 
data/basis.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = "basis-processing"
3
- s.version = "0.5.9"
3
+ s.version = "0.6.0"
4
4
  s.add_dependency('knnball', '>= 0.0.6')
5
5
  s.author = "Avishek Sen Gupta"
6
6
  s.email = "avishek.sen.gupta@gmail.com"
@@ -18,9 +18,9 @@ class CoordinateSystem
18
18
  UNIT_TRANSFORM = [[1,0],[0,1]]
19
19
  attr_accessor :x_basis_vector, :y_basis_vector, :basis_matrix
20
20
 
21
- def self.standard(x_range, y_range, artist)
22
- x_basis_vector = {:x => 1.0, :y => 0.0}
23
- y_basis_vector = {:x => 0.0, :y => 1.0}
21
+ def self.standard(x_range, y_range, artist, labels = {:x => 'x', :y => 'y'})
22
+ x_basis_vector = {:x => 1.0, :y => 0.0, :label => labels[:x]}
23
+ y_basis_vector = {:x => 0.0, :y => 1.0, :label => labels[:y]}
24
24
 
25
25
  x_range = ContinuousRange.new(x_range)
26
26
  y_range = ContinuousRange.new(y_range)
data/lib/demo.rb CHANGED
@@ -35,7 +35,7 @@ class Demo < Processing::App
35
35
  # @basis = CoordinateSystem.new(Axis.new(@x_unit_vector,x_range), Axis.new(@y_unit_vector,y_range), self, [[1,0],[0,1]])
36
36
 
37
37
  # Accomplish the above in a single line below...
38
- @basis = CoordinateSystem.standard({:minimum => 0, :maximum => 200}, {:minimum => 0, :maximum => 300}, self)
38
+ @basis = CoordinateSystem.standard({:minimum => 0, :maximum => 200}, {:minimum => 0, :maximum => 300}, self, {:x => "X-Axis", :y => "Y-Axis"})
39
39
 
40
40
  screen_transform = Transform.new({:x => 2, :y => -2}, {:x => 300, :y => 900})
41
41
  @screen = Screen.new(screen_transform, self, @basis)
@@ -43,11 +43,9 @@ class Demo < Processing::App
43
43
  stroke(1,1,0,1)
44
44
  fill(1,1,0)
45
45
  rect_mode(CENTER)
46
- points.each do |p|
47
- @screen.plot(p, :track => true) do |original, mapped, s|
48
- s.in_basis do
49
- rect(original[:x], original[:y], 3, 3)
50
- end
46
+ @screen.plot(points, :track => true) do |original, mapped, s|
47
+ s.in_basis do
48
+ rect(original[:x], original[:y], 3, 3)
51
49
  end
52
50
  end
53
51
  end
data/lib/interactive.rb CHANGED
@@ -6,6 +6,7 @@ module Interactive
6
6
  base.class_eval do
7
7
  alias :old_setup :setup
8
8
  alias :old_draw :draw
9
+
9
10
  def setup
10
11
  old_setup
11
12
  @cache = Cache.new(self).refresh
data/lib/legend_box.rb ADDED
@@ -0,0 +1,14 @@
1
+ class LegendBox
2
+ def initialize(artist, top_left = {:x => 20, :y => 20})
3
+ @x = top_left[:x]
4
+ @y = top_left[:y]
5
+ @artist = artist
6
+ end
7
+
8
+ def draw(legend)
9
+ @artist.rect(@x,@y,10,10)
10
+ @artist.text(legend.strip == '' ? '[Unknown]' : legend, @x + 50, @y)
11
+ @y += 15
12
+ end
13
+ end
14
+
data/lib/screen.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'transform'
2
2
  require 'knnball'
3
3
  require 'text_output'
4
+ require 'legend_box'
4
5
 
5
6
  class Screen
6
7
  attr_accessor :points
@@ -11,7 +12,8 @@ class Screen
11
12
  @buffer = nil if !@should_join
12
13
  end
13
14
 
14
- def initialize(transform, artist, basis, output=TextOutput.new)
15
+ def initialize(transform, artist, basis, legend_box=LegendBox.new(artist), output=TextOutput.new)
16
+ @legend_box = legend_box
15
17
  @transform = transform
16
18
  @artist = artist
17
19
  @basis = basis
@@ -51,7 +53,19 @@ class Screen
51
53
  end
52
54
  end
53
55
 
54
- def plot(point, options = {:bar => false, :track => false}, &block)
56
+ def plot(points, options = {:bar => false, :track => false, :legend => ''}, &block)
57
+ if points.kind_of? Array
58
+ points.each {|p| plot_single(p, options, &block)}
59
+ else
60
+ plot_single(points, options, &block)
61
+ end
62
+ return if options[:legend].nil?
63
+ outside_basis do
64
+ @legend_box.draw(options[:legend])
65
+ end
66
+ end
67
+
68
+ def plot_single(point, options = {:bar => false, :track => false}, &block)
55
69
  if (!point[:x] || !point[:y])
56
70
  @artist.reset_matrix
57
71
  block.call(point, self) if block
@@ -129,6 +143,21 @@ class Screen
129
143
  @artist.line(x_ticks.first[:from][:x],x_ticks.first[:from][:y],x_ticks.last[:from][:x],x_ticks.last[:from][:y])
130
144
  @artist.line(y_ticks.first[:from][:x],y_ticks.first[:from][:y],y_ticks.last[:from][:x],y_ticks.last[:from][:y])
131
145
 
146
+ x_axis_label_position = {:x => (x_ticks.first[:from][:x] + x_ticks.last[:from][:x])/2, :y => (x_ticks.first[:from][:y] + x_ticks.last[:from][:y])/2 + 50}
147
+ y_axis_label_position = {:x => (y_ticks.first[:from][:x] + y_ticks.last[:from][:x])/2 - 60, :y => (y_ticks.first[:from][:y] + y_ticks.last[:from][:y])/2}
148
+
149
+ @artist.push_matrix
150
+ @artist.translate(x_axis_label_position[:x], x_axis_label_position[:y])
151
+ @artist.rotate(2*Math::PI - Math.atan2(@basis.x_basis_vector[:y], @basis.x_basis_vector[:x]))
152
+ @artist.text(@basis.x_basis_vector[:label], 0, 0)
153
+ @artist.pop_matrix
154
+
155
+ @artist.push_matrix
156
+ @artist.translate(y_axis_label_position[:x], y_axis_label_position[:y])
157
+ @artist.rotate(2*Math::PI - Math.atan2(@basis.y_basis_vector[:y], @basis.y_basis_vector[:x]))
158
+ @artist.text(@basis.y_basis_vector[:label], 0, 0)
159
+ @artist.pop_matrix
160
+
132
161
  draw_ticks(x_ticks, {:x => 0, :y => 20}, options[:x])
133
162
  draw_ticks(y_ticks, {:x => -50, :y => 0}, options[:y])
134
163
 
@@ -143,5 +172,7 @@ class Screen
143
172
  def write(p)
144
173
  @output.notify(p)
145
174
  end
175
+
176
+ private :draw_ticks, :normal, :plot_single
146
177
  end
147
178
 
data/redeploy.sh CHANGED
@@ -1,3 +1,3 @@
1
1
  gem build basis.gemspec
2
2
  sudo /home/avishek/jruby/jruby-1.6.4/bin/jruby -S gem uninstall basis-processing
3
- sudo /home/avishek/jruby/jruby-1.6.4/bin/jruby -S gem install basis-processing-0.5.9.gem
3
+ sudo /home/avishek/jruby/jruby-1.6.4/bin/jruby -S gem install basis-processing-0.6.0.gem
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: basis-processing
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 5
9
- - 9
10
- version: 0.5.9
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Avishek Sen Gupta
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-25 00:00:00 Z
18
+ date: 2011-10-26 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: knnball
@@ -53,6 +53,7 @@ files:
53
53
  - lib/demo.rb
54
54
  - lib/hash_vector.rb
55
55
  - lib/interactive.rb
56
+ - lib/legend_box.rb
56
57
  - lib/matrix_extensions.rb
57
58
  - lib/ranges.rb
58
59
  - lib/screen.rb