Skip to content

Commit 4507c3b

Browse files
committed
composablepl_plotting wip
1 parent d676801 commit 4507c3b

1 file changed

Lines changed: 57 additions & 38 deletions

File tree

src/data_visualization/aog/composable_plotting.clj

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
;; Everything renders to [SVG](https://en.wikipedia.org/wiki/SVG) via [Hiccup](https://github.com/weavejester/hiccup). The post builds up incrementally:
7878
;; scatter plots, histograms, regression lines, bars,
7979
;; multi-panel layouts, polar coordinates, and interactivity.
80+
;;
8081
;; ---
8182

8283
;; ## Motivation
@@ -107,6 +108,7 @@ splom-tut/iris-splom-4x4
107108
;; Everything that the SPLOM Tutorial does — grid layout,
108109
;; scale sharing, color assignment, diagonal detection —
109110
;; should follow from the composed specification.
111+
;;
110112
;; ---
111113

112114
;; ## Glossary
@@ -150,6 +152,7 @@ splom-tut/iris-splom-4x4
150152
;;
151153
;; **Layout** -- how panels are arranged: a single plot,
152154
;; a scatterplot matrix, or a faceted grid.
155+
;;
153156
;; ---
154157

155158
;; ## Setup
@@ -201,6 +204,7 @@ mpg
201204

202205
tips
203206

207+
;;
204208
;; ---
205209

206210
;; ## Composing Views
@@ -412,6 +416,7 @@ tips
412416
;; > *The next sections build the rendering pipeline piece by piece.
413417
;; > To see results first and return for the implementation,
414418
;; > skip to [Scatter Plots](#scatter-plots).*
419+
;;
415420
;; ---
416421

417422
;; ## Theme and Colors
@@ -504,6 +509,7 @@ tips
504509

505510
(mapv fmt-name [:sepal-length :petal_width :species])
506511

512+
;;
507513
;; ---
508514

509515
;; ## Inference and Defaults
@@ -658,6 +664,7 @@ tips
658664

659665
(select-keys (merge defaults {:point-radius 5 :bar-opacity 0.9})
660666
[:point-radius :bar-opacity :line-width])
667+
;;
661668
;; ---
662669

663670
;; ## Computing Statistics
@@ -742,6 +749,7 @@ tips
742749
(defmethod compute-stat :identity [view]
743750
(prepare-points view))
744751

752+
;;
745753
;; ---
746754

747755
;; ## Scales -- Data to Pixels
@@ -809,6 +817,7 @@ tips
809817
{:A-position (s "A")
810818
:B-band-info (s "B" true)
811819
:ticks (ws/ticks s)})
820+
;;
812821
;; ---
813822

814823
;; ## Coordinate Systems
@@ -865,6 +874,7 @@ tips
865874
(defmethod render-grid :default [_ sx sy pw ph m cfg]
866875
(render-grid :cartesian sx sy pw ph m cfg))
867876

877+
;;
868878
;; ---
869879

870880
;; ## Drawing Marks
@@ -928,6 +938,7 @@ tips
928938
[:rect {:x 0 :y 0 :width 600 :height 400 :fill (:bg theme)}]
929939
marks]))
930940

941+
;;
931942
;; ---
932943

933944
;; ## Axes and Grid Lines
@@ -1015,6 +1026,7 @@ tips
10151026
(render-x-ticks :numeric sx pw ph m defaults)
10161027
(render-y-ticks :numeric sy pw ph m defaults)]))
10171028

1029+
;;
10181030
;; ---
10191031

10201032
;; ## Assembling a Panel
@@ -1160,6 +1172,7 @@ tips
11601172
(view [[:x :y]])
11611173
(lay (point)))
11621174
600 400 25)])
1175+
;;
11631176
;; ---
11641177

11651178
;; ## Rendering the Plot
@@ -1188,11 +1201,9 @@ tips
11881201

