Finished doc page for plot/utils
This commit is contained in:
parent
9cc2c441ee
commit
55f71c9fa7
|
@ -3,6 +3,7 @@
|
|||
;; Functions that sample from functions, and functions that create memoized samplers.
|
||||
|
||||
(require racket/match racket/flonum racket/math racket/contract racket/list
|
||||
"contract.rkt" "contract-doc.rkt"
|
||||
"math.rkt"
|
||||
"axis-transform.rkt"
|
||||
"parameters.rkt"
|
||||
|
@ -14,14 +15,6 @@
|
|||
#:property prop:procedure
|
||||
(λ (g x) ((mapped-function-f g) x)))
|
||||
|
||||
(struct mapped-function/bounds mapped-function (x-min x-max) #:transparent)
|
||||
|
||||
(define (make-mapped-function fmap)
|
||||
(mapped-function (λ (x) (first (fmap (list x)))) fmap))
|
||||
|
||||
(define (make-mapped-function/bounds fmap x-min x-max)
|
||||
(mapped-function/bounds (λ (x) (first (fmap (list x)))) fmap x-min x-max))
|
||||
|
||||
(define (map* f xs)
|
||||
(match f
|
||||
#;; gives obviously wrong chaperone error (tries to apply a hash?):
|
||||
|
@ -29,9 +22,12 @@
|
|||
[(? mapped-function?) ((mapped-function-fmap f) xs)]
|
||||
[_ (map f xs)]))
|
||||
|
||||
(define (nonlinear-seq x-min x-max samples transform #:start? [start? #t] #:end? [end? #t])
|
||||
(match-define (invertible-function _ finv) (transform x-min x-max))
|
||||
(map finv (linear-seq x-min x-max samples #:start? start? #:end? end?)))
|
||||
(defproc (nonlinear-seq [start real?] [end real?] [num (integer>=/c 0)]
|
||||
[transform (real? real? . -> . invertible-function?)]
|
||||
[#:start? start? boolean? #t]
|
||||
[#:end? end? boolean? #t]) (listof real?)
|
||||
(match-define (invertible-function _ finv) (transform start end))
|
||||
(map finv (linear-seq start end num #:start? start? #:end? end?)))
|
||||
|
||||
(define ((2d-polar->3d-function f) x y z)
|
||||
(let ([x (exact->inexact x)]
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"renderer.rkt"
|
||||
"line.rkt")
|
||||
|
||||
(provide make-kde density)
|
||||
(provide kde density)
|
||||
|
||||
;; make-kde/windowed : (vectorof flonum) flonum flonum flonum -> (listof flonum) -> (listof flonum)
|
||||
;; (can assume that xs is sorted)
|
||||
|
@ -81,9 +81,11 @@
|
|||
;; Making this odd ensures fast-gauss doesn't return negatives (the series partial sums alternate +/-)
|
||||
(define series-terms 9)
|
||||
|
||||
(defproc (make-kde [xs (listof real?)] [h real?]) mapped-function/bounds?
|
||||
(defproc (kde [xs (listof real?)] [h real?]) (values mapped-function?
|
||||
(or/c real? #f)
|
||||
(or/c real? #f))
|
||||
(if (empty? xs)
|
||||
(mapped-function/bounds (λ (y) 0) (λ (ys) (map (λ _ 0.0) ys)) #f #f)
|
||||
(values (mapped-function (λ (y) 0) (λ (ys) (map (λ _ 0.0) ys))) #f #f)
|
||||
(let* ([xs (list->vector (sort (map exact->inexact xs) fl<))]
|
||||
[h (exact->inexact h)])
|
||||
(define N (vector-length xs))
|
||||
|
@ -127,7 +129,7 @@
|
|||
(append first-ps
|
||||
(map (λ (p) (fl* p c)) mid-ps)
|
||||
last-ps)))))
|
||||
(make-mapped-function/bounds fmap x-min x-max))))
|
||||
(values (mapped-function (λ (x) (first (fmap (list x)))) fmap) x-min x-max))))
|
||||
|
||||
(defproc (density [xs (listof real?)] [bw-adjust real? 1]
|
||||
[#:x-min x-min (or/c real? #f) #f] [#:x-max x-max (or/c real? #f) #f]
|
||||
|
@ -142,8 +144,8 @@
|
|||
(define n (length xs))
|
||||
(define sd (sqrt (- (/ (sum sqr xs) n) (sqr (/ (sum values xs) n)))))
|
||||
(define h (* bw-adjust 1.06 sd (expt n -0.2)))
|
||||
(define f (make-kde xs h))
|
||||
(let ([x-min (if x-min x-min (mapped-function/bounds-x-min f))]
|
||||
[x-max (if x-max x-max (mapped-function/bounds-x-max f))])
|
||||
(define-values (f fx-min fx-max) (kde xs h))
|
||||
(let ([x-min (if x-min x-min fx-min)]
|
||||
[x-max (if x-max x-max fx-max)])
|
||||
(function f x-min x-max #:y-min y-min #:y-max y-max #:samples samples
|
||||
#:color color #:width width #:style style #:alpha alpha #:label label)))
|
||||
|
|
|
@ -49,8 +49,7 @@
|
|||
null-2d-bounds-fun
|
||||
x-min x-max y-min y-max))]))
|
||||
|
||||
(defproc (parametric [f (or/c (real? . -> . (vector/c real? real?))
|
||||
mapped-function?)]
|
||||
(defproc (parametric [f (real? . -> . (vector/c real? real?))]
|
||||
[t-min real?] [t-max real?]
|
||||
[#:x-min x-min (or/c real? #f) #f] [#:x-max x-max (or/c real? #f) #f]
|
||||
[#:y-min y-min (or/c real? #f) #f] [#:y-max y-max (or/c real? #f) #f]
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
(define plot-eval
|
||||
(let ([eval (make-base-eval)])
|
||||
(eval #'(require racket/math racket/match racket/list
|
||||
(eval #'(require racket/math racket/match racket/list racket/draw racket/class
|
||||
(rename-in (except-in plot plot plot3d)
|
||||
[plot-bitmap plot]
|
||||
[plot3d-bitmap plot3d])
|
||||
|
|
|
@ -3,3 +3,9 @@
|
|||
@(require "common.rkt")
|
||||
|
||||
@title[#:tag "custom"]{Making Custom Plot Renderers}
|
||||
|
||||
@defmodule[plot/custom]
|
||||
|
||||
Eventually, enough of the underlying PLoT API will be exposed that anyone can create new @tech{renderers}.
|
||||
However, the underlying API still changes too often.
|
||||
As soon as it settles, @racketmodname[plot/custom] will export it, and this page will document how to use it.
|
||||
|
|
|
@ -11,7 +11,7 @@ Returns @racket[#t] if @racket[value] is a 3D @tech{renderer}; that is, if @rack
|
|||
The following functions create such renderers.
|
||||
}
|
||||
|
||||
@section[#:tag "renderer3d-function-arguments"]{3D Renderer Function Arguments}
|
||||
@section{3D Renderer Function Arguments}
|
||||
|
||||
As with functions that return 2D renderers, functions that return 3D renderers always have these kinds of arguments:
|
||||
@itemlist[
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
|
||||
@defmodule[plot/utils]
|
||||
|
||||
@doc-apply[bounds->intervals]{
|
||||
TODO
|
||||
}
|
||||
|
||||
@doc-apply[degrees->radians]{
|
||||
Converts degrees to radians.
|
||||
}
|
||||
|
@ -28,54 +24,168 @@ Given a range, returns the number of decimal places necessary to distinguish num
|
|||
}
|
||||
|
||||
@doc-apply[->plot-label]{
|
||||
Converts a Racket value into a label. Used by @(racket discrete-histogram) and @(racket discrete-histogram3d).
|
||||
Converts a Racket value to a label. Used by @(racket discrete-histogram) and @(racket discrete-histogram3d).
|
||||
}
|
||||
|
||||
@doc-apply[linear-seq]{
|
||||
TODO
|
||||
Returns a list of evenly spaced real numbers between @(racket start) and @(racket end).
|
||||
If @(racket start?) is @(racket #t), the list includes @(racket start).
|
||||
If @(racket end?) is @(racket #t), the list includes @(racket end).
|
||||
|
||||
This function is used internally to generate sample points.
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(linear-seq 0 1 5)
|
||||
(linear-seq 0 1 5 #:start? #f)
|
||||
(linear-seq 0 1 5 #:end? #f)
|
||||
(linear-seq 0 1 5 #:start? #f #:end? #f)]
|
||||
}
|
||||
|
||||
@doc-apply[linear-seq*]{
|
||||
TODO
|
||||
Like @(racket linear-seq), but accepts a list of reals instead of a start and end.
|
||||
The @(racket #:start?) and @(racket #:end?) keyword arguments work as in @(racket linear-seq).
|
||||
This function does not guarantee that each inner value will be in the returned list.
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(linear-seq* '(0 1 2) 5)
|
||||
(linear-seq* '(0 1 2) 6)
|
||||
(linear-seq* '(0 1 0) 5)]
|
||||
}
|
||||
|
||||
@doc-apply[bounds->intervals]{
|
||||
Given a list of points, returns intervals between each pair.
|
||||
|
||||
Use this to construct inputs for @(racket rectangles) and @(racket rectangles3d).
|
||||
@examples[#:eval plot-eval (bounds->intervals (linear-seq 0 1 5))]
|
||||
}
|
||||
|
||||
@doc-apply[color-seq]{
|
||||
TODO
|
||||
Interpolates between colors---red, green and blue components separately---using @(racket linear-seq).
|
||||
The @(racket #:start?) and @(racket #:end?) keyword arguments work as in @(racket linear-seq).
|
||||
|
||||
@examples[#:eval plot-eval (plot (contour-intervals (λ (x y) (+ x y)) -2 2 -2 2
|
||||
#:levels 4 #:contour-styles '(transparent)
|
||||
#:colors (color-seq "red" "blue" 5)))]
|
||||
}
|
||||
|
||||
@doc-apply[color-seq*]{
|
||||
TODO
|
||||
Interpolates between colors---red, green and blue components separately---using @(racket linear-seq*).
|
||||
The @(racket #:start?) and @(racket #:end?) keyword arguments work as in @(racket linear-seq).
|
||||
|
||||
@examples[#:eval plot-eval (plot (contour-intervals (λ (x y) (+ x y)) -2 2 -2 2
|
||||
#:levels 4 #:contour-styles '(transparent)
|
||||
#:colors (color-seq* '(red white blue) 5)))]
|
||||
}
|
||||
|
||||
@doc-apply[->color]{
|
||||
Converts a color into an RGB triplet.
|
||||
Converts a non-integer plot color to an RGB triplet.
|
||||
|
||||
Symbols are converted to strings, and strings are looked up in a @(racket color-database<%>).
|
||||
Lists are unchanged, and @(racket color%) objects are converted straightforwardly.
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(->color 'navy)
|
||||
(->color "navy")
|
||||
(->color '(36 36 140))
|
||||
(->color (make-object color% 36 36 140))]
|
||||
|
||||
This function does not convert integers to RGB triplets, because there is no way for it to know whether the color will be used for a pen or for a brush.
|
||||
Use @(racket ->pen-color) and @(racket ->brush-color) to convert integers.
|
||||
}
|
||||
|
||||
@doc-apply[->pen-color]{
|
||||
Converts a @italic{pen} color into an RGB triplet. This interprets numbers as darker and more saturated than @(racket ->brush-color) does.
|
||||
Converts a @italic{line} color to an RGB triplet. This function interprets integer colors as darker and more saturated than @(racket ->brush-color) does.
|
||||
|
||||
Non-integer colors are converted using @(racket ->color).
|
||||
Integer colors are chosen for good pairwise contrast, especially between neighbors.
|
||||
Integer colors repeat starting with @(racket 8).
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(equal? (->pen-color 0) (->pen-color 8))
|
||||
(plot (contour-intervals
|
||||
(λ (x y) (+ x y)) -2 2 -2 2
|
||||
#:levels 7 #:contour-styles '(transparent)
|
||||
#:colors (map ->pen-color (build-list 8 values))))]
|
||||
}
|
||||
|
||||
@doc-apply[->brush-color]{
|
||||
Converts a @italic{brush} color into an RGB triplet. This interprets numbers as lighter and less saturated than @(racket ->brush-color) does.
|
||||
Converts a @italic{fill} color to an RGB triplet. This function interprets integer colors as lighter and less saturated than @(racket ->pen-color) does.
|
||||
|
||||
Non-integer colors are converted using @(racket ->color).
|
||||
Integer colors are chosen for good pairwise contrast, especially between neighbors.
|
||||
Integer colors repeat starting with @(racket 8).
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(equal? (->brush-color 0) (->brush-color 8))
|
||||
(plot (contour-intervals
|
||||
(λ (x y) (+ x y)) -2 2 -2 2
|
||||
#:levels 7 #:contour-styles '(transparent)
|
||||
#:colors (map ->brush-color (build-list 8 values))))]
|
||||
|
||||
In the above example, @(racket map)ping @(racket ->brush-color) over the list is actually unnecessary, because @(racket contour-intervals) uses @(racket ->brush-color) internally to convert fill colors.
|
||||
|
||||
The @(racket function-interval) function generally plots areas using a fill color and lines using a line color.
|
||||
Both kinds of color have the default value @(racket 3).
|
||||
The following example reverses the default behavior; i.e it draws areas using @italic{line} color @(racket 3) and lines using @italic{fill} color @(racket 3):
|
||||
@interaction[#:eval plot-eval (plot (function-interval sin (λ (x) 0) -4 4
|
||||
#:color (->pen-color 3)
|
||||
#:line1-color (->brush-color 3)
|
||||
#:line2-color (->brush-color 3)
|
||||
#:line1-width 4 #:line2-width 4))]
|
||||
}
|
||||
|
||||
@doc-apply[->pen-style]{
|
||||
Converts a symbolic pen style or a number into a symbolic pen style.
|
||||
Converts a symbolic pen style or a number to a symbolic pen style.
|
||||
Symbols are unchanged.
|
||||
Integer pen styles repeat starting at @(racket 5).
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(eq? (->pen-style 0) (->pen-style 5))
|
||||
(map ->pen-style '(0 1 2 3 4))]
|
||||
}
|
||||
|
||||
@doc-apply[->brush-style]{
|
||||
Converts a symbolic brush style or a number into a symbolic brush style.
|
||||
Converts a symbolic brush style or a number to a symbolic brush style.
|
||||
Symbols are unchanged.
|
||||
Integer brush styles repeat starting at @(racket 7).
|
||||
|
||||
@examples[#:eval plot-eval
|
||||
(eq? (->brush-style 0) (->brush-style 7))
|
||||
(map ->brush-style '(0 1 2 3 4 5 6))]
|
||||
}
|
||||
|
||||
@defstruct[invertible-function ([f (real? . -> . real?)] [finv (real? . -> . real?)])]{
|
||||
Axis transforms return these, given axis bounds. See @(racket plot-x-transform).
|
||||
Represents an invertible function.
|
||||
|
||||
The function itself is @(racket f), and its inverse is @(racket finv).
|
||||
Because @(racket real?)s can be inexact, this invariant must be approximate and therefore cannot be enforced.
|
||||
(For example, @(racket (exp (log 10))) = @(racket 10.000000000000002).)
|
||||
The obligation to maintain it rests on whomever constructs one.
|
||||
|
||||
An axis transform such as @(racket plot-x-transform) is a function from bounds @(racket start end) to an @(racket invertible-function) for which @(racket (f start)) = @(racket start) and @(racket (f end)) = @(racket end) (approximately), and the same is true of @(racket finv).
|
||||
The function @(racket f) is used to transform points before drawing; its inverse @(racket finv) is used to generate samples that will be evenly spaced after being transformed by @(racket f).
|
||||
|
||||
(Technically, because of the way PLoT uses @(racket invertible-function), @(racket f) must only be a left inverse of @(racket finv); there is no requirement that @(racket f) also be a right inverse of @(racket finv).)
|
||||
}
|
||||
|
||||
@defstruct[mapped-function ([f (real? . -> . real?)] [fmap ((listof real?) . -> . (listof real?))])]{
|
||||
@doc-apply[nonlinear-seq]{
|
||||
Generates a list of reals that, if transformed using @(racket transform), would be evenly spaced.
|
||||
This is used to generate samples for transformed axes.
|
||||
@examples[#:eval plot-eval
|
||||
(linear-seq 1 10 4)
|
||||
(nonlinear-seq 1 10 4 log-transform)
|
||||
(parameterize ([plot-x-transform log-transform])
|
||||
(plot (area-histogram sqr (nonlinear-seq 1 10 4 log-transform))))]
|
||||
}
|
||||
|
||||
@defstruct[mapped-function/bounds ([f (real? . -> . real?)] [fmap ((listof real?) . -> . (listof real?))])]{
|
||||
@defstruct[mapped-function ([f (any/c . -> . any/c)] [fmap ((listof any/c) . -> . (listof any/c))])]{
|
||||
Represents a function that maps over lists differently than @(racket (map f xs)).
|
||||
|
||||
With some functions, mapping over a list can be done much more quickly if done specially.
|
||||
(An example is a piecewise function with many pieces that first must decide which interval its input belongs to. Deciding that for many inputs can be done more efficiently by sorting all the inputs first.)
|
||||
Renderer-producing functions that accept a @(racket (real? . -> . real?)) also accept a @(racket mapped-function), and use its @(racket fmap) to sample more efficiently.
|
||||
}
|
||||
|
||||
@doc-apply[make-kde]{
|
||||
@doc-apply[kde]{
|
||||
Given samples and a kernel bandwidth, returns a @(racket mapped-function) representing a kernel density estimate, and bounds, outside of which the density estimate is zero. Used by @(racket density).
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
(provide (struct-out invertible-function))
|
||||
|
||||
(require "common/sample.rkt")
|
||||
(provide (struct-out mapped-function)
|
||||
(struct-out mapped-function/bounds))
|
||||
(provide nonlinear-seq
|
||||
(struct-out mapped-function))
|
||||
|
||||
(require "plot2d/kde.rkt")
|
||||
(provide make-kde)
|
||||
(provide kde)
|
||||
|
|
Loading…
Reference in New Issue
Block a user