Skip to content

Commit d853751

Browse files
committed
aog wip
1 parent 307496f commit d853751

File tree

1 file changed

+41
-95
lines changed

1 file changed

+41
-95
lines changed

src/data_visualization/aog_in_clojure_part1.clj

Lines changed: 41 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -356,16 +356,11 @@
356356

357357
;; ### 📖 The Solution Works: Standard Merge Composes
358358

359-
;; Show this actually solves the problem:
359+
;; Standard `merge` preserves all properties - nothing lost:
360360

361361
(merge {:=x :bill-length-mm :=color :species}
362362
{:=y :bill-depth-mm :=alpha 0.5})
363-
;; => {:=x :bill-length-mm
364-
;; :=y :bill-depth-mm
365-
;; :=color :species
366-
;; :=alpha 0.5}
367363

368-
;; Nothing lost! All properties preserved.
369364
;; This is why `=*` (our composition operator) can use standard `merge` internally.
370365

371366
;; # Design Overview
@@ -3888,107 +3883,58 @@ iris
38883883

38893884
;; # Design Discussion
38903885
;;
3891-
;; ## 📖 Plot-Level Properties in Layer Vectors
3886+
;; ## 📖 Map-Based IR: Separating Layers from Plot Configuration
38923887
;;
3893-
;; ### The Tension
3894-
;;
3895-
;; Our current design uses a vector of layer maps as the intermediate representation:
3896-
;;
3897-
;; ```clojure
3898-
;; (-> penguins
3899-
;; (mapping :x :y)
3900-
;; (scatter)
3901-
;; (target :vl)
3902-
;; (size 800 600))
3903-
;; ;; => [{:=data ... :=x :x :=y :y :=plottype :scatter
3904-
;; ;; :=target :vl :=width 800 :=height 600}]
3905-
;; ```
3906-
;;
3907-
;; Notice that `:=target`, `:=width`, and `:=height` appear in every layer,
3908-
;; even though their meaning applies to **all layers together**, not individual layers.
3909-
;; These are plot-level properties, not layer-level properties.
3910-
;;
3911-
;; This creates a conceptual impurity: properties about "how to render the whole plot"
3912-
;; are stored alongside properties about "what data to show and how to transform it."
3913-
;;
3914-
;; ### Why This Happens
3915-
;;
3916-
;; It's a consequence of our choice to use **vectors of maps** as the IR:
3917-
;;
3918-
;; - The `*` operator merges maps: `(merge layer-a layer-b)`
3919-
;; - When we do `(=* layers (target :vl))`, the target gets merged into all layers
3920-
;; - Same for `(=* layers (size 800 600))` - dimensions merge into every layer
3921-
;;
3922-
;; The current workaround: `plot-impl` extracts the first occurrence:
3923-
;; ```clojure
3924-
;; (some :=target layers-vec) ;; Get first non-nil target
3925-
;; (some :=width layers-vec) ;; Get first non-nil width
3926-
;; ```
3927-
;;
3928-
;; ### Alternative Approaches Considered
3929-
;;
3930-
;; **1. Metadata on the Vector**
3931-
;;
3932-
;; ```clojure
3933-
;; (defn target [target-kw]
3934-
;; (with-meta [] {:=target target-kw}))
3935-
;;
3936-
;; ;; Result:
3937-
;; ^{:=target :vl :=width 800 :=height 600}
3938-
;; [{:=data ... :=x :x :=plottype :scatter}]
3939-
;; ```
3940-
;;
3941-
;; **Pros**: Conceptually clean separation - layers are grammar, metadata is rendering config
3942-
;;
3943-
;; **Cons**: Metadata easily lost, less inspectable, threading needs special handling
3944-
;;
3945-
;; **2. Wrapper Map**
3946-
;;
3947-
;; ```clojure
3948-
;; {:layers [{:=data ... :=x :x}
3949-
;; {:=transformation :linear}]
3950-
;; :config {:target :vl :width 800 :height 600}}
3951-
;; ```
3952-
;;
3953-
;; **Pros**: Explicit separation, no duplication, easy to inspect
3954-
;;
3955-
;; **Cons**: Breaks the algebra (`*` and `+` work on vectors), operators become complex
3956-
;;
3957-
;; **3. Special Marker Layer**
3888+
;; ### The Design Choice
39583889
;;
3890+
;; The internal representation uses a map structure with explicit separation:
3891+
3892+
(-> penguins
3893+
(mapping :bill-length-mm :bill-depth-mm)
3894+
(scatter)
3895+
(target :vl)
3896+
(size 800 600))
3897+
3898+
;; This produces a map with `:=layers` and plot-level properties separated:
3899+
39593900
;; ```clojure
3960-
;; [{:=data ... :=x :x :=plottype :scatter}
3961-
;; {:=plot-config true
3962-
;; :=target :vl :=width 800 :=height 600}]
3901+
;; {:=layers [{:=data penguins
3902+
;; :=x :bill-length-mm
3903+
;; :=y :bill-depth-mm
3904+
;; :=plottype :scatter}]
3905+
;; :=target :vl
3906+
;; :=width 800
3907+
;; :=height 600}
39633908
;; ```
39643909
;;
3965-
;; **Pros**: Keeps vector structure, filterable
3966-
;;
3967-
;; **Cons**: Still mixed concerns, just specially marked
3968-
;;
3969-
;; **4. Accept the Duplication (Current)**
3910+
;; ### Why This Structure?
39703911
;;
3971-
;; Keep plot-level properties duplicated in every layer.
3912+
;; **Clean separation of concerns:**
3913+
;; - **Layer properties** (`:=data`, `:=x`, `:=y`, `:=plottype`) describe what to visualize
3914+
;; - **Plot properties** (`:=target`, `:=width`, `:=height`, scales) describe how to render
39723915
;;
3973-
;; **Pros**: Simple, works with current algebra, extraction via `some` is straightforward
3974-
;;
3975-
;; **Cons**: Conceptually impure, wasteful (though negligible), could confuse on inspection
3916+
;; **Benefits:**
3917+
;; 1. **Inspectable** - `kind/pprint` shows clear structure
3918+
;; 2. **No duplication** - Plot config appears once, not in every layer
3919+
;; 3. **Composable** - `=*` and `=+` can merge both levels correctly
3920+
;; 4. **Extensible** - Easy to add new plot-level properties (themes, titles, etc.)
39763921
;;
3977-
;; ### Current Decision
3922+
;; ### How Operators Handle It
39783923
;;
3979-
;; We've chosen **Alternative 4** (accept duplication) for now because:
3924+
;; **`=*` (merge):**
3925+
;; - Performs cross-product on `:=layers` vectors
3926+
;; - Merges plot-level properties (right side wins)
39803927
;;
3981-
;; 1. **Simplicity**: No special cases in `*` and `+` operators
3982-
;; 2. **Works**: The `some` extraction pattern is fast and reliable
3983-
;; 3. **Practical**: The duplication overhead is negligible in practice
3984-
;; 4. **Revisable**: If this becomes problematic, we can migrate to metadata later
3928+
;; **`=+` (overlay):**
3929+
;; - Concatenates `:=layers` vectors
3930+
;; - Merges plot-level properties (right side wins)
39853931
;;
3986-
;; The key insight: this is a **limitation of using vectors of maps as IR**, not a
3987-
;; fundamental flaw. If plot-level configuration grows significantly, the metadata
3988-
;; approach (Alternative 1) would be the natural evolution, as it mirrors Clojure's
3989-
;; philosophy of metadata for "information about the thing" vs "the thing itself."
3932+
;; **Constructors:**
3933+
;; - Layer constructors (`data`, `mapping`, `scatter`) return `{:=layers [...]}`
3934+
;; - Plot constructors (`target`, `size`, `scale`) return `{:=property value}`
3935+
;; - Both compose naturally via `=*`
39903936
;;
3991-
;; For now, the simplicity trade-off is worth it.
3937+
;; This design balances compositional elegance with practical clarity.
39923938

39933939
;; # Summary
39943940
;;

0 commit comments

Comments
 (0)