11891202
(defn infer-layout [views]
11901203
(let [facet-rows (seq (remove nil? (map :facet-row views)))
1191-
facet-cols (seq (remove nil? (map :facet-col views)))
1192-
facet-vals (seq (remove nil? (map :facet-val views)))]
1204+
facet-cols (seq (remove nil? (map :facet-col views)))]
11931205
(cond
1194-
(and facet-rows facet-cols) :facet-grid
1195-
facet-vals :facet
1206+
(or facet-rows facet-cols) :facet-grid
11961207
:else (let [x-vars (distinct (map :x views))
11971208
y-vars (distinct (map :y views))]
11981209
(if (or (> (count x-vars) 1) (> (count y-vars) 1))
@@ -1296,16 +1307,13 @@ tips
12961307
layout-type (infer-layout non-ann-views)
12971308
x-vars (distinct (map :x non-ann-views))
12981309
y-vars (distinct (map :y non-ann-views))
1299-
facet-vals (distinct (remove nil? (map :facet-val non-ann-views)))
13001310
facet-row-vals (distinct (remove nil? (map :facet-row non-ann-views)))
13011311
facet-col-vals (distinct (remove nil? (map :facet-col non-ann-views)))
13021312
cols (case layout-type
13031313
:facet-grid (count facet-col-vals)
1304-
:facet (count facet-vals)
13051314
(count x-vars))
13061315
rows (case layout-type
13071316
:facet-grid (count facet-row-vals)
1308-
:facet 1
13091317
(count y-vars))
13101318
multi? (and (= layout-type :multi-variable) (> cols 1) (> rows 1))
13111319
m (if multi? (:margin-multi cfg) (:margin cfg))
@@ -1361,7 +1369,7 @@ tips
13611369
:shape-categories shape-categories :coord-type coord-type-main
13621370
:global-x-doms global-x-doms :global-y-doms global-y-doms
13631371
:x-vars x-vars :y-vars y-vars
1364-
:facet-vals facet-vals :facet-row-vals facet-row-vals :facet-col-vals facet-col-vals
1372+
:facet-row-vals facet-row-vals :facet-col-vals facet-col-vals
13651373
:color-cols color-cols :shape-col shape-col :scale-mode scale-mode
13661374
:cfg cfg}
13671375
svg-content
@@ -1413,6 +1421,7 @@ tips
14131421
(into [:g] (remove nil? (arrange-panels layout-type ctx)))]]]
14141422
(wrap-plot (cond-> #{} tooltip (conj :tooltip) brush (conj :brush)) svg-content))))
14151423

1424+
;;
14161425
;; ---
14171426

14181427
;; ## Scatter Plots
@@ -1459,6 +1468,7 @@ tips
14591468
(lay (point {:color "steelblue" :size 6}))
14601469
plot)
14611470

1471+
;;
14621472
;; ---
14631473

14641474
;; ## Histograms
@@ -1565,6 +1575,7 @@ tips
15651575
(coord :flip)
15661576
plot)
15671577

1578+
;;
15681579
;; ---
15691580

15701581
;; ## Line Charts
@@ -1619,6 +1630,7 @@ tips
16191630
(lay (line {:color :region}))
16201631
plot)
16211632

1633+
;;
16221634
;; ---
16231635

16241636
;; ## Layers
@@ -1652,6 +1664,7 @@ tips
16521664
(lay (point {:color :region}) (line {:color :region}))
16531665
plot)
16541666

1667+
;;
16551668
;; ---
16561669

16571670
;; ## Regression and Smooth Lines
@@ -1796,6 +1809,7 @@ tips
17961809
(loess {:color :species}))
17971810
plot)
17981811

1812+
;;
17991813
;; ---
18001814

18011815
;; ## Categorical Charts
@@ -2078,6 +2092,7 @@ tips
20782092
(lay (value-bar))
20792093
plot)
20802094

2095+
;;
20812096
;; ---
20822097

20832098
;; ## Multi-Panel Layouts
@@ -2191,29 +2206,29 @@ tips
21912206
;; ### ⚙️ Faceting
21922207

21932208
(defn facet
2194-
"Split each view by a categorical column."
2195-
[views col]
2196-
(mapcat
2197-
(fn [v]
2198-
(validate-columns (:data v) :facet col)
2199-
(let [groups (tc/group-by (:data v) [col] {:result-type :as-map})]
2200-
(map (fn [[gk gds]]
2201-
(assoc v :data gds :facet-val (get gk col)))
2202-
groups)))
2203-
views))
2209+
"Split each view by a categorical column.
2210+
Default layout is a horizontal row of panels.
2211+
Pass :col as direction for a vertical column of panels."
2212+
([views col] (facet views col :row))
2213+
([views col direction]
2214+
(case direction
2215+
:row (facet-grid views nil col)
2216+
:col (facet-grid views col nil))))
22042217

22052218
(defn facet-grid
2206-
"Split each view by two categorical columns for a row × column grid."
2219+
"Split each view by two categorical columns for a row × column grid.
2220+
Either column may be nil for a single-dimension facet."
22072221
[views row-col col-col]
22082222
(mapcat
22092223
(fn [v]
2210-
(validate-columns (:data v) :facet-row row-col)
2211-
(validate-columns (:data v) :facet-col col-col)
2212-
(let [groups (tc/group-by (:data v) [row-col col-col] {:result-type :as-map})]
2224+
(when row-col (validate-columns (:data v) :facet-row row-col))
2225+
(when col-col (validate-columns (:data v) :facet-col col-col))
2226+
(let [group-cols (filterv some? [row-col col-col])
2227+
groups (tc/group-by (:data v) group-cols {:result-type :as-map})]
22132228
(map (fn [[gk gds]]
22142229
(assoc v :data gds
2215-
:facet-row (get gk row-col)
2216-
:facet-col (get gk col-col)))
2230+
:facet-row (if row-col (get gk row-col) "_")
2231+
:facet-col (if col-col (get gk col-col) "_")))
22172232
groups)))
22182233
views))
22192234

