This is a notespace – a namespace that is a sequence of notes. It is intented to be a tutorial about creating and using notespaces.
It is recommended to read this notespace alongside its rendered result.
To use notespace, require the namespace notespace.v2.note
, bringing the symbols of the relevant note kinds to your own namespace using :refer
. For example, if you want to use notes of kind :md
, you may like to (require '[notespace.v2.note :refer [note-md]])
. More about note kinds – below.
To see your rendered results with a live-reload experience, require the namespace notespace.v2.live-reload
too. This will setup a live-reload server using Ring and Mirador and will open a browser showing the rendered data.
To compute and render the whole notespace, save the file and call:
(notespace.v2.note/compute-this-notespace!)
To compute and rerender a certain note, save the file and call:
(notespace.v2.note/compute-note-at-line! line)
where line
is one of the lines of the file that are taken by that note.
The notespace library is still experimental. In the (not unlikely) case where something breaks, our current recommendation to reset the system's state.
(notespace.v2.note/reset-state!)
Soon things will be more robust.
Sometimes, the live-reload stops happening. A browser refresh sometimes fixes that.
It is handy to be able to invoke the API functions using commands (and keybindings) of your editor. All you need is to figure out how to make your editor call Clojure functions and pass them the current line of the cursor.
In Emacs, one may do this using the following Elisp code:
(defun notespace/compute-note-at-this-line ()
(interactive)
(save-buffer)
(cider-interactive-eval
(concat "(notespace.v2.note/compute-note-at-line! "
(number-to-string (count-lines 1 (point)))
")")
(cider-interactive-eval-handler nil (point))
nil
nil)))
(defun notespace/compute-this-notespace ()
(interactive)
(save-buffer)
(cider-interactive-eval
"(notespace.v2.note/compute-this-notespace!)"
(cider-interactive-eval-handler nil (point))
nil
nil)
We can have all kinds of different notes. The different kinds behave differently when rendered.
This one is a note of kind :md
. When rendered, it renders as markdown and does not show the source string.
The following is a 'regular' note, of kind :code
. When renders, it shows both the source code and the printed return value.
(def x 1) (+ x 1)
2
The following is a note of kind :void
. It shows the source, but does not show the output.
(+ 1 2)
The following is a note of kind :hiccup
. It does not show the source, and renders the return value as hiccup.
Sometimes, we may want to render things as markdown or hiccup, but do want to see the source too. The following two kinds of notes are useful in those cases.
"This is a note of kind `:as-md`. Shows the source, renders as markdown."
This is a note of kind :as-md
. Shows the source, renders as markdown.
The following is a note of kind :as-hiccup
. Shows the source, renders as hiccup.
(->> 4 range (map (fn [i] [:li i])) (into [:ul]))
Here is the summary of the note kinds we mentioned:
kind | symbol | render source? | value-rendering |
---|---|---|---|
:code | note | v | pretty printing |
:void | note-void | v | x |
:md | note-md | x | as markdown |
:as-md | note-as-md | v | as markdown |
:hiccup | note-hiccup | x | as hiccup |
:as-hiccup | note-as-hiccup | v | as hiccup |
In the definition of the following note, we begin with a keyword: :label-example
. This keyword is called the label of the note, and it is not rendered. It creates a link to that note from the table-of-contents.
It may be handy to render data in interactive tables. We have some auxiliary functions to render this using the DataTables JS library.
(require '[notespace.v2.table :as table]) (table/->datatable (for [i (range 99)] {:x i, :y (if (even? i) "a" "b"), :z (rand)}))
x | y | z |
---|---|---|
0 | a | 0.6361780716615545 |
1 | b | 0.7644770537959592 |
2 | a | 0.4886920785040235 |
3 | b | 0.6387305689788544 |
4 | a | 0.9861212687099417 |
5 | b | 0.44394313163413013 |
6 | a | 0.7285023482154864 |
7 | b | 0.9804849021255813 |
8 | a | 0.1273298013557259 |
9 | b | 0.022658529247208015 |
10 | a | 0.640517230384827 |
11 | b | 0.16816465788694868 |
12 | a | 0.7594426477762842 |
13 | b | 0.33557920784374384 |
14 | a | 0.04219345473628877 |
15 | b | 0.22713072077552854 |
16 | a | 0.2646871413363411 |
17 | b | 0.27463054833943545 |
18 | a | 0.26797071278116913 |
19 | b | 0.745043193116581 |
20 | a | 0.8401064405839067 |
21 | b | 0.3623633390335328 |
22 | a | 0.6496746967085532 |
23 | b | 0.3332934056868798 |
24 | a | 0.9007306177297291 |
25 | b | 0.39041457854725103 |
26 | a | 0.702327027773344 |
27 | b | 0.9984705522816368 |
28 | a | 0.7263781454033537 |
29 | b | 0.3330089965057921 |
30 | a | 0.2932252463832967 |
31 | b | 0.927556623077441 |
32 | a | 0.6929386631671927 |
33 | b | 0.9029634833259095 |
34 | a | 0.08094388351638915 |
35 | b | 0.6133928266027976 |
36 | a | 0.3284017820439096 |
37 | b | 0.05613279247031189 |
38 | a | 0.5509474982398552 |
39 | b | 0.9510639699430181 |
40 | a | 0.8645611269334761 |
41 | b | 0.4699622151484303 |
42 | a | 0.0457955134237954 |
43 | b | 0.9211978145866174 |
44 | a | 0.9172363778518059 |
45 | b | 0.5227888209769815 |
46 | a | 0.2904575159081767 |
47 | b | 0.7427782643795166 |
48 | a | 0.42102046504647306 |
49 | b | 0.5827596778479656 |
50 | a | 0.04704698953752773 |
51 | b | 0.9259229716821037 |
52 | a | 0.9689732571553716 |
53 | b | 0.47871225651192195 |
54 | a | 0.6983202659484025 |
55 | b | 0.48417713588886735 |
56 | a | 0.26334650432832807 |
57 | b | 0.8700882153100667 |
58 | a | 0.7555767624550503 |
59 | b | 0.6762274348893558 |
60 | a | 0.47033993322238077 |
61 | b | 0.858928885231274 |
62 | a | 0.5141356582764328 |
63 | b | 0.03854071613101495 |
64 | a | 0.8900511550905329 |
65 | b | 0.594227053174338 |
66 | a | 0.33835281616535107 |
67 | b | 0.14328460264797438 |
68 | a | 0.502197225084001 |
69 | b | 0.8073863534623976 |
70 | a | 0.3481816104645675 |
71 | b | 0.46998796446639024 |
72 | a | 0.6288493166704608 |
73 | b | 0.18726571100587308 |
74 | a | 0.6005693050862092 |
75 | b | 0.014751217616446599 |
76 | a | 0.16733558455511077 |
77 | b | 0.2542638456995152 |
78 | a | 0.21152077410410908 |
79 | b | 0.7774177491260685 |
80 | a | 0.5896323727936814 |
81 | b | 0.9251238382558339 |
82 | a | 0.2484496502505703 |
83 | b | 0.06496945502195861 |
84 | a | 0.17897700993623267 |
85 | b | 0.2736161927903875 |
86 | a | 0.6374764773573444 |
87 | b | 0.6285109277813936 |
88 | a | 0.7801000665140811 |
89 | b | 0.08698360323027421 |
90 | a | 0.7766222988325973 |
91 | b | 0.011558165357516859 |
92 | a | 0.676388807398329 |
93 | b | 0.6940086233521582 |
94 | a | 0.02338502107469509 |
95 | b | 0.128949779318267 |
96 | a | 0.07545762109271192 |
97 | b | 0.19779099152902124 |
98 | a | 0.7339756827548065 |
Graphics can be rendered as hiccup. Here is an example using SVG.
[:svg {:height 100, :width 100} [:circle {:cx 50, :cy 50, :fill "#d7d2c3", :r 40, :stroke "#3e3c3f", :stroke-width 4}]]
Vega or Vega-lite plots can be converted to hiccup and then rendered.
Currently we use darkstar for rendering vega/vega-lite to svg. This is work in progress. The API may change, and eventually we want to support interactive plots using vega.js.
(defn play-data [& names] (for [n names i (range 20)] {:time i, :item n, :quantity (+ (Math/pow (* i (count n)) 0.8) (rand-int (count n)))})) (def line-plot {:width 300, :height 300, :data {:values (play-data "monkey" "slipper" "broom")}, :encoding {:x {:field "time", :type "quantitative"}, :y {:field "quantity", :type "quantitative"}, :color {:field "item", :type "nominal"}}, :mark "line"})
(notespace.v2.vega/vega->svg line-plot :vega-lite)
(def vega-spec {:style "cell", :width 300, :height 300, :data [{:name "source_0", :url "https://vega.github.io/editor/data/cars.json", :format {:type "json"}}], :marks [{:name "marks", :type "symbol", :style ["point"], :from {:data "source_0"}, :encode {:update {:stroke {:scale "color", :field "Origin"}, :x {:scale "x", :field "Horsepower"}, :y {:scale "y", :field "Miles_per_Gallon"}}}}], :scales [{:name "x", :type "linear", :domain {:data "source_0", :field "Horsepower"}, :range [0 {:signal "width"}]} {:name "y", :type "linear", :domain {:data "source_0", :field "Miles_per_Gallon"}, :range [{:signal "height"} 0]} {:name "color", :type "ordinal", :domain {:data "source_0", :field "Origin"}, :range "category"}]})
(notespace.v2.vega/vega->svg vega-spec :vega)
Here is a basic example of how one can include image files in a notespace. In the future we want to provide some less verbose ways to do it.
(def target-path (notespace.v2.note/ns->out-dir *ns*))
(require '[clojure.java.io :as io]) (defn copy "Download a file -- see https://stackoverflow.com/a/19297746/1723677" [uri file] (with-open [in (io/input-stream uri) out (io/output-stream file)] (io/copy in out)))
#'notespace.v2.tutorial-test/copy
(def logo-filename "clojure-logo-120b.png") (def logo-path (str target-path "clojure-logo-120b.png"))
(copy "https://clojure.org/images/clojure-logo-120b.png" logo-path)
nil
One may use the check
function to create tests using arbitrary functions.
(->> (+ 1 2) (check = 3))
[:PASSED 3]
(check pos? -9)
[:FAILED -9]