notespace.v2.tutorial-test

notespace.v2.tutorial-test - created by notespace, Thu Apr 30 17:34:06 CEST 2020.
Checks: 1 PASSED 1 FAILED
Table of contents

Intro

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.

Computing and rendering

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.

Editor integration.

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)

Note kinds

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:

kindsymbolrender source?value-rendering
:codenotevpretty printing
:voidnote-voidvx
:mdnote-mdxas markdown
:as-mdnote-as-mdvas markdown
:hiccupnote-hiccupxas hiccup
:as-hiccupnote-as-hiccupvas hiccup

Labels

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.

(+ 1 2)
3

Tables

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)}))
xyz
0a0.6361780716615545
1b0.7644770537959592
2a0.4886920785040235
3b0.6387305689788544
4a0.9861212687099417
5b0.44394313163413013
6a0.7285023482154864
7b0.9804849021255813
8a0.1273298013557259
9b0.022658529247208015
10a0.640517230384827
11b0.16816465788694868
12a0.7594426477762842
13b0.33557920784374384
14a0.04219345473628877
15b0.22713072077552854
16a0.2646871413363411
17b0.27463054833943545
18a0.26797071278116913
19b0.745043193116581
20a0.8401064405839067
21b0.3623633390335328
22a0.6496746967085532
23b0.3332934056868798
24a0.9007306177297291
25b0.39041457854725103
26a0.702327027773344
27b0.9984705522816368
28a0.7263781454033537
29b0.3330089965057921
30a0.2932252463832967
31b0.927556623077441
32a0.6929386631671927
33b0.9029634833259095
34a0.08094388351638915
35b0.6133928266027976
36a0.3284017820439096
37b0.05613279247031189
38a0.5509474982398552
39b0.9510639699430181
40a0.8645611269334761
41b0.4699622151484303
42a0.0457955134237954
43b0.9211978145866174
44a0.9172363778518059
45b0.5227888209769815
46a0.2904575159081767
47b0.7427782643795166
48a0.42102046504647306
49b0.5827596778479656
50a0.04704698953752773
51b0.9259229716821037
52a0.9689732571553716
53b0.47871225651192195
54a0.6983202659484025
55b0.48417713588886735
56a0.26334650432832807
57b0.8700882153100667
58a0.7555767624550503
59b0.6762274348893558
60a0.47033993322238077
61b0.858928885231274
62a0.5141356582764328
63b0.03854071613101495
64a0.8900511550905329
65b0.594227053174338
66a0.33835281616535107
67b0.14328460264797438
68a0.502197225084001
69b0.8073863534623976
70a0.3481816104645675
71b0.46998796446639024
72a0.6288493166704608
73b0.18726571100587308
74a0.6005693050862092
75b0.014751217616446599
76a0.16733558455511077
77b0.2542638456995152
78a0.21152077410410908
79b0.7774177491260685
80a0.5896323727936814
81b0.9251238382558339
82a0.2484496502505703
83b0.06496945502195861
84a0.17897700993623267
85b0.2736161927903875
86a0.6374764773573444
87b0.6285109277813936
88a0.7801000665140811
89b0.08698360323027421
90a0.7766222988325973
91b0.011558165357516859
92a0.676388807398329
93b0.6940086233521582
94a0.02338502107469509
95b0.128949779318267
96a0.07545762109271192
97b0.19779099152902124
98a0.7339756827548065

Graphics

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(-lite) plots

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)
02468101214161820time0510152025303540455055quantitybroommonkeyslipperitem
(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)

Images

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

Tests

One may use the check function to create tests using arbitrary functions.

(->> (+ 1 2)
      (check = 3))
[:PASSED 3]
(check pos? -9)
[:FAILED -9]

Checks: 1 PASSED 1 FAILED
notespace.v2.tutorial-test - created by notespace, Thu Apr 30 17:34:06 CEST 2020.