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 +36 -9
- data/basis.gemspec +1 -1
- data/lib/coordinate_system.rb +3 -3
- data/lib/demo.rb +4 -6
- data/lib/interactive.rb +1 -0
- data/lib/legend_box.rb +14 -0
- data/lib/screen.rb +33 -2
- data/redeploy.sh +1 -1
- metadata +6 -5
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
|
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
|
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
|
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
|
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.
|
221
|
-
@y_unit_vector = {:x => 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
|
-
##
|
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
data/lib/coordinate_system.rb
CHANGED
@@ -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
|
47
|
-
|
48
|
-
|
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
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(
|
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.
|
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:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
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-
|
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
|