[racket] Controlling the size of plot symbols
On 04/10/2014 08:16 PM, Konrad Hinsen wrote:
> Neil Toronto writes:
>
> > It's unfortunately not. But I think there's something you can do
> > instead: use `parametric-interval' to draw the circles instead.
>
> Thanks for the example, which contains some nice tricks I'll keep in
> mind for some other application. But I don't see a way to use this for
> my molecules, because I am need 3D plots. What I really want is
> spheres. If I draw my own parametric circles in 3D, I'd have to take
> into account the view point and compute projections.
Ew. Also, there's not a nice way to do it that works well with
interactive plots.
> I did play with the idea of defining spheres as 3D surfaces, but I'd
> expect this to be much too slow.
The isosurface renderer applies its function argument only to points
inside its bounds, and also just outside its bounds if its bounds don't
line up perfectly with the sample grid. So something like this for each
sphere might be fast enough, where x0,y0,z0,r are the sphere's center
and radius:
(isosurface3d (λ (x y z) (sqrt (+ (sqr (- x0 x))
(sqr (- y0 y))
(sqr (- z0 z)))))
r (- x0 r) (+ x0 r) (- y0 r) (+ y0 r) (- z0 r) (+ z0 r))
If some of the spheres are too close or intersect, the current released
version of Plot will sometimes draw their polygons in the wrong order.
You'd need a recent nightly build to fix that.
Or... draw all the spheres using one isosurface. The idea is to define
the R^3 -> R function that returns the distance to the nearest sphere,
and plot the inputs for which it returns zero.
#lang racket
(require plot math)
(define n 50)
(define xs (sample (normal-dist 0 1) n))
(define ys (sample (normal-dist 0 1) n))
(define zs (sample (normal-dist 0 1) n))
(define rs (sample (uniform-dist 0.1 0.5) n))
(define (spheres3d xs ys zs rs color)
(define x-min (apply min (map - xs rs)))
(define x-max (apply max (map + xs rs)))
(define y-min (apply min (map - ys rs)))
(define y-max (apply max (map + ys rs)))
(define z-min (apply min (map - zs rs)))
(define z-max (apply max (map + zs rs)))
(isosurface3d (λ (x y z)
(for/fold ([d +inf.0]) ([x0 (in-list xs)]
[y0 (in-list ys)]
[z0 (in-list zs)]
[r (in-list rs)])
(min d (- (sqrt (+ (sqr (- x0 x))
(sqr (- y0 y))
(sqr (- z0 z))))
r))))
0 x-min x-max y-min y-max z-min z-max
#:line-style 'transparent
#:color color))
(plot3d-samples 121)
(time (plot3d (spheres3d xs ys zs rs 3)
#:x-min -3 #:x-max 3
#:y-min -3 #:y-max 3
#:z-min -3 #:z-max 3))
On git HEAD this takes about 15-20 seconds on my computer, depending on
random sphere placement and size. It takes 5-6 seconds for 81 samples
instead of 121. For comparison, the following takes 7-10 seconds with
121 samples and 3-4 seconds with 81 samples.
(define (sphere3d x0 y0 z0 r color)
(isosurface3d (λ (x y z) (sqrt (+ (sqr (- x0 x))
(sqr (- y0 y))
(sqr (- z0 z)))))
r (- x0 r) (+ x0 r) (- y0 r) (+ y0 r) (- z0 r) (+ z0 r)
#:line-style 'transparent
#:color color))
(time (plot3d (for/list ([x0 (in-list xs)]
[y0 (in-list ys)]
[z0 (in-list zs)]
[r (in-list rs)]
[color (in-naturals)])
(sphere3d x0 y0 z0 r color))
#:x-min -3 #:x-max 3
#:y-min -3 #:y-max 3
#:z-min -3 #:z-max 3))
Plus, every sphere gets its own purty pastel color.
Neil ⊥