9 Graphs with Noj
9.1 Bar graphs
ns chapter-4-data-visualisation.noj-examples
(:require [tablecloth.api :as tc]
(:as hc]
[aerial.hanami.common :as ht]
[aerial.hanami.templates :as vht]
[scicloj.noj.v1.vis.hanami.templates :as vis]
[scicloj.noj.v1.vis :as stats]
[scicloj.noj.v1.stats :as datasets]
[scicloj.noj.v1.datasets :as dtype]
[tech.v3.datatype :as fun]
[tech.v3.datatype.functional :as kind]
[scicloj.kindly.v4.kind :as hiccup]
[hiccup.core :as color]
[clojure2d.color :as kind-clerk])) [scicloj.kind-clerk.api
(kind-clerk/setup!)
:ok
9.2 Raw html
-> "<p>Hello, <i>Noj</i>.</p>"
( kind/html)
Hello, Noj.
(kind/html"
<svg height=100 width=100>
<circle cx=50 cy=50 r=40 stroke='purple' stroke-width=3 fill='floralwhite' />
</svg> ")
9.3 Visualizing datases with Hanami
Noj offers a few convenience functions to make Hanami plotting work smoothly with Tablecloth and Kindly.
def random-walk
(let [n 20]
(-> {:x (range n)
(:y (->> (repeatedly n #(- (rand) 0.5))
+))}
(reductions tc/dataset)))
9.3.1 A simple plot
We can plot a Tablecloth datasete using a Hanami template:
-> random-walk
(
(vis/hanami-plot ht/point-chart:MSIZE 200})) {
Let us look inside the resulting vega-lite space. We can see the dataset is included as CSV:
-> random-walk
(
(vis/hanami-plot ht/point-chart:MSIZE 200})
{ kind/pprint)
:encoding
{:y {:field "y", :type "quantitative"},
{:x {:field "x", :type "quantitative"}},
:mark {:type "circle", :size 200, :tooltip true},
:width 400,
:background "floralwhite",
:height 300,
:data
:values
{"x,y\n0,0.25915143611932323\n1,0.07679044186868467\n2,-0.16838373926426764\n3,-0.3472917379109737\n4,-0.4185674782284593\n5,-0.3275712090765166\n6,0.06499031613330208\n7,-0.12473464521100663\n8,0.24581959605889236\n9,0.3872343668945971\n10,0.20630731645770806\n11,0.4283007097190942\n12,0.8577253018355132\n13,1.029799282228336\n14,1.500296189747702\n15,1.802090709990422\n16,1.675173594897049\n17,1.5406670970402527\n18,1.5912246361060238\n19,1.7546356050436023\n",
:format {:type "csv"}}}
9.3.2 Additional Hanami templates
The scicloj.noj.v1.vis.hanami.templates
namespace add Hanami templates to Hanami’s own collection.
-> datasets/mtcars
(
(vis/hanami-plot vht/boxplot-chart:X :gear
{:XTYPE :nominal
:Y :mpg}))
9.3.3 Layers
-> random-walk
(
(vis/hanami-layers:TITLE "points and a line"}
{nil
[(vis/hanami-plot
ht/point-chart:MSIZE 400})
{nil
(vis/hanami-plot
ht/line-chart:MSIZE 4
{:MCOLOR "brown"})]))
9.3.4 Concatenation
-> random-walk
(
(vis/hanami-vconcat
{}nil
[(vis/hanami-plot
ht/point-chart:MSIZE 400
{:HEIGHT 100
:WIDTH 100})
nil
(vis/hanami-plot
ht/line-chart:MSIZE 4
{:MCOLOR "brown"
:HEIGHT 100
:WIDTH 100})]))
-> random-walk
(
(vis/hanami-hconcat
{}nil
[(vis/hanami-plot
ht/point-chart:MSIZE 400
{:HEIGHT 100
:WIDTH 100})
nil
(vis/hanami-plot
ht/line-chart:MSIZE 4
{:MCOLOR "brown"
:HEIGHT 100
:WIDTH 100})]))
9.3.5 Linear regression
-> datasets/mtcars
(:mpg [:wt]
(stats/add-predictions :model-type :smile.regression/ordinary-least-square})
{
(vis/hanami-layers {}nil
[(vis/hanami-plot
ht/point-chart:X :wt
{:Y :mpg
:MSIZE 200
:HEIGHT 200
:WIDTH 200})
nil
(vis/hanami-plot
ht/line-chart:X :wt
{:Y :mpg-prediction
:MSIZE 5
:MCOLOR "purple"
:YTITLE :mpg})]))
9.3.6 Histogram
-> datasets/iris
(:sepal-width
(vis/hanami-histogram :nbins 10})) {
9.3.7 Combining a few things together
The following is inspired by the example at Plotnine’s main page. Note how we add regression lines here. We take care of layout and colouring on our side, not using Vega-Lite for that.
let [pallete (->> :accent
(
color/palettemapv color/format-hex))]
(-> datasets/mtcars
(:gear {:result-type :as-map})
(tc/group-by ->> (sort-by key)
(
(map-indexedfn [i [group-name ds]]
(-> ds
(:mpg [:wt]
(stats/add-predictions :model-type :smile.regression/ordinary-least-square})
{:gear :wt :mpg :mpg-prediction])
(tc/select-columns [:TITLE (str "grear=" group-name)}
(vis/hanami-layers {nil
[(vis/hanami-plot
ht/point-chart:X :wt
{:Y :mpg
:MSIZE 200
:MCOLOR (pallete i)
:HEIGHT 200
:WIDTH 200})
nil
(vis/hanami-plot
ht/line-chart:X :wt
{:Y :mpg-prediction
:MSIZE 5
:MCOLOR (pallete i)
:YTITLE :mpg})]
))))nil {})))) (vis/hanami-vconcat
A similar example with histograms:
let [pallete (->> :accent
(
color/palettemapv color/format-hex))]
(-> datasets/iris
(:species {:result-type :as-map})
(tc/group-by ->> (sort-by key)
(
(map-indexedfn [i [group-name ds]]
(-> ds
(:sepal-width
(vis/hanami-histogram :nbins 10}))))
{nil {})))) (vis/hanami-vconcat
Scatterplots and regression lines again, this time using Vega-Lite for layout and coloring (using its “facet” option).
-> datasets/mtcars
(:gear])
(tc/group-by [:mpg [:wt]
(stats/add-predictions :model-type :smile.regression/ordinary-least-square})
{
(tc/ungroup):gear :wt :mpg :mpg-prediction])
(tc/select-columns [
(vis/hanami-layers {}nil
[(vis/hanami-plot
ht/point-chart:X :wt
{:Y :mpg
:MSIZE 200
:COLOR "gear"
:HEIGHT 100
:WIDTH 200})
nil
(vis/hanami-plot
ht/line-chart:X :wt
{:Y :mpg-prediction
:MSIZE 5
:COLOR "gear"
:YTITLE :mpg})])
fn [spec]
((:facet {:row {:field "gear"}}
{:spec (dissoc spec :data)
:data (:data spec)}))
kind/vega-lite)
:bye
:bye