Module

Hylograph.HATS

Package
purescript-hylograph-selection
Repository
afcondon/purescript-hylograph-selection

HATS: Hylomorphic Abstract Tree Syntax

A principled AST for data visualization based on recursion schemes.

The core insight: a visualization is a transduction from data to DOM, composed of two orthogonal choices:

  • Enumeration: How to traverse/extract elements from input (coalgebra)
  • Assembly: How to structure the output DOM (algebra)

This version uses existentially-scoped data binding:

  • Tree has no type parameter - all trees compose freely with <>
  • Each Fold brings its own datum type a into scope
  • Attributes and behaviors inside templates capture datum via closures

#Tree Source

data Tree

The HATS tree type - a specification for visual structure.

No type parameter - trees compose freely with <> regardless of what data they bind internally.

Only three constructors:

  • Elem - A DOM element with attributes, children, and behaviors
  • MkFold - An existentially-wrapped iteration (enumerate, transform, assemble)
  • Empty - Nothing to render

Constructors

Instances

  • Semigroup Tree

    Semigroup instance: trees combine as siblings

    This enables compositional chart building:

    chart = title <> xAxis <> yAxis <> plotArea <> legend
    

    Key feature: linksLayer <> nodesLayer works even when they bind different data types internally!

  • Monoid Tree

    Monoid instance with Empty as identity

#Enumeration Source

data Enumeration a

How to extract elements from a data structure.

Constructors

#Assembly Source

data Assembly

How to structure the output DOM.

Constructors

#TraversalOrder Source

data TraversalOrder

Traversal order for tree enumeration

Constructors

#GUPSpec Source

type GUPSpec :: forall k. k -> Typetype GUPSpec a = { enter :: Maybe (PhaseSpec a), exit :: Maybe (PhaseSpec a), update :: Maybe (PhaseSpec a) }

Specification for differential updates (enter/update/exit).

#PhaseSpec Source

type PhaseSpec :: forall k. k -> Typetype PhaseSpec a = { attrs :: Array Attr, transition :: Maybe TransitionConfig }

Specification for one phase of GUP

#SomeFold Source

newtype SomeFold

Existentially-wrapped Fold specification.

The datum type a is scoped to the Fold - it doesn't appear in the outer Tree type. This allows heterogeneous composition.

Uses CPS encoding since PureScript doesn't have native existentials: SomeFold packs a FoldSpec a and can only be consumed by a polymorphic continuation that works for any a.

#FoldSpec Source

type FoldSpec a = { assemble :: Assembly, elementType :: ElementType, enumerate :: Enumeration a, gup :: Maybe (GUPSpec a), keyFn :: a -> String, name :: String, template :: a -> Tree }

Fold specification with its datum type.

The template function receives a datum and returns a Tree. Inside the template, attributes and behaviors capture the datum via closures - the datum is "baked in" at template evaluation time.

#mkSomeFold Source

mkSomeFold :: forall a. FoldSpec a -> SomeFold

Create a SomeFold from a FoldSpec (existentially packs the type)

#runSomeFold Source

runSomeFold :: forall r. SomeFold -> (forall a. FoldSpec a -> r) -> r

Consume a SomeFold with a polymorphic handler

#Attr Source

data Attr

Attribute type - either static or a thunk (closure).

Thunked attributes capture their datum value at construction time. The interpreter just invokes the thunk to get the value.

Constructors

#ThunkedBehavior Source

data ThunkedBehavior

Behavior type with thunked handlers.

Handlers are closures that capture datum values. The interpreter invokes them without needing to know the datum type.

Constructors

#elem Source

elem :: ElementType -> Array Attr -> Array Tree -> Tree

Create an element node

#fold Source

fold :: forall a. FoldSpec a -> Tree

Create a fold node from a spec

#empty Source

empty :: Tree

Empty tree

#siblings Source

siblings :: Array Tree -> Tree

Combine multiple trees as siblings

#forEach Source

forEach :: forall a. String -> ElementType -> Array a -> (a -> String) -> (a -> Tree) -> Tree

