File: point.rkt

package info (click to toggle)
racket 7.9%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 178,684 kB
  • sloc: ansic: 282,112; lisp: 234,887; pascal: 70,954; sh: 27,112; asm: 16,268; makefile: 4,613; cpp: 2,715; ada: 1,681; javascript: 1,244; cs: 879; exp: 499; csh: 422; python: 274; xml: 106; perl: 104
file content (336 lines) | stat: -rw-r--r-- 16,637 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#lang typed/racket/base

;; Renderers for points and other point-like things.

(require typed/racket/class racket/match racket/math racket/list
         (only-in typed/pict pict)
         plot/utils
         "../common/type-doc.rkt"
         "../common/utils.rkt")

(require/typed
 "../common/untyped-utils.rkt"
 [fix-vector-field-fun  (-> Symbol
                            (U (-> Real Real (Sequenceof Real))
                               (-> (Vector Real Real) (Sequenceof Real)))
                            (-> Real Real (Vectorof Real)))])

(provide (all-defined-out))

;; ===================================================================================================
;; Points (scatter plots)

(: points-render-fun (-> (Listof (Vectorof Real)) Point-Sym
                         Plot-Color Plot-Color Nonnegative-Real Nonnegative-Real
                         Nonnegative-Real
                         2D-Render-Proc))
