rubylabs 0.5.5 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|