Simple iteration over an array (most common case)

The datum type a is inferred from items and available in the template function. Use attr constructors that capture values:

forEach "circles" Circle points _.id \pt ->
  elem Circle
    [ thunkedNum "cx" pt.x
    , thunkedNum "cy" pt.y
    , staticNum "r" 5.0
    ] []

#forEachP Source

forEachP :: forall source target. Project source target => String -> ElementType -> source -> (target -> String) -> (target -> Tree) -> Tree

forEach with projection - iterates over any Projectable source

The killer feature: one Map, three projections, one diagram.

mapDiagram :: Map k v -> Tree
mapDiagram m =
  elem SVG [...]
    [ -- Domain nodes from keys
      forEachP "keys" Group (MapKeys m) show \key -> keyNode key

    -- Codomain nodes from values (auto-deduplicated)
    , forEachP "values" Group (MapValues m) show \value -> valueNode value

    -- Arrows from entries
    , forEachP "arrows" Path (MapEntries m) (\(Tuple k _) -> show k) \(Tuple k v) ->
        arrow (keyPos k) (valuePos v)
    ]

#forEachWithGUP Source

forEachWithGUP :: forall a. String -> ElementType -> Array a -> (a -> String) -> (a -> Tree) -> GUPSpec a -> Tree

Iteration with GUP (enter/update/exit transitions)

#fromTree Source

fromTree :: forall a. String -> ElementType -> a -> (a -> Array a) -> (a -> String) -> TraversalOrder -> Boolean -> (a -> Tree) -> Tree

Unfold a tree structure to flat output

#preserveTree Source

preserveTree :: forall a. String -> ElementType -> a -> (a -> Array a) -> (a -> String) -> (a -> Tree) -> Tree

Unfold a tree structure preserving hierarchy in output

#Project Source

class Project source target | source -> target where

Project a source structure into an array of target elements.

The functional dependency source -> target ensures each source type has a canonical projection. Use newtypes for multiple projections from the same underlying type.

This is "finally tagless" because:

  • The type class is open for extension - users can add new instances
  • Multiple projections from one source use newtypes to select
  • The story: "One Map, three views, one diagram"

Members

Instances

#MapKeys Source

newtype MapKeys k v

Project a Map to its keys

Use when you want to iterate over just the keys:

forEachP "keys" Circle (MapKeys myMap) show \key -> ...

Constructors

Instances

#MapValues Source

newtype MapValues k v

Project a Map to its unique values

Values are deduplicated - if multiple keys map to the same value, that value appears only once. This is the mathematical codomain.

Constructors

Instances

#MapEntries Source

newtype MapEntries k v

Project a Map to its key-value entries

Each entry is a Tuple k v representing one mapping.

Constructors

Instances

#withBehaviors Source

withBehaviors :: Array ThunkedBehavior -> Tree -> Tree

Attach behaviors to an element

#staticStr Source

staticStr :: String -> String -> Attr

Static string attribute (value known at build time)

#staticNum Source

staticNum :: String -> Number -> Attr

Static numeric attribute

#thunkedStr Source

thunkedStr :: String -> String -> Attr

Thunked string attribute (captures a value)

Use inside templates to capture datum-derived values:

\node -> elem Text [ thunkedStr "text-anchor" node.anchor ] []

#thunkedNum Source

thunkedNum :: String -> Number -> Attr

Thunked numeric attribute (captures a value)

Use inside templates to capture datum-derived values:

\node -> elem Circle [ thunkedNum "cx" node.x, thunkedNum "cy" node.y ] []

#onMouseEnter Source

onMouseEnter :: Effect Unit -> ThunkedBehavior

Mouse enter handler (captures handler in closure)

\node -> withBehaviors [ onMouseEnter (callbacks.onHover node.path) ] $
         elem Circle [...] []

#onMouseLeave Source

onMouseLeave :: Effect Unit -> ThunkedBehavior

Mouse leave handler

#onClick Source

onClick :: Effect Unit -> ThunkedBehavior

Click handler

#onDrag Source

