;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; plot-stream cleans up any old viewports, creates a new viewport and ;; plots into that viewport. ;; plot-stream-no-init assumes that the caller is handling an initial call to ;; (init-plotting) and is calling (reset-plotting) as needed. ;; it will force enough of the stream to plot the requested number of points. ;; plotizing-stream creates a stream with side-effects: as elements of the ;; stream are accessed, they are plotted in the viewport, and returned. ;; If you handle (init-plotting) and (reset-plotting) as needed, ;; you can call plotizing stream to return a stream identical to its argument ;; except that every time you use an element of the returned stream it is ;; plotted. ;; A minor nuisance here is that the first element of a stream is not delayed ;; so it is plotted immediately. ;; ;; This runs on top of the MzScheme viewport graphics library, and standard ;; stream routines. ;; ;; You can reset globals *viewport-width* and *viewport-height* to suit ;; your preferred viewport size. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (require (lib "graphics.ss" "graphics")) (define *the-viewport* 'uninitialized) (define *viewport-width* 400) ; pixels width (define *viewport-height* 200) ; pixels height (define *last-position* 'uninitialized) ;; ;; next plotted point is a left of viewport ;; (define (reset-screen-x-position) (set! *last-position* (make-posn 0 (/ *viewport-height* 2)))) ;; ;; next plotted point is at left of a cleared viewport ;; (define (reset-plotting) ((clear-viewport *the-viewport*)) (reset-screen-x-position)) ;; ;; Only need to call this once at setup, could call reset-plotting ;; otherwise. ;; (define (init-plotting) ; (if (not (viewport? *the-viewport*)) (begin (close-graphics) ; just in case re-initing (open-graphics) ; init graphics package (set! *the-viewport* ; pop up a "viewport" (open-viewport "heart monitor" *viewport-width* *viewport-height*)));) (reset-plotting)) ; any initial fussing with coordinates ;; ;; The proper way to cean up when done... ;; (define (cleanup-plotting) (if (viewport? *the-viewport*) (begin (close-viewport *the-viewport*) (set! *the-viewport* 'uninitialized))) (close-graphics)) ;; ;; plotizing-stream will turn the stream into a plot: the size of the ;; initial segment of the stream that is generated determines the number ;; of points plotted. Since the first element of a stream is not delayed, ;; plotizing-stream will plot at least one element. ;; (define (plotizing-stream stream max-y max-no-of-xs) (map-stream (make-element-plotter-for-frame max-y max-no-of-xs) stream)) ;; Expecting x to run from 0 to max-no-of-xs ;; Expecting y to run from -max-y to max-y ;; Flip sign on y (0,0) in this graphics package is in upper left ;; rather than the usual lower left ;; ;; This returns a function that creates side-effects when called: ;; both drawing on the viewport and updating the global *last-position* (define (make-element-plotter-for-frame max-y max-no-of-xs) ;; Scheme defines abs but not sign (define (sign x) (if (< x 0) -1 1)) ; (let ((x-counter 0)) (lambda (y) (let ((next-x-coord (+ (/ *viewport-width* max-no-of-xs) (posn-x *last-position*))) (next-y-coord (- (/ *viewport-height* 2) (* *viewport-height* (/ y max-y 2))))) (let ((current-position (make-posn next-x-coord next-y-coord))) ((draw-line *the-viewport*) *last-position* current-position) (cond ((< next-y-coord 0) ((draw-string *the-viewport*) (make-posn (- next-x-coord 4) 10) "*")) ((>= next-y-coord *viewport-height*) (draw-string *the-viewport*) (make-posn (- next-x-coord 4) (+ *viewport-height* 5)) "*")) ; (display (list x-counter y next-x-coord next-y-coord)) ; (newline) (set! x-counter (+ 1 x-counter)) (set! *last-position* current-position) y)))) ;) ;; ;; Plot the first num-vals elements of the stream s in a pop-up window. ;; You should call this with max-y being the absolute value of the largest ;; element of the stream that you need to see in the window. You can often ;; guess this value. ;; If a value goes outside the bounds of the window, a "*" is placed at the ;; edge of the window. ;; (define (plot-stream s max-y num-vals) (define (stream-ref n s) (cond ((stream-null? s) 'done) ((= n 0) (stream-car s)) (else (stream-ref (- n 1) (stream-cdr s))))) (init-plotting) (stream-ref (- num-vals 1) (plotizing-stream s max-y num-vals))) (define (plot-stream-no-init s max-y num-vals) (define (stream-ref n s) (cond ((stream-null? s) 'done) ((= n 0) (stream-car s)) (else (stream-ref (- n 1) (stream-cdr s))))) (stream-ref (- num-vals 1) (plotizing-stream s max-y num-vals)))