hgg-svg-0.1.0.0: examples/DocFig/Decoration.hs
-- | 03-decoration.md の図 (ラベル / scale / theme / facet / subplot / 座標 /
-- 参照線 / 注釈 / 重畳)。
{-# LANGUAGE OverloadedStrings #-}
module DocFig.Decoration (figures) where
import Data.Text (Text)
import qualified Data.Vector as V
import DocFig.Common
figures :: [Figure]
figures =
-- Lesson 4: 重畳 (scatter + 回帰直線 overlay)
[ fig "lesson4-overlay.svg" $
purePlot
<> layer (scatter (inline oxs) (inline oys) <> alpha 0.85 <> size 6)
<> layer (line (inline oxs) (inline ofit) <> color (fromHex "#dc2626") <> stroke 2)
<> title "Lesson 4: 重畳 (散布 + 回帰直線)" <> xLabel "x" <> yLabel "y"
-- 3c タイトル・ラベル: labs を一括
, fig "s3c-labs.svg" $
purePlot
<> layer (scatter xs ys <> size 6)
<> labs (emptyLabs
{ labsTitle = Just "3c. title"
, labsSubtitle = Just "subtitle (副題)"
, labsCaption = Just "caption (脚注)"
, labsX = Just "x 軸", labsY = Just "y 軸" })
-- 3d scale: 連続色 gradient (scaleColorGradient2)
, fig "s3d-scale.svg" $
purePlot
<> layer (scatter xs ys <> colorContinuousBy cz <> size 9)
<> scaleColorGradient2 "#2166AC" "#F7F7F7" "#B2182B" 3.0
<> legend
<> title "3d. scaleColorGradient2 (連続色)"
-- 3e theme: ThemeDark
, fig "s3e-theme.svg" $
purePlot
<> layer (scatter xs ys <> color (fromHex "#38bdf8") <> size 6)
<> theme ThemeDark
<> title "3e. theme ThemeDark"
-- 3e theme gallery: 代表テーマ全 13 種を 1 枚に
, figW "s3e-theme-gallery.svg" 1280 1040 $
subplots (map themePanel allThemes) <> subplotCols 4
<> title "theme 一覧 (代表テーマ 13 種)"
-- 3e theme × subplots: 外側に theme を足すと全 panel に効く
, figW "s3e-theme-subplots.svg" 960 400 $
subplots [ layer (scatter xs ys <> color (fromHex "#38bdf8") <> size 5) <> title "散布"
, layer (bar cats vals) <> title "棒" ]
<> subplotCols 2 <> theme ThemeDark
<> title "subplots <> theme ThemeDark (外側 theme が全 panel に伝播)"
-- 3f facet: facetWrap で群ごとに小分け (facet 列は名前解決が要るため Resolver 版)
, figR "s3f-facet.svg" rFacet $
purePlot
<> layer (scatter "x" "y" <> colorBy "g" <> size 6)
<> facetWrap "g" 2
<> title "3f. facetWrap"
-- 3f-2 subplot: 独立図の並置 (subplots) ─ geom も軸も別でよい
, fig "s3f2-subplot.svg" $
subplots [ layer (scatter (inline [1,2,3,4,5]) (inline [2,4,3,5,4])) <> title "散布"
, layer (line (inline [1,2,3,4,5]) (inline [1,3,2,4,3])) <> title "折れ線"
, layer (bar cats vals) <> title "棒" ]
<> subplotCols 3
<> title "3f-2. subplots ─ 独立図の並置"
-- 3f-2 selectPanels (Phase 18 A1): repeatFields で量産した panel から名前で選択
, fig "s3f2-select-panels.svg" $
repeatFields ["a", "b", "c", "d"] selPanelOf
<> selectPanels ["c", "a"]
<> subplotCols 2
<> title "3f-2. selectPanels ─ panel の名前選択 (c, a の順)"
-- 3d discrete limits (Phase 18 A2): forest の行を選択 + 列挙順に並べ替え
, fig "s3d-discrete-limits.svg" $
layer (forest (inlineCat (["b0", "b1", "b2", "b3", "sigma"] :: [Text]))
(inline [1.0, 2.0, 0.1, -0.45, 0.3])
(inline [0.2, 0.4, 0.3, 0.1, 0.05])
<> forestNull 0)
<> scaleYDiscreteLimits ["b1", "b0", "sigma"]
<> title "3d. scaleYDiscreteLimits ─ forest の行選択 + 並べ替え"
-- 3f-2 nested: 入れ子 subplots (B1) ─ 主図 + 周辺分布を入れ子グリッドで
, fig "s3f2-nested.svg" $
subplots [ layer (scatter nx ny) <> title "主図 (x vs y)"
, subplots [ layer (histogram nx) <> title "x 分布"
, layer (histogram ny) <> title "y 分布" ]
<> subplotCols 1 <> title "周辺分布 (入れ子)" ]
<> subplotCols 2
<> title "3f-2. nested subplots ─ 主図 + 入れ子グリッド"
-- 3f-2 concat: 演算子 <-> / <:> での非対称合成 ─ (a <-> b <-> c) <:> d
, fig "concat.svg" $
((cA <-> cB <-> cC) <:> cD)
<> title "3f-2. (a <-> b <-> c) <:> d (横3列 + 全幅)"
-- 3g coord: coordFlip で横棒
, fig "s3g-coord.svg" $
purePlot <> layer (bar cats vals)
<> coordFlip
<> title "3g. coordFlip (横棒)" <> xLabel "群" <> yLabel "値"
-- 3h 補助: 参照線 + 凡例
, fig "s3h-guides.svg" $
purePlot
<> layer (scatter xs ys <> colorBy gs <> size 6)
<> refHorizontal 2.5
<> refVertical 2.5
<> legend
<> title "3h. refHorizontal / refVertical + legend"
-- 03 scale: 既製パレット okabeIto
, fig "s3d-palette-okabe.svg" $
purePlot <> layer (scatter xs ys <> colorBy gs <> size 7) <> palette okabeIto <> legend
<> title "palette okabeIto (色覚多様性対応)"
-- 03 theme: 要素単位の部分上書き
, fig "s3e-theme-override.svg" $
purePlot <> layer (scatter xs ys <> size 6)
<> theme ThemeMinimal
<> titleFont (fontSize 18 <> fontWeight "bold")
<> tickFont (fontSize 10 <> fontColor "#64748b")
<> panelBorder True <> themeGrid False <> themeAxisTextAngle 45
<> title "theme 要素の部分上書き"
-- 03 theme × facet strip
, figR "s3e-theme-strip.svg" rFacet $
purePlot <> layer (scatter "x" "y" <> colorBy "g") <> facet "g"
<> themeStrip True <> stripFill "#eef2ff"
<> title "facet strip 背景 (stripFill)"
-- 03 guides: 軸の細かい制御 (log + 範囲 + 回転)
, fig "s3h-axis.svg" $
purePlot <> layer (scatter axx axy <> size 6)
<> xAxis (logAxis <> axisRange 1 1000 <> axisRotate 45)
<> yAxis (axisRange 0 100)
<> title "xAxis (logAxis <> axisRange <> axisRotate)"
-- 03 guides: 第 2 軸 (右 y)
, figR "s3h-second-axis.svg" rSec $
purePlot
<> layer (line "t" "price" <> color (fromHex "#1f77b4") <> stroke 2)
<> layer (line "t" "volume" <> toRightY <> color (fromHex "#d62728") <> stroke 2)
<> yAxisRight (axisRange 0 1000000)
<> title "第 2 軸 (price=左 / volume=右)"
-- 03 guides: 注釈
, fig "s3h-annotate.svg" $
purePlot <> layer (scatter xs ys <> size 6)
<> annotText 2.0 3.6 "注釈"
<> annotArrow 1.4 3.0 1.95 3.5
<> annotRect 3.0 1.0 4.0 2.0 "領域"
<> marginalX
<> insetAt 0.72 0.1 0.25 0.25 (layer (histogram xs))
<> title "annotText / annotArrow / annotRect / marginalX / insetAt"
-- 高度な図: 多数の設定を一枚に
, fig "advanced.svg" $
purePlot
<> layer ( scatter (inline axs) (inline ays)
<> colorContinuousBy (inline azs)
<> sizeBy (inline asz)
<> alpha 0.85 )
<> layer ( line (inline axs) (inline afit)
<> color (fromHex "#ef4444") <> stroke 2 )
<> scaleSize 4 16
<> refHorizontal 1.0
<> theme ThemeMinimal
<> legend
<> labs (emptyLabs
{ labsTitle = Just "高度な図: 連続色 + サイズ + 回帰 + 参照線"
, labsSubtitle = Just "colorContinuousBy / sizeBy / line overlay / refHorizontal / theme"
, labsCaption = Just "hgg ─ <> で設定を積層"
, labsX = Just "x"
, labsY = Just "y" })
]
where
xs = inline [1,2,3,4, 1,2,3,4]
ys = inline [2,3,1,4, 3,1,4,2]
gs = inlineCat (concatMap (replicate 4) (["alpha","beta"] :: [Text]))
cats = inlineCat (["A","B","C"] :: [Text])
vals = inline [3.0, 7.0, 5.0]
cz = inline [1.0, 2.5, 4.0, 1.5, 3.0, 4.5, 2.0, 3.5]
oxs = [1,2,3,4,5,6,7,8,9,10] :: [Double]
oys = [1.2, 1.9, 3.4, 3.1, 5.2, 5.0, 6.8, 7.3, 8.1, 9.4]
(oa, ob) = linFit oxs oys
ofit = [ oa * x + ob | x <- oxs ]
themePanel (nm, th) =
layer (scatter xs ys <> color (fromHex "#3b82f6") <> size 5) <> theme th <> title nm
allThemes :: [(Text, ThemeName)]
allThemes =
[ ("Default", ThemeDefault), ("Minimal", ThemeMinimal), ("Dark", ThemeDark)
, ("Light", ThemeLight), ("Grey", ThemeGrey), ("BW", ThemeBW)
, ("Classic", ThemeClassic), ("Void", ThemeVoid), ("Linedraw", ThemeLinedraw)
, ("Noir", ThemeNoir), ("Lumen", ThemeLumen)
, ("Parchment", ThemeParchment), ("ParchmentDark", ThemeParchmentDark) ]
selPanelOf f = layer (scatter (inline [1,2,3,4,5 :: Double])
(inline [2,4,3,5,4 :: Double]))
<> title f
nx = inline [ sin (0.5 * fromIntegral i) + 0.15 * fromIntegral (i `mod` 7)
| i <- [0 .. 60 :: Int] ]
ny = inline [ cos (0.4 * fromIntegral i) | i <- [0 .. 60 :: Int] ]
cA = layer (scatter (inline [1,2,3,4,5]) (inline [1,4,9,16,25])) <> title "x²"
cB = layer (line (inline [1,2,3,4,5]) (inline [2,4,8,16,32])) <> title "2^x"
cC = layer (bar (inlineCat (["a","b","c","d"] :: [Text])) (inline [3,7,5,9])) <> title "bar"
cD = layer (scatter (inline [0,1,2,3,4]) (inline [0,3,1,4,2])) <> title "full-width row"
axx = inline ([1,3,10,30,100,300,1000] :: [Double])
axy = inline ([3,7,12,20,33,52,78] :: [Double])
n = 60 :: Int
axs = [ fromIntegral i * 0.18 | i <- [0 .. n - 1] ] :: [Double]
noise = take n (lcg 12345)
ays = [ 0.55 * x + 1.0 + (e - 0.5) * 2.2 | (x, e) <- zip axs noise ]
azs = ays -- 連続色は y 値で
asz = [ 0.5 + e | e <- noise ] -- サイズは別の擬似量
(fa, fb) = linFit axs ays
afit = [ fa * x + fb | x <- axs ]
rFacet :: Resolver
rFacet "x" = Just (NumData (V.fromList [1,2,3,4, 1,2,3,4]))
rFacet "y" = Just (NumData (V.fromList [2,3,1,4, 3,1,4,2]))
rFacet "g" = Just (TxtData (V.fromList (concatMap (replicate 4) ["A","B"])))
rFacet _ = Nothing
rSec :: Resolver
rSec "t" = Just (NumData (V.fromList [1,2,3,4,5,6,7,8,9,10]))
rSec "price" = Just (NumData (V.fromList [10,11,13,12,15,16,15,18,17,20]))
rSec "volume" = Just (NumData (V.fromList [3e5,5e5,4e5,7e5,6e5,9e5,8e5,7e5,9e5,1e6]))
rSec _ = Nothing