onDrag :: DragConfig -> ThunkedBehavior

Drag behavior

#onZoom Source

onZoom :: ZoomConfig -> ThunkedBehavior

Zoom behavior

#onCoordinatedHighlight Source

onCoordinatedHighlight :: { classify :: String -> HighlightClass, group :: Maybe String, identify :: String } -> ThunkedBehavior

Coordinated highlighting behavior

When this element is hovered, ALL elements with coordinated highlighting in the same group receive CSS classes based on their relationship:

  • .highlight-primary - the hovered element itself
  • .highlight-related - elements related to hovered
  • .highlight-dimmed - unrelated elements

Use inside forEach templates to capture datum:

forEach "nodes" Circle nodes _.id \node ->
  withBehaviors
    [ onCoordinatedHighlight
        { identify: node.name
        , classify: \hoveredId ->
            if node.name == hoveredId then Primary
            else if hoveredId `elem` node.connections then Related
            else Dimmed
        , group: Nothing  -- global coordination
        , tooltip: Nothing  -- or Just { content: "...", showWhen: OnHover }
        }
    ] $
  elem Circle [...] []

#onCoordinatedHighlightWithTooltip Source

onCoordinatedHighlightWithTooltip :: { classify :: String -> HighlightClass, group :: Maybe String, identify :: String, tooltip :: Maybe { content :: String, showWhen :: TooltipTrigger } } -> ThunkedBehavior

Coordinated highlight with tooltip support

Same as onCoordinatedHighlight but with optional tooltip configuration. When tooltip is provided, it will show on hover (or based on showWhen trigger).

forEach "nodes" Circle nodes _.id \node ->
  withBehaviors
    [ onCoordinatedHighlightWithTooltip
        { identify: node.name
        , classify: \hoveredId -> if node.name == hoveredId then Primary else Dimmed
        , group: Nothing
        , tooltip: Just { content: node.description, showWhen: OnHover }
        }
    ] $
  elem Circle [...] []

#onCoordinatedInteraction Source

onCoordinatedInteraction :: { group :: Maybe String, identify :: String, position :: Maybe { x :: Number, y :: Number }, respond :: InteractionTrigger -> InteractionState } -> ThunkedBehavior

Full coordinated interaction behavior (supports brush, hover, focus, selection)

Unlike onCoordinatedHighlight which only handles hover, this behavior responds to ALL interaction triggers including brush regions.

forEach "points" Circle points _.id \pt ->
  withBehaviors
    [ onCoordinatedInteraction
        { identify: pt.id
        , respond: \trigger -> case trigger of
            HoverTrigger id -> if pt.id == id then Primary else Dimmed
            BrushTrigger box -> if pointInBox pt.pos box then Selected else Dimmed
            ClearTrigger -> Neutral
            _ -> Neutral
        , position: Just pt.pos  -- For automatic brush hit-testing
        , group: Nothing
        }
    ] $
  elem Circle [...] []

#onBrush Source

onBrush :: { extent :: BoundingBox, group :: Maybe String } -> ThunkedBehavior

Attach a brush overlay to an element

When users brush (drag) on this element, a BrushTrigger is emitted to all elements registered with onCoordinatedInteraction in the same group.

elem Group [ staticStr "class" "brush-overlay" ] []
  # withBehaviors
      [ onBrush
          { extent: { x0: 0.0, y0: 0.0, x1: 400.0, y1: 300.0 }
          , group: Just "scatter-plot"
          }
      ]

Re-exports from Hylograph.Internal.Behavior.Types

#ZoomConfig Source

newtype ZoomConfig

Zoom behavior configuration

The target is the selection that will be transformed when zooming. Typically this is an inner <g> element, while the zoom behavior is attached to the outer <svg> element.

Example:

zoomConfig = ZoomConfig
  { scaleExtent: ScaleExtent 0.5 4.0  -- 50% to 400%
  , targetSelector: ".zoom-group"      -- What to transform
  }

Instances

#TooltipTrigger Source

data TooltipTrigger

