This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-03-23
Channels
- # announcements (2)
- # babashka (25)
- # beginners (33)
- # biff (13)
- # calva (13)
- # clerk (82)
- # clj-commons (3)
- # clj-kondo (8)
- # clj-on-windows (23)
- # cljdoc (6)
- # clojure (16)
- # clojure-belgium (1)
- # clojure-dev (58)
- # clojure-europe (53)
- # clojure-nl (1)
- # clojure-norway (15)
- # clojure-uk (2)
- # clojurescript (17)
- # core-async (5)
- # cursive (6)
- # datahike (1)
- # datomic (8)
- # emacs (25)
- # etaoin (21)
- # events (4)
- # graalvm (33)
- # honeysql (7)
- # hyperfiddle (1)
- # lsp (49)
- # luminus (4)
- # malli (18)
- # off-topic (63)
- # reagent (11)
- # releases (1)
- # shadow-cljs (200)
- # timbre (1)
- # tools-build (17)
Hey friends! Regarding long-running computations, I’ve been wondering whether it might make sense to make use of clojure.core/delay
in combination with a custom viewer. 🧵
My goals are to: 1. Reduce the delay before the notebook renders. 2. Give the user control of when to kick off the long-running computation.
Here’s a first attempt at the viewer that mostly works:
(def delay
{:pred delay?
:var-from-def? true
:transform-fn
(comp clerk/mark-presented
(clerk/update-val (fn [{::clerk/keys [var-from-def]}]
(let [realized (realized? @var-from-def)]
(cond-> {:delay @var-from-def
:var-name (symbol var-from-def)
:realized realized}
realized (assoc :value @@var-from-def))))))
:render-fn
'(fn [{:keys [delay var-name realized value]}]
(if realized
(nextjournal.clerk.render/inspect value)
(reagent.core/with-let [!evaluating (reagent.core/atom false)]
(nextjournal.clerk.viewer/html
(if @!evaluating
"Loading..."
[:<>
[:button {:type "button"
:on-click #(when-not @!evaluating
(reset! !evaluating true)
(nextjournal.clerk.viewer/clerk-eval
`(force ~var-name)))}
"Eval"]
(nextjournal.clerk.render/inspect delay)])))))})
Clicking the button to force the delay seems to work, and for simple expressions like (range 10)
the result gets rendered to the page once the delay is realized. But for more complex expressions, like charts from vega/vl
, nothing gets rendered to the page when after the delay is realized. :thinking_face:
I imagine my issue is something simple. Perhaps I’m misusing nextjournal.clerk.render/inspect
?
Any console warnings, out of curiosity?
@U050CT4HR here’s an approach that works:
(ns scratch
(:require [nextjournal.clerk :as clerk]))
(def future-viewer
{:pred future?
:transform-fn (clerk/update-val (fn [fut] (if (realized? fut)
@fut
(clerk/html [:p "Loading…"]))))})
(clerk/add-viewers! [future-viewer])
(def my-future
(future (Thread/sleep 3400)
(future (clerk/recompute!))
(clerk/vl {:width 650 :height 400 :data {:url ""
:format {:type "topojson" :feature "counties"}}
:transform [{:lookup "id" :from {:data {:url ""}
:key "id" :fields ["rate"]}}]
:projection {:type "albersUsa"} :mark "geoshape" :encoding {:color {:field "rate" :type "quantitative"}}
:embed/opts {:actions false}})))
and think recomputing when it’s done is more what you want probably, so not needing a button?
or here with a small macro
(ns scratch
(:require [nextjournal.clerk :as clerk]))
(def future-viewer
{:pred #(-> % meta ::future-compute)
:transform-fn (clerk/update-val (fn [fut] (if (realized? fut)
@fut
(clerk/html [:p "Loading…"]))))})
(clerk/add-viewers! [future-viewer])
(defmacro future-compute [& body]
"Like `clojure.core/future` but for computing a result for Clerk in the background."
`(with-meta (future (let [res# @(future ~@body)]
(future (clerk/recompute!))
res#))
{::future-compute true}))
(def my-future
(future-compute (Thread/sleep 3400)
(clerk/vl {:width 650 :height 400 :data {:url ""
:format {:type "topojson" :feature "counties"}}
:transform [{:lookup "id" :from {:data {:url ""}
:key "id" :fields ["rate"]}}]
:projection {:type "albersUsa"} :mark "geoshape" :encoding {:color {:field "rate" :type "quantitative"}}
:embed/opts {:actions false}}))
)
or with the first rule of macro club applied:
(ns scratch
(:require [nextjournal.clerk :as clerk]))
(def future-viewer
{:pred #(-> % meta ::future-compute)
:transform-fn (clerk/update-val (fn [fut] (if (realized? fut)
@fut
(clerk/html [:p "Loading…"]))))})
(clerk/add-viewers! [future-viewer])
(defn recompute-when-realized [fut]
(with-meta (future (let [res @fut]
(future (clerk/recompute!))
res))
{::future-compute true}))
(def my-future
(recompute-when-realized
(future (Thread/sleep 3400)
(clerk/vl {:width 650 :height 400 :data {:url ""
:format {:type "topojson" :feature "counties"}}
:transform [{:lookup "id" :from {:data {:url ""}
:key "id" :fields ["rate"]}}]
:projection {:type "albersUsa"} :mark "geoshape" :encoding {:color {:field "rate" :type "quantitative"}}
:embed/opts {:actions false}}))))
Amazing. Thanks, @U5H74UNSF!
> so not needing a button? Actually, no. As I mentioned above, part of the goal is to delay kicking off the execution of the expensive computation until the reader explicitly triggers it.
But I think I can see how to combine what I had with what you wrote. Will try and circle back.
This does the trick.
{::clerk/viewer
{:var-from-def? true
:transform-fn
(comp clerk/mark-presented
(clerk/update-val
(fn [{:nextjournal.clerk/keys [var-from-def]}]
(let [var-symbol (symbol var-from-def)
delay @var-from-def
realized (realized? delay)]
(cond-> {:var-symbol var-symbol
:delay (viewer/present delay)
:realized realized}
realized (assoc :val (viewer/present @delay)))))))
:render-fn
'(fn [{:keys [realized delay var-symbol val]}]
(if realized
(nextjournal.clerk.render/inspect-presented val)
(reagent.core/with-let [!evaluating (reagent.core/atom false)]
(nextjournal.clerk.viewer/html
(if @!evaluating
[:p "Loading..."]
[:<>
[:button {:type "button"
:on-click #(when-not @!evaluating
(reset! !evaluating true)
(nextjournal.clerk.viewer/clerk-eval
`(force ~var-symbol)))}
"Eval"]
(nextjournal.clerk.render/inspect-presented delay)])))))}}
Here’s an attempt at a future viewer that supports restarting:
{:pred future?
:var-from-def? true
:transform-fn
(comp clerk/mark-presented
(clerk/update-val
(fn [{:nextjournal.clerk/keys [var-from-def]}]
(assert (var? var-from-def))
(let [var-symbol (symbol var-from-def)
future @var-from-def
cancelled (future-cancelled? future)
done (future-done? future)]
(cond-> {:var-symbol var-symbol
:future (viewer/present future)
:done done
:cancelled cancelled}
(and (not cancelled) done)
(assoc :val (viewer/present @future)))))))
:render-fn
'(fn [{:keys [future var-symbol val done cancelled]}]
(cond cancelled
[:button {:type "button"
:on-click #(nextjournal.clerk.viewer/clerk-eval
`(nextjournal.clerk/clear-cache! '~var-symbol))}
"Restart"]
done (nextjournal.clerk.render/inspect-presented val)
:else
[:<>
[:button {:type "button"
:on-click #(nextjournal.clerk.viewer/clerk-eval
`(future-cancel ~var-symbol))}
"Cancel"]
(nextjournal.clerk.render/inspect-presented future)]))}
I am getting an error when I try to run a function that wraps a Specter fn. This user fn takes a Specter path (which is a vector of navigator functions/symbols).
Getting Execution error (ExceptionInfo) at clojure.tools.analyzer/parse-var (analyzer.clj:803) var not found: custom-path
I have {:nextjournal.clerk/error-on-missing-vars :off}
below my namespace name. And normal specter code seems to be working.
This used to be working. Is there a type hint that might help out?
Can you make a minimal reproduction so we can investigate?
I couldn’t reproduce in a minimal repo. Seems to be working the way I normally wrap a fn. Here is part of the stack trace from the Clerk view, from my original project, for context. I will investigate further.
Unhandled clojure.lang.ExceptionInfo
var not found: custom-path
{:var custom-path}
analyzer.clj: 803 clojure.tools.analyzer/parse-var
analyzer.clj: 792 clojure.tools.analyzer/parse-var
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
protocols.clj: 168 clojure.core.protocols/fn--8249
protocols.clj: 124 clojure.core.protocols/fn--8249
protocols.clj: 19 clojure.core.protocols/fn--8204/G--8199--8213
protocols.clj: 31 clojure.core.protocols/seq-reduce
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 13 clojure.core.protocols/fn--8178/G--8173--8191
core.clj: 6886 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 781 clojure.tools.analyzer/parse-invoke
analyzer.clj: 777 clojure.tools.analyzer/parse-invoke
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
PersistentVector.java: 343 clojure.lang.PersistentVector
core.clj: 6885 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 183 clojure.tools.analyzer/analyze-vector
analyzer.clj: 180 clojure.tools.analyzer/analyze-vector
analyzer.clj: 50 clojure.tools.analyzer/eval4369/fn--4370
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
protocols.clj: 168 clojure.core.protocols/fn--8249
protocols.clj: 124 clojure.core.protocols/fn--8249
protocols.clj: 19 clojure.core.protocols/fn--8204/G--8199--8213
protocols.clj: 31 clojure.core.protocols/seq-reduce
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 13 clojure.core.protocols/fn--8178/G--8173--8191
core.clj: 6886 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 781 clojure.tools.analyzer/parse-invoke
analyzer.clj: 777 clojure.tools.analyzer/parse-invoke
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 503 clojure.tools.analyzer/analyze-let
analyzer.clj: 490 clojure.tools.analyzer/analyze-let
analyzer.clj: 528 clojure.tools.analyzer/parse-let*
analyzer.clj: 523 clojure.tools.analyzer/parse-let*
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 300 clojure.tools.analyzer/parse-if
analyzer.clj: 292 clojure.tools.analyzer/parse-if
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 503 clojure.tools.analyzer/analyze-let
analyzer.clj: 490 clojure.tools.analyzer/analyze-let
analyzer.clj: 528 clojure.tools.analyzer/parse-let*
analyzer.clj: 523 clojure.tools.analyzer/parse-let*
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
protocols.clj: 168 clojure.core.protocols/fn--8249
protocols.clj: 124 clojure.core.protocols/fn--8249
protocols.clj: 19 clojure.core.protocols/fn--8204/G--8199--8213
protocols.clj: 31 clojure.core.protocols/seq-reduce
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 13 clojure.core.protocols/fn--8178/G--8173--8191
core.clj: 6886 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 781 clojure.tools.analyzer/parse-invoke
analyzer.clj: 777 clojure.tools.analyzer/parse-invoke
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
PersistentVector.java: 343 clojure.lang.PersistentVector
core.clj: 6885 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 183 clojure.tools.analyzer/analyze-vector
analyzer.clj: 180 clojure.tools.analyzer/analyze-vector
analyzer.clj: 50 clojure.tools.analyzer/eval4369/fn--4370
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
protocols.clj: 168 clojure.core.protocols/fn--8249
protocols.clj: 124 clojure.core.protocols/fn--8249
protocols.clj: 19 clojure.core.protocols/fn--8204/G--8199--8213
protocols.clj: 31 clojure.core.protocols/seq-reduce
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 13 clojure.core.protocols/fn--8178/G--8173--8191
core.clj: 6886 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 781 clojure.tools.analyzer/parse-invoke
analyzer.clj: 777 clojure.tools.analyzer/parse-invoke
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
PersistentVector.java: 343 clojure.lang.PersistentVector
core.clj: 6885 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 183 clojure.tools.analyzer/analyze-vector
analyzer.clj: 180 clojure.tools.analyzer/analyze-vector
analyzer.clj: 50 clojure.tools.analyzer/eval4369/fn--4370
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 127 clojure.tools.analyzer/analyze-in-env/fn--4416
core.clj: 6979 clojure.core/mapv/fn--8535
protocols.clj: 168 clojure.core.protocols/fn--8249
protocols.clj: 124 clojure.core.protocols/fn--8249
protocols.clj: 19 clojure.core.protocols/fn--8204/G--8199--8213
protocols.clj: 31 clojure.core.protocols/seq-reduce
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 75 clojure.core.protocols/fn--8234
protocols.clj: 13 clojure.core.protocols/fn--8178/G--8173--8191
core.clj: 6886 clojure.core/reduce
core.clj: 6970 clojure.core/mapv
core.clj: 6970 clojure.core/mapv
analyzer.clj: 781 clojure.tools.analyzer/parse-invoke
analyzer.clj: 777 clojure.tools.analyzer/parse-invoke
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 503 clojure.tools.analyzer/analyze-let
analyzer.clj: 490 clojure.tools.analyzer/analyze-let
analyzer.clj: 528 clojure.tools.analyzer/parse-let*
analyzer.clj: 523 clojure.tools.analyzer/parse-let*
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 272 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 300 clojure.tools.analyzer/parse-if
analyzer.clj: 292 clojure.tools.analyzer/parse-if
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 503 clojure.tools.analyzer/analyze-let
analyzer.clj: 490 clojure.tools.analyzer/analyze-let
analyzer.clj: 528 clojure.tools.analyzer/parse-let*
analyzer.clj: 523 clojure.tools.analyzer/parse-let*
analyzer.clj: 809 clojure.tools.analyzer/-parse
analyzer.clj: 805 clojure.tools.analyzer/-parse
jvm.clj: 427 clojure.tools.analyzer.jvm/parse
jvm.clj: 424 clojure.tools.analyzer.jvm/parse
analyzer.clj: 271 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 272 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 272 clojure.tools.analyzer/analyze-seq
analyzer.clj: 262 clojure.tools.analyzer/analyze-seq
analyzer.clj: 63 clojure.tools.analyzer/eval4381/fn--4382
MultiFn.java: 234 clojure.lang.MultiFn
analyzer.clj: 284 clojure.tools.analyzer/parse-do
analyzer.clj: 276 clojure.tools.analyzer/parse-do
...
Seems to be something with naming specter paths with def
or defn
and using them in wrapper fns.
(defn mypath [x] (path ALL x))
(select (mypath MAP-VALS) data)
Everything compiles in repl fine.
But I haven’t locked down a reproduction yet.
Will have to postpone til later.does clerk work in babashka project? I am assuming the answer is no
we looked into this in https://github.com/nextjournal/clerk/pull/232 a while ago
@U02Q6L92FEJ Here is a very light-weight way to get a notebook like thing in babashka: https://www.loop-code-recur.io/live-clojure-cookbooks/ It's not clerk, but it's something. The above PR would be better though
is this still of interest? I use babashka to do ad hoc analysis and it would be nice to visualise and potentially publish some of the results within the company. having plotly, html, vega lite blocks is really convenient
@U5H74UNSF btw, tools.analyzer is now also almost compatible with babashka, more so than a while ago (but maybe too much for bb clerk)
something without the analysis and incremental computation would probably be reasonable for the bb variant, if you want incremental computation I think it’s better to use the normal clerk
clerk’s viewers could also run all in the browser in a custom scittle build for example
doesn't clerk's bundle already run and come with SCI? why would it not work as is with bb-clerk?
@U5H74UNSF the analysis and incremental computation could also be less sophisticated, e.g. only look at the superficial forms
I think it could still be useful, e.g. when you're making http requests etc to not have to do them over and over (rate-limiting etc)
so far the PR has gotten no interested except for four hearts so unsure there’s a strong user demand
@U02Q6L92FEJ: maybe add a heart ;)
file watcher is solvable in bb using the pod. but also: most people don't use the file watcher probably and we could do without
and that's why I suggested a less sophisticated form of caching: just based on the hash of the superficial s-expression
and 1-file based, ignoring all dependencies. just run clerk/clear-cache when you change a dep
maybe a first goal could be a really simple thing where bb is mainly being used to serve a local file to the browser
@U9EQP1K0X maybe we should submit a talk to bb conf 🙃
or not even hash of s-expression: just the s-expression itself, since you can compare by value
@U5H74UNSF your clerk + bb talk could be a talk about clerk, but also about how to make a library bb-compatible, experience report ;)
What is the right way to render an image inside some Hiccup code? I'm trying to render a chess board?
(ns local.chess-board
"Renders a chess board from a chess position map."
(:require [ :as io]
[nextjournal.clerk :as clerk])
(:import (javax.imageio ImageIO)))
(defn- read-asset [asset-name]
(ImageIO/read (io/file "assets" (str "chess_" (name asset-name) ".png"))))
(def knight (read-asset :knight))
(clerk/html
[:div.bg-black
knight])
I'm having a bit of trouble composing viewers. I have my 4x4 chess board, and code to output it as HTML: https://gist.github.com/hlship/ad554ccfb7bb39e7cce16afb65302b4c And when I create a new board, this seems to work:
But, I want to be able to output HTML that includes the board output. I seem to be hanging browser with:
(clerk/html
(b/render-board (new-board 1 1 :pawn))
(b/render-board (new-board 2 2 :queen)))
I was hoping that there was an automatical way that I can use clerk/html to produce some labels intermixed with HTML output for boards (I want to show a sequence of moves and how the board changes with each one).nice, yeah, clerk/html
does a bit of manipulations on the JVM, prior to sending hiccup data to the client... maybe you could try a sync atom (https://github.com/nextjournal/clerk/blob/9fa6b3761fec5544bacdf4117d0ec9b87b411a40/notebooks/viewers/control_lab.clj#L36-L45 ) which holds board data on the JVM side and have a :render-fn
that takes care of representing your data in the client when the “board model” change (see the link above). I guess the problem here is how to manage the images for the pieces... maybe an SVG format could be more amenable.
@U04VDKC4G thanks for reporting the issue, I think nested calls to clerk/html
don’t work at present. As you figured out, a single outer call against a hiccup vector with interspersed clerk viewers inside it does work.
@U9EQP1K0X guess we could drop the nested html calls?