@@ -2264,18 +2279,6 @@ tips
22642279
:transform (str "rotate(-90," (- pw 5) "," (/ ph 2) ")")}
22652280
(fmt-name yv)])]))))
22662281

2267-
;; ### ⚙️ `arrange-panels` `:facet`
2268-
2269-
(defmethod arrange-panels :facet [_ ctx]
2270-
(let [{:keys [non-ann-views ann-views pw ph facet-vals]} ctx]
2271-
(for [[ci fv] (map-indexed vector facet-vals)
2272-
:let [fviews (concat (filter #(= fv (:facet-val %)) non-ann-views)
2273-
ann-views)]]
2274-
[:g {:transform (str "translate(" (* ci pw) ",0)")}
2275-
(panel-from-ctx ctx fviews :show-y? (zero? ci))
2276-
[:text {:x (/ pw 2) :y 12 :text-anchor "middle"
2277-
:font-size 10 :fill "#333"} (str fv)]])))
2278-
22792282
;; ### ⚙️ `arrange-panels` `:facet-grid`
22802283

22812284
(defmethod arrange-panels :facet-grid [_ ctx]
@@ -2290,10 +2293,10 @@ tips
22902293
(panel-from-ctx ctx panel-views
22912294
:show-x? (= ri (dec rows))
22922295
:show-y? (zero? ci))
2293-
(when (zero? ri)
2296+
(when (and (zero? ri) (not= cv "_"))
22942297
[:text {:x (/ pw 2) :y 12 :text-anchor "middle"
22952298
:font-size 10 :fill "#333"} (str cv)])
2296-
(when (= ci (dec cols))
2299+
(when (and (= ci (dec cols)) (not= rv "_"))
22972300
[:text {:x (- pw 5) :y (/ ph 2) :text-anchor "end"
22982301
:font-size 10 :fill "#333"
22992302
:transform (str "rotate(-90," (- pw 5) "," (/ ph 2) ")")}
@@ -2328,6 +2331,15 @@ tips
23282331
(facet :species)
23292332
plot)
23302333

2334+
;; ### 🧪 Vertical Facet
2335+
;;
2336+
;; Pass `:col` to stack panels vertically instead:
2337+
2338+
(-> (view iris [[:sepal-length :sepal-width]])
2339+
(lay (point {:color :species}))
2340+
(facet :species :col)
2341+
(plot {:width 400 :height 900}))
2342+
23312343
;; ### 🧪 Row × Column Faceting
23322344
;;
23332345
;; `facet-grid` maps two columns to rows and columns of panels:
@@ -2404,6 +2416,7 @@ tips
24042416
(facet :cyl)
24052417
plot)
24062418

2419+
;;
24072420
;; ---
24082421

24092422
;; ## Scales and Coordinates
@@ -2568,6 +2581,7 @@ tips
25682581
(coord :polar)
25692582
plot)
25702583

2584+
;;
25712585
;; ---
25722586

25732587
;; ## Annotations and Text
@@ -2683,6 +2697,7 @@ tips
26832697
(lay (text :species))))
26842698
plot))
26852699

2700+
;;
26862701
;; ---
26872702

26882703
;; ## More Aesthetics
@@ -2705,6 +2720,7 @@ tips
27052720
(lay (point {:color :species :shape :species}))
27062721
plot)
27072722

2723+
;;
27082724
;; ---
27092725

27102726
;; ## Interactivity
@@ -2855,6 +2871,7 @@ tips
28552871
(facet :species)
28562872
(plot {:brush true}))
28572873

2874+
;;
28582875
;; ---
28592876

28602877
;; ## Edge Cases
@@ -2889,6 +2906,7 @@ tips
28892906
(lay (value-bar))
28902907
plot)
28912908

2909+
;;
28922910
;; ---
28932911

28942912
;; ## Reflection
@@ -3050,4 +3068,5 @@ tips
30503068
;; Feedback is welcome. This work is part of the Scicloj
30513069
;; [Real-World Data dev group](https://scicloj.github.io/docs/community/groups/real-world-data/).
30523070

3071+
;;
30533072
;; ---

0 commit comments

Comments
 (0)