nextjournal / clerk

⚡️ Moldable Live Programming for Clojure

Home Page:https://clerk.vision

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

clerk/vl doesn't update reactively

sritchie opened this issue · comments

This notebook produces quite a bit of flickering. I've added a recursive fibonacci to create an artificial delay, but in https://probcomp.github.io/gen-finance/ the delay is real:

(ns finance.check
  (:require [nextjournal.clerk.viewer :as clerk]))

(clerk/with-viewer
  {:render-fn
   '(fn [_]
      (reagent.core/with-let [!trials (reagent.core/atom 10)]
        [:div
         [:input {:type :range
                  :value @!trials
                  :on-change
                  #(swap! !trials (constantly (int (.. % -target -value))))}]
         [nextjournal.clerk/inspect
          (nextjournal.clerk/vl
           {:schema "https://vega.github.io/schema/vega-lite/v5.json"
            :embed/opts {:actions false}
            :width 650 :height 300
            :data (letfn [(fib [n]
                            (if (or (= n 0) (= n 1))
                              n
                              (+ (fib (- n 1)) (fib (- n 2)))))]
                    {:values (for [x (range @!trials)]
                               (do (fib 16)
                                   {:x (rand)
                                    :y (rand)}))})
            :layer
            [{:mark :point
              :encoding {:x {:field :x :type "quantitative"}
                         :y {:field :y :type "quantitative"}}}]})]]))}
  {})

Here's the effect:
2023-11-21 11 32 00

Since this is all just in a single :render-fn here's a version that doesn't use the render/inspect indirection but uses the vega-lite viewer's render-fn, nextjournal.clerk.render/render-vega-lite directly. This updates without flickering.

I'd recommend this in general since the other parts of Clerk's viewer API like clerk/mark-presented aren't needed when rendering happens in the same runtime.

(clerk/with-viewer
  {:render-fn
   '(fn [_]
      (reagent.core/with-let [!trials (reagent.core/atom 10)]
        [:div
         [:input {:type :range
                  :value @!trials
                  :on-change
                  #(swap! !trials (constantly (int (.. % -target -value))))}]
         [nextjournal.clerk.render/render-vega-lite
          {:schema "https://vega.github.io/schema/vega-lite/v5.json"
           :embed/opts {:actions false}
           :width 650 :height 300
           :data (letfn [(fib [n]
                           (if (or (= n 0) (= n 1))
                             n
                             (+ (fib (- n 1)) (fib (- n 2)))))]
                   {:values (for [x (range @!trials)]
                              (do (fib 16)
                                  {:x (rand)
                                   :y (rand)}))})
           :layer
           [{:mark :point
             :encoding {:x {:field :x :type "quantitative"}
                        :y {:field :y :type "quantitative"}}}]}]]))}
  {})

Let me know if using the render-fn directly like this is feasible in your use case. If not, we might want to investigate if we can make inspect work across reactive boundaries like that but for the moment I'd recommend not going through inspect.