Skip to content

Instantly share code, notes, and snippets.

@otfrom
Last active September 5, 2023 14:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save otfrom/2785ab6767d2e887d6f44e357b968f9f to your computer and use it in GitHub Desktop.
Save otfrom/2785ab6767d2e887d6f44e357b968f9f to your computer and use it in GitHub Desktop.
(ns witan.cic.tuairisc.alpha.clerk.charting
(:require
[nextjournal.clerk :as clerk]
[tablecloth.api :as tc]))
(defn color-and-shape-lookup [domain]
(tc/dataset
{:domain-value domain
:color (cycle ["#29733c" "#fa814c" "#256cc6" "#fbe44c" "#50b938" "#59c4b8"])
:shape (cycle ["circle", "square", "cross", "diamond", "triangle-up", "triangle-down", "triangle-right", "triangle-left"])}))
(defn color-map [plot-data color-field color-lookup]
(let [group-keys (into (sorted-set) (get plot-data color-field))
filtered-colors (tc/select-rows color-lookup #(group-keys (get % :domain-value)))]
{:field color-field
:scale {:range (into [] (:color filtered-colors))
:domain (into [] (:domain-value filtered-colors))}}))
(defn shape-map [plot-data shape-field shape-lookup]
(let [group-keys (into (sorted-set) (get plot-data shape-field))
filtered-shapes (tc/select-rows shape-lookup #(group-keys (get % :domain-value)))]
{:field shape-field
:scale {:range (into [] (:shape filtered-shapes))
:domain (into [] (:domain-value filtered-shapes))}}))
(defn line-plot
[{:keys [data
chart-title
chart-height chart-width
clerk-width
x x-title x-format
y y-title
group group-title
colors-and-shapes]
:or {chart-height 640
chart-width 825
clerk-width :full}}]
(clerk/vl
{::clerk/width clerk-width}
{:height chart-height
:width chart-width
:title {:text chart-title
:fontSize 24}
:config {:legend {:titleFontSize 20
:labelFontSize 14}
:axisX {:titleFontSize 16
:labelFontSize 12}
:axisY {:titleFontSize 16
:labelFontSize 12}}
:data {:values (tc/rows data :as-maps)}
:layer [{:mark {:type "line", :point {:filled false,
:fill "white",
:size 50
:strokeWidth 0.5}},
:encoding {:y {:field y, :title y-title :type "quantitative"},
:x {:field x, :title x-title :type "temporal"},
;; color and shape scale and range must be specified or you get extra things in the legend
:color (color-map data group colors-and-shapes)
:shape (shape-map data group colors-and-shapes)
:tooltip [{:field group, :title group-title},
{:field x, :type "temporal", :format x-format, :title x-title},
{:field y, :title y-title}]}}]}))
(defn line-and-ribbon-plot
[{:keys [data
chart-title
chart-height chart-width
clerk-width
x x-title x-format
y y-title
irl iru ir-title
orl oru or-title
group group-title
colors-and-shapes]
:or {chart-height 640
chart-width 825
clerk-width :full}}]
(clerk/vl
{::clerk/width clerk-width}
{:height chart-height
:width chart-width
:title {:text chart-title
:fontSize 24}
:config {:legend {:titleFontSize 20
:labelFontSize 14}
:axisX {:titleFontSize 16
:labelFontSize 12}
:axisY {:titleFontSize 16
:labelFontSize 12}}
:data {:values (-> data
(tc/map-columns :ir [irl iru] (fn [lower upper]
(format "%,f - %,1f" lower upper)))
(tc/map-columns :or [orl oru] (fn [lower upper]
(format "%,1f - %,1f" lower upper)))
(tc/rows :as-maps))}
:layer [{:mark "errorband"
:encoding {:y {:field iru :title y-title :type "quantitative"}
:y2 {:field irl}
:x {:field x :title x-title :type "temporal"}
:color {:field group :title group-title}
:tooltip [{:field group, :title group-title},
{:field x, :type "temporal", :format x-format, :title x-title},
{:field y, :title y-title}
{:field :ir :title ir-title}
{:field :or :title or-title}]}}
{:mark "errorband"
:encoding {:y {:field oru :title y-title :type "quantitative"}
:y2 {:field orl}
:x {:field x :title x-title :type "temporal"}
:color {:field group :title group-title}
:tooltip [{:field group, :title group-title},
{:field x, :type "temporal", :format x-format, :title x-title},
{:field y, :title y-title}
{:field :ir :title ir-title}
{:field :or :title or-title}]}}
{:mark {:type "line", :point {:filled false,
:fill "white",
:size 50
:strokeWidth 0.5}},
:encoding {:y {:field y, :title y-title :type "quantitative"},
:x {:field x, :title x-title :type "temporal"},
;; color and shape scale and range must be specified or you get extra things in the legend
:color (color-map data group colors-and-shapes)
:shape (shape-map data group colors-and-shapes)
:tooltip [{:field group, :title group-title},
{:field x, :type "temporal", :format x-format, :title x-title},
{:field y, :title y-title}
{:field :ir :title ir-title}
{:field :or :title or-title}]}}]}))
(comment
(def pa-lookup (color-and-shape-lookup (into (sorted-set "K2" "P2H5" "Q2") (:placement-type placement-analysis))))
(line-plot {:data (-> costs-by-placement
;; (tc/map-columns "Week" :string [:week-starts] (fn [d] (str d)))
(ds/column-map "Week" str [:week-start])
(tc/rename-columns {:placement-type "Placement" :week-starts "Week" :median "Median"}))
:chart-title "Weeks in care by placement type"
:x "Week" :x-title "Week" :x-format "%b %Y"
:y "Median" :y-title "# of Children Looked After"
:group "Placement" :group-title "Placement"
:colors-and-shapes lookup})
;;; ## Weeks in Care by Placement Type
(line-and-ribbon-plot
{:data (-> costs-by-placement
(tc/map-columns :week-start [:week-start] (fn [d] (str d))))
:chart-title "Weeks in care by placement type"
:x :week-start :x-title "Week" :x-format "%b %Y"
:y :median :y-title "# of Children Looked After"
:irl :q1 :iru :q3 :ir-title "50% range"
:orl :low-5 :oru :hi-95 :or-title "90% range"
:group :placement-type :group-title "Placement"
:colors-and-shapes pa-lookup})
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment