packages feed

hgg-core-0.2.0.0: src/Graphics/Hgg/Spec.hs

-- |
-- Module      : Graphics.Hgg.Spec
-- Description : Layer 3 — VisualSpec / Layer / ColRef types, with Monoid instances
-- Copyright   : (c) 2026 Aelysce Project (Toshiaki Honda)
-- License     : BSD-3-Clause
--
-- [日本語]: 設計方針 (詳細: design/api-style-discussion-2.md + 続き):
--
--   * 2 階層 Monoid: 'Layer' (= 1 layer 内属性) と 'VisualSpec' (= 図全体)
--   * 全 helper が `<>` で paren 無し合成可能 (= plotnine 風)
--   * 'ColRef' で「文字列 col 参照」 と「Vector inline」 両対応、
--     (@OverloadedStrings@ で `"weight" :: ColRef` が自動 'ColByName')
--   * core は DataFrame 型に非依存。 col 名 → Vector 解決は 'Resolver'
--     callback で render 時に行う (= core 内ではデータ source を持たない)
--   * Generic + ToJSON/FromJSON で Spec 全体が __JSON serializable__
--     (= frontend ↔ backend 間で共有し、 差分 Patch を送るユースケースを想定)
--
-- [English]: Design policy (details: design/api-style-discussion-2.md and
-- its follow-ups):
--
--   * Two-level Monoid: 'Layer' (attributes within a single layer) and
--     'VisualSpec' (the whole figure)
--   * Every helper composes with `<>` without parentheses (plotnine style)
--   * 'ColRef' supports both "a string column reference" and "an inline
--     Vector" (@OverloadedStrings@ turns `"weight" :: ColRef` automatically
--     into 'ColByName')
--   * core is agnostic to any DataFrame type; resolving a column name to a
--     Vector happens at render time via the 'Resolver' callback (core
--     itself holds no data source)
--   * Generic + ToJSON/FromJSON make the whole Spec __JSON serializable__
--     (shared between a frontend and a backend, with sending diff Patches
--     as the intended use case)
{-# LANGUAGE DeriveGeneric             #-}
{-# LANGUAGE DerivingStrategies        #-}
{-# LANGUAGE DerivingVia               #-}
{-# LANGUAGE DuplicateRecordFields     #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE OverloadedStrings         #-}
module Graphics.Hgg.Spec
  ( -- * ColRef + Resolver
    ColRef(..)
  , ColData(..)
  , Resolver
  , emptyResolver
  , resolveCol
  , bakeSpec
  , resolveNum
  , resolveTxt
  , colRefName
    -- * Inline column conversion
  , Numeric(..)
  , Categorical(..)
  , inline
  , inlineCat
    -- * Layer
  , Layer(..)
  , MarkKind(..)
  , ColorEnc(..)
    -- ** 固定色 'Color' 型 (re-export from "Graphics.Hgg.Color")
  , Color(..)
  , rgb
  , fromHex
  , fromHexMaybe
  , fromHexA
  , fromHexAMaybe
  , ConnectSpec(..)
  , defaultConnectSpec
    -- * 2D 点 'Point2' (= 3D 'Graphics.Hgg.ThreeD.Types.Point3' と対称)
  , Point2(..)
    -- * custom mark (拡張可能な描画語彙)
  , RenderCtx(..)
  , CustomMark(..)
  , customMark
  , customMarkWith
  , encX
  , encY
  , encZ
  , ternaryScatter, ternaryLine   -- ★ Phase 69 A3: 三角座標 mark 束ね
    -- * Layer constructors (= Layer 返却)
  , scatter
  , line
  , scatterPoints       -- ★ Phase 30 A7 inline [Point2] (= 3D scatter3DPoints と対称)
  , linePoints          -- ★ Phase 30 A7 inline [Point2] (= 3D line3DPoints と対称)
  , bar
  , quiver
  , arrowScale
  , arrowColorByMagnitude
  , text
  , label
  , qq
  , ecdf
  , lineRange
  , pointRange
  , crossbar
  , statFunction
  , histogram
  , freqpoly             -- ★ Ch10 EDA (Phase 28) geom_freqpoly (= 頻度多角形)
  , countXY              -- ★ Ch10 EDA (Phase 28) geom_count (= 2 カテゴリ件数)
  , histogramWide        -- ★ P1 (Phase 6 A10) wide-form 重ね
  , autocorr             -- ★ P19 (Phase 6 A4) MCMC autocorrelation
  , autocorrMaxLag       -- ★ Phase 6 A4 max lag override
  , ess                  -- ★ P20 (Phase 6 A5) Effective Sample Size
  , chain                -- ★ Phase 6 A5 chain group 設定
  , forest               -- ★ Phase 6 A2 Forest plot (= horizontal CI bar)
  , forestNull           -- ★ Phase 6 A2 null effect 位置 (= 縦 0 線、 default 0)
  , funnel               -- ★ Phase 6 A3 Funnel plot (= effect vs SE)
  , boxplot
  , groupBy             -- ★ Phase 36: 群配置チャネル (色なし・ggplot aes(group=))
  , density
  , densityNorm
  , pie
  , waterfall
  , heatmap
  , contour
  , contourFilled
  , contourLevels
  , contourBreaks
  , bin2d
  , bin2dCount           -- ★ Ch10 EDA (Phase 28) geom_bin2d (count 版)
  , tile                 -- ★ Phase 60: 連続軸タイル塗り (geom_tile/raster・決定境界)
  , hexbin               -- ★ Phase 40: 六角ビニング (geom_hex / matplotlib hexbin)
  , hexbinBins           -- ★ Phase 40: hexbin の x 方向セル分割数 (既定 30)
  , HexCell(..)          -- ★ Phase 40: 六角セル (中心+件数+頂点)
  , hexbinCells          -- ★ Phase 40: 六角ビニング純関数 (d3-hexbin)
  , hexbinLayerCells     -- ★ Phase 40: Layer 解決版 (render/colorbar 共有)
  , subplots
  , subplotCols
  , subplotWidths      -- ★ Phase 63 A6: 列の相対幅 (rel_widths)
  , subplotHeights     -- ★ Phase 63 A6: 行の相対高 (rel_heights)
  , subplotTags        -- ★ Phase 63 A7: panel 自動タグ (labels="AUTO")
  , TagStyle(..)       -- ★ Phase 63 A7
  , selectPanels
  , selectedSubplots
  , scaleXDiscreteLimits
  , scaleYDiscreteLimits
  , applyDiscreteLimits
  , reindexLayer         -- ★ Phase 62 A2: facet の inline 部分列化 (Render.Layer) で共用
  , hconcat
  , vconcat
  , (<->)
  , (<:>)
  , repeatFields
  , pairs
  , step
  , stem
  , statLm
  , statLmLevel
  , statSmooth
  , statSmoothCI
  , statPoly
  , statResid
  , band
  , stream
  , violin
  , strip
  , swarm
  , raincloud
  , (<+>)
  , distCols
  , compositeLanes
  , ridge
  , ridgeAutoFlip
  , jitterX
  , jitterY
  , sqrtAxis
  , timeAxis
  , AxisBreak(..)
  , axisBreak
  , axisBreaksAt
  , axisTickLabels
  , axisBreaksLabeled
  , hideTicks
  , Annotation(..)
  , annotate
  , annotText
  , annotTextP
  , annotArrow
  , annotArrowP
  , annotRect
  , annotRectP
  , annotLine
  , annotLineP
  , Inset(..)
  , inset
  , insetAt
  , insetElement
  , palette
  , paletteGGplot
  , continuousPalette
  , scaleColorManual
  , scaleColorGradient2
  , scaleSize
  , YAxisSide(..)
  , yAxisRight
  , toRightY
  , toLeftY
  , statMean
  , statMedian
  , parallelCoords
  , dag
  , dagFromLists
  , dagFromListsWithPlates
  , dagNode
  , dagNodeDist
  , dagEdge
  , trace
  , traceLines
    -- * Layer-local attribute (= Layer 返却)
  , color
  , colorRGBA
  , colorRGBAMaybe
  , colorBy
  , distGroupRef
  , distDodgeRef
  , colorContinuousBy
  , alpha
  , size
  , stroke
  , edgeOn
  , edge
  , edgeWidth
  , hoverCols
  , errorX
  , errorY
  , connect
  , connectOrder
  , connectGroup
  , connectColor
  , connectWidth
    -- * Axis
  , AxisSpec(..)
  , AxisKind(..)
  , AxisFormat(..)
  , axisKindOf
  , axisFormatOf
  , axTickValsOf
  , axTickLabelsOf
  , axisRotateOf
  , resolveAxisAngle
  , axisShowTicksOf
  , axisRotate
  , linearAxis
  , logAxis
  , axisFormat
  , axisMin
  , axisMax
  , axisRange
  , binCount
  , binWidth
  , histBinning
  , histogramDensity
  , histBorder
  , densityFill
  , hollow
    -- * 分布 mark の位置決め
  , Side(..)
  , nudge
  , markWidth
  , side
    -- * Bar position adjustment
  , Position(..)
  , position
  , Coord(..)
  , PolarOpts(..)
  , defaultPolarOpts
  , TernaryOpts(..)             -- ★ Phase 69 A4
  , defaultTernaryOpts
  , coordFlip
  , coordPolar
  , coordPolarY
  , coordPolarWith
  , coordPolarYWith
  , coordTernary
  , coordTernaryWith   -- ★ Phase 69 A4
  , reverseX
  , reverseY
  , coordCartesianX
  , coordCartesianY
  , coordCartesian
    -- * Reference line
  , ReferenceLine(..)
    -- * Marginal histogram
  , MarginalSpec(..)
  , MarginalKind(..)
  , defaultMarginalSpec
  , LegendSpec(..)
  , LegendPosition(..)
  , defaultLegendSpec
  , legend
  , legendOff
  , legendPos
  , guideColorNone
  , legendReverse
  , legendNcol
  , legendNrow
    -- * DAG (= HBM ModelGraph)
  , DAGSpec(..)
  , DAGNode(..)
  , DAGEdge(..)
  , RoutedEdge(..)
  , EdgeShapeKind(..)
  , DAGPlate(..)
  , DAGNodeKind(..)
  , DAGLayoutAlgorithm(..)
    -- * Top-level
  , VisualSpec(..)
  , ThemeName(..)
  , themeSeriesPalette
  , okabeIto, tolBright, brewerSet2, brewerDark2
  , ThemeOverride(..)
  , TickDir(..)                                                 -- ★ Phase 63 A4
  , Margin(..)                                                  -- ★ Phase 63 A5
  , themeGrid, themeGridMajor, themeGridMinor, themeLegendPos   -- ★ Phase 63 A2/A3
  , themeTickLength, themeTickDir                               -- ★ Phase 63 A4
  , themeGridWidth, themeGridMinorWidth, themeAxisLineWidth     -- ★ Phase 68
  , themePlotMargin                                             -- ★ Phase 63 A5
  , themeBaseFontSize                                           -- ★ Phase 63 A12
  , themeCowplot, themeMinimalGrid, themeMap                    -- ★ Phase 63 A8
  , themeCowplotSized, themeMinimalGridSized, themeMapSized     -- ★ Phase 63 A14
  , themePlotBg                                                 -- ★ Phase 63 A18
  , themeAxisText, themeAxisTitle                                -- ★ Phase 63 A19
  , themeLegendKeySize                                           -- ★ Phase 63 A19.5
  , themeFontFamily                                              -- ★ Phase 63 A20.5
  , panelFill, panelBorder, themeAxisLine, gridColor, plotBg, axisColor, textColor
  , themeTitleFont, themeAxisLabelFont, themeTickFont, themeLegendFont, themeAxisTextAngle
  , themeAxisTextAngleX, themeAxisTextAngleY, axisTextAngleXOf, axisTextAngleYOf
  , stripFill, themeStrip
  , titleHjust, titleColor, tickColor, legendKeyBg   -- ★ Phase 43 A4
    -- * Top-level setters (= VisualSpec 返却)
  , purePlot
  , layer
  , layers   -- ★ Phase 66
  , title
  , theme
  , facet
  , facetWrap
  , facetCols
  , facetGrid
  , FacetScales(..)
  , freeScaleX
  , freeScaleY
  , facetScales
  , FacetSpace(..)
  , freeSpaceX
  , freeSpaceY
  , facetSpace
  , xLabel
  , yLabel
  , zLabel
  , legendTitle
  , subtitle
  , caption
  , tag
  , Labs(..)
  , emptyLabs
  , labs
  , width
  , height
  , widthMm
  , heightMm
  , widthUnit
  , heightUnit
  , dpi
  , aspectRatio
  , xAxis
  , yAxis
  , refLine
  , refIdentity
  , refHorizontal
  , refVertical
  , marginal
  , marginalX
  , marginalY
    -- * C-6 Shape encoding
  , MarkShape(..)
  , ShapeMapEntry(..)
  , shape
  , shapeBy
  , shapeMapEntry
  , sizeBy
  , alphaBy              -- ★ Phase 30 A8 連続 alpha encoding (= ggplot scale_alpha)
  , colorCats
  , orderedCats
    -- * linetype encoding
  , LineType(..)
  , linetype
  , linetypeBy
  , lineTypeDash
  , lineTypeForIndex
    -- * Font customization (= hgg-frontend-settings-spec v0.1 §1.3)
  , FontSpec(..)
  , emptyFontSpec
  , fontSize
  , fontFamily
  , fontWeight
  , fontItalic
  , fontColor
  , titleFont
  , axisLabelFont
  , tickFont
  , legendFont
  ) where

import           Graphics.Hgg.Color (Color (..), rgb, fromHex, fromHexMaybe,
                                     fromHexA, fromHexAMaybe, toCss)
import           Data.Aeson      (FromJSON, ToJSON, toJSON, parseJSON, toEncoding,
                                  Value (Object))
import qualified Data.Aeson      as Aeson
import qualified Data.Aeson.KeyMap as KM
import qualified Data.Char       as Char
import qualified Data.List
import           Data.Maybe      (catMaybes)
import           Data.Monoid     (First (..), Last (..))
import           Data.String     (IsString (..))
import           Data.Text       (Text)
import qualified Data.Text       as T
import           Data.Vector     (Vector)
import qualified Data.Vector     as V
import           GHC.Generics    (Generic, Generically (..))

import           Graphics.Hgg.Unit (Length, Pos (..), lengthToPt, mm, (*~))
import           Graphics.Hgg.Primitive (Primitive, Rect (..))  -- Phase 51: custom mark closure 型
-- Phase 55: Spec の module 分割 (本 module は facade として全 API を re-export)
import           Graphics.Hgg.Spec.Axis
import           Graphics.Hgg.Spec.Bake
import           Graphics.Hgg.Spec.Column
import           Graphics.Hgg.Spec.Concat
import           Graphics.Hgg.Spec.Constructors
import           Graphics.Hgg.Spec.Decoration
import           Graphics.Hgg.Spec.CustomMark
import           Graphics.Hgg.Spec.Layer
import           Graphics.Hgg.Spec.Mark
import           Graphics.Hgg.Spec.Setters
import           Graphics.Hgg.Spec.Theme
import           Graphics.Hgg.Spec.Visual