2 Kindly
Kindly is a standard for requesting data visualizations in Clojure.
It specifies in what kinds of way Clojure forms and values should be displayed.
ns kindly
(:require [scicloj.kindly.v4.api :as kindly]
(:as kind]
[scicloj.kindly.v4.kind :as tc])) [tablecloth.api
2.1 Why
Different tools have had different ways of writing notes. For example:
- Anglican tutorials (source) - written in Gorilla REPL
- thi-ng/geom viz examples (source) - written in Org-babel-clojure
- Clojure2d docs (source1, source2) - written in Codox and Metadoc
- Tablecloth API docs (source) - written in rmarkdown-clojure
- R interop ClojisR examples (source) - written in Notespace v2
- Bayesian optimization tutorial (source) - written in Nextjournal
- scicloj.ml tutorials (source) - written in Notespace v3
- Clojure2d color tutorial (source) - written in Clerk
- Tablecloth documentation (source) - written in Kindly using Clay
- …
2.2 Goal
- Have a standard way to request data visualizations
- for blog posts, books, slideshows, reports, dashboards, and interactive analyses,
- that just will work across different tools,
- without even mentioning those tools in the code.
- We aim for copy/paste compatibility of visualisation code accross different tools:
- as it is a given for normal Clojure code producing textual output in a text oriented repl,
- visualisation code working in one tool should produce the same or very similar result in all compatible tools.
2.3 Status
- supported by Clay
- implemented a partially working adapter for Portal (kind-portal)
- implemented a partially working adapter for Clerk (kind-clerk)
- actively working to support other tools such as Cursive, Calva, and Clojupyter
2.4 Existing book/notebook projects using Kindly
- Tablecloth documentation
- Fastmath 3 documentation
- ClojisR documentation
- Wolframite documentation
- Clay documentation
- Kindly-noted - documenting the ecosystem around Kindly - WIP
- Noj documentation - WIP
- Clojure Tidy Tuesdays data-science explorations
- Clojure Data Tutorials
- Clojure Data Scrapbook
- LLMs tutorial (in spanish) by Kyle Passarelli
- Statistical Computing in Clojure: Functional Approaches to Unsupervised Learning by Jaryt Salvo
2.5 Example
Here is how one may request something of kind/md
, which means Markdown:
(kind/md"hello *hello* **hello**")
hello hello hello
2.6 The set of kinds
sort kindly/known-kinds) (
:kind/code
(:kind/cytoscape
:kind/dataset
:kind/echarts
:kind/edn
:kind/emmy-viewers
:kind/fn
:kind/fragment
:kind/hiccup
:kind/hidden
:kind/highcharts
:kind/html
:kind/htmlwidgets-ggplotly
:kind/htmlwidgets-plotly
:kind/image
:kind/map
:kind/md
:kind/mermaid
:kind/observable
:kind/plotly
:kind/portal
:kind/pprint
:kind/println
:kind/reagent
:kind/scittle
:kind/seq
:kind/set
:kind/smile-model
:kind/table
:kind/test
:kind/test-last
:kind/tex
:kind/var
:kind/vector
:kind/vega
:kind/vega-lite
:kind/video)
You can find more (details and examples of using these kinds)[/kindly-noted/kinds.html] in the Kindly book.
2.7 How to use Kinds?
2.7.1 Attaching metadata to forms
:kind/md
^"hello *hello* **hello**"] [
hello hello hello
^kind/md"hello *hello* **hello**"] [
hello hello hello
2.7.2 Attaching metadata to values
-> ["hello *hello* **hello**"]
( kind/md)
hello hello hello
-> ["hello *hello* **hello**"]
(
kind/mdmeta
:kindly/kind)
:kind/md
2.7.3 Attaching metadata to values - cont.
-> "hello *hello* **hello**"
(
kind/mdmeta
:kindly/kind)
:kind/md
Values that cannot have metadata are wrapped in a vector before attaching metadata.
-> "hello *hello* **hello**"
(
kind/md kind/pprint)
"hello *hello* **hello**"] [
-> "hello *hello* **hello**"
(
kind/mdmeta)
:kindly{:kind :kind/md, :options {:wrapped-value true}} #
2.7.4 Using values annotated by libraries
defn my-library-function-for-big-big-text [text]
(
(kind/hiccup:big {:style {:background "#ccddcc"}}
[:big text]])) [
-> "hello"
( my-library-function-for-big-big-text)
-> "hello"
(
my-library-function-for-big-big-textassoc-in [1 :style]
(:background "#ddccdd"})) {
2.7.5 Automatically-inferred kinds
In certain situations, kinds are inferred without annotation. The kindly-advice library provides the default inference behaviour and an option to extend it.
For example, images:
def clj-image
(-> "https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_Tree_-_geograph.org.uk_-_590710.jpg"
(
(java.net.URL.) (javax.imageio.ImageIO/read)))
Can’t get input stream from URL! Server returned HTTP response code: 403 for URL: https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_Tree_-geograph.org.uk-_590710.jpg
clojure.core/eval core.clj: 3215
...
jdk.internal.reflect.DirectMethodHandleAccessor.invoke DirectMethodHandleAccessor.java: 103
javax.imageio.ImageIO.read ImageIO.java: 1405
java.net.URL.openStream URL.java: 1325
sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream HttpsURLConnectionImpl.java: 223
sun.net.www.protocol.http.HttpURLConnection.getInputStream HttpURLConnection.java: 1615
sun.net.www.protocol.http.HttpURLConnection.getInputStream0 HttpURLConnection.java: 2014
java.io.IOException: Server returned HTTP response code: 403 for URL: https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_Tree_-_geograph.org.uk_-_590710.jpg
javax.imageio.IIOException: Can't get input stream from URL!
clojure.lang.Compiler$CompilerException: Syntax error macroexpanding at (dev.clj:137:8).
data: #:clojure.error{:phase :execution,
:line 137,
:column 8,
:source "dev.clj"}
source: notebooks/kindly.clj