diff --git a/docs/index.html b/docs/index.html index f9157206..562f5ee5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -77,20 +77,7 @@ } */ } -
.
(credit: Wikimedia Commons)
Clay is a minimalistic Clojure tool for data visualization and literate programming, compatible with the Kindly convention.
Also see the Babashka Conf 2023 talk.
Easily explore & share things for others to easily pick & use.
Encourage writing Kindly-compatible notes for future compatiblity with other tools.
Flow with the REPL: encourage user interactions that flow naturally with the typical use of Clojure in editors and REPLs.
See the example project for a concrete example. To enjoy Clay's dynamic interaction, you also need to inform it about code evaluations. This requires some setup at the your editor.
See the suggested setup for popular editors below. If your favourite editor is not supported yet, let us talk and make it work.
(to be updated soon)
Please add the following command to your keybindings.json
file at the VScode setup (you may pick another key, of course). This command would evaluate a piece of code and send the result to be visualized in Clay.
{ -"key": "ctrl+shift+enter", -"command": "calva.runCustomREPLCommand", -"args": "(scicloj.clay.v2.api/handle-form! (quote $current-form))" -} -
(to be updated soon)
Please load clay.el at your Emacs config.
It offers the following functions, that you may wish to create keybindings for:
name | function |
---|---|
clay/start | start clay if not started yet |
clay/show-namespace | save clj buffer and render it in the browser view |
clay/show-namespace-and-write-html | save clj buffer, render it in the browser view, and save the result as html |
clay/write-quarto | save clj buffer, and generate a Quarto mardkown document |
clay/render-quarto | save clj buffer, generate a Quarto markdown document, render it as HTML, and show it in the browser view |
clay/send | send a single clj form to be rendered in the browser view |
clay/send-last-sexp | send the last s-expression |
clay/send-defun-at-point | send the defun-at-point |
Under preferences, search for "REPL Commands" (or use the menu IntelliJ -> Preferences -> Languages and Frameworks -> Clojure -> REPL Commands)
Then add a global command, and edit it with these settings:
Name: | Send top-level to Clay |
Before Execution: | "Do nothing" |
Execution: | Command (scicloj.clay.v2.api/handle-form! (quote ~top-level-form)) |
Echo to REPL: | Executed form |
Execution namespace: | Current REPL namespace |
It is useful to add 3 commands:
(scicloj.clay.v2.api/handle-form! (quote ~top-level-form))
(scicloj.clay.v2.api/handle-form! (quote ~form-before-caret))
(scicloj.clay.v2.api/show-namespace-and-write-html! "~file-path")
You can then add keybindings under Preferences -> Keymap for the new commands.
See the Cursive documentation on REPL commands and substitutions for more details.
Now, we can write a namespace and play with Clay.
(ns index
- (:require [scicloj.clay.v2.api :as clay]
- [scicloj.kindly.v4.api :as kindly]
- [scicloj.kindly.v4.kind :as kind]))
(defonce memoized-slurp
- (memoize slurp))
nil
-
Let us set up Clay.
(clay/swap-options!
- assoc
- :remote-repo {:git-url "https://github.com/scicloj/clay"
- :branch "main"}
- :quarto {:format {:html {:toc true
- :theme :spacelab}}
- :highlight-style :solarized
- :code-block-background true
- :embed-resources false
- :execute {:freeze true}})
:ok
-
These initializations can also be done in a user.clj
file, making them available for all namespaces in the project. The browser view should open automatically.
Showing the whole namespace:
(comment
- (clay/show-doc! "notebooks/index.clj"))
Writing the document:
(comment
- (clay/show-doc-and-write-html!
- "notebooks/index.clj"
- {:toc? true}))
Reopening the Clay view in the browser (in case you closed the browser tab previously opened by clay/start!
)
(comment
- (clay/browse!))
These can be conveniently bound to functions and keys at your editor (to b documented soon).
Clay responds to user evaluations by displaying the result visually.
(+ 1111 2222)
3333
-
In Emacs CIDER, after evaluation of a form (or a region), the browser view should show the evaluation result. In VSCode Calva, a similar effect can be achieved using the dedicated command and keybinding defined above.
The way things should be visualized is determined by the advice of Kindly. In this namespace we demonstrate Kindly's default advice. User-defined Kindly advices should work as well. Kindly advises tools (like Clay) about the kind of way a given context should be displayed, by assigning to it a so-called kind. Please refer to the Kindly documentation for details about specifying and using kinds.
By default, when there is no kind information provided by Kindly, values are simply pretty-printed.
(+ 4 5)
9
-
(str "abcd" "efgh")
"abcdefgh"
-
Hiccup, a popular Clojure way to represent HTML, can be specified by kind:
(kind/hiccup
- [:ul
- [:li [:p "hi"]]
- [:li [:big [:big [:p {:style ; https://www.htmlcsscolor.com/hex/7F5F3F
- {:color "#7F5F3F"}}
- "hello"]]]]])
hi
hello
As we can see, this kind is displayed by converting Hiccup to HTML.
Markdown text (a vector of strings) can be handled using a kind too.
(kind/md
- ["
-* This is [markdown](https://www.markdownguide.org/).
- * *Isn't it??*"
- "
-* Here is **some more** markdown."])
This is markdown.
Isn't it??
Here is some more markdown.
As we can see, this kind is displayed by converting Hiccup to HTML.
Java BufferedImage objects are displayed as images.
(import javax.imageio.ImageIO
- java.net.URL)
java.net.URL
-
(defonce clay-image
- (-> "https://upload.wikimedia.org/wikipedia/commons/2/2c/Clay-ss-2005.jpg"
- (URL.)
- (ImageIO/read)))
nil
-
clay-image
Plain data structures (lists and sequnces, vectors, sets, maps) are pretty printed if there isn't any value inside which needs to be displayed in special kind of way.
(def people-as-maps
- (->> (range 29)
- (mapv (fn [i]
- {:preferred-language (["clojure" "clojurescript" "babashka"]
- (rand-int 3))
- :age (rand-int 100)}))))
(def people-as-vectors
- (->> people-as-maps
- (mapv (juxt :preferred-language :age))))
(take 5 people-as-maps)
({:preferred-language "clojurescript", :age 59}
- {:preferred-language "babashka", :age 53}
- {:preferred-language "babashka", :age 17}
- {:preferred-language "clojure", :age 36}
- {:preferred-language "clojure", :age 80})
-
(take 5 people-as-vectors)
(["clojurescript" 59]
- ["babashka" 53]
- ["babashka" 17]
- ["clojure" 36]
- ["clojure" 80])
-
(->> people-as-vectors
- (take 5)
- set)
#{["clojure" 80]
- ["babashka" 17]
- ["clojurescript" 59]
- ["clojure" 36]
- ["babashka" 53]}
-
When something inside needs to be displayed in a special kind of way, the data structures are printed in a way that makes that clear.
(def nested-structure-1
- {:vector-of-numbers [2 9 -1]
- :vector-of-different-things ["hi"
- (kind/hiccup
- [:big [:big "hello"]])]
- :map-of-different-things {:markdown (kind/md ["*hi*, **hi**"])
- :number 9999}
- :hiccup (kind/hiccup
- [:big [:big "bye"]])})
nested-structure-1
|
|
| [
|
| {
|
| bye |
The :kind/pprint
kind makes sure to simply pretty-print values:
(kind/pprint nested-structure-1)
{:vector-of-numbers [2 9 -1],
- :vector-of-different-things ["hi" [:big [:big "hello"]]],
- :map-of-different-things {:markdown ["*hi*, **hi**"], :number 9999},
- :hiccup [:big [:big "bye"]]}
-
tech.ml.dataset datasets currently use the default printing of the library, Let us create such a dataset using Tablecloth.
(require '[tablecloth.api :as tc])
nil
-
(-> {:x (range 6)
- :y [:A :B :C :A :B :C]}
- tc/dataset)
_unnamed [6 2]:
:x | :y |
---|---|
0 | :A |
1 | :B |
2 | :C |
3 | :A |
4 | :B |
5 | :C |
(-> {:x [1 [2 3] 4]
- :y [:A :B :C]}
- tc/dataset)
_unnamed [3 2]:
:x | :y |
---|---|
1 | :A |
[2 3] | :B |
4 | :C |
(-> [{:x 1 :y 2 :z 3}
- {:y 4 :z 5}]
- tc/dataset)
_unnamed [2 3]:
:x | :y | :z |
---|---|---|
1 | 2 | 3 |
4 | 5 |
(-> people-as-maps
- tc/dataset)
_unnamed [29 2]:
:preferred-language | :age |
---|---|
clojurescript | 59 |
babashka | 53 |
babashka | 17 |
clojure | 36 |
clojure | 80 |
clojurescript | 59 |
clojure | 81 |
clojurescript | 32 |
clojure | 77 |
clojure | 9 |
... | ... |
babashka | 39 |
babashka | 3 |
clojure | 29 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 14 |
clojurescript | 2 |
clojure | 53 |
clojure | 46 |
clojure | 41 |
babashka | 69 |
The :kind/table
kind can be handy for an interactive table view.
(kind/table
- {:column-names [:preferred-language :age]
- :row-vectors people-as-vectors})
preferred-language | age |
---|---|
clojurescript | 59 |
babashka | 53 |
babashka | 17 |
clojure | 36 |
clojure | 80 |
clojurescript | 59 |
clojure | 81 |
clojurescript | 32 |
clojure | 77 |
clojure | 9 |
clojure | 21 |
clojure | 78 |
clojurescript | 13 |
clojure | 49 |
clojurescript | 20 |
clojurescript | 99 |
clojurescript | 79 |
babashka | 68 |
babashka | 39 |
babashka | 3 |
clojure | 29 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 14 |
clojurescript | 2 |
clojure | 53 |
clojure | 46 |
clojure | 41 |
babashka | 69 |
(kind/table
- {:column-names [:preferred-language :age]
- :row-maps people-as-maps})
preferred-language | age |
---|---|
clojurescript | 59 |
babashka | 53 |
babashka | 17 |
clojure | 36 |
clojure | 80 |
clojurescript | 59 |
clojure | 81 |
clojurescript | 32 |
clojure | 77 |
clojure | 9 |
clojure | 21 |
clojure | 78 |
clojurescript | 13 |
clojure | 49 |
clojurescript | 20 |
clojurescript | 99 |
clojurescript | 79 |
babashka | 68 |
babashka | 39 |
babashka | 3 |
clojure | 29 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 14 |
clojurescript | 2 |
clojure | 53 |
clojure | 46 |
clojure | 41 |
babashka | 69 |
(kind/table
- {:column-names [:preferred-language :age]
- :row-maps (take 5 people-as-maps)})
preferred-language | age |
---|---|
clojurescript | 59 |
babashka | 53 |
babashka | 17 |
clojure | 36 |
clojure | 80 |
(-> people-as-maps
- tc/dataset
- kind/table)
preferred-language | age |
---|---|
clojurescript | 59 |
babashka | 53 |
babashka | 17 |
clojure | 36 |
clojure | 80 |
clojurescript | 59 |
clojure | 81 |
clojurescript | 32 |
clojure | 77 |
clojure | 9 |
clojure | 21 |
clojure | 78 |
clojurescript | 13 |
clojure | 49 |
clojurescript | 20 |
clojurescript | 99 |
clojurescript | 79 |
babashka | 68 |
babashka | 39 |
babashka | 3 |
clojure | 29 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 14 |
clojurescript | 2 |
clojure | 53 |
clojure | 46 |
clojure | 41 |
babashka | 69 |
(defn vega-lite-point-plot [data]
- (-> {:data {:values data},
- :mark "point"
- :encoding
- {:size {:field "w" :type "quantitative"}
- :x {:field "x", :type "quantitative"},
- :y {:field "y", :type "quantitative"},
- :fill {:field "z", :type "nominal"}}}
- kind/vega-lite))
(defn random-data [n]
- (->> (repeatedly n #(- (rand) 0.5))
- (reductions +)
- (map-indexed (fn [x y]
- {:w (rand-int 9)
- :z (rand-int 9)
- :x x
- :y y}))))
(defn random-vega-lite-plot [n]
- (-> n
- random-data
- vega-lite-point-plot))
(random-vega-lite-plot 9)
Clojure Delays are a common way to define computations that do not take place immediately. The computation takes place when dereferencing the value for the first time. Clay makes sure to dererence Delays when passing values for visualization. This is handy for slow example snippets and explorations, that one would typically not like to slow down the evaluation of the whole namespace, but would like to visualize them on demand and also include in them in the final document.
(delay
- (Thread/sleep 500)
- (+ 1 2))
3
-
(kind/portal {:x (range 3)})
(kind/portal
- [(-> [:img {:height 50 :width 50
- :src "https://clojure.org/images/clojure-logo-120b.png"}]
- kind/hiccup)
- (-> [:img {:height 50 :width 50
- :src "https://raw.githubusercontent.com/djblue/portal/fbc54632adc06c6e94a3d059c858419f0063d1cf/resources/splash.svg"}]
- kind/hiccup)])
(kind/portal
- [(kind/hiccup [:big [:big "a plot"]])
- (random-vega-lite-plot 9)])
(kind/hiccup
- [:div {:style {:background "#f5f3ff"
- :border "solid"}}
-
- [:hr]
- [:h3 [:code ":kind/md"]]
- (kind/md "*some text* **some more text**")
-
- [:hr]
- [:h3 [:code ":kind/code"]]
- (kind/code "{:x (1 2 [3 4])}")
-
- [:hr]
- [:h3 [:code "kind/dataset"]]
- (tc/dataset {:x (range 33)
- :y (map inc (range 33))})
-
- [:hr]
- [:h3 [:code "kind/table"]]
- (kind/table
- (tc/dataset {:x (range 33)
- :y (map inc (range 33))}))
-
- [:hr]
- [:h3 [:code "kind/vega"]]
- (random-vega-lite-plot 9)])
:kind/md
some text some more text
:kind/code
{:x (1 2 [3 4])}
kind/dataset
_unnamed [33 2]:
:x | :y |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
9 | 10 |
... | ... |
22 | 23 |
23 | 24 |
24 | 25 |
25 | 26 |
26 | 27 |
27 | 28 |
28 | 29 |
29 | 30 |
30 | 31 |
31 | 32 |
32 | 33 |
kind/table
x | y |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
9 | 10 |
10 | 11 |
11 | 12 |
12 | 13 |
13 | 14 |
14 | 15 |
15 | 16 |
16 | 17 |
17 | 18 |
18 | 19 |
19 | 20 |
20 | 21 |
21 | 22 |
22 | 23 |
23 | 24 |
24 | 25 |
25 | 26 |
26 | 27 |
27 | 28 |
28 | 29 |
29 | 30 |
30 | 31 |
31 | 32 |
32 | 33 |
kind/vega
(kind/table
- {:column-names [:x :y]
- :row-vectors [[(kind/md "*some text* **some more text**")
- (kind/code "{:x (1 2 [3 4])}")]
- [(tc/dataset {:x (range 3)
- :y (map inc (range 3))})
- (random-vega-lite-plot 9)]]})
x | y | ||||||||
---|---|---|---|---|---|---|---|---|---|
some text some more text |
| ||||||||
_unnamed [3 2]:
|
In the past, Clay used to support various data visualization libraries such as ECharts, Cytoscape, Plotly, Leaflet, 3DMol, MathBox, and KaTeX.
These have been disabled in a recent refactoring (Oct. 2023) and will be brought back soon.
.
(credit: Wikimedia Commons)
Clay is a minimalistic Clojure tool for data visualization and literate programming, compatible with the Kindly convention.
Also see the Babashka Conf 2023 talk.
Easily explore & share things for others to easily pick & use.
Encourage writing Kindly-compatible notes for future compatiblity with other tools.
Flow with the REPL: encourage user interactions that flow naturally with the typical use of Clojure in editors and REPLs.
See the example project for a concrete example. To enjoy Clay's dynamic interaction, you also need to inform it about code evaluations. This requires some setup at the your editor.
See the suggested setup for popular editors below. If your favourite editor is not supported yet, let us talk and make it work.
(to be updated soon)
Please add the following command to your keybindings.json
file at the VScode setup (you may pick another key, of course). This command would evaluate a piece of code and send the result to be visualized in Clay.
{ +"key": "ctrl+shift+enter", +"command": "calva.runCustomREPLCommand", +"args": "(scicloj.clay.v2.api/handle-form! (quote $current-form))" +} +
(to be updated soon)
Please load clay.el at your Emacs config.
It offers the following functions, that you may wish to create keybindings for:
name | function |
---|---|
clay/start | start clay if not started yet |
clay/show-namespace | save clj buffer and render it in the browser view |
clay/show-namespace-and-write-html | save clj buffer, render it in the browser view, and save the result as html |
clay/write-quarto | save clj buffer, and generate a Quarto mardkown document |
clay/render-quarto | save clj buffer, generate a Quarto markdown document, render it as HTML, and show it in the browser view |
clay/send | send a single clj form to be rendered in the browser view |
clay/send-last-sexp | send the last s-expression |
clay/send-defun-at-point | send the defun-at-point |
Under preferences, search for "REPL Commands" (or use the menu IntelliJ -> Preferences -> Languages and Frameworks -> Clojure -> REPL Commands)
Then add a global command, and edit it with these settings:
Name: | Send top-level to Clay |
Before Execution: | "Do nothing" |
Execution: | Command (scicloj.clay.v2.api/handle-form! (quote ~top-level-form)) |
Echo to REPL: | Executed form |
Execution namespace: | Current REPL namespace |
It is useful to add 3 commands:
(scicloj.clay.v2.api/handle-form! (quote ~top-level-form))
(scicloj.clay.v2.api/handle-form! (quote ~form-before-caret))
(scicloj.clay.v2.api/show-namespace-and-write-html! "~file-path")
You can then add keybindings under Preferences -> Keymap for the new commands.
See the Cursive documentation on REPL commands and substitutions for more details.
Now, we can write a namespace and play with Clay.
(ns index
+ (:require [scicloj.clay.v2.api :as clay]
+ [scicloj.kindly.v4.api :as kindly]
+ [scicloj.kindly.v4.kind :as kind]))
(defonce memoized-slurp
+ (memoize slurp))
nil
+
Let us set up Clay.
(clay/swap-options!
+ assoc
+ :remote-repo {:git-url "https://github.com/scicloj/clay"
+ :branch "main"}
+ :quarto {:format {:html {:toc true
+ :theme :spacelab}}
+ :highlight-style :solarized
+ :code-block-background true
+ :embed-resources false
+ :execute {:freeze true}})
:ok
+
These initializations can also be done in a user.clj
file, making them available for all namespaces in the project. The browser view should open automatically.
Showing the whole namespace:
(comment
+ (clay/show-doc! "notebooks/index.clj"))
Writing the document:
(comment
+ (clay/show-doc-and-write-html!
+ "notebooks/index.clj"
+ {:toc? true}))
Reopening the Clay view in the browser (in case you closed the browser tab previously opened by clay/start!
)
(comment
+ (clay/browse!))
These can be conveniently bound to functions and keys at your editor (to b documented soon).
Clay responds to user evaluations by displaying the result visually.
(+ 1111 2222)
3333
+
In Emacs CIDER, after evaluation of a form (or a region), the browser view should show the evaluation result. In VSCode Calva, a similar effect can be achieved using the dedicated command and keybinding defined above.
The way things should be visualized is determined by the advice of Kindly. In this namespace we demonstrate Kindly's default advice. User-defined Kindly advices should work as well. Kindly advises tools (like Clay) about the kind of way a given context should be displayed, by assigning to it a so-called kind. Please refer to the Kindly documentation for details about specifying and using kinds.
By default, when there is no kind information provided by Kindly, values are simply pretty-printed.
(+ 4 5)
9
+
(str "abcd" "efgh")
"abcdefgh"
+
Hiccup, a popular Clojure way to represent HTML, can be specified by kind:
(kind/hiccup
+ [:ul
+ [:li [:p "hi"]]
+ [:li [:big [:big [:p {:style ; https://www.htmlcsscolor.com/hex/7F5F3F
+ {:color "#7F5F3F"}}
+ "hello"]]]]])
hi
hello
As we can see, this kind is displayed by converting Hiccup to HTML.
(kind/reagent
+ ['(fn [numbers]
+ [:p {:style {:background "#d4ebe9"}}
+ (pr-str (map inc numbers))])
+ (vec (range 40))])
Markdown text (a vector of strings) can be handled using a kind too.
(kind/md
+ ["
+* This is [markdown](https://www.markdownguide.org/).
+ * *Isn't it??*"
+ "
+* Here is **some more** markdown."])
This is markdown.
Isn't it??
Here is some more markdown.
As we can see, this kind is displayed by converting Hiccup to HTML.
Java BufferedImage objects are displayed as images.
(import javax.imageio.ImageIO
+ java.net.URL)
java.net.URL
+
(defonce clay-image
+ (-> "https://upload.wikimedia.org/wikipedia/commons/2/2c/Clay-ss-2005.jpg"
+ (URL.)
+ (ImageIO/read)))
nil
+
clay-image
Plain data structures (lists and sequnces, vectors, sets, maps) are pretty printed if there isn't any value inside which needs to be displayed in special kind of way.
(def people-as-maps
+ (->> (range 29)
+ (mapv (fn [i]
+ {:preferred-language (["clojure" "clojurescript" "babashka"]
+ (rand-int 3))
+ :age (rand-int 100)}))))
(def people-as-vectors
+ (->> people-as-maps
+ (mapv (juxt :preferred-language :age))))
(take 5 people-as-maps)
({:preferred-language "babashka", :age 58}
+ {:preferred-language "clojure", :age 14}
+ {:preferred-language "clojurescript", :age 7}
+ {:preferred-language "babashka", :age 28}
+ {:preferred-language "clojure", :age 23})
+
(take 5 people-as-vectors)
(["babashka" 58]
+ ["clojure" 14]
+ ["clojurescript" 7]
+ ["babashka" 28]
+ ["clojure" 23])
+
(->> people-as-vectors
+ (take 5)
+ set)
#{["clojurescript" 7]
+ ["babashka" 28]
+ ["babashka" 58]
+ ["clojure" 14]
+ ["clojure" 23]}
+
When something inside needs to be displayed in a special kind of way, the data structures are printed in a way that makes that clear.
(def nested-structure-1
+ {:vector-of-numbers [2 9 -1]
+ :vector-of-different-things ["hi"
+ (kind/hiccup
+ [:big [:big "hello"]])]
+ :map-of-different-things {:markdown (kind/md ["*hi*, **hi**"])
+ :number 9999}
+ :hiccup (kind/hiccup
+ [:big [:big "bye"]])})
nested-structure-1
|
|
| [
|
| {
|
| bye |
The :kind/pprint
kind makes sure to simply pretty-print values:
(kind/pprint nested-structure-1)
{:vector-of-numbers [2 9 -1],
+ :vector-of-different-things ["hi" [:big [:big "hello"]]],
+ :map-of-different-things {:markdown ["*hi*, **hi**"], :number 9999},
+ :hiccup [:big [:big "bye"]]}
+
tech.ml.dataset datasets currently use the default printing of the library, Let us create such a dataset using Tablecloth.
(require '[tablecloth.api :as tc])
nil
+
(-> {:x (range 6)
+ :y [:A :B :C :A :B :C]}
+ tc/dataset)
_unnamed [6 2]:
:x | :y |
---|---|
0 | :A |
1 | :B |
2 | :C |
3 | :A |
4 | :B |
5 | :C |
(-> {:x [1 [2 3] 4]
+ :y [:A :B :C]}
+ tc/dataset)
_unnamed [3 2]:
:x | :y |
---|---|
1 | :A |
[2 3] | :B |
4 | :C |
(-> [{:x 1 :y 2 :z 3}
+ {:y 4 :z 5}]
+ tc/dataset)
_unnamed [2 3]:
:x | :y | :z |
---|---|---|
1 | 2 | 3 |
4 | 5 |
(-> people-as-maps
+ tc/dataset)
_unnamed [29 2]:
:preferred-language | :age |
---|---|
babashka | 58 |
clojure | 14 |
clojurescript | 7 |
babashka | 28 |
clojure | 23 |
clojurescript | 35 |
babashka | 23 |
babashka | 85 |
clojure | 49 |
clojure | 75 |
... | ... |
babashka | 5 |
clojurescript | 84 |
clojurescript | 58 |
clojure | 66 |
babashka | 67 |
clojurescript | 61 |
babashka | 46 |
clojurescript | 10 |
clojurescript | 93 |
babashka | 88 |
babashka | 20 |
The :kind/table
kind can be handy for an interactive table view.
(kind/table
+ {:column-names [:preferred-language :age]
+ :row-vectors people-as-vectors})
preferred-language | age |
---|---|
babashka | 58 |
clojure | 14 |
clojurescript | 7 |
babashka | 28 |
clojure | 23 |
clojurescript | 35 |
babashka | 23 |
babashka | 85 |
clojure | 49 |
clojure | 75 |
clojurescript | 8 |
clojure | 58 |
clojurescript | 56 |
clojure | 41 |
clojure | 48 |
clojurescript | 27 |
babashka | 53 |
clojure | 46 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 58 |
clojure | 66 |
babashka | 67 |
clojurescript | 61 |
babashka | 46 |
clojurescript | 10 |
clojurescript | 93 |
babashka | 88 |
babashka | 20 |
(kind/table
+ {:column-names [:preferred-language :age]
+ :row-maps people-as-maps})
preferred-language | age |
---|---|
babashka | 58 |
clojure | 14 |
clojurescript | 7 |
babashka | 28 |
clojure | 23 |
clojurescript | 35 |
babashka | 23 |
babashka | 85 |
clojure | 49 |
clojure | 75 |
clojurescript | 8 |
clojure | 58 |
clojurescript | 56 |
clojure | 41 |
clojure | 48 |
clojurescript | 27 |
babashka | 53 |
clojure | 46 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 58 |
clojure | 66 |
babashka | 67 |
clojurescript | 61 |
babashka | 46 |
clojurescript | 10 |
clojurescript | 93 |
babashka | 88 |
babashka | 20 |
(kind/table
+ {:column-names [:preferred-language :age]
+ :row-maps (take 5 people-as-maps)})
preferred-language | age |
---|---|
babashka | 58 |
clojure | 14 |
clojurescript | 7 |
babashka | 28 |
clojure | 23 |
(-> people-as-maps
+ tc/dataset
+ kind/table)
preferred-language | age |
---|---|
babashka | 58 |
clojure | 14 |
clojurescript | 7 |
babashka | 28 |
clojure | 23 |
clojurescript | 35 |
babashka | 23 |
babashka | 85 |
clojure | 49 |
clojure | 75 |
clojurescript | 8 |
clojure | 58 |
clojurescript | 56 |
clojure | 41 |
clojure | 48 |
clojurescript | 27 |
babashka | 53 |
clojure | 46 |
babashka | 5 |
clojurescript | 84 |
clojurescript | 58 |
clojure | 66 |
babashka | 67 |
clojurescript | 61 |
babashka | 46 |
clojurescript | 10 |
clojurescript | 93 |
babashka | 88 |
babashka | 20 |
(defn vega-lite-point-plot [data]
+ (-> {:data {:values data},
+ :mark "point"
+ :encoding
+ {:size {:field "w" :type "quantitative"}
+ :x {:field "x", :type "quantitative"},
+ :y {:field "y", :type "quantitative"},
+ :fill {:field "z", :type "nominal"}}}
+ kind/vega-lite))
(defn random-data [n]
+ (->> (repeatedly n #(- (rand) 0.5))
+ (reductions +)
+ (map-indexed (fn [x y]
+ {:w (rand-int 9)
+ :z (rand-int 9)
+ :x x
+ :y y}))))
(defn random-vega-lite-plot [n]
+ (-> n
+ random-data
+ vega-lite-point-plot))
(random-vega-lite-plot 9)
Clojure Delays are a common way to define computations that do not take place immediately. The computation takes place when dereferencing the value for the first time. Clay makes sure to dererence Delays when passing values for visualization. This is handy for slow example snippets and explorations, that one would typically not like to slow down the evaluation of the whole namespace, but would like to visualize them on demand and also include in them in the final document.
(delay
+ (Thread/sleep 500)
+ (+ 1 2))
3
+
(kind/portal {:x (range 3)})
(kind/portal
+ [(-> [:img {:height 50 :width 50
+ :src "https://clojure.org/images/clojure-logo-120b.png"}]
+ kind/hiccup)
+ (-> [:img {:height 50 :width 50
+ :src "https://raw.githubusercontent.com/djblue/portal/fbc54632adc06c6e94a3d059c858419f0063d1cf/resources/splash.svg"}]
+ kind/hiccup)])
(kind/portal
+ [(kind/hiccup [:big [:big "a plot"]])
+ (random-vega-lite-plot 9)])
(kind/hiccup
+ [:div {:style {:background "#f5f3ff"
+ :border "solid"}}
+
+ [:hr]
+ [:h3 [:code ":kind/md"]]
+ (kind/md "*some text* **some more text**")
+
+ [:hr]
+ [:h3 [:code ":kind/code"]]
+ (kind/code "{:x (1 2 [3 4])}")
+
+ [:hr]
+ [:h3 [:code "kind/dataset"]]
+ (tc/dataset {:x (range 33)
+ :y (map inc (range 33))})
+
+ [:hr]
+ [:h3 [:code "kind/table"]]
+ (kind/table
+ (tc/dataset {:x (range 33)
+ :y (map inc (range 33))}))
+
+ [:hr]
+ [:h3 [:code "kind/vega"]]
+ (random-vega-lite-plot 9)])
:kind/md
some text some more text
:kind/code
{:x (1 2 [3 4])}
kind/dataset
_unnamed [33 2]:
:x | :y |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
9 | 10 |
... | ... |
22 | 23 |
23 | 24 |
24 | 25 |
25 | 26 |
26 | 27 |
27 | 28 |
28 | 29 |
29 | 30 |
30 | 31 |
31 | 32 |
32 | 33 |
kind/table
x | y |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
9 | 10 |
10 | 11 |
11 | 12 |
12 | 13 |
13 | 14 |
14 | 15 |
15 | 16 |
16 | 17 |
17 | 18 |
18 | 19 |
19 | 20 |
20 | 21 |
21 | 22 |
22 | 23 |
23 | 24 |
24 | 25 |
25 | 26 |
26 | 27 |
27 | 28 |
28 | 29 |
29 | 30 |
30 | 31 |
31 | 32 |
32 | 33 |
kind/vega
(kind/table
+ {:column-names [:x :y]
+ :row-vectors [[(kind/md "*some text* **some more text**")
+ (kind/code "{:x (1 2 [3 4])}")]
+ [(tc/dataset {:x (range 3)
+ :y (map inc (range 3))})
+ (random-vega-lite-plot 9)]]})
x | y | ||||||||
---|---|---|---|---|---|---|---|---|---|
some text some more text |
| ||||||||
_unnamed [3 2]:
|
In the past, Clay used to support various data visualization libraries such as ECharts, Cytoscape, Plotly, Leaflet, 3DMol, MathBox, and KaTeX.
These have been disabled in a recent refactoring (Oct. 2023) and will be brought back soon.