(define ((points-render-fun vs sym color fill-color size line-width alpha) area)
  (send area put-alpha alpha)
  (send area put-pen color line-width 'solid)
  (send area put-brush fill-color 'solid)
  (send area put-glyphs vs sym size))

(:: points
    (->* [(Sequenceof (Sequenceof Real))]
         [#:x-min (U Real #f) #:x-max (U Real #f)
          #:y-min (U Real #f) #:y-max (U Real #f)
          #:sym Point-Sym
          #:color Plot-Color
          #:fill-color (U Plot-Color 'auto)
          #:x-jitter Nonnegative-Real
          #:y-jitter Nonnegative-Real
          #:size Nonnegative-Real
          #:line-width Nonnegative-Real
          #:alpha Nonnegative-Real
          #:label (U String pict #f)]
         renderer2d))
(define (points vs
                #:x-min [x-min #f] #:x-max [x-max #f]
                #:y-min [y-min #f] #:y-max [y-max #f]
                #:sym [sym (point-sym)]
                #:color [color (point-color)]
                #:fill-color [fill-color 'auto]
                #:x-jitter [x-jitter (point-x-jitter)]
                #:y-jitter [y-jitter (point-y-jitter)]
                #:size [size (point-size)]
                #:line-width [line-width (point-line-width)]
                #:alpha [alpha (point-alpha)]
                #:label [label #f])
  (define fail/kw (make-raise-keyword-error 'points))
  (cond
    [(and x-min (not (rational? x-min)))  (fail/kw "#f or rational" '#:x-min x-min)]
    [(and x-max (not (rational? x-max)))  (fail/kw "#f or rational" '#:x-max x-max)]
    [(and y-min (not (rational? y-min)))  (fail/kw "#f or rational" '#:y-min y-min)]
    [(and y-max (not (rational? y-max)))  (fail/kw "#f or rational" '#:y-max y-max)]
    [(not (rational? size))  (fail/kw "rational?" '#:size size)]
    [(or (> alpha 1) (not (rational? alpha)))  (fail/kw "real in [0,1]" '#:alpha alpha)]
    [else
     (let* ([vs  (sequence->listof-vector 'points vs 2)]
            [vs  (filter vrational? vs)])
       (cond
         [(empty? vs)  empty-renderer2d]
         [else
          (unless (= 0 x-jitter y-jitter)
            (points-apply-jitters vs (vector x-jitter y-jitter) #:ivls (vector (ivl x-min x-max) (ivl y-min y-max))))
          (match-define (list (vector #{xs : (Listof Real)} #{ys : (Listof Real)}) ...) vs)
          (let ([x-min  (if x-min x-min (apply min* xs))]
                [x-max  (if x-max x-max (apply max* xs))]
                [y-min  (if y-min y-min (apply min* ys))]
                [y-max  (if y-max y-max (apply max* ys))]
                [fill-color  (if (eq? fill-color 'auto) (->pen-color color) fill-color)])
            (renderer2d
             (vector (ivl x-min x-max) (ivl y-min y-max)) #f default-ticks-fun
             (and label (λ (_) (point-legend-entry label sym color fill-color size line-width)))
             (points-render-fun vs sym color fill-color
                                size line-width alpha)))]))]))

;; ===================================================================================================
;; Vector fields

(: vector-field-render-fun
   (-> (-> Real Real (Vectorof Real))
       Positive-Integer (U Real 'auto 'normalized)
       Plot-Color Nonnegative-Real Plot-Pen-Style
       Nonnegative-Real
       2D-Render-Proc))
(define ((vector-field-render-fun f samples scale color line-width line-style alpha) area)
  (match-define (vector (ivl x-min x-max) (ivl y-min y-max)) (send area get-bounds-rect))
  
  (when (and x-min x-max y-min y-max)
    (define xs0 (linear-seq x-min x-max samples #:start? #t #:end? #t))
    (define ys0 (linear-seq y-min y-max samples #:start? #t #:end? #t))
     
    (define-values (xs ys dxs dys angles mags)
      (for*/lists ([xs : (Listof Real)]
                   [ys : (Listof Real)]
                   [dxs : (Listof Real)]
                   [dys : (Listof Real)]
                   [angles : (Listof Real)]
                   [mags : (Listof Nonnegative-Real)]
                   ) ([x   (in-list xs0)]
                      [y   (in-list ys0)]
                      [dv  (in-value (f x y))] #:when (vrational? dv))
        (match-define (vector dx dy) dv)
        (values x y dx dy (atan2 dy dx) (sqrt (+ (sqr dx) (sqr dy))))))
     
    (unless (empty? xs)
      (define box-x-size (/ (- x-max x-min) samples))
      (define box-y-size (/ (- y-max y-min) samples))
                 
      (define new-mags
        (match scale
          [(? real?)  (map (λ ([mag : Real]) (* scale mag)) mags)]
          ['normalized  (define box-size (min box-x-size box-y-size))
                        (build-list (length dxs) (λ _ box-size))]
          ['auto
           ;; When all dxs or dys are (exact) zero, the calculation of scale
           ;; will raise a 'division by zero' error. If we convert the values
           ;; to flonums, the partial result will be +inf.0, and the correct
           ;; scale can be calculated.
           (define dx-max (real->double-flonum (apply max (map abs dxs))))
           (define dy-max (real->double-flonum (apply max (map abs dys))))
           (define scale (min (/ box-x-size dx-max)
                              (/ box-y-size dy-max)))
           (map (λ ([mag : Real]) (* scale mag)) mags)]))
                 
      (send area put-alpha alpha)
      (send area put-pen color line-width line-style)
      (for ([x      (in-list xs)]
            [y      (in-list ys)]
            [angle  (in-list angles)]
            [mag    (in-list new-mags)])
        (send area put-arrow
              (vector x y)
              (vector (+ x (* mag (cos angle))) (+ y (* mag (sin angle)))))))))

(:: vector-field
    (->* [(U (-> Real Real (Sequenceof Real))
             (-> (Vector Real Real) (Sequenceof Real)))]
         [(U Real #f) (U Real #f)
          (U Real #f) (U Real #f)
          #:samples Positive-Integer
          #:scale (U Real 'auto 'normalized)
          #:color Plot-Color
          #:line-width Nonnegative-Real
          #:line-style Plot-Pen-Style
          #:alpha Nonnegative-Real
          #:label (U String pict #f)]
         renderer2d))
(define (vector-field f [x-min #f] [x-max #f] [y-min #f] [y-max #f]
                      #:samples [samples (vector-field-samples)]
                      #:scale [scale (vector-field-scale)]
                      #:color [color (vector-field-color)]
                      #:line-width [line-width (vector-field-line-width)]
                      #:line-style [line-style (vector-field-line-style)]
                      #:alpha [alpha (vector-field-alpha)]
                      #:label [label #f])
  (define fail/pos (make-raise-argument-error 'vector-field3d f x-min x-max y-min y-max))
  (define fail/kw (make-raise-keyword-error 'vector-field3d))
  (cond
    [(and x-min (not (rational? x-min)))  (fail/pos "#f or rational" 1)]
    [(and x-max (not (rational? x-max)))  (fail/pos "#f or rational" 2)]
    [(and y-min (not (rational? y-min)))  (fail/pos "#f or rational" 3)]
    [(and y-max (not (rational? y-max)))  (fail/pos "#f or rational" 4)]
    [(and (real? scale) (not (rational? scale)))
     (fail/kw "'auto, 'normalized or rational" '#:scale scale)]
    [(not (rational? line-width))  (fail/kw "rational?" '#:line-width line-width)]
    [(or (> alpha 1) (not (rational? alpha)))  (fail/kw "real in [0,1]" '#:alpha alpha)]
    [else
     (let ([f  (fix-vector-field-fun 'vector-field f)])
       (renderer2d (vector (ivl x-min x-max) (ivl y-min y-max)) #f default-ticks-fun
                   (and label (λ (_) (arrow-legend-entry label color line-width line-style)))
                   (vector-field-render-fun
                    f samples scale color line-width line-style alpha)))]))

;; ===================================================================================================
;; Error bars

(: error-bars-render-fun (-> (Listof Real) (Listof Real) (Listof Real)
                             Plot-Color Nonnegative-Real Plot-Pen-Style
                             Nonnegative-Real Nonnegative-Real Boolean
                             2D-Render-Proc))
(define ((error-bars-render-fun xs ys hs color line-width line-style width alpha invert?) area)
  (define clip-rect (send area get-clip-rect))
  (define radius (* 1/2 width))
  (define angle (if invert? (/ pi 2) 0))

  (: maybe-invert (All (A) (-> A A (Vectorof A))))
  (define maybe-invert (if invert? (λ (x y) (vector y x)) vector))
  
  (send area put-alpha alpha)
  (send area put-pen color line-width line-style)
  (for ([x  (in-list xs)] [y  (in-list ys)] [h  (in-list hs)])
    (when (rect-contains? clip-rect (maybe-invert x y))
      (define v1 (maybe-invert x (- y h)))
      (define v2 (maybe-invert x (+ y h)))
      (send area put-line v1 v2)
      (send area put-tick v1 radius angle)
      (send area put-tick v2 radius angle))))

(:: error-bars
    (->* [(Sequenceof (Sequenceof Real))]
         [#:x-min (U Real #f) #:x-max (U Real #f)
          #:y-min (U Real #f) #:y-max (U Real #f)
          #:color Plot-Color
          #:line-width Nonnegative-Real
          #:line-style Plot-Pen-Style
          #:width Nonnegative-Real
          #:alpha Nonnegative-Real
          #:invert? Boolean]
         renderer2d))
(define (error-bars bars
                    #:x-min [x-min #f] #:x-max [x-max #f]
                    #:y-min [y-min #f] #:y-max [y-max #f]
                    #:color [color (error-bar-color)]
                    #:line-width [line-width (error-bar-line-width)]
                    #:line-style [line-style (error-bar-line-style)]
                    #:width [width (error-bar-width)]
                    #:alpha [alpha (error-bar-alpha)]
                    #:invert? [invert? #f])
  (define fail/kw (make-raise-keyword-error 'error-bars))
  (cond
    [(and x-min (not (rational? x-min)))  (fail/kw "#f or rational" '#:x-min x-min)]
    [(and x-max (not (rational? x-max)))  (fail/kw "#f or rational" '#:x-max x-max)]
    [(and y-min (not (rational? y-min)))  (fail/kw "#f or rational" '#:y-min y-min)]
    [(and y-max (not (rational? y-max)))  (fail/kw "#f or rational" '#:y-max y-max)]
    [(not (rational? line-width))  (fail/kw "rational?" '#:line-width line-width)]
    [(or (> alpha 1) (not (rational? alpha)))  (fail/kw "real in [0,1]" '#:alpha alpha)]
    [else
     (let* ([bars  (sequence->listof-vector 'error-bars bars 3)]
            [bars  (filter vrational? bars)])
       (cond [(empty? bars)  empty-renderer2d]
             [else
              (match-define (list (vector #{xs : (Listof Real)}
                                          #{ys : (Listof Real)}
                                          #{hs : (Listof Real)})
                                  ...)
                bars)
              (let ([x-min  (if x-min x-min (apply min* xs))]
                    [x-max  (if x-max x-max (apply max* xs))]
                    [y-min  (if y-min y-min (apply min* (map - ys hs)))]
                    [y-max  (if y-max y-max (apply max* (map + ys hs)))])
                (: maybe-invert (All (A) (-> A A (Vectorof A))))
                (define maybe-invert (if invert? (λ (x y) (vector y x)) vector))
                (renderer2d
                 (maybe-invert (ivl x-min x-max) (ivl y-min y-max))
                 #f default-ticks-fun #f
                 (error-bars-render-fun xs ys hs
                                        color line-width line-style width alpha invert?)))]))]))

;; ===================================================================================================
;; Candlesticks

(: candlesticks-render-fun (-> (Listof Real) (Listof Real) (Listof Real) (Listof Real) (Listof Real)
                               Plot-Color Plot-Color Nonnegative-Real Plot-Pen-Style
                               Nonnegative-Real Nonnegative-Real
                               2D-Render-Proc))
(define ((candlesticks-render-fun xs opens highs lows closes up-color down-color line-width line-style width alpha) area)
  (define clip-rect (send area get-clip-rect))
  (define radius (* 1/2 width))
  
  (send area put-alpha alpha)
  (send area put-pen up-color line-width line-style)
  (for ([x  (in-list xs)] [open  (in-list opens)] [high  (in-list highs)] [low  (in-list lows)] [close  (in-list closes)])
      (define v1 (vector x open))
      (define v2 (vector x high))
      (define v3 (vector x low))
      (define v4 (vector x close))
      (define r1 (vector (ivl (- x radius) (+ x radius)) (ivl open close)))
      (cond [(> open close) (send area put-pen down-color line-width line-style)
                            (send area put-line v2 v1)
                            (send area put-line v4 v3)
                            (send area put-brush down-color 'solid)
                            (send area put-rect r1)]
            [else (send area put-pen up-color line-width line-style)
                  (send area put-line v2 v4)
                  (send area put-line v1 v3)
                  (send area put-brush up-color 'solid)
                  (send area put-rect r1)])))

(:: candlesticks
    (->* [(Sequenceof (Sequenceof Real))]
         [#:x-min (U Real #f) #:x-max (U Real #f)
          #:y-min (U Real #f) #:y-max (U Real #f)
          #:up-color Plot-Color
          #:down-color Plot-Color
          #:line-width Nonnegative-Real
          #:line-style Plot-Pen-Style
          #:width Nonnegative-Real
          #:alpha Nonnegative-Real]
         renderer2d))
(define (candlesticks candles
                      #:x-min [x-min #f] #:x-max [x-max #f]
                      #:y-min [y-min #f] #:y-max [y-max #f]
                      #:up-color [up-color (candlestick-up-color)]
                      #:down-color [down-color (candlestick-down-color)]
                      #:line-width [line-width (candlestick-line-width)]
                      #:line-style [line-style (candlestick-line-style)]
                      #:width [width (candlestick-width)]
                      #:alpha [alpha (candlestick-alpha)])
  (define fail/kw (make-raise-keyword-error 'candlesticks))
  (cond
    [(and x-min (not (rational? x-min)))  (fail/kw "#f or rational" '#:x-min x-min)]
    [(and x-max (not (rational? x-max)))  (fail/kw "#f or rational" '#:x-max x-max)]
    [(and y-min (not (rational? y-min)))  (fail/kw "#f or rational" '#:y-min y-min)]
    [(and y-max (not (rational? y-max)))  (fail/kw "#f or rational" '#:y-max y-max)]
    [(not (rational? line-width))  (fail/kw "rational?" '#:line-width line-width)]
    [(or (> alpha 1) (not (rational? alpha)))  (fail/kw "real in [0,1]" '#:alpha alpha)]
    [else
     (let* ([candles  (sequence->listof-vector 'candlesticks candles 5)]
            [candles  (filter vrational? candles)])
       (cond [(empty? candles)  empty-renderer2d]
             [else
              (match-define (list (vector #{xs : (Listof Real)}
                                          #{opens : (Listof Real)}
                                          #{highs : (Listof Real)}
                                          #{lows : (Listof Real)}
                                          #{closes : (Listof Real)})
                                  ...)
                candles)
              (let ([x-min  (if x-min x-min (- (apply min* xs) width))]
                    [x-max  (if x-max x-max (+ (apply max* xs) width))]
                    [y-min  (if y-min y-min (apply min* lows))]
                    [y-max  (if y-max y-max (apply max* highs))])
                (renderer2d (vector (ivl x-min x-max) (ivl y-min y-max)) #f default-ticks-fun #f
                            (candlesticks-render-fun xs opens highs lows closes
                                                     up-color down-color line-width line-style width alpha)))]))]))