rubylabs 0.5.5 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/marslab.rb +1147 -0
- data/lib/randomlab.rb +436 -201
- data/lib/rubylabs.rb +15 -14
- data/test/mars_test.rb +519 -0
- data/test/random_test.rb +75 -19
- metadata +4 -4
- data/lib/temps.rb +0 -41
- data/test/temps_test.rb +0 -24
data/lib/randomlab.rb
CHANGED
@@ -11,145 +11,122 @@ module RubyLabs
|
|
11
11
|
|
12
12
|
module RandomLab
|
13
13
|
|
14
|
-
require 'statistics2.rb'
|
15
|
-
|
16
14
|
=begin rdoc
|
17
|
-
|
15
|
+
Pseudo-random number generator. Constraints on a, c, and m:
|
16
|
+
* c and m must be relatively prime
|
17
|
+
* a-1 divisible by prime factors of m
|
18
|
+
* if m is multiple of 4, a-1 must also be a multiple of 4
|
19
|
+
|
20
|
+
Note: some good values (for small m) from Numerical Recipes:
|
21
|
+
m = 53125, a = 171, c = 11213
|
18
22
|
=end
|
19
23
|
|
20
|
-
class
|
24
|
+
class PRNG
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
attr_accessor :a, :c, :m, :x
|
27
|
+
|
28
|
+
def initialize(a, c, m)
|
29
|
+
@a = a
|
30
|
+
@c = c
|
31
|
+
@m = m
|
32
|
+
@x = 0
|
33
|
+
end
|
25
34
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
35
|
+
def state
|
36
|
+
return @x
|
37
|
+
end
|
30
38
|
|
31
|
-
|
32
|
-
|
33
|
-
return [@@x, @@m, @@c]
|
34
|
-
elsif args.length == 3
|
35
|
-
@@x, @@m, @@c = args
|
36
|
-
else
|
37
|
-
raise "params: expected 3 integers"
|
39
|
+
def seed(val)
|
40
|
+
@x = val
|
38
41
|
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
=begin rdoc
|
43
|
-
Better random number generator, using parameters from Numerical Recipes in C.
|
44
|
-
=end
|
45
|
-
|
46
|
-
class PRNG
|
47
|
-
|
48
|
-
@@x = 0
|
49
|
-
@@a = 3
|
50
|
-
@@c = 337
|
51
|
-
@@m = 1000
|
52
42
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
43
|
+
# :begin :advance
|
44
|
+
def advance
|
45
|
+
@x = (@x * @a + @c) % @m
|
46
|
+
end
|
47
|
+
# :end :advance
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
return
|
61
|
-
|
62
|
-
|
63
|
-
else
|
64
|
-
raise "params: expected 4 integers"
|
49
|
+
# :begin :random
|
50
|
+
def random(min, max)
|
51
|
+
return nil if max <= min
|
52
|
+
range = max - min + 1
|
53
|
+
return (advance() % range) + min
|
65
54
|
end
|
66
|
-
|
55
|
+
# :end :random
|
67
56
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# :begin :poker_test
|
84
|
-
def poker_test(n, opt = nil)
|
85
|
-
types = [:nada, :pair, :two_pair, :three_of_a_kind, :full_house, :straight, :flush, :four_of_a_kind, :straight_flush]
|
86
|
-
counts = Hash.new
|
87
|
-
types.each { |x| counts[x] = 0 }
|
88
|
-
n.times do
|
89
|
-
h = random_deal(5)
|
90
|
-
# p h
|
91
|
-
t = poker_hand(h)
|
92
|
-
counts[t] += 1
|
57
|
+
def inspect
|
58
|
+
sprintf "#<RandomLab::PRNG a: #{@a} c: #{@c} m: #{@m}>"
|
59
|
+
end
|
60
|
+
|
61
|
+
alias to_s inspect
|
62
|
+
|
63
|
+
end # class PRNG
|
64
|
+
|
65
|
+
# :begin :prng_sequence
|
66
|
+
def prng_sequence(a, c, m)
|
67
|
+
seq = [0]
|
68
|
+
(m-1).times do
|
69
|
+
seq << (a * seq.last + c) % m
|
70
|
+
end
|
71
|
+
return seq
|
93
72
|
end
|
94
|
-
|
95
|
-
end
|
96
|
-
# :end :poker_test
|
73
|
+
# :end :prng_sequence
|
97
74
|
|
98
75
|
=begin rdoc
|
99
|
-
|
100
|
-
The two parameters are arrays of equal length, containing the observed and expected values.
|
101
|
-
Return +true+ if the chi-square is less than the critical value for p = 0.95 (i.e. return
|
102
|
-
false if the hypothesis that the distributions are the same is rejected).
|
76
|
+
Make a new deck of cards
|
103
77
|
=end
|
104
78
|
|
105
|
-
def
|
106
|
-
|
107
|
-
p = Statistics2.chi2dist(obs.length-1, x2)
|
108
|
-
if opt == :trace
|
109
|
-
printf "chi-square: %7.3f p = %.2f\n", x2, p
|
110
|
-
end
|
111
|
-
return p < 0.95
|
112
|
-
end
|
113
|
-
|
114
|
-
def chi_square(obs, exp)
|
115
|
-
sum = 0.0
|
116
|
-
for i in 0...obs.length
|
117
|
-
sum += ( (obs[i] - exp[i])**2 ).to_f / exp[i]
|
79
|
+
def new_deck
|
80
|
+
(0..51).map { |i| Card.new(i) }
|
118
81
|
end
|
119
|
-
return sum
|
120
|
-
end
|
121
82
|
|
122
83
|
=begin rdoc
|
123
|
-
|
84
|
+
Permute the order of items in x. Does not copy x -- shuffles the
|
85
|
+
items in place. Works for strings, arrays, any container that responds to
|
86
|
+
length, [], and []=
|
124
87
|
=end
|
125
88
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
a << Card.new(x)
|
89
|
+
# :begin :permute
|
90
|
+
def permute(x)
|
91
|
+
for i in 0..x.length-2
|
92
|
+
r = random(i, x.length-1)
|
93
|
+
x[i], x[r] = x[r], x[i]
|
94
|
+
end
|
95
|
+
return x
|
134
96
|
end
|
135
|
-
|
136
|
-
end
|
97
|
+
# :end :permute
|
137
98
|
|
138
99
|
=begin rdoc
|
139
|
-
|
100
|
+
A "helper method" for permute, that makes it easier to see which two
|
101
|
+
locations are being swapped. A call to random(i,j) returns a random
|
102
|
+
integer in the range i..j. See also PRNG::random
|
140
103
|
=end
|
141
104
|
|
142
|
-
def
|
143
|
-
|
144
|
-
|
105
|
+
def random(min, max)
|
106
|
+
return nil if max < min
|
107
|
+
range = max - min + 1
|
108
|
+
return rand(range) + min
|
109
|
+
end
|
145
110
|
|
146
111
|
=begin rdoc
|
147
|
-
|
112
|
+
A "helper method" that can be called via a probe, to print the contents
|
113
|
+
of an array during the execution of the permute method
|
148
114
|
=end
|
149
115
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
116
|
+
def brackets(a, i, r)
|
117
|
+
res = "#{r}: "
|
118
|
+
if i <= 0
|
119
|
+
res += ("[" + a.join(" ") + "]")
|
120
|
+
elsif i >= a.length
|
121
|
+
res += (" " + a.join(" ") + " [ ]")
|
122
|
+
else
|
123
|
+
pre = a.slice(0..(i-1))
|
124
|
+
post = a.slice(i..-1)
|
125
|
+
res += (" " + pre.join(" ") + " [" + post.join(" ") + "]")
|
126
|
+
end
|
127
|
+
return res
|
128
|
+
end
|
129
|
+
|
153
130
|
|
154
131
|
=begin rdoc
|
155
132
|
Classify a poker hand -- returns a symbol describing a hand. Return values:
|
@@ -163,32 +140,40 @@ end
|
|
163
140
|
:straight_flush
|
164
141
|
=end
|
165
142
|
|
166
|
-
|
143
|
+
def poker_rank(a)
|
144
|
+
rcount = Array.new(Card::Ranks.length, 0)
|
145
|
+
scount = Array.new(Card::Suits.length, 0)
|
146
|
+
a.each do |x|
|
147
|
+
rcount[ Card::Ranks.index(x.rank) ] += 1
|
148
|
+
scount[ Card::Suits.index(x.suit) ] += 1
|
149
|
+
end
|
150
|
+
if rcount.max == 1
|
151
|
+
straight = (rcount.rindex(1) - rcount.index(1) == 4)
|
152
|
+
flush = scount.max == 5
|
153
|
+
return :straight_flush if (straight && flush)
|
154
|
+
return :straight if straight
|
155
|
+
return :flush if flush
|
156
|
+
return :high_card
|
157
|
+
else
|
158
|
+
rcount.reject! { |x| x == 0 }
|
159
|
+
rcount.sort! { |x,y| y <=> x }
|
160
|
+
return :four_of_a_kind if rcount[0] == 4
|
161
|
+
return :full_house if (rcount[0] == 3 && rcount[1] == 2)
|
162
|
+
return :three_of_a_kind if rcount[0] == 3
|
163
|
+
return :two_pair if (rcount[0] == 2 && rcount[1] == 2)
|
164
|
+
return :pair
|
165
|
+
end
|
166
|
+
end
|
167
167
|
|
168
|
-
def
|
169
|
-
|
170
|
-
scount = Array.new(Card::Suits.length, 0)
|
171
|
-
a.each do |x|
|
172
|
-
rcount[ Card::Ranks.index(x.rank) ] += 1
|
173
|
-
scount[ Card::Suits.index(x.suit) ] += 1
|
168
|
+
def poker_rankings
|
169
|
+
return [:high_card, :pair, :two_pair, :three_of_a_kind, :straight, :flush, :full_house, :four_of_a_kind, :straight_flush]
|
174
170
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
return
|
180
|
-
return :flush if flush
|
181
|
-
return :nada
|
182
|
-
else
|
183
|
-
rcount.reject! { |x| x == 0 }
|
184
|
-
rcount.sort! { |x,y| y <=> x }
|
185
|
-
return :four_of_a_kind if rcount[0] == 4
|
186
|
-
return :full_house if (rcount[0] == 3 && rcount[1] == 2)
|
187
|
-
return :three_of_a_kind if rcount[0] == 3
|
188
|
-
return :two_pair if (rcount[0] == 2 && rcount[1] == 2)
|
189
|
-
return :pair
|
171
|
+
|
172
|
+
def poker_counts
|
173
|
+
h = Hash.new
|
174
|
+
poker_rankings.each { |x| h[x] = 0 }
|
175
|
+
return h
|
190
176
|
end
|
191
|
-
end
|
192
177
|
|
193
178
|
|
194
179
|
=begin rdoc
|
@@ -202,93 +187,343 @@ end
|
|
202
187
|
# To test the expression that assigns suits and ranks:
|
203
188
|
# 52.times { |x| puts (x/13).to_s + " " + (x%13).to_s }
|
204
189
|
|
205
|
-
class Card
|
206
|
-
|
190
|
+
class Card
|
191
|
+
attr_accessor :rank, :suit
|
207
192
|
|
208
|
-
|
209
|
-
|
210
|
-
|
193
|
+
unless defined? Suits
|
194
|
+
Suits = [:spades, :hearts, :diamonds, :clubs]
|
195
|
+
end
|
211
196
|
|
212
|
-
|
213
|
-
|
214
|
-
|
197
|
+
unless defined? Ranks
|
198
|
+
Ranks = [:ace, :king, :queen, :jack, :ten, :nine, :eight, :seven, :six, :five, :four, :three, :two]
|
199
|
+
end
|
215
200
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
201
|
+
def initialize(id = nil)
|
202
|
+
id = rand(52) if id.nil?
|
203
|
+
raise "card must be between 0 and 51" if id < 0 || id > 51
|
204
|
+
@suit = Suits[id / 13]
|
205
|
+
@rank = Ranks[id % 13]
|
206
|
+
end
|
222
207
|
|
223
|
-
|
224
|
-
|
225
|
-
|
208
|
+
def ==(x)
|
209
|
+
return @suit == x.suit && @rank == x.rank
|
210
|
+
end
|
226
211
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
212
|
+
def <=>(x)
|
213
|
+
r0 = Ranks.index(@rank); r1 = Ranks.index(x.rank)
|
214
|
+
s0 = Suits.index(@suit); s1 = Suits.index(x.suit)
|
215
|
+
if (res = (s0 <=> s1)) == 0
|
216
|
+
return (r0 <=> r1)
|
217
|
+
else
|
218
|
+
return res
|
219
|
+
end
|
234
220
|
end
|
235
|
-
end
|
236
221
|
|
237
|
-
|
222
|
+
@@outputform = :utf8
|
238
223
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
224
|
+
def inspect
|
225
|
+
s = ""
|
226
|
+
s << case @rank
|
227
|
+
when :ace : "A"
|
228
|
+
when :king : "K"
|
229
|
+
when :queen : "Q"
|
230
|
+
when :jack : "J"
|
231
|
+
when :ten : "10"
|
232
|
+
when :nine : "9"
|
233
|
+
when :eight : "8"
|
234
|
+
when :seven : "7"
|
235
|
+
when :six : "6"
|
236
|
+
when :five : "5"
|
237
|
+
when :four : "4"
|
238
|
+
when :three : "3"
|
239
|
+
when :two : "2"
|
240
|
+
end
|
241
|
+
if $KCODE[0] == ?U
|
242
|
+
if @@outputform == :utf8
|
243
|
+
s << case @suit
|
244
|
+
when :spades : "\xe2\x99\xa0"
|
245
|
+
when :hearts : "\xe2\x99\xa5"
|
246
|
+
when :clubs : "\xe2\x99\xa3"
|
247
|
+
when :diamonds : "\xe2\x99\xa6"
|
248
|
+
end
|
249
|
+
else
|
250
|
+
s << "!irb" + @suit.to_s.chop
|
263
251
|
end
|
264
252
|
else
|
265
|
-
s <<
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
when :clubs : "C"
|
272
|
-
when :diamonds : "D"
|
253
|
+
s << case @suit
|
254
|
+
when :spades : "S"
|
255
|
+
when :hearts : "H"
|
256
|
+
when :clubs : "C"
|
257
|
+
when :diamonds : "D"
|
258
|
+
end
|
273
259
|
end
|
260
|
+
return s
|
261
|
+
# "#{@rank} #{@suit}"
|
274
262
|
end
|
275
|
-
return s
|
276
|
-
# "#{@rank} #{@suit}"
|
277
|
-
end
|
278
263
|
|
279
|
-
|
264
|
+
alias to_s inspect
|
280
265
|
|
281
|
-
|
282
|
-
|
283
|
-
|
266
|
+
def Card.print_latex
|
267
|
+
@@outputform = :latex
|
268
|
+
end
|
284
269
|
|
285
|
-
|
286
|
-
|
287
|
-
|
270
|
+
def Card.print_utf8
|
271
|
+
@@outputform = :utf8
|
272
|
+
end
|
288
273
|
|
274
|
+
end # class Card
|
275
|
+
|
276
|
+
=begin rdoc
|
277
|
+
Visualization helpers (private):
|
278
|
+
make_canvas create a new blank canvas (same one used for all tests)
|
279
|
+
Visualization methods called by students to test a PRNG object:
|
280
|
+
view(type,*args) initialize canvas for a visualization of the specified type
|
281
|
+
tick_mark(i) add a tick mark at location i on the number line
|
282
|
+
State vars maintained by the visualization methods:
|
283
|
+
@@drawing initially nil, set to a Draw object when canvas has been created
|
284
|
+
@@tkroot top level Tk application that manages the canvas (should never be used)
|
285
|
+
@@visual set to :line, :histogram, or :dot_plot when drawing initialized
|
286
|
+
@@endpoint last point on number line (value of n passed to init_line)
|
287
|
+
=end
|
288
|
+
|
289
|
+
def make_canvas
|
290
|
+
require 'tk'
|
289
291
|
|
290
|
-
|
292
|
+
if ! defined? @@tkroot
|
293
|
+
@@tkroot = TkRoot.new { title "RandomLab" }
|
294
|
+
end
|
295
|
+
|
296
|
+
if @@drawing == nil
|
297
|
+
@@drawing = Draw.new(@tkroot)
|
298
|
+
@@threads = []
|
299
|
+
@@threads << Thread.new() do
|
300
|
+
Tk.mainloop
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def view(*args)
|
306
|
+
kind = args.shift
|
307
|
+
if ! @@views.include?(kind)
|
308
|
+
puts "view type must be one of #{@@views.join(', ')}"
|
309
|
+
else
|
310
|
+
@@visual = kind
|
311
|
+
case kind
|
312
|
+
when :line
|
313
|
+
@@npoints = args[0]
|
314
|
+
if @@npoints.kind_of? Numeric
|
315
|
+
make_canvas if @@drawing.nil?
|
316
|
+
@@drawing.new_line(@@npoints)
|
317
|
+
else
|
318
|
+
puts "usage: view(:line, npoints)"
|
319
|
+
end
|
320
|
+
when :dotplot
|
321
|
+
@@max = args[0]
|
322
|
+
if @@max.kind_of? Numeric
|
323
|
+
make_canvas if @@drawing.nil?
|
324
|
+
@@drawing.new_dotplot(@@max)
|
325
|
+
else
|
326
|
+
puts "usage: view(:dotplot, max)"
|
327
|
+
end
|
328
|
+
when :histogram
|
329
|
+
if args[0].class == Array
|
330
|
+
@@keys = args[0]
|
331
|
+
@@nbins = @@max = @@keys.length
|
332
|
+
@@counts = Hash.new
|
333
|
+
@@keys.each { |k| @@counts[k] = 0 }
|
334
|
+
else
|
335
|
+
@@nbins, @@max = args
|
336
|
+
@@max = @@nbins if @@max.nil?
|
337
|
+
@@keys = nil
|
338
|
+
end
|
339
|
+
if [@@nbins, @@max].all? { |x| x.kind_of? Numeric }
|
340
|
+
make_canvas if @@drawing.nil?
|
341
|
+
@@drawing.new_histogram(@@nbins, @@max)
|
342
|
+
else
|
343
|
+
puts "usage: view(:histogram, nbins, max) or view(:histogram, keys)"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def tick_mark(i)
|
350
|
+
if @@visual != :line
|
351
|
+
puts "call 'view(:line,n)' to make a number line of size n'"
|
352
|
+
elsif i < 0 || i >= @@npoints
|
353
|
+
puts "tick_mark: 0 <= i < #{@@npoints}"
|
354
|
+
else
|
355
|
+
@@drawing.add_tick(i)
|
356
|
+
sleep(@@delay)
|
357
|
+
end
|
358
|
+
return nil
|
359
|
+
end
|
360
|
+
|
361
|
+
def update_bin(x)
|
362
|
+
if @@visual != :histogram
|
363
|
+
puts "call view(:histogram, n, max) to initialize a histogram with n bins"
|
364
|
+
else
|
365
|
+
i = @@keys ? @@keys.index(x) : x
|
366
|
+
if i.nil?
|
367
|
+
puts "unknown item: #{x}"
|
368
|
+
elsif i < 0 || i >= @@max
|
369
|
+
puts "count: 0 <= i < #{@@max}"
|
370
|
+
else
|
371
|
+
@@drawing.add_hist(i)
|
372
|
+
@@counts[x] += 1 if @@keys
|
373
|
+
sleep(@@delay)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
return nil
|
377
|
+
end
|
378
|
+
|
379
|
+
def get_counts
|
380
|
+
return @@counts
|
381
|
+
end
|
382
|
+
|
383
|
+
def plot_point(x,y)
|
384
|
+
if @@visual != :dotplot
|
385
|
+
puts "call view(:dotplot, max) to initialize a dot plot"
|
386
|
+
elsif x < 0 || x >= @@max || y < 0 || y >= @@max
|
387
|
+
puts "plot_point: 0 <= x, y < #{@@max}"
|
388
|
+
else
|
389
|
+
@@drawing.add_point(x,y)
|
390
|
+
sleep(@@delay)
|
391
|
+
end
|
392
|
+
return nil
|
393
|
+
end
|
291
394
|
|
395
|
+
|
396
|
+
=begin rdoc
|
397
|
+
Make a window to display dot plots and histograms
|
398
|
+
=end
|
399
|
+
|
400
|
+
class Draw
|
401
|
+
|
402
|
+
attr_accessor :canvas, :ticks, :bins
|
403
|
+
|
404
|
+
@@canvasWidth = @@canvasHeight = 500
|
405
|
+
@@tickHeight = 20
|
406
|
+
@@tickWidth = 1
|
407
|
+
@@traceSize = 10
|
408
|
+
@@tickColor = 'blue'
|
409
|
+
@@histColor = '#000080'
|
410
|
+
@@dotSize = 2
|
411
|
+
@@dotColor = '#000080'
|
412
|
+
|
413
|
+
def new_line(nticks)
|
414
|
+
self.erase_objects
|
415
|
+
@title = TkcText.new(@@drawing.canvas, 100, 10, :text => "Number Line")
|
416
|
+
@endpoint = nticks
|
417
|
+
y = @@canvasHeight / 2
|
418
|
+
@line = TkcLine.new( @canvas, 0, y, @@canvasWidth, y, :width => 3, :fill => '#777777' )
|
419
|
+
return nil
|
420
|
+
end
|
421
|
+
|
422
|
+
def add_tick(i)
|
423
|
+
x = (i.to_f / @endpoint) * @@canvasWidth
|
424
|
+
y = @@canvasHeight / 2
|
425
|
+
@ticks << TkcLine.new( @canvas, x, y, x, y-@@tickHeight, :width => @@tickWidth, :fill => @@tickColor )
|
426
|
+
@ticks.last(@@traceSize).each_with_index { |t,i| t['fill'] = @palette[i] }
|
427
|
+
end
|
428
|
+
|
429
|
+
def new_histogram(nbins, max)
|
430
|
+
self.erase_objects
|
431
|
+
@title = TkcText.new(@@drawing.canvas, 100, 10, :text => "Histogram")
|
432
|
+
@nbins, @max = nbins, max
|
433
|
+
@baseline = @@canvasHeight / 2
|
434
|
+
w = @@canvasWidth / @nbins
|
435
|
+
@nbins.times do |i|
|
436
|
+
x = i * w
|
437
|
+
@bins[i] = TkcRectangle.new( @canvas, x, @baseline, x+w, @baseline-3, :outline => "#CCCCCC", :fill => @@histColor )
|
438
|
+
end
|
439
|
+
@dy = 8.0
|
440
|
+
@yt = 50
|
441
|
+
return nil
|
442
|
+
end
|
443
|
+
|
444
|
+
def add_hist(x)
|
445
|
+
i = (x.to_f / @max) * @nbins
|
446
|
+
rect = @bins[i]
|
447
|
+
x1, y1, x2, y2 = rect.coords
|
448
|
+
y1 = y1 - @dy
|
449
|
+
rect.coords = [x1, y1, x2, y2]
|
450
|
+
if y1 < @yt
|
451
|
+
@bins.each do |rect|
|
452
|
+
x1, y1, x2, y2 = rect.coords
|
453
|
+
y1 = @baseline - ((@baseline - y1) / 2)
|
454
|
+
rect.coords = [x1, y1, x2, y2]
|
455
|
+
end
|
456
|
+
@dy = @dy / 2
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
def new_dotplot(n)
|
461
|
+
self.erase_objects
|
462
|
+
@title = TkcText.new(@@drawing.canvas, 100, 10, :text => "Dot Plot")
|
463
|
+
@max = n.to_f
|
464
|
+
end
|
465
|
+
|
466
|
+
def add_point(i,j)
|
467
|
+
x = (i.to_f / @max) * @@canvasWidth
|
468
|
+
y = (j.to_f / @max) * @@canvasHeight
|
469
|
+
@points << TkcRectangle.new( @canvas, x, y, x+@@dotSize, y+@@dotSize, :outline => @@dotColor, :fill => @@dotColor )
|
470
|
+
# @points.last(@@traceSize).each_with_index { |p,i| p[:outline] = p['fill'] = @palette[i] }
|
471
|
+
end
|
472
|
+
|
473
|
+
def erase_objects
|
474
|
+
zap(@ticks)
|
475
|
+
zap(@bins)
|
476
|
+
zap(@points)
|
477
|
+
@title.delete if @title
|
478
|
+
@line.delete if @line
|
479
|
+
return nil
|
480
|
+
end
|
481
|
+
|
482
|
+
private
|
483
|
+
|
484
|
+
def zap(a)
|
485
|
+
a.each { |x| x.delete }
|
486
|
+
a.clear
|
487
|
+
end
|
488
|
+
|
489
|
+
# Make a range of colors starting from first and going to last in n steps.
|
490
|
+
# First and last are expected to be 3-tuples of integer RGB values. The
|
491
|
+
# result is an array that starts with first, has n-1 intermediate colors,
|
492
|
+
# and ends with last. Example:
|
493
|
+
# makePalette( [255,0,0], [0,0,0], 10)
|
494
|
+
# makes 11 colors starting with red and ending with black.
|
495
|
+
|
496
|
+
def makePalette(first, last, n)
|
497
|
+
d = Array.new(3)
|
498
|
+
3.times { |i| d[i] = (first[i] - last[i]) / n }
|
499
|
+
a = [first]
|
500
|
+
(n-1).times do |i|
|
501
|
+
a << a.last.clone
|
502
|
+
3.times { |j| a.last[j] -= d[j] }
|
503
|
+
end
|
504
|
+
a << last
|
505
|
+
a.map { |c| sprintf("#%02X%02X%02X",c[0],c[1],c[2]) }
|
506
|
+
end
|
507
|
+
|
508
|
+
def initialize(parent)
|
509
|
+
content = TkFrame.new(parent)
|
510
|
+
@canvas = TkCanvas.new(content, :borderwidth => 1, :width => @@canvasWidth, :height => @@canvasHeight)
|
511
|
+
@canvas.grid :column => 0, :row => 0, :columnspan => 4, :padx => 10, :pady => 10
|
512
|
+
content.pack :pady => 20
|
513
|
+
@palette = makePalette( [128,128,255], [32, 32, 255], @@traceSize-1 )
|
514
|
+
@palette << "#0000FF"
|
515
|
+
@ticks = Array.new
|
516
|
+
@bins = Array.new
|
517
|
+
@points = Array.new
|
518
|
+
end
|
519
|
+
|
520
|
+
end # class Draw
|
521
|
+
|
522
|
+
@@drawing = nil
|
523
|
+
@@views = [:line, :dotplot, :histogram]
|
524
|
+
@@delay = 0.01
|
525
|
+
@@keys = nil
|
526
|
+
|
292
527
|
end # RandomLab
|
293
528
|
|
294
529
|
end # RubyLabs
|