lukego / blog

Luke Gorrie's blog
566 stars 11 forks source link

kons-9 for ad-hoc data visualization #37

Open lukego opened 1 year ago

lukego commented 1 year ago

kons-9, the 3D IDE in Lisp, really came in handy this week for ad-hoc data visualization while debugging a Sequential Monte Carlo (aka particle filter) simulation.

It feels like a superpower to load a 3D modeling environment directly into the process where my simulator is running and to fluidly insert new data into the visualization as it is being generated. There turned out to be a whole lot of diagnostics I could run just by spinning the model around and eyeballing it.

This turned out to be much more productive than my initial approach of dumping simulation data into DuckDB tables for separate inspection with ggplot2-based notebooks. Thanks @kaveh808 for a great tool in the toolbox!

Here's some eye candy with rough notes below:

https://user-images.githubusercontent.com/13791/235121210-e47544b2-fc7d-4924-bf29-7b4d2421e52b.mp4

Background:

Observations:

Cute aspects:

Three cheers for kons-9!

and especially because coding the hook from simulator to 3D model was no trouble at all:

;;; trail.lisp -- diagnostic to follow the tracks of a simulation

(defpackage #:smc-trace
  (:use #:permo #:permo-lisp)
  (:export #:reset #:smc-step #:*step*))
(in-package #:smc-trace)

(defparameter *z* 0)
(defvar *step* nil)

(defun reset ()
  "Reset the SMC visualization."
  (setf *z* 0)
  (kons-9::clear-scene kons-9::*scene*))

(defun smc-step (particles)
  "Visualize the next simulation step with PARTICLES.
   Particles is a list of parameter-vectors."
  (draw-particles particles))

(in-package #:kons-9)

(defun smc-trace::draw-particles (ps)
  (setf (shading-color *drawing-settings*) (c-rand))
  (let ((pc (particles-to-point-cloud ps)))
    (allocate-point-colors pc)
    (add-shape *scene* pc)
    (when smc-trace::*step* (break))))

(defun particles-to-point-cloud (particles)
  "Return a point-cloud mapping the two dimensions of PARTICLES onto X/Y.
   Step the Z-axis forward."
  (loop with n = (length (first particles))
        with point-array = (make-array n)
        for i below n
        do (setf (aref point-array i)
                 (p (aref (first particles) i) (aref (second particles) i) smc-trace::*z*))
        finally (progn
                  (incf smc-trace::*z* 0.25)
                  (return (make-point-cloud point-array)))))

(defun p (x y z)
  "Return the point (X Y Z)."
  (p:vec (coerce x 'single-float)
         (coerce y 'single-float)
         (coerce z 'single-float)))
aykaramba commented 1 year ago

This was a great read, thank you for putting in the time to blog about this. It's a good entry point for those of us that want to explored this sort of thing a bit more, particularly if we have no familiarity with the topic.