When to show a tooltip

  • OnHover: Traditional tooltip - only when mouse is directly over element
  • WhenPrimary: Show when this element becomes Primary (from any view's hover)
  • WhenRelated: Show when this element becomes Related (use judiciously!)

Constructors

Instances

#HighlightClass Source

data HighlightClass

Classification of an element's highlight state

When an element is hovered, ALL elements with CoordinatedHighlight behavior are classified based on their relationship to the hovered element.

  • Primary: The hovered element itself
  • Related: Connected/related to the hovered element
  • Upstream: Dependencies (things this element depends on)
  • Downstream: Dependents (things that depend on this element)
  • Dimmed: Not related (de-emphasized)
  • Neutral: No highlight state change (default appearance)

Constructors

Instances

#DragConfig Source

data DragConfig

Drag behavior configuration

  • SimpleDrag: Basic dragging with transform
  • SimulationDrag: Drag with force simulation reheat (datum IS the simulation node)
  • SimulationDragNested: Drag where datum has a .node field containing the simulation node

Instances

Modules
Data.DependencyGraph
Hylograph.AST
Hylograph.Axis.Axis
Hylograph.Brush
Hylograph.Brush.FFI
Hylograph.Brush.Types
Hylograph.Classify
Hylograph.Data.Graph
Hylograph.Data.Graph.Algorithms
Hylograph.Data.Node
Hylograph.Data.Tree
Hylograph.Expr.Animation
Hylograph.Expr.Attr
Hylograph.Expr.Datum
Hylograph.Expr.Expr
Hylograph.Expr.Friendly
Hylograph.Expr.Integration
Hylograph.Expr.Interpreter.CodeGen
Hylograph.Expr.Interpreter.Eval
Hylograph.Expr.Interpreter.Meta
Hylograph.Expr.Interpreter.PureSVG
Hylograph.Expr.Interpreter.SVG
Hylograph.Expr.Path
Hylograph.Expr.Path.Generators
Hylograph.Expr.Sugar
Hylograph.Expr.Units
Hylograph.HATS
Hylograph.HATS.Friendly
Hylograph.HATS.InterpreterTick
Hylograph.HATS.Transitions
Hylograph.Interaction.Brush
Hylograph.Interaction.Coordinated
Hylograph.Interaction.Pointer
Hylograph.Interaction.Zoom
Hylograph.Internal.Attribute
Hylograph.Internal.Behavior.FFI
Hylograph.Internal.Behavior.Types
Hylograph.Internal.Capabilities.Selection
Hylograph.Internal.Capabilities.Transition
Hylograph.Internal.FFI
Hylograph.Internal.Selection.Join
Hylograph.Internal.Selection.Operations
Hylograph.Internal.Selection.Operations.Conversions
Hylograph.Internal.Selection.Operations.Helpers
Hylograph.Internal.Selection.Operations.Selection
Hylograph.Internal.Selection.Query
Hylograph.Internal.Selection.Types
Hylograph.Internal.Transition.FFI
Hylograph.Internal.Transition.Manager
Hylograph.Internal.Transition.Scene
Hylograph.Internal.Transition.Types
Hylograph.Internal.Types
Hylograph.Interpreter.D3
Hylograph.Interpreter.English
Hylograph.Interpreter.Mermaid
Hylograph.Interpreter.MetaAST
Hylograph.Interpreter.SemiQuine
Hylograph.Interpreter.SemiQuine.TreeToCode
Hylograph.Interpreter.SemiQuine.Types
Hylograph.Render
Hylograph.Scale
Hylograph.Scale.FP
Hylograph.Shape.Arc
Hylograph.Shape.Pie
Hylograph.Shape.Polygon
Hylograph.Tooltip
Hylograph.Transform
Hylograph.TreeDSL
Hylograph.TreeDSL.ShapeTree
Hylograph.Unified
Hylograph.Unified.Attribute
Hylograph.Unified.DataDSL
Hylograph.Unified.Display
Hylograph.Unified.Examples
Hylograph.Unified.Join
Hylograph.Unified.Sugar