Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #lang racket/gui
- (require racket/gui/base)
- ;; sizes
- (define canvas-width 800)
- (define canvas-height 600)
- (define offset-x 30) ; moves grid right
- (define offset-y 30) ; moves grid up
- (define actual-width (- canvas-width 16)) ; window padding
- (define actual-height (- canvas-height 40)) ; window padding
- (define grid-width (- actual-width offset-x))
- (define grid-height (- actual-height offset-y))
- (define point-width 4)
- ;; window
- (define frame (new frame% [label "Graph"] [width canvas-width] [height canvas-height]))
- (define canvas (new canvas% [parent frame]))
- (define context (send canvas get-dc))
- ;; pens
- (define thin-pen (new pen% [color "lightgray"] [width 0.5] [style 'dot])) ; gridlines
- (define thick-pen (new pen% [color "black"] [width 1.5] [style 'solid])) ; axis
- (define red-pen (new pen% [color "red"] [width 1] [style 'solid])) ; lines
- ;; brush
- (define point-brush (new brush% [color "black"])) ; points
- (send context set-brush point-brush)
- ;; fonts
- (define title-font (make-object font% 12 'roman 'italic)) ; axis titles
- (define label-font (make-object font% 6 'roman 'normal 'light)) ; axis numbers/labels
- ;; label axis numbers
- (define (label-number axis label x/y increment lines-per-increment)
- (let ([n (if (integer? (inexact->exact (/ (* label increment) lines-per-increment)))
- (inexact->exact (/ (* label increment) lines-per-increment))
- (string->number (real->decimal-string (/ (* label increment) lines-per-increment) 3)))])
- (let-values ([(label-width label-height base-whitespace extra-vertical)
- (send context get-text-extent (number->string n))])
- (cond
- [(eq? axis 'x)
- (send context draw-text (number->string n) (- x/y (/ label-width 2)) (add1 grid-height))]
- [(eq? axis 'y)
- (send context draw-text (number->string n) (- offset-x label-width 1) (- x/y (/ label-height 2)))]))))
- ;; grid drawing
- (define (draw-grid x-title ; x-axis title
- x-interval ; range of x-axis values (cons lower upper)
- x-increment ; how much labels on x-axis increase
- lines-per-x-increment ; added lines for each value in range
- y-title
- y-interval
- y-increment
- lines-per-y-increment)
- ;; AXIS TITLES
- (send context set-font title-font)
- ;; x-axis title
- (let-values ([(title-width ; width in px of `x-title`
- title-height ; height in px of `x-title`
- base-whitespace
- extra-vertical)
- (send context get-text-extent x-title)])
- (send context draw-text x-title (/ (+ offset-x canvas-width title-width) 2) (- actual-height (/ (+ offset-y (/ title-height 2)) 2))))
- ;; y-axis title
- (let-values ([(title-width title-height base-whitespace extra-vertical)
- (send context get-text-extent y-title)])
- (send context draw-text y-title 0 (/ (- grid-height title-width) 2) #f 0 (/ pi 2)))
- ;; AXIS
- (send context set-pen thick-pen)
- ;; draw axis
- (send context draw-line offset-x grid-height canvas-width grid-height) ; x-axis
- (send context draw-line offset-x 0 offset-x grid-height) ; y-axis
- ;; arrow heads
- (send context draw-lines (list (make-object point% (- offset-x 2) 2)
- (make-object point% offset-x 0)
- (make-object point% (+ offset-x 2) 2)))
- (send context draw-lines (list (make-object point% (- actual-width 2) (- grid-height 2))
- (make-object point% actual-width grid-height)
- (make-object point% (- actual-width 2) (+ grid-height 2))))
- ;; GRIDLINES AND LABELS
- (send context set-pen thin-pen)
- (send context set-font label-font)
- (let* ([interval-width (- (cdr x-interval) (car x-interval))] ; change in values along x-axis
- [interval-height (- (cdr y-interval) (car y-interval))]
- [num-x-lines (/ (* interval-width lines-per-x-increment) x-increment)] ; number of vertical lines in grid (not including y-axis)
- [num-y-lines (/ (* interval-height lines-per-y-increment) y-increment)]
- [cell-width (/ (- grid-width 5) num-x-lines)] ; distance bewteen vertical lines
- [cell-height (/ (- grid-height 5) num-y-lines)])
- (label-number 'x 0 offset-x x-increment lines-per-x-increment) ; 0
- ;; y-axis gridlines
- (for ([i (in-range 1 (add1 (* num-y-lines y-increment)))])
- (let ([y (- grid-height (/ (* i cell-height) y-increment))])
- (send context draw-line offset-x y actual-width y)
- ;; y-axis labels
- (cond [(= (remainder i lines-per-y-increment) 0)
- (label-number 'y i y y-increment lines-per-y-increment)])))
- ;; x-axis gridlines
- (for ([i (in-range 1 (add1 num-x-lines))])
- (let ([x (+ offset-x (/ (* i cell-width) 1))])
- (send context draw-line x 0 x grid-height)
- ;; x-axis labels
- (cond [(= (remainder i lines-per-x-increment) 0)
- (label-number 'x i x x-increment lines-per-x-increment)])))))
- ;; convert x-values on grid to within the frame/window
- (define (grid-x->frame-x x precision-offset interval-width num-points precision)
- (+ (/ (* grid-width (+ x (/ precision-offset precision))) num-points) offset-x))
- ;; compute y-values and convert them to within the frame/window
- (define (grid-x->frame-y x f precision-offset interval-width interval-height num-points precision)
- (- grid-height (* (f (/ (* (+ x (/ precision-offset precision)) interval-width) num-points)) (/ grid-height interval-height))))
- (define (draw-connecting-curve f x interval-width interval-height num-points precision)
- (for ([i (* num-points precision)])
- (send context draw-line (grid-x->frame-x x (sub1 i) interval-width num-points precision)
- (grid-x->frame-y x f (sub1 i) interval-width interval-height num-points precision)
- (grid-x->frame-x x i interval-width num-points precision)
- (grid-x->frame-y x f i interval-width interval-height num-points precision))))
- (define (draw-curve f interval-width interval-height num-points precision)
- (send context set-pen red-pen)
- (for ([i (* num-points precision)])
- (draw-connecting-curve f i interval-width interval-height num-points precision)))
- (define (plot-points f interval-width interval-height num-points precision)
- (send context set-pen thick-pen)
- (for ([i num-points])
- (send context draw-ellipse (+ (- (/ (* grid-width i) num-points) (/ point-width 2)) offset-x)
- (- grid-height (* (f (/ (* i interval-width) num-points)) (/ grid-height interval-height)) (/ point-width 2))
- ;; (- grid-height (* interval-height (f (* i num-points))) (/ point-width 2))
- point-width
- point-width)))
- (define (plot f x-interval y-interval num-points precision)
- (let* ([interval-width (- (cdr x-interval) (car x-interval))]
- [interval-height (- (cdr y-interval) (car y-interval))])
- (draw-curve f interval-width interval-height num-points precision)
- (plot-points f interval-width interval-height num-points precision)))
- (send frame show #t)
- (sleep/yield 1)
- ;; calls
- (draw-grid "n" (cons 0 10) 1 4 "{a(n)}" (cons 0 20) 1 1)
- ;; (draw-grid-mod 20 20 (lambda (x) (/ 10 x)) (lambda (y) y))
- (define e (exp 1))
- ;; Stirling approximation for efficiency
- (define (factorial n)
- (* (sqrt (* 2 pi n))
- (expt (/ n e) n)))
- ;; (plot (lambda (x) (abs (* x (sin (factorial x))))) (cons 0 2) (cons 0 2) 10 10)
- (plot (lambda (x) (+ (abs (sin x)) (* 2 x))) (cons 0 10) (cons 0 20) 20 10)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement