Obsah
1. Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
2. Instalace využívající nástroj Conda
3. Vytvoření kostry projektu umožňujícího spuštění Jupyter Notebooku
4. Spuštění Jupyter Notebooku s novým kernelem
5. Základní použití Clojure v Jupyter Notebooku, načtení standardních modulů
6. Automatické zobrazení rastrových obrázků typu java.awt.image.BufferedImage
7. Typické knihovny a frameworky, které lze využít v kombinaci Jupyter Notebooku s jazykem Clojure
8. Knihovna clojure.core.matrix
9. Představení možností knihovny clojure.core.matrix
12. Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
13. Instalace prostředí Incanter
14. Ukázky základních možností při tvorbě grafů v Incanteru
15. Konverze diářů do zdrojových kódů jazyka Clojure
16. Historie příkazů zapisovaných do Jupyter Notebooku
17. Repositář s demonstračními příklady
18. Odkazy na články o Jupyter Notebooku
19. Odkazy na předchozí části seriálu o programovacím jazyku Clojure
1. Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
Pro dnes velmi populární projekt Jupyter vznikla celá řada takzvaných kernelů, z nichž mnohé podporují další programovací jazyky (i když Python bude pravděpodobně stále nejpoužívanějším jazykem). Jedná se o různé typy jazyků, většinou o klasické interpretry, ovšem nalezneme zde i jazyky překládané (kompilované), jazyky určené pro běh nad virtuálními stroji (především JVM a CLR) i jazyky s vlastním virtuálním strojem. V dnešním článku nás budou zajímat jazyky provozované nad virtuálním strojem programovacího jazyka Java (se všemi z toho plynoucími výhodami a některými nevýhodami) a současně i jazyky z LISPovské větve, které mohou být v oblasti zpracování dat a interaktivního programování poměrně užitečné. V současnosti nad JVM běží hned několik jazyků z LISPovské větve. Především se jedná o Clojure a o sice méně známý, ale stále velmi zajímavý jazyk Kawa. V Jupyter Notebooku je podporován jazyk Clojure, a to dokonce několika kernely – viz též následující tabulku se zvýrazněnými řádky:
Kernel | Jazyk |
---|---|
Dyalog Jupyter Kernel | APL (Dyalog) |
Coarray-Fortran | Fortran 2008/2015 |
IJulia | Julia |
IHaskell | ghc >= 7.6 |
IRuby | ruby >= 2.3 |
tslab | Typescript 3.7.2, JavaScript ESNext |
IJavascript | nodejs >= 0.10 |
ITypeScript | Typescript >= 2.0 |
jpCoffeescript | coffeescript >= 1.7 |
jp-LiveScript | livescript >= 1.5 |
ICSharp | C# 4.0+ |
IFSharp | F# |
lgo | Go >= 1.8 |
iGalileo | Galileo >= 0.1.3 |
gopherlab | Go >= 1.6 |
Gophernotes | Go >= 1.9 |
IScala | Scala |
IErlang | Erlang |
ITorch | Torch 7 (LuaJIT) |
IElixir | Elixir >= 1.5 |
ierl | Erlang >= 19, Elixir >= 1.4, LFE 1.2 |
OCaml-Jupyter | OCaml >= 4.02 |
IForth | Forth |
peforth | Forth |
IPerl | Perl 5 |
Perl6 | Perl 6.c |
IPerl6 | Perl 6 |
Jupyter-Perl6 | Perl 6.C |
IPHP | PHP >= 5.4 |
Jupyter-PHP | PHP >= 7.0.0 |
IOctave | Octave |
IScilab | Scilab |
MATLAB Kernel | Matlab |
Bash | bash |
Z shell | zsh >= 5.3 |
PowerShell | PowerShell |
CloJupyter | Clojure >= 1.7 |
jupyter-kernel-jsr223 | Clojure 1.8 |
Hy Kernel | Hy |
Calysto Hy | Hy |
jp-babel | Babel |
Lua Kernel | Lua |
IPurescript | Purescript |
IPyLua | Lua |
ILua | Lua |
Calysto Scheme | Scheme |
Calysto Processing | Processing.js >= 2 |
idl_kernel | IDL |
Mochi Kernel | Mochi |
Lua (used in Splash) | Lua |
Calysto Bash | bash |
IBrainfuck | Brainfuck |
cling | C++ |
xeus-cling | C++ |
Prolog | Prolog |
SWI-Prolog | SWI-Prolog |
cl-jupyter | Common Lisp |
common-lisp-jupyter | Common Lisp |
IJython | Jython 2.7 |
ROOT | C++/python |
Tcl | Tcl 8.5 |
J | J 805–807 (J901beta) |
Jython | Jython>=2.7.0 |
C | C |
Coconut | Coconut |
Pike | Pike >= 7.8 |
jupyter-kotlin | Kotlin 1.1-M04 EAP |
mit-scheme-kernel | MIT Scheme 9.2 |
elm-kernel | elm |
SciJava Jupyter Kernel | Java + 9 scripting languages |
BeakerX | Groovy, Java, Scala, Clojure, Kotlin, SQL |
IJava | Java 9 |
Guile | Guile 2.0.12 |
IRacket | Racket >= 6.10 |
EvCxR Jupyter Kernel | Rust >= 1.29.2 |
SSH Kernel | Bash |
Emu86 Kernel | Intel Assembly Language |
2. Instalace využívající nástroj Conda
Nejprve si ukažme, jakým způsobem je možné nainstalovat Jupyter Notebook a kernel nazvaný Clojupyter, tedy jeden z kernelů, který umožňuje používat interpret programovacího jazyka Clojure přímo z Jupyter Notebooku. První varianta instalace je založena na použití nástroje Conda, což je – zjednodušeně řečeno – správce balíčků pro více programovacích jazyků, včetně Pythonu.
V prvním kroku se připraví virtuální prostředí pro Python:
$ conda create -n clojupyter_test python=3.6
Dále následuje aktivace virtuálního prostředí Pythonu:
$ source activate clojupyter_test
Po aktivaci virtuálního prostředí následuje instalace Jupyter Notebooku a všech knihoven, na nichž tento dnes již velmi rozsáhlý a široce konfigurovatelný nástroj závisí:
$ conda install jupyter
Po úspěšném dokončení předchozího příkazu by měl být Jupyter Notebook připraven pro spuštění, samozřejmě s tím, že je v něm dostupný především kernel s interpretrem programovacího jazyka Python:
$ jupyter notebook
Obrázek 1: Úvodní stránka Jupyter Notebooku.
Nyní můžeme Jupyter Notebook zastavit, z konzole například pomocí klávesové zkratky Ctrl+D.
Druhá část instalace spočívá v naklonování repositáře se zdrojovými kódy kernelu Clojupyter:
$ git clone https://github.com/roryk/clojupyter
Po naklonování je nutné provést konfiguraci, překlad a instalaci tohoto kernelu, což vyžaduje běžný postup make+make install:
$ cd clojupyter $ make $ make install
Po novém spuštění Jupyter Notebooku by již měl být k dispozici i nový kernel:
$ jupyter notebook
Obrázek 2: V nabídce by se měla objevit nabídka nového kernelu.
3. Vytvoření kostry projektu umožňujícího spuštění Jupyter Notebooku
Existuje ovšem i alternativní možnost instalace, která předpokládá, že je na počítači již nainstalován Jupyter Notebook (viz například Instalace Jupyter Notebooku) a současně je k dispozici i programovací jazyk Clojure doplněný o nástroj Leiningen. Pokud jsou tyto podmínky splněny, lze instalaci provést tak, že se vytvoří kostra nového projektu, doplní se seznam pluginů, provede se instalace pluginů a spustí se Jupyter Notebook.
Vytvoření kostry projektu:
$ lein new app xyz
Výše uvedený příkaz by měl vytvořit nový podadresář nazvaný xyz, jehož interní struktura bude následující:
. ├── CHANGELOG.md ├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources ├── src │ └── xyz │ └── core.clj └── test └── xyz └── core_test.clj
Ručně musíme provést jedinou úpravu, a to konkrétně v projektovém souboru project.clj, v němž je nutné přidat deklaraci pluginu nazvaného lein-jupyter. Provedená změna je naznačena tučně:
(defproject xyz "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]] :main ^:skip-aot xyz.core :target-path "target/%s" :plugins [[lein-jupyter "0.1.16"]] :profiles {:uberjar {:aot :all}})
Dále se spustí příkaz zajišťující instalaci všech knihoven, na kterých projekt závisí:
$ lein deps
Podle aktuálního stavu systému se postahují desítky a v některých případech (čistá instalace Clojure) i stovky (pod)knihoven!
4. Spuštění Jupyter Notebooku s novým kernelem
Nyní by již mělo být možné spustit (v adresáři s projektem!) Jupyter Notebook a otestovat, zda je k dispozici i nový kernel:
$ jupyter notebook [I 16:29:19.360 NotebookApp] Writing notebook server cookie secret to /run/user/1000/jupyter/notebook_cookie_secret [W 16:29:19.833 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended. [I 16:29:19.844 NotebookApp] Serving notebooks from local directory: /home/ptisnovs/temp/xyz [I 16:29:19.844 NotebookApp] 0 active kernels [I 16:29:19.844 NotebookApp] The Jupyter Notebook is running at: [I 16:29:19.844 NotebookApp] http://[all ip addresses on your system]:8888/ [I 16:29:19.844 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). [I 16:29:20.147 NotebookApp] 302 GET /tree (::1) 1.26ms [I 16:29:22.596 NotebookApp] 302 POST /login?next=%2Ftree (::1) 2.21ms
Může se však stát, že se v terminálu objeví chybová zpráva o tom, že není nastavena proměnná prostředí LEIN_WORKING_DIRECTORY:
Traceback (most recent call last): File "/home/ptisnovs/.local/share/jupyter/kernels/lein-clojure/leinclojure.py", line 12, in <module> raise RuntimeError("The environment variable 'LEIN_WORKING_DIRECTORY'" RuntimeError: The environment variable 'LEIN_WORKING_DIRECTORY' for this kernel to run
V tomto případě Jupyter Notebook ukončete (postačuje stisknout klávesovou zkratku Ctrl+C v terminálu) a proměnnou nastavte na aktuální adresář:
$ export LEIN_WORKING_DIRECTORY=.
Nové spuštění by již mělo proběhnout bez chyby:
$ jupyter notebook [W 16:32:28.633 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended. [I 16:32:28.643 NotebookApp] Serving notebooks from local directory: /home/ptisnovs/temp/xyz [I 16:32:28.643 NotebookApp] 0 active kernels [I 16:32:28.643 NotebookApp] The Jupyter Notebook is running at: [I 16:32:28.643 NotebookApp] http://[all ip addresses on your system]:8888/ [I 16:32:28.643 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). [I 16:32:31.865 NotebookApp] Creating new notebook in [I 16:32:32.514 NotebookApp] Kernel started: f6363137-8b71-4e78-83d8-d65a425e58a1 [I 16:34:32.495 NotebookApp] Saving file at /Untitled1.ipynb
Obrázek 3: Prázdný diář s připraveným interpretrem programovacího jazyka Clojure.
5. Základní použití Clojure v Jupyter Notebooku, načtení standardních modulů
Diář s kernelem Clojupyer se chová podobně, jako například diář s kernelem programovacího jazyka Python. Editace buněk, přesuny buněk, vyhodnocení obsahu buněk atd. lze provádět buď s využitím myši (velmi rychle přijdete na to, že jsou to pomalé operace) nebo pomocí klávesových zkratek, které jsou aktivní v příkazovém režimu (command mode). Do tohoto režimu se dostanete stiskem klávesy Esc. Mezi nejdůležitější klávesové zkratky, jen je možné využít prakticky ve všech typech diářů, patří:
# | Klávesová zkratka | Popis provedené operace |
---|---|---|
1 | Esc+Enter | editace buňky (důležité například u buněk s Markdownem) |
2 | Esc+A | vytvoření nové buňky nad buňkou aktivní (above) |
3 | Esc+B | vytvoření nové buňky pod buňkou aktivní (below) |
4 | Esc+X | cut |
5 | Esc+C | copy |
6 | Esc+V | paste |
7 | Esc+D,D | vymazání buňky (D se stiskne dvakrát) |
8 | Esc+S | uložení celého diáře |
9 | Esc+Y | přepnutí typu buňky (jejího obsahu) na programový kód |
10 | Esc+M | přepnutí typu buňky (jejího obsahu) na Markdown |
11 | Esc+H | zobrazení nápovědy k příkazovému režimu |
Obrázek 4: Nápověda k příkazovému režimu (command mode).
Obrázek 5: Nápověda k editačnímu režimu (edit mode).
Konkrétně v Clojupyteru je navíc implementováno automatické doplňování názvů funkcí, maker či symbolů pomocí klávesy Tab a taktéž zvýraznění párových závorek, což je pro LISPovský programovací jazyk neocenitelná výhoda.
Jedním z rozdílů mezi Clojupyterem a standardní interaktivní smyčkou REPL je fakt, že se do Clojupyteru implicitně nenačítají všechny standardní moduly. To se týká i velmi užitečného makra určeného pro zobrazení dokumentace:
Obrázek 6: Po spuštění Clojupyteru není k dispozici makro doc.
Řešení je jednoduché – na začátku diáře je možné všechny potřebné importy provést. Týká se to především jmenného prostoru clojure.repl, který se načte příkazem:
(use 'clojure.repl)
Obrázek 7: Načtení modulu clojure.repl. Po provedení tohoto příkazu je již možné bez problémů používat makro doc i další funkce a makra z tohoto jmenného prostoru.
6. Automatické zobrazení rastrových obrázků typu java.awt.image.BufferedImage
Jednou z velmi dobrých a prakticky použitelných vlastností kernelu Clojupyer je jeho schopnost automaticky zobrazit rastrové obrázky reprezentované objektem typu java.awt.image.BufferedImage. Co to v praxi znamená? Pokud nějaká forma (neboli zjednodušeně řečeno výraz) zapsaná do buňky vrátí objekt tohoto typu, je rastrový obrázek rozpoznán a zobrazen přímo na ploše diáře. Tímto způsobem lze vytvářet všechny typy diagramů, grafů, výsledků různých simulací atd. Ostatně si můžeme vyzkoušet jednoduchý příklad:
(import java.awt.image.BufferedImage) (defn create "Create new bitmap." [width height] (new BufferedImage width height BufferedImage/TYPE_INT_RGB)) (create 256 256)
Tento příklad (zapsaný do diáře) by měl zobrazit prázdnou (černou) bitmapu o rozměrech 256×256 pixelů:
Obrázek 8: Rastrový obrázek o rozměrech 256×256 zobrazený v ploše diáře.
Nic nám samozřejmě nebrání do obrázku vykreslit nějaké tvary, popř. postupně vybarvit jeho pixely:
(import java.awt.image.BufferedImage) (defn create "Create new bitmap." [width height] (new BufferedImage width height BufferedImage/TYPE_INT_RGB)) (defn ->rgb [r g b] (bit-or b (bit-shift-left g 8) (bit-shift-left r 16))) (defn putpixel "Change pixel color." ( [bitmap x y rgb] (.setRGB bitmap x y rgb)) ( [bitmap x y r g b] (.setRGB bitmap x y (->rgb r g b)))) (create 256 256) (let [bitmap (create 256 256)] (doseq [y (range 256)] (doseq [x (range 256)] (putpixel bitmap x y x 255 y))) bitmap)
Výsledek by měl vypadat následovně:
Obrázek 9: Rastrový obrázek o rozměrech 256×256 zobrazený v ploše diáře. Pixely byly individuálně vybarveny.
7. Typické knihovny a frameworky, které lze využít v kombinaci Jupyter Notebooku s jazykem Clojure
Již v úvodní kapitole jsme si řekli, že jedním z důvodů pro použití kernelu Clojupyter může být fakt, že z programovacího jazyka Clojure je možné přistupovat k obrovskému množství knihoven a frameworků vytvořených pro ekosystém okolo JVM. Kromě toho ovšem vznikly i vhodné knihovny určené přímo pro jazyk Clojure. V kontextu typického použití Jupyter Notebooku jsou zajímavé především dvě knihovny – clojure.core.matrix (či jen core.matrix) a taktéž projekt Incanter, resp. přesněji řečeno knihovny, které jsou v rámci tohoto projektu dostupné. Zatímco core.matrix svým záběrem zhruba odpovídá knihovně Numpy pro Python, je Incanter mnohem rozsáhlejší, protože kromě statistických výpočtů nabízí uživatelům i možnost zobrazení různých typů grafů, tj. může se jednat o alternativu k projektu Matplotlib, s nímž jsme se již v seriálu o Jupyter Notebooku alespoň ve stručnosti seznámili.
Obrázek 10: Graf zobrazený Matplotlibem.
8. Knihovna clojure.core.matrix
V této kapitole si připomeneme existenci knihovny pojmenované core.matrix či plným označením clojure.core.matrix, která vývojářům pracujícím s programovacím jazykem Clojure nabízí prakticky všechny potřebné operace, které jsou vyžadovány při práci s vektory a maticemi (včetně například výpočtu inverzní matice). Navíc je tato knihovna zajímavá tím, že předepisuje rozhraní pro všechny operace, ovšem konkrétní implementaci je možné si vybrat. To například znamená, že pokud je řešen nějaký problém, v němž se ve velké míře používají takzvané řídké matice (pěkným příkladem z praxe může být Google matrix), lze – beze změny zdrojového kódu uživatelského programu – vybrat takovou reprezentaci matic a takové algoritmy, které jsou optimalizovány právě pro práci s řídkými maticemi a nikoli s maticemi uloženými ve formě „hutného“ dvourozměrného pole. Díky tomuto přístupu a taktéž díky dalším vlastnostem programovacího jazyka Clojure (existence tzv. threading makra a funkcí vyššího řádu) se práce s maticemi do značné míry začíná podobat práci v programovacím jazyku APL, až na ten rozdíl, že algoritmy zapisované v Clojure jsou pro většinu vývojářů přece jen více čitelnější :-).
Nejprve si knihovnu core.matrix nainstalujeme. Je to snadné – postačuje vytvořit nový projekt:
$ lein new app enter-the-matrix
Následně upravit projektový soubor – přidat do něj novou závislost:
(defproject matrix1 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] [net.mikera/core.matrix "0.62.0"]] :main ^:skip-aot matrix1.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
A spustit příkaz pro zjištění a stažení všech závislostí:
$ lein deps
V dnešním článku však použijeme poněkud jiný projektový soubor, který navíc obsahuje deklaraci pluginu umožňujícího spuštění Jupyter Notebooku s novým kernelem:
(defproject xyz "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] [net.mikera/core.matrix "0.62.0"]] :main ^:skip-aot xyz.core :target-path "target/%s" :plugins [[lein-jupyter "0.1.16"]] :profiles {:uberjar {:aot :all}})
Pokud se Jupyter Notebook spustí z adresáře s tímto projektovým souborem, bude možné core.matrix přímo použít v Jupyter Notebooku.
9. Představení možností knihovny clojure.core.matrix
Některé základní možnosti knihovny clojure.core.matrix jsou prezentovány na diáři dostupném na adrese https://github.com/tisnik/jupyter-notebook-examples/tree/master/Clojupyter%20-%20introduction%20to%20clojure.core.matrix.ipynb. Můžeme v něm vidět dvojici příkazů use, které načtou všechny funkce a všechna makra ze jmenných prostorů clojure.core.matrix a clojure.core.matrix.operators. Následně se vytvoří čtvercová matice nazvaná M a dvouprvkový vektor nazvaný v, s nimiž je provedeno několik operací. Funkce pm slouží pro výpis obsahu matice na standardní výstup v „pěkném“ tvaru (pretty print). Lze samozřejmě použít i funkci print či println:
(use 'clojure.core.matrix) (use 'clojure.core.matrix.operators) (let [M (matrix [[1 2] [3 4]]) v (matrix [1 2])] (pm M) (pm v) (pm (* v 2)) (pm (mul M v)) (pm (* M M)) (pm (inner-product M v))) ; vektor (pm (matrix [1 2 3])) ; vektor (pm (matrix '(1 2 3))) ; matice (pm (matrix [[1 2] [3 4]])) ; matice (pm (matrix (range 1 10))) ; matice (pm (matrix [[1 2 3] [4 5 6] [7 8 9]])) (zero-matrix 10 1) (pm *1) (zero-matrix 1 10) (pm *1) (zero-matrix 2 3) (pm *1) (zero-matrix 4 4) (pm *1) (identity-matrix 4 4) (pm *1) ; vektor udává pozice jedniček na jednotlivých řádcích matice ; rozměry matice jsou získány na základě velikosti tohoto vektoru (permutation-matrix [1 4 2 3 0]) (pm *1)
Obrázek 10: Diář se základními operacemi pro práci s maticemi zobrazený v Jupyter Notebooku.
10. Operace s vektory
V knihovně core.matrix je deklarováno velké množství funkcí, které dokážou pracovat s celými vektory, popř. s jednotlivými prvky, z nichž se vektory skládají. Podívejme se nyní na úryvek z demonstračního příkladu:
(defn immutable-vector-functions "Test chování vybraných funkcí, které lze nalézt ve jmenných prostorech clojure.core.matrix a clojure.core.matrix.operators." [vector1 vector2 vector3] (println "*** Test funkcí aplikovaných na vektory ***") (println "Vstupní data (vektory):") (print-vector vector1) (print-vector vector2) (print-vector vector3) (println "Vyhodnocení:") (print-vector (emin vector1)) (print-vector (emin vector2)) (print-vector (emin vector3)) (print-vector (emax vector1)) (print-vector (emax vector2)) (print-vector (emax vector3)) (print-vector (normalise vector1)) (print-vector (normalise vector2)) (print-vector (normalise vector3)) (print-vector (length vector1)) (print-vector (length vector2)) (print-vector (length vector3)) (print-vector (length-squared vector1)) (print-vector (length-squared vector2)) (print-vector (length-squared vector3)) (print-vector (distance vector1 vector2)) (print-vector (distance vector1 vector3)) (print-vector (distance vector2 vector3)) (print-vector (join vector1 vector2)) (print-vector (join vector1 vector2 vector3)) (println))
Nejprve se podívejme na výsledky vypsané po spuštění této funkce:
*** Test funkcí aplikovaných na vektory *** Vstupní data (vektory): vector1 = [1.000 2.000 3.000] vector2 = [2.000 3.000 4.000] vector3 = [1.000 1.000] Vyhodnocení: (emin vector1) = 1.000 (emin vector2) = 2.000 (emin vector3) = 1.000 (emax vector1) = 3.000 (emax vector2) = 4.000 (emax vector3) = 1.000 (normalise vector1) = [0.267 0.535 0.802] (normalise vector2) = [0.371 0.557 0.743] (normalise vector3) = [0.707 0.707] (length vector1) = 3.742 (length vector2) = 5.385 (length vector3) = 1.414 (length-squared vector1) = 14.000 (length-squared vector2) = 29.000 (length-squared vector3) = 2.000 (distance vector1 vector2) = 1.732 (distance vector1 vector3) = 1.000 (distance vector2 vector3) = 2.236 (join vector1 vector2) = [1.000 2.000 3.000 2.000 3.000 4.000] (join vector1 vector2 vector3) = [1.000 2.000 3.000 2.000 3.000 4.000 1.000 1.000]
Význam jednotlivých funkcí použitých v předchozím příkladu je vysvětlen v tabulce:
# | Funkce | Výsledek | Popis |
---|---|---|---|
1 | emin | skalár | nalezne nejmenší prvek vektoru |
2 | emax | skalár | nalezne největší prvek vektoru |
3 | normalize | vektor | normalizace vektoru (na délku rovnou jedné) |
4 | length | skalár | výpočet délky vektoru |
5 | length-squared | skalár | výpočet druhé mocniny délky vektoru |
6 | distance | skalár | dva vektory jsou chápány jako 2D/3D body, vypočítá se jejich vzdálenost |
7 | join | vektor | spojení dvou čí většího množství vektorů |
V předchozím odstavci jsme se mj. zmínili i o funkci/operátoru *, který slouží k vynásobení těch prvků vektorů, které mají shodný index, tj. první prvek vektoru číslo 1 je vynásoben s prvním prvkem vektoru číslo 2 atd. Kromě toho se však v mnoha disciplínách (mj. i v počítačové grafice) pracuje se skalárním a vektorovým součinem. I tyto operace jsou samozřejmě v knihovně core.matrix podporovány:
# | Funkce | Výsledek | Popis |
---|---|---|---|
1 | dot | skalár | skalární součin dvou vektorů |
2 | inner-product | skalár | zobecnění skalárního součinu (pro matice má význam násobení matic) |
3 | cross | vektor | vektorový součin dvou vektorů |
Opět se podívejme na způsob použití těchto funkcí:
(defn immutable-vector-products "Skalární a vektorový součin dvou trojsložkových vektorů." [vector1 vector2] (println "*** Skalární a vektorový součin dvou trojsložkových vektorů ***") (println "Vstupní data (vektory):") (print-vector vector1) (print-vector vector2) (println "Vyhodnocení:") (print-vector (dot vector1 vector1)) (print-vector (dot vector1 vector2)) (print-vector (dot vector2 vector1)) (print-vector (dot vector2 vector2)) (print-vector (inner-product vector1 vector1)) (print-vector (inner-product vector1 vector2)) (print-vector (inner-product vector2 vector1)) (print-vector (inner-product vector2 vector2)) (print-vector (cross vector1 vector1)) (print-vector (cross vector1 vector2)) (print-vector (cross vector2 vector1)) (print-vector (cross vector2 vector2)) (println)) (defn immutable-vector-tests "Spustí všechny testovací funkce s neměnitelnými vektory." [] (let [v0 (zero-vector 3) v1 (array [1 2 3]) v2 (array [2 3 4]) v3 (array [1 1])] (immutable-vector-products v1 v2) (immutable-vector-products v0 v1)))
Výsledek zavolání testovací funkce:
*** Skalární a vektorový součin dvou trojsložkových vektorů *** Vstupní data (vektory): vector1 = [1.000 2.000 3.000] vector2 = [2.000 3.000 4.000] Vyhodnocení: (dot vector1 vector1) = 14.000 (dot vector1 vector2) = 20.000 (dot vector2 vector1) = 20.000 (dot vector2 vector2) = 29.000 (inner-product vector1 vector1) = 14.000 (inner-product vector1 vector2) = 20.000 (inner-product vector2 vector1) = 20.000 (inner-product vector2 vector2) = 29.000 (cross vector1 vector1) = [0.000 0.000 0.000] (cross vector1 vector2) = [-1.000 2.000 -1.000] (cross vector2 vector1) = [1.000 -2.000 1.000] (cross vector2 vector2) = [0.000 0.000 0.000] *** Skalární a vektorový součin dvou trojsložkových vektorů *** Vstupní data (vektory): vector1 = [0.000 0.000 0.000] vector2 = [1.000 2.000 3.000] Vyhodnocení: (dot vector1 vector1) = 0.000 (dot vector1 vector2) = 0.000 (dot vector2 vector1) = 0.000 (dot vector2 vector2) = 14.000 (inner-product vector1 vector1) = 0.000 (inner-product vector1 vector2) = 0.000 (inner-product vector2 vector1) = 0.000 (inner-product vector2 vector2) = 14.000 (cross vector1 vector1) = [0.000 0.000 0.000] (cross vector1 vector2) = [0.000 0.000 0.000] (cross vector2 vector1) = [0.000 0.000 0.000] (cross vector2 vector2) = [0.000 0.000 0.000]
Obrázek 11: Diář s operacemi s vektory.
11. Operace s maticemi
Nejdůležitější datovou strukturou, s níž se v knihovně core.matrix pracuje, jsou samozřejmě matice, především pak dvourozměrné matice. Tyto matice mohou mít libovolné rozměry a při jejich vytváření je možné si zvolit jak způsob jejich uložení v operační paměti počítače, tak i to, zda se bude jednat o matice měnitelné (mutable) či neměnitelné (immutable). V první řadě se jedná o funkce sloužící pro vytvoření matic různých typů, viz též následující tabulku:
# | Funkce | Výsledek | Popis |
---|---|---|---|
1 | matrix | matice | vytvoření matice a inicializace jejích prvků |
2 | zero-matrix | matice | vytvoření matice s nulovými prvky |
3 | identity-matrix | matice | vytvoření jednotkové matice |
4 | permutation-matrix | matice | vytvoření matice, v níž jsou jedničky umístěny podle specifikovaného vektoru |
Další velmi důležitou funkcí je funkce reshape, která dokáže změnit velikost matice a vhodným způsobem přeorganizovat prvky v původní matici.
Podívejme se nyní na některé další funkce, které lze použít pro práci s maticemi. Nejprve se budeme zabývat již zmíněnými funkcemi/operátory, které mají u matic v některých případech odlišný význam, než tomu bylo u vektorů:
# | Funkce | Výsledek | Popis |
---|---|---|---|
1 | + | matice | součet matic (může se provést broadcast) |
2 | – | matice | rozdíl matic (může se provést broadcast) |
3 | * | matice | maticový součin (nikoli prvek po prvku!) |
4 | / | matice | maticový součin s inverzní maticí |
Chování těchto funkcí/operátorů si samozřejmě vyzkoušíme v praxi:
(defn immutable-matrix-tests "Spustí všechny testovací funkce s neměnitelnými maticemi" [] (let [m0 (zero-matrix 3 3) m1 (identity-matrix 3 3) m2 (array [[1 2 3] [4 5 6] [7 8 9]]) m3 (array [[0 1] [2 3]])] (immutable-matrix-operators m0 m1) (immutable-matrix-operators m1 m2) ;(immutable-matrix-special-operators m1 m2) ; bude použito níže ;(immutable-matrix-functions m1 m2 m3))) ; bude použito níže
(defn immutable-matrix-operators "Test chování operátorů předefinovaných ve jmenném prostoru clojure.core.matrix.operators." [matrix1 matrix2] (println "*** Test základních operátorů aplikovaných na matice ***") (println "Vstupní data (matice):") (print-matrix matrix1) (print-matrix matrix2) (println "Vyhodnocení:") ; operace provedené mezi maticí a skalární hodnotou (print-matrix (+ matrix1 10)) (print-matrix (- matrix1 10)) (print-matrix (* matrix1 10)) (print-matrix (/ matrix1 10)) ; operace provedené mezi skalární hodnotou a maticí (print-matrix (+ 10 matrix1)) (print-matrix (- 10 matrix1)) (print-matrix (* 10 matrix1)) (try (print-matrix (/ 10 matrix1)) (catch java.lang.ArithmeticException e (println "Exception: " (.toString e)))) ; operace provedené mezi dvěma maticemi (print-matrix (+ matrix1 matrix2)) (print-matrix (- matrix1 matrix2)) (print-matrix (* matrix1 matrix2)) (try (print-matrix (/ matrix1 matrix2)) (catch java.lang.ArithmeticException e (println "Exception: " (.toString e)))) (println))
Výsledky vypadají následovně (povšimněte si, že může dojít k vyhození výjimky při dělení nulou):
*** Test základních operátorů aplikovaných na matice *** Vstupní data (matice): matrix1 = [[0.000 0.000 0.000] [0.000 0.000 0.000] [0.000 0.000 0.000]] matrix2 = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] Vyhodnocení: (+ matrix1 10) = [[10.000 10.000 10.000] [10.000 10.000 10.000] [10.000 10.000 10.000]] (- matrix1 10) = [[-10.000 -10.000 -10.000] [-10.000 -10.000 -10.000] [-10.000 -10.000 -10.000]] (* matrix1 10) = [[0.000 0.000 0.000] [0.000 0.000 0.000] [0.000 0.000 0.000]] (/ matrix1 10) = [[0.000 0.000 0.000] [0.000 0.000 0.000] [0.000 0.000 0.000]] (+ 10 matrix1) = [[10.000 10.000 10.000] [10.000 10.000 10.000] [10.000 10.000 10.000]] (- 10 matrix1) = [[10.000 10.000 10.000] [10.000 10.000 10.000] [10.000 10.000 10.000]] (* 10 matrix1) = [[0.000 0.000 0.000] [0.000 0.000 0.000] [0.000 0.000 0.000]] (/ 10 matrix1) = Exception: java.lang.ArithmeticException: Divide by zero (+ matrix1 matrix2) = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] (- matrix1 matrix2) = [[-1.000 0.000 0.000] [ 0.000 -1.000 0.000] [ 0.000 0.000 -1.000]] (* matrix1 matrix2) = [[0.000 0.000 0.000] [0.000 0.000 0.000] [0.000 0.000 0.000]] (/ matrix1 matrix2) = Exception: java.lang.ArithmeticException: Divide by zero *** Test základních operátorů aplikovaných na matice *** Vstupní data (matice): matrix1 = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] matrix2 = [[1.000 2.000 3.000] [4.000 5.000 6.000] [7.000 8.000 9.000]] Vyhodnocení: (+ matrix1 10) = [[11.000 10.000 10.000] [10.000 11.000 10.000] [10.000 10.000 11.000]] (- matrix1 10) = [[ -9.000 -10.000 -10.000] [-10.000 -9.000 -10.000] [-10.000 -10.000 -9.000]] (* matrix1 10) = [[10.000 0.000 0.000] [ 0.000 10.000 0.000] [ 0.000 0.000 10.000]] (/ matrix1 10) = [[0.100 0.000 0.000] [0.000 0.100 0.000] [0.000 0.000 0.100]] (+ 10 matrix1) = [[11.000 10.000 10.000] [10.000 11.000 10.000] [10.000 10.000 11.000]] (- 10 matrix1) = [[ 9.000 10.000 10.000] [10.000 9.000 10.000] [10.000 10.000 9.000]] (* 10 matrix1) = [[10.000 0.000 0.000] [ 0.000 10.000 0.000] [ 0.000 0.000 10.000]] (/ 10 matrix1) = Exception: java.lang.ArithmeticException: Divide by zero (+ matrix1 matrix2) = [[2.000 2.000 3.000] [4.000 6.000 6.000] [7.000 8.000 10.000]] (- matrix1 matrix2) = [[ 0.000 -2.000 -3.000] [-4.000 -4.000 -6.000] [-7.000 -8.000 -8.000]] (* matrix1 matrix2) = [[1.000 0.000 0.000] [0.000 5.000 0.000] [0.000 0.000 9.000]] (/ matrix1 matrix2) = [[1.000 0.000 0.000] [0.000 0.200 0.000] [0.000 0.000 0.111]]
Zajímavé je i chování operátorů ** (aplikován prvek po prvku s případným broadcastem) a == (taktéž aplikován prvek po prvku):
(defn immutable-matrix-special-operators "Test chování speciálních operátorů předefinovaných ve jmenném prostoru clojure.core.matrix.operators." [matrix1 matrix2] (println "*** Test speciálních operátorů aplikovaných na matice ***") (println "Vstupní data (matice):") (print-matrix matrix1) (print-matrix matrix2) (println "Vyhodnocení:") ; operace provedené mezi maticí a skalární hodnotou (print-matrix (** matrix1 10)) ; operace provedené mezi skalární hodnotou a maticí (print-matrix (** 10 matrix1)) ; operace provedené mezi dvěma maticemi (print-matrix (** matrix1 matrix2)) ; operátor ekvivalence aplikovaný na dvojici matic (print-vector (== matrix1 matrix2)) (print-vector (== matrix1 matrix1)) (print-vector (== matrix1 (identity-matrix 3 3))) (print-vector (== matrix2 (array [[1 2 3] [4 5 6] [7 8 9]]))) (println))
Opět se podívejme na výsledky:
*** Test speciálních operátorů aplikovaných na matice *** Vstupní data (matice): matrix1 = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] matrix2 = [[1.000 2.000 3.000] [4.000 5.000 6.000] [7.000 8.000 9.000]] Vyhodnocení: (** matrix1 10) = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] (** 10 matrix1) = [[10.000 1.000 1.000] [ 1.000 10.000 1.000] [ 1.000 1.000 10.000]] (** matrix1 matrix2) = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] (== matrix1 matrix2) = false (== matrix1 matrix1) = true (== matrix1 (identity-matrix 3 3)) = true (== matrix2 (array [[1 2 3] [4 5 6] [7 8 9]])) = true
Podívejme se ještě na některé významné funkce, které je možné aplikovat na matice. Některé z těchto funkcí vrací skalární hodnotu, jiné naopak vektor či (jinou) matici. Některé z těchto funkcí již známe z kapitol o vektorech, další funkce jsou zcela nové:
# | Funkce | Výsledek | Popis |
---|---|---|---|
1 | emin | skalár | nalezne nejmenší prvek matice |
2 | emax | skalár | nalezne největší prvek matice |
3 | esum | skalár | sečte prvky v matici |
4 | ecount | skalár | vrátí celkový počet prvků matice |
5 | zero-count | skalár | vrátí počet nulových prvků matice |
6 | inverse | matice | výpočet inverzní matice |
7 | non-zero-indices | matice | vrací indexy nenulových prvků pro všechny řezy maticí |
8 | outer-product | matice (vyšší počet dimenzí) | vnější součin matice/matic či vektorů |
9 | join | matice | spojení dvou či více matic (zvětší se počet řádků) |
Nezbývá než si chování výše popsaných funkcí vyzkoušet:
(defn immutable-matrix-functions "Test chování vybraných funkcí, které lze nalézt ve jmenných prostorech clojure.core.matrix a clojure.core.matrix.operators." [matrix1 matrix2 matrix3] (println "*** Test funkcí aplikovaných na matice ***") (println "Vstupní data (matice):") (print-matrix matrix1) (print-matrix matrix2) (print-matrix matrix3) (println "Vyhodnocení:") (print-vector (emin matrix1)) (print-vector (emin matrix2)) (print-vector (emin matrix3)) (print-vector (emax matrix1)) (print-vector (emax matrix2)) (print-vector (emax matrix3)) (print-vector (esum matrix1)) (print-vector (esum matrix2)) (print-vector (esum matrix3)) (print-vector (ecount matrix1)) (print-vector (ecount matrix2)) (print-vector (ecount matrix3)) (print-vector (zero-count matrix1)) (print-vector (zero-count matrix2)) (print-vector (zero-count matrix3)) (print-matrix (inverse matrix1)) (print-matrix (inverse matrix2)) (print-matrix (inverse matrix3)) (print-matrix (non-zero-indices matrix1)) (print-matrix (non-zero-indices matrix2)) (print-matrix (non-zero-indices matrix3)) (print-matrix (outer-product matrix1)) (print-matrix (outer-product matrix2)) (print-matrix (outer-product matrix3)) (print-matrix (join matrix1 matrix2)) (println))
Po zavolání této funkce by se na standardní výstup měly vypsat následující řádky:
*** Test funkcí aplikovaných na matice *** Vstupní data (matice): matrix1 = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] matrix2 = [[1.000 2.000 3.000] [4.000 5.000 6.000] [7.000 8.000 9.000]] matrix3 = [[0.000 1.000] [2.000 3.000]] Vyhodnocení: (emin matrix1) = 0.000 (emin matrix2) = 1.000 (emin matrix3) = 0.000 (emax matrix1) = 1.000 (emax matrix2) = 9.000 (emax matrix3) = 3.000 (esum matrix1) = 3.000 (esum matrix2) = 45.000 (esum matrix3) = 6.000 (ecount matrix1) = 9.000 (ecount matrix2) = 9.000 (ecount matrix3) = 4.000 (zero-count matrix1) = 6.000 (zero-count matrix2) = 0.000 (zero-count matrix3) = 1.000 (inverse matrix1) = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] (inverse matrix2) = [[-4503599627370498.000 9007199254740992.000 -4503599627370496.000] [ 9007199254740996.000 -18014398509481984.000 9007199254740991.000] [-4503599627370498.000 9007199254740992.000 -4503599627370495.500]] (inverse matrix3) = [[-1.500 0.500] [ 1.000 0.000]] (non-zero-indices matrix1) = [[0.000] [1.000] [2.000]] (non-zero-indices matrix2) = [[0.000 1.000 2.000] [0.000 1.000 2.000] [0.000 1.000 2.000]] (non-zero-indices matrix3) = [[1.000] [0.000]] (outer-product matrix1) = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000]] (outer-product matrix2) = [[1.000 2.000 3.000] [4.000 5.000 6.000] [7.000 8.000 9.000]] (outer-product matrix3) = [[0.000 1.000] [2.000 3.000]] (join matrix1 matrix2) = [[1.000 0.000 0.000] [0.000 1.000 0.000] [0.000 0.000 1.000] [1.000 2.000 3.000] [4.000 5.000 6.000] [7.000 8.000 9.000]]
Vnější součin dvou matic již dá složitější výsledek (jedná se vlastně o výsledek součinu každého prvku s každým prvkem a uspořádání do matice se čtyřmi rozměry):
(pm (outer-product m2 m2)) [[[[ 1.000 2.000 3.000] [ 4.000 5.000 6.000] [ 7.000 8.000 9.000]] [[ 2.000 4.000 6.000] [ 8.000 10.000 12.000] [14.000 16.000 18.000]] [[ 3.000 6.000 9.000] [12.000 15.000 18.000] [21.000 24.000 27.000]]] [[[ 4.000 8.000 12.000] [16.000 20.000 24.000] [28.000 32.000 36.000]] [[ 5.000 10.000 15.000] [20.000 25.000 30.000] [35.000 40.000 45.000]] [[ 6.000 12.000 18.000] [24.000 30.000 36.000] [42.000 48.000 54.000]]] [[[ 7.000 14.000 21.000] [28.000 35.000 42.000] [49.000 56.000 63.000]] [[ 8.000 16.000 24.000] [32.000 40.000 48.000] [56.000 64.000 72.000]] [[ 9.000 18.000 27.000] [36.000 45.000 54.000] [63.000 72.000 81.000]]]]
Jednodušší je vysvětlení chování této funkce na dvojici vektorů – jednorozměrných matic:
(def v1 (array [1 2 3])) (pm (outer-product v1 v1)) [[1.000 2.000 3.000] [2.000 4.000 6.000] [3.000 6.000 9.000]]
Příklad z praxe – tabulka malé násobilky:
(def v1 (array (range 1 11))) (pm (outer-product v1 v1)) [[ 1.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000 9.000 10.000] [ 2.000 4.000 6.000 8.000 10.000 12.000 14.000 16.000 18.000 20.000] [ 3.000 6.000 9.000 12.000 15.000 18.000 21.000 24.000 27.000 30.000] [ 4.000 8.000 12.000 16.000 20.000 24.000 28.000 32.000 36.000 40.000] [ 5.000 10.000 15.000 20.000 25.000 30.000 35.000 40.000 45.000 50.000] [ 6.000 12.000 18.000 24.000 30.000 36.000 42.000 48.000 54.000 60.000] [ 7.000 14.000 21.000 28.000 35.000 42.000 49.000 56.000 63.000 70.000] [ 8.000 16.000 24.000 32.000 40.000 48.000 56.000 64.000 72.000 80.000] [ 9.000 18.000 27.000 36.000 45.000 54.000 63.000 72.000 81.000 90.000] [10.000 20.000 30.000 40.000 50.000 60.000 70.000 80.000 90.000 100.000]]
Obrázek 12: Diář s operacemi s maticemi.
12. Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
Na stránce www.clojure-toolbox.com, na níž se nachází seznam nejužitečnějších a samozřejmě taktéž nejpopulárnějších knihoven a nástrojů určených pro programovací jazyk Clojure, popř. pro ClojureScript, nalezneme mj. i nástroj nazvaný Incanter. Jedná se o skupinu knihoven pro Clojure (tedy nikoli pro ClojureScript), jejichž cílem je vytvořit rychlejší a rozšiřitelnější alternativu k nástroji a programovacímu jazyku R, který se používá v oblasti statistických výpočtů, vizualizace dat apod. (a navíc se podle některých statistik stává jedním z nejvíce populárních programovacích jazyků, což je pro jazyk poměrně úzce specializovaný poněkud zvláštní). Základní informace o nepochybně zajímavém projektu Incanter získáte ze slajdů prezentace Data Sorcery with Clojure & Incanter.
Obrázek 13: Logo projektu Incanter.
Nástroj Incanter svým uživatelům nabízí zejména tyto funkce:
- Statistické funkce (nejenom ty základní, ale i poměrně pokročilé).
- Matematické funkce pro práci s vektory a maticemi (založené na již popsané knihovně clojure.core.matrix).
- Podporu pro tvorbu různých typů grafů a pro vizualizaci dat.
- Export grafů do rastrových formátů (což využijeme dnes), popř. do vektorového formátu SVG.
- Funkce pro manipulaci s daty a s datovými zdroji (mj. i z Excelu atd.).
- Základní symbolické výpočty (prozatím je podporována symbolická derivace).
Zajímavé a možná i poučné bude zjistit, z jakého důvodu vlastně projekt Incanter vznikl a proč by pro nás mohl být zajímavý, resp. proč použít Incanter a nikoli R, jazyk Julia či řešení založené na Pythonu, resp. na kombinaci Python+Numpy+SciPy). Hlavní motivací autorů tohoto projektu bylo vytvoření rozšiřitelné platformy určené pro statistické výpočty s umožněním vizualizace výsledků pomocí různých typů grafů. Tato platforma by měla uživatelům nabízet stejné či lepší vyjadřovací schopnosti než projekt R, ovšem s tím, že Incanter využije všech výhod aplikace běžící na virtuálním stroji Javy (JVM). Důvodem, proč je – minimálně slovy autorů – JVM vhodnou platformou, je mj. i to, že pro ni existuje prakticky nepřeberné množství knihoven určených pro načítání dat (použita je například knihovna xls), zpracování dat, jejich konverzi, prezentaci, přístupu k různým databázím (relační, dokumentové, objektové) atd. (ostatně přímo Incanter používá rozhraní k MongoDB pro serializaci svých datových struktur). A zapomenout nesmíme ani na velmi kvalitní klienty pro různé databáze, systém Kafka atd.
Obrázek 14: Incanter je do značné míry alternativou ke známému nástroji R.
Se základními vlastnostmi projektu Incanter jsme se seznámili i v miniseriálu, který již na Rootu vyšel:
- Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
https://www.root.cz/clanky/incanter-prostredi-pro-statisticke-vypocty-s-grafickym-vystupem-zalozene-na-clojure/ - Incanter: operace s maticemi
https://www.root.cz/clanky/incanter-operace-s-maticemi/ - Tvorba jednoduchých grafů v systému Incanter
https://www.root.cz/clanky/tvorba-jednoduchych-grafu-v-systemu-incanter/ - Tvorba grafů v systému Incanter (pokračování)
https://www.root.cz/clanky/tvorba-grafu-v-systemu-incanter-pokracovani/
13. Instalace prostředí Incanter
Většinu běžných knihoven určených pro programovací jazyk Clojure je možné nainstalovat přímo z prostředí Jupyter Notebooku, což ovšem pro poměrně komplikovaný Incanter neplatí (resp. přesněji řečeno – teoreticky by tato instalace měla proběhnout v pořádku, ovšem při praktickém odzkoušení dojde k chybě). Proto je vhodnější vyzkoušet alternativní způsob instalace, který spočívá v tom, že příkazem:
$ lein new app incanter-app
vytvoříme kostru nové aplikace a následně upravíme projektový soubor project.clj – vložíme do něj informaci o nové závislosti:
(defproject xyz "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] [incanter "1.9.3"]] :main ^:skip-aot xyz.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Pokud se navíc jedná o projekt určený současně i pro spouštění Jupyter Notebooku (což je i náš případ), bude úprava projektového souboru project.clj spočívat v přidání dvou řádků:
(defproject xyz "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] [incanter "1.9.3"]] :main ^:skip-aot xyz.core :target-path "target/%s" :plugins [[lein-jupyter "0.1.16"]] :profiles {:uberjar {:aot :all}})
Následně spustíme příkaz určený pro stažení všech závislostí:
$ lein deps Retrieving incanter/incanter/1.9.3/incanter-1.9.3.pom from clojars Retrieving incanter/incanter-core/1.9.3/incanter-core-1.9.3.pom from clojars Retrieving org/clojure/math.combinatorics/0.1.4/math.combinatorics-0.1.4.pom from central Retrieving net/mikera/vectorz-clj/0.44.1/vectorz-clj-0.44.1.pom from clojars Retrieving net/mikera/clojure-pom/0.6.0/clojure-pom-0.6.0.pom from clojars Retrieving net/mikera/mikera-pom/0.6.0/mikera-pom-0.6.0.pom from central Retrieving net/mikera/vectorz/0.62.0/vectorz-0.62.0.pom from central Retrieving us/bpsm/edn-java/0.4.6/edn-java-0.4.6.pom from central ... ... ...
Následně můžeme – pochopitelně z adresáře, v němž je projekt vytvořen – spustit interaktivní smyčku REPL a otestovat, zda instalace Incanteru proběhla v pořádku:
$ lein repl
Měla by se vypsat klasická uvítací obrazovka REPLu jazyka Clojure:
nREPL server started on port 42197 on host 127.0.0.1 - nrepl://127.0.0.1:42197 REPL-y 0.3.7, nREPL 0.2.12 Clojure 1.8.0 OpenJDK 64-Bit Server VM 1.8.0_191-b12 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e
Dále můžeme otestovat, jestli jsou na CLASSPATH umístěny všechny důležité knihovny Incanteru:
(use '(incanter core stats charts)) nil
V případě, že se skutečně (po několika sekundách) vypíše pouze nil, znamená to, že všechny tři importované knihovny je skutečně možné použít. Zkusme si tedy vykreslit například histogram náhodných hodnot s normálním rozložením:
(view (histogram (sample-normal 1000)))
Obrázek 15: Histogram náhodných hodnot s normálním rozložením.
14. Ukázky základních možností při tvorbě grafů v Incanteru
Vzhledem k tomu, že vykreslování grafů v Incanteru již bylo na stránkách Rootu popsáno (a taktéž kvůli zmenšení rozsahu tohoto článku) jsou ukázky některých typů grafů dostupné ve formě interaktivních diářů určených pro Jupyter Notebook. Diáře je možné si prohlédnout na následujících adresách, popř. je možné je přímo naimportovat do Jupyter Notebooku (ovšem v tomto případě vyžadují instalaci Clojupyteru zmíněnou v první části článku):
- Sloupcové grafy vykreslené funkcemi z projektu Incanter
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%231.ipynb - Základní úpravy sloupcových grafů
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%232.ipynb - Sloupcové grafy s více kategoriemi
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%233.ipynb - Zobrazení průběhů funkcí
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%234.ipynb - Vykreslení grafu s průběhem funkce
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%235.ipynb - Vykreslení funkce i její derivace
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%236.ipynb - Přidání popisků do grafu
https://github.com/tisnik/jupyter-notebook-examples/blob/master/Clojupyter%20-%20Incanter%20charts%20%237.ipynb
Obrázek 16: Histogram vygenerovaný Incanterem
Obrázek 17: Bodový graf vygenerovaný Incanterem.
15. Konverze diářů do zdrojových kódů jazyka Clojure
Libovolný diář lze z Jupyter Notebooku v případě potřeby vyexportovat do dalších formátů. Můžeme se například pokusit o export do Markdownu, což bude úspěšné jen částečně, a to z toho důvodu, že standardní Markdown neobsahuje podporu pro tabulky. Ty tedy musí být vloženy pomocí HTML. Grafy jsou vyexportovány do rastrových obrázků uložených v samostatném podadresáři. Podporovány jsou i exporty do dalších formátů, včetně LaTeXu, PDF nebo AsciiDocu. Pro tyto typy exportů je však nutné mít nainstalován systém Pandoc, jehož popisu bude věnován samostatný článek.
Ovšem kromě exportu do „dokumentových“ formátů je podporován i export skriptu naprogramovaného v Clojure. V tomto případě se vyexportuje skutečně pouze programový kód zapsaný do jednotlivých buněk, který by mělo být možné spustit i mimo rámec Jupyter Notebooku:
$ jupyter nbconvert --to script Clojupyter\ -\ BufferedBitmap.ipynb [NbConvertApp] Converting notebook Clojupyter - BufferedBitmap.ipynb to script [NbConvertApp] Writing 575 bytes to Clojupyter - BufferedBitmap.clj
nebo, chcete-li:
$ jupyter nbconvert --to script "Clojupyter - BufferedBitmap.ipynb" [NbConvertApp] Converting notebook Clojupyter - BufferedBitmap.ipynb to script [NbConvertApp] Writing 575 bytes to Clojupyter - BufferedBitmap.clj
Obrázek 18: Ukázka některých základních jazykových konstrukcí jazyka Clojure.
16. Historie příkazů zapisovaných do Jupyter Notebooku
Mnoho jazyků vybavených interaktivní smyčkou REPL podporuje i uložení (a pochopitelně i znovupoužití) dříve zadaných příkazů. Je tomu tak i v případě projektu Clojupyter, který tak umožňuje velmi snadno příkazy přenášet mezi různými diáři, používat výše zmíněný příkaz use se základními moduly atd. Historie zadaných příkazů ovšem není ukládána do textových souborů (u nichž je velmi problematická sémantika – kdo, jak a kdy může historii ukládat); namísto toho se používá databáze SQLite(3) a soubor s historií je uložen přímo v domácím adresáři uživatele:
$ file .clojupyter_history .clojupyter_history: SQLite 3.x database, last written using SQLite version 3007002
Strukturu tohoto souboru si můžeme snadno prohlédnou s využitím řádkového klienta sqlite3:
$ sqlite3 .clojupyter_history SQLite version 3.20.1 2017-08-24 16:21:36 Enter ".help" for usage hints.
Výpis všech databázových tabulek:
sqlite> .tables history sessions
Zobrazení schématu (struktury) obou databázových tabulek:
sqlite> .schema history CREATE TABLE history (session integer, line integer, source text, primary key (session, line)); sqlite> .schema sessions CREATE TABLE sessions (session integer primary key autoincrement, start timestamp, end timestamp, num_cmds integer default 0, remark text);
Zobrazení historie zadávaných příkazů (povšimněte si, že historie je rozdělena podle jednotlivých sezení, což je jeden z důvodů, proč by nebyl běžný textový soubor ideální):
sqlite> select * from history; 1|1|(doc doc) 1|2|(+ 1 1) 1|3|(help help) 1|4|(doc doc) 1|5|(doc 'doc) 1|6|(print "foo") 1|7|(doc "foo") 1|8|(clojure.core/use '[clojure.repl :only (doc)]) 1|9|(doc "foo") 1|10|(doc doc) 1|11|(repeat 100 1) 2|1|(clojure.core/use '[clojure.repl :only (doc)]) 2|2|(require '[clojupyter.misc.display :as display]) 2|3|(scatter-plot) 2|4|(display/scatter-plot) 2|5|(require '[clojupyter.display :as display]) (require '[clojupyter.misc.helper :as helper]) (helper/add-dependencies '[org.clojure/data.json "0.2.6"]) 2|6|(require '[clojupyter.misc.display :as display]) (require '[clojupyter.misc.helper :as helper]) (helper/add-dependencies '[org.clojure/data.json "0.2.6"]) 3|1|(doc doc) 3|2|(ns user) 3|3|(doc) 3|4|(inc 0) 3|5|(import clojure.repl) 3|6|(require clojure.repl) 3|7|(use clojure.repl) 3|8|(use 'clojure.repl) 3|9|(doc doc) 3|10|(doc if)
17. Repositář s demonstračními příklady
Všechny demonstrační příklady určené pro programovací jazyk Clojure verze 1.9.0, popř. Clojure 1.8.0, byly uloženy do repositáře, který naleznete na adrese https://github.com/tisnik/jupyter-notebook-examples:
18. Odkazy na články o Jupyter Notebooku
Se samotným nástrojem Jupyter Notebook jsme se již na stránkách Rootu čtyřikrát setkali, a to konkrétně v následujících článcích:
- Jupyter Notebook – nástroj pro programátory, výzkumníky i lektory
https://www.root.cz/clanky/jupyter-notebook-nastroj-pro-programatory-vyzkumniky-i-lektory/ - Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib
https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib/ - Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib (dokončení)
https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib-dokonceni/ - Jupyter Notebook – operace s rastrovými obrázky a UML diagramy, literate programming
https://www.root.cz/clanky/jupyter-notebook-operace-s-rastrovymi-obrazky-a-uml-diagramy-literate-programming/
19. Odkazy na předchozí části seriálu o programovacím jazyku Clojure
- Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Multimetody v Clojure aneb polymorfismus bez použití OOP
https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/ - Práce s externími Java archivy v programovacím jazyku Clojure
https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - Novinky v Clojure verze 1.9.0
https://www.root.cz/clanky/novinky-v-clojure-verze-1–9–0/ - Validace dat s využitím knihovny spec v Clojure 1.9.0
https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure (2)
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure-2/ - Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
https://www.root.cz/clanky/incanter-prostredi-pro-statisticke-vypocty-s-grafickym-vystupem-zalozene-na-clojure/ - Incanter: operace s maticemi
https://www.root.cz/clanky/incanter-operace-s-maticemi/
20. Odkazy na Internetu
- How to create Clojure notebooks in Jupyter
https://s01blog.wordpress.com/2017/12/10/how-to-create-clojure-notebooks-in-jupyter/ - Dokumentace k nástroji Conda
https://docs.conda.io/en/latest/ - Notebook interface
https://en.wikipedia.org/wiki/Notebook_interface - Jypyter: open source, interactive data science and scientific computing across over 40 programming languages
https://jupyter.org/ - Calysto Scheme
https://github.com/Calysto/calysto_scheme - scheme.py (základ projektu Calysto Scheme)
https://github.com/Calysto/calysto_scheme/blob/master/calysto_scheme/scheme.py - Matplotlib Home Page
http://matplotlib.org/ - Matplotlib (Wikipedia)
https://en.wikipedia.org/wiki/Matplotlib - Popis barvových map modulu matplotlib.cm
https://gist.github.com/endolith/2719900#id7 - Ukázky (palety) barvových map modulu matplotlib.cm
http://matplotlib.org/examples/color/colormaps_reference.html - Galerie grafů vytvořených v Matplotlibu
https://matplotlib.org/3.2.1/gallery/ - showcase example code: xkcd.py
https://matplotlib.org/xkcd/examples/showcase/xkcd.html - Customising contour plots in matplotlib
https://philbull.wordpress.com/2012/12/27/customising-contour-plots-in-matplotlib/ - Graphics with Matplotlib
http://kestrel.nmt.edu/~raymond/software/python_notes/paper004.html - The IPython Notebook
http://ipython.org/notebook.html - nbviewer: a simple way to share Jupyter Notebooks
https://nbviewer.jupyter.org/ - Back to the Future: Lisp as a Base for a Statistical Computing System
https://www.stat.auckland.ac.nz/~ihaka/downloads/Compstat-2008.pdf - gg4clj: a simple wrapper for using R's ggplot2 in Clojure and Gorilla REPL
https://github.com/JonyEpsilon/gg4clj - Analemma: a Clojure-based SVG DSL and charting library
http://liebke.github.io/analemma/ - Clojupyter: a Jupyter kernel for Clojure
https://github.com/roryk/clojupyter - Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
http://incanter.org/ - Evolution of incanter (Gource Visualization)
https://www.youtube.com/watch?v=TVfL5nPELr4 - Questions tagged [incanter] (na Stack Overflow)
https://stackoverflow.com/questions/tagged/incanter?sort=active - Data Sorcery with Clojure
https://data-sorcery.org/contents/ - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - R Markdown: The Definitive Guide
https://bookdown.org/yihui/rmarkdown/ - Single-page application
https://en.wikipedia.org/wiki/Single-page_application - Video streaming in the Jupyter Notebook
https://towardsdatascience.com/video-streaming-in-the-jupyter-notebook-635bc5809e85 - How IPython and Jupyter Notebook work
https://jupyter.readthedocs.io/en/latest/architecture/how_jupyter_ipython_work.html - Jupyter kernels
https://github.com/jupyter/jupyter/wiki/Jupyter-kernels - Keras: The Python Deep Learning library
https://keras.io/ - TensorFlow
https://www.tensorflow.org/ - PyTorch
https://pytorch.org/ - Seriál Torch: framework pro strojové učení
https://www.root.cz/serialy/torch-framework-pro-strojove-uceni/ - Scikit-learn
https://scikit-learn.org/stable/ - Java Interop (Clojure)
https://clojure.org/reference/java_interop - Obrazy s balíčky Jupyter Notebooku pro Docker
https://hub.docker.com/u/jupyter/#! - Správce balíčků Conda (dokumentace)
https://docs.conda.io/en/latest/ - Lorenzův atraktor
https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-vi/#k02 - Lorenzův atraktor
https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-iii/#k03 - Graphics with Matplotlib
http://kestrel.nmt.edu/~raymond/software/python_notes/paper004.html - Embedding Matplotlib Animations in Jupyter Notebooks
http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-notebooks/ - Literate programing, Kolokviální práce Pavla Starého
https://www.fi.muni.cz/usr/jkucera/pv109/starylp.htm - PlantUML (home page)
http://plantuml.sourceforge.net/ - PlantUML (download page)
http://sourceforge.net/projects/plantuml/files/plantuml.jar/download - PlantUML (Language Reference Guide)
http://plantuml.sourceforge.net/PlantUML_Language_Reference_Guide.pdf - Plain-text diagrams take shape in Asciidoctor!
http://asciidoctor.org/news/2014/02/18/plain-text-diagrams-in-asciidoctor/ - Graphviz – Graph Visualization Software
http://www.graphviz.org/ - graphviz (Manual Page)
http://www.root.cz/man/7/graphviz/ - PIL: The friendly PIL fork (home page)
https://python-pillow.org/ - Python Imaging Library (PIL), (home page)
http://www.pythonware.com/products/pil/ - PIL 1.1.6 na PyPi
https://pypi.org/project/PIL/ - Pillow 5.2.0 na PyPi
https://pypi.org/project/Pillow/ - Python Imaging Library na Wikipedii
https://en.wikipedia.org/wiki/Python_Imaging_Library - Pillow na GitHubu
https://github.com/python-pillow/Pillow - Pillow – dokumentace na readthedocs.io
http://pillow.readthedocs.io/en/5.2.x/ - How to use Pillow, a fork of PIL
https://www.pythonforbeginners.com/gui/how-to-use-pillow - Humane test output for clojure.test
https://github.com/pjstadig/humane-test-output - iota
https://github.com/juxt/iota - 5 Differences between clojure.spec and Schema
https://lispcast.com/clojure.spec-vs-schema/ - Schema: Clojure(Script) library for declarative data description and validation
https://github.com/plumatic/schema - Zip archiv s Clojure 1.9.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.9.0/clojure-1.9.0.zip - Clojure 1.9 is now available
https://clojure.org/news/2017/12/08/clojure19 - Deps and CLI Guide
https://clojure.org/guides/deps_and_cli - Changes to Clojure in Version 1.9
https://github.com/clojure/clojure/blob/master/changes.md - clojure.spec – Rationale and Overview
https://clojure.org/about/spec - Zip archiv s Clojure 1.8.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip - Clojure 1.8 is now available
http://clojure.org/news/2016/01/19/clojure18 - Socket Server REPL
http://dev.clojure.org/display/design/Socket+Server+REPL - CLJ-1671: Clojure socket server
http://dev.clojure.org/jira/browse/CLJ-1671 - CLJ-1449: Add clojure.string functions for portability to ClojureScript
http://dev.clojure.org/jira/browse/CLJ-1449 - Launching a Socket Server
http://clojure.org/reference/repl_and_main#_launching_a_socket_server - API for clojure.string
http://clojure.github.io/clojure/branch-master/clojure.string-api.html - Clojars:
https://clojars.org/ - Seznam knihoven na Clojars:
https://clojars.org/projects - Clojure Cookbook: Templating HTML with Enlive
https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc - An Introduction to Enlive
https://github.com/swannodette/enlive-tutorial/ - Enlive na GitHubu
https://github.com/cgrand/enlive - Expectations: příklady atd.
http://jayfields.com/expectations/ - Expectations na GitHubu
https://github.com/jaycfields/expectations - Lein-expectations na GitHubu
https://github.com/gar3thjon3s/lein-expectations - Testing Clojure With Expectations
https://semaphoreci.com/blog/2014/09/23/testing-clojure-with-expectations.html - Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
https://www.reddit.com/r/Clojure/comments/1viilt/clojure_testing_tddbdd_libraries_clojuretest_vs/ - Testing: One assertion per test
http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html - Rewriting Your Test Suite in Clojure in 24 hours
http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/ - Clojure doc: zipper
http://clojuredocs.org/clojure.zip/zipper - Clojure doc: parse
http://clojuredocs.org/clojure.xml/parse - Clojure doc: xml-zip
http://clojuredocs.org/clojure.zip/xml-zip - Clojure doc: xml-seq
http://clojuredocs.org/clojure.core/xml-seq - Parsing XML in Clojure
https://github.com/clojuredocs/guides - Clojure Zipper Over Nested Vector
https://vitalyper.wordpress.com/2010/11/23/clojure-zipper-over-nested-vector/ - Understanding Clojure's PersistentVector implementation
http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation - Understanding Clojure's PersistentHashMap (deftwice…)
http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html - Assoc and Clojure's PersistentHashMap: part ii
http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html - Ideal Hashtrees (paper)
http://lampwww.epfl.ch/papers/idealhashtrees.pdf - Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure Sequences
http://clojure.org/sequences - Clojure Data Structures
http://clojure.org/data_structures - The Structure and Interpretation of Computer Programs: 2.2.1 Representing Sequences
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec2.2.1 - The Structure and Interpretation of Computer Programs: 3.3.1 Mutable List Structure
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec3.3.1 - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Čistě funkcionální (datové struktury, jazyky, programování)
http://cs.wikipedia.org/wiki/Čistě_funkcionální - Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-i-getting.html - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - Třída java.lang.String
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html - Třída java.lang.StringBuffer
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html - Třída java.lang.StringBuilder
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html - StringBuffer versus String
http://www.javaworld.com/article/2076072/build-ci-sdlc/stringbuffer-versus-string.html - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients