{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wall #-}

-- | Base 'Chart' and 'ChartTree' types and support
module Chart.Primitive
  ( -- * Charts

    Chart (..),
    ChartTree (..),
    tree',
    chart',
    charts',
    named,
    unnamed,
    rename,
    blank,
    group,
    filterChartTree,
    Orientation (..),
    Stacked (..),
    ChartAspect (..),

    -- * Boxes

    -- $boxes
    box,
    sbox,
    projectWith,
    maybeProjectWith,
    moveChart,
    scaleChart,
    scaleStyle,
    colourChart,
    projectChartTree,
    boxes,
    box',
    styleBoxes,
    styleBox',

    -- * Combinators
    vert,
    hori,
    stack,
    frameChart,
    isEmptyChart,
    padChart,
    rectangularize,
    glyphize,
    overText,
  renamed)
where

import Chart.Data
import Chart.Style
import Data.Bifunctor
import Data.Bool
import Data.Colour
import Data.Foldable
import Data.Maybe
import Data.Path
import Data.Text (Text)
import Data.Tree
import GHC.Generics
import qualified NumHask.Prelude as NH
import Optics.Core
import Prelude

-- $setup
--
-- >>> :set -XOverloadedLabels
-- >>> :set -XOverloadedStrings
-- >>> import Chart
-- >>> import Optics.Core
-- >>> let r = RectChart defaultRectStyle [one]

-- | There are 6 Chart primitives, unified as the Chart type.
--
-- - 'RectChart': a rectangle in the XY-domain. For example, a @'Rect' 0 1 0 1@ is the set of points on the XY Plane bounded by (0,0), (0,1), (1,0) & (1,1). Much of the library is built on 'Rect' 'Double''s but the base types are polymorphic.
-- - 'LineChart': a list of points which represent connected straight lines. ['Point' 0 0, 'Point' 1 1, 'Point' 2 2, 'Point' 3 3] is an example; three lines connected up to form a line from (0,0) to (3,3).
-- - 'GlyphChart': a 'GlyphShape' which is a predefined shaped centered at a 'Point' in XY space.
-- - 'TextChart': text centered at a 'Point' in XY space.
-- - 'PathChart': specification of curvilinear paths using the SVG standards.
-- - 'BlankChart': a rectangular space that has no visual representation.
--
-- What is a Chart is usually a combination of these primitives into a tree or list of charts.
--
-- Each Chart primitive is a product of a style (the syntactic representation of the data) and a list of data.
--
-- A simple example is:
--
-- >>> let r = RectChart defaultRectStyle [one]
-- >>> r
-- RectChart (RectStyle {borderSize = 1.0e-2, borderColor = Colour 0.02 0.29 0.48 1.00, color = Colour 0.02 0.73 0.80 0.10}) [Rect -0.5 0.5 -0.5 0.5]
--
-- Using the defaults, this chart is rendered as:
--
-- > writeChartSvg "other/unit.hs" $ mempty & #hudOptions .~ defaultHudOptions & #charts .~ unnamed [r]
--
-- ![unit example](other/unit.svg)
data Chart where
  RectChart :: RectStyle -> [Rect Double] -> Chart
  LineChart :: LineStyle -> [[Point Double]] -> Chart
  GlyphChart :: GlyphStyle -> [Point Double] -> Chart
  TextChart :: TextStyle -> [(Text, Point Double)] -> Chart
  PathChart :: PathStyle -> [PathData Double] -> Chart
  BlankChart :: [Rect Double] -> Chart
  deriving (Chart -> Chart -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Chart -> Chart -> Bool
$c/= :: Chart -> Chart -> Bool
== :: Chart -> Chart -> Bool
$c== :: Chart -> Chart -> Bool
Eq, Int -> Chart -> ShowS
[Chart] -> ShowS
Chart -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Chart] -> ShowS
$cshowList :: [Chart] -> ShowS
show :: Chart -> String
$cshow :: Chart -> String
showsPrec :: Int -> Chart -> ShowS
$cshowsPrec :: Int -> Chart -> ShowS
Show)

-- | A group of charts represented by a 'Tree' of chart lists with labelled branches. The labelling is particularly useful downstream, when groupings become grouped SVG elements with classes or ids.
newtype ChartTree = ChartTree {ChartTree -> Tree (Maybe Text, [Chart])
tree :: Tree (Maybe Text, [Chart])} deriving (ChartTree -> ChartTree -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChartTree -> ChartTree -> Bool
$c/= :: ChartTree -> ChartTree -> Bool
== :: ChartTree -> ChartTree -> Bool
$c== :: ChartTree -> ChartTree -> Bool
Eq, Int -> ChartTree -> ShowS
[ChartTree] -> ShowS
ChartTree -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ChartTree] -> ShowS
$cshowList :: [ChartTree] -> ShowS
show :: ChartTree -> String
$cshow :: ChartTree -> String
showsPrec :: Int -> ChartTree -> ShowS
$cshowsPrec :: Int -> ChartTree -> ShowS
Show, forall x. Rep ChartTree x -> ChartTree
forall x. ChartTree -> Rep ChartTree x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ChartTree x -> ChartTree
$cfrom :: forall x. ChartTree -> Rep ChartTree x
Generic)

-- | Apply a filter to ChartTree
filterChartTree :: (Chart -> Bool) -> ChartTree -> ChartTree
filterChartTree :: (Chart -> Bool) -> ChartTree -> ChartTree
filterChartTree Chart -> Bool
p (ChartTree (Node (Maybe Text
a, [Chart]
cs) [Tree (Maybe Text, [Chart])]
xs)) =
  Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree (forall a. a -> [Tree a] -> Tree a
Node (Maybe Text
a, forall a. [Maybe a] -> [a]
catMaybes (Chart -> Maybe Chart
rem' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Chart]
cs)) (ChartTree -> Tree (Maybe Text, [Chart])
tree forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Chart -> Bool) -> ChartTree -> ChartTree
filterChartTree Chart -> Bool
p forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Tree (Maybe Text, [Chart])]
xs))
  where
    rem' :: Chart -> Maybe Chart
rem' Chart
x = forall a. a -> a -> Bool -> a
bool forall a. Maybe a
Nothing (forall a. a -> Maybe a
Just Chart
x) (Chart -> Bool
p Chart
x)

-- | Lens between ChartTree and the underlying Tree representation
tree' :: Iso' ChartTree (Tree (Maybe Text, [Chart]))
tree' :: Iso' ChartTree (Tree (Maybe Text, [Chart]))
tree' = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso ChartTree -> Tree (Maybe Text, [Chart])
tree Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree

-- | A traversal of each chart list in a tree.
charts' :: Traversal' ChartTree [Chart]
charts' :: Traversal' ChartTree [Chart]
charts' = Iso' ChartTree (Tree (Maybe Text, [Chart]))
tree' forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% forall (t :: * -> *) a b.
Traversable t =>
Traversal (t a) (t b) a b
traversed forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% forall s t a b. Field2 s t a b => Lens s t a b
_2

-- | A traversal of each chart in a tree.
chart' :: Traversal' ChartTree Chart
chart' :: Traversal' ChartTree Chart
chart' = Iso' ChartTree (Tree (Maybe Text, [Chart]))
tree' forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% forall (t :: * -> *) a b.
Traversable t =>
Traversal (t a) (t b) a b
traversed forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% forall s t a b. Field2 s t a b => Lens s t a b
_2 forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% forall (t :: * -> *) a b.
Traversable t =>
Traversal (t a) (t b) a b
traversed

-- | Convert a chart list to a tree, adding a specific text label.
named :: Text -> [Chart] -> ChartTree
named :: Text -> [Chart] -> ChartTree
named Text
l [Chart]
cs = Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall a b. (a -> b) -> a -> b
$ forall a. a -> [Tree a] -> Tree a
Node (forall a. a -> Maybe a
Just Text
l, [Chart]
cs) []

-- | Convert a chart list to a tree, with no text label.
unnamed :: [Chart] -> ChartTree
unnamed :: [Chart] -> ChartTree
unnamed [Chart]
cs = Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall a b. (a -> b) -> a -> b
$ forall a. a -> [Tree a] -> Tree a
Node (forall a. Maybe a
Nothing, [Chart]
cs) []

-- | Rename a ChartTree, removing descendent names
renamed :: Text -> ChartTree -> ChartTree
renamed :: Text -> ChartTree -> ChartTree
renamed Text
l ChartTree
ct = Text -> [Chart] -> ChartTree
named Text
l forall a b. (a -> b) -> a -> b
$ forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts' ChartTree
ct

-- | Rename a top-level label in a tree.
rename :: Maybe Text -> ChartTree -> ChartTree
rename :: Maybe Text -> ChartTree -> ChartTree
rename Maybe Text
l (ChartTree (Node (Maybe Text
_, [Chart]
cs) [Tree (Maybe Text, [Chart])]
xs)) = Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree (forall a. a -> [Tree a] -> Tree a
Node (Maybe Text
l, [Chart]
cs) [Tree (Maybe Text, [Chart])]
xs)

-- | A tree with no charts and no label.
blank :: Rect Double -> ChartTree
blank :: Rect Double -> ChartTree
blank Rect Double
r = [Chart] -> ChartTree
unnamed [[Rect Double] -> Chart
BlankChart [Rect Double
r]]

-- | Group a list of trees into a new tree.
group :: Maybe Text -> [ChartTree] -> ChartTree
group :: Maybe Text -> [ChartTree] -> ChartTree
group Maybe Text
name [ChartTree]
cs = Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall a b. (a -> b) -> a -> b
$ forall a. a -> [Tree a] -> Tree a
Node (Maybe Text
name, []) (ChartTree -> Tree (Maybe Text, [Chart])
tree forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ChartTree]
cs)

instance Semigroup ChartTree where
  <> :: ChartTree -> ChartTree -> ChartTree
(<>) (ChartTree x :: Tree (Maybe Text, [Chart])
x@(Node (Maybe Text
n, [Chart]
cs) [Tree (Maybe Text, [Chart])]
xs)) (ChartTree x' :: Tree (Maybe Text, [Chart])
x'@(Node (Maybe Text
n', [Chart]
cs') [Tree (Maybe Text, [Chart])]
xs')) =
    case (Maybe Text
n, Maybe Text
n') of
      (Maybe Text
Nothing, Maybe Text
Nothing) -> Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall a b. (a -> b) -> a -> b
$ forall a. a -> [Tree a] -> Tree a
Node (forall a. Maybe a
Nothing, [Chart]
cs forall a. Semigroup a => a -> a -> a
<> [Chart]
cs') ([Tree (Maybe Text, [Chart])]
xs forall a. Semigroup a => a -> a -> a
<> [Tree (Maybe Text, [Chart])]
xs')
      (Maybe Text, Maybe Text)
_ -> Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall a b. (a -> b) -> a -> b
$ forall a. a -> [Tree a] -> Tree a
Node (forall a. Maybe a
Nothing, []) [Tree (Maybe Text, [Chart])
x, Tree (Maybe Text, [Chart])
x']

instance Monoid ChartTree where
  mempty :: ChartTree
mempty = Tree (Maybe Text, [Chart]) -> ChartTree
ChartTree forall a b. (a -> b) -> a -> b
$ forall a. a -> [Tree a] -> Tree a
Node (forall a. Maybe a
Nothing, []) []

-- $boxes
--
-- Library functionality (rescaling, combining charts, working out axes and generally putting charts together) is driven by a box model. A box is a rectangular space that bounds chart elements.

-- | The 'Rect' which encloses the data elements of the chart. /Bounding box/ is a synonym.
--
-- >>> box r
-- Just Rect -0.5 0.5 -0.5 0.5
box :: Chart -> Maybe (Rect Double)
box :: Chart -> Maybe (Rect Double)
box (RectChart RectStyle
_ [Rect Double]
a) = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect [Rect Double]
a
box (TextChart TextStyle
_ [(Text, Point Double)]
a) = forall s (f :: * -> *).
(Space s, Traversable f) =>
f (Element s) -> Maybe s
space1 forall a b. (a -> b) -> a -> b
$ forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Text, Point Double)]
a
box (LineChart LineStyle
_ [[Point Double]]
a) = forall s (f :: * -> *).
(Space s, Traversable f) =>
f (Element s) -> Maybe s
space1 forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [[Point Double]]
a
box (GlyphChart GlyphStyle
_ [Point Double]
a) = forall s (f :: * -> *).
(Space s, Traversable f) =>
f (Element s) -> Maybe s
space1 [Point Double]
a
box (PathChart PathStyle
_ [PathData Double]
a) = [PathData Double] -> Maybe (Rect Double)
pathBoxes [PathData Double]
a
box (BlankChart [Rect Double]
a) = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect [Rect Double]
a

-- | The bounding box for a chart including both data and style elements.
--
-- >>> sbox r
-- Just Rect -0.505 0.505 -0.505 0.505
--
-- In the above example, the border of the rectangle adds an extra 0.1 to the height and width of the bounding box enclosing the chart.
sbox :: Chart -> Maybe (Rect Double)
sbox :: Chart -> Maybe (Rect Double)
sbox (RectChart RectStyle
s [Rect Double]
a) = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect forall a b. (a -> b) -> a -> b
$ forall a. Subtractive a => a -> Rect a -> Rect a
padRect (Double
0.5 forall a. Num a => a -> a -> a
* forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view forall a. IsLabel "borderSize" a => a
#borderSize RectStyle
s) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
a
sbox (TextChart TextStyle
s [(Text, Point Double)]
a) = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (TextStyle -> Text -> Point Double -> Rect Double
styleBoxText TextStyle
s) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Text, Point Double)]
a
sbox (LineChart LineStyle
s [[Point Double]]
a) = forall a. Subtractive a => a -> Rect a -> Rect a
padRect (Double
0.5 forall a. Num a => a -> a -> a
* LineStyle
s forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. forall a. IsLabel "size" a => a
#size) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall s (f :: * -> *).
(Space s, Traversable f) =>
f (Element s) -> Maybe s
space1 forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [[Point Double]]
a)
sbox (GlyphChart GlyphStyle
s [Point Double]
a) = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect forall a b. (a -> b) -> a -> b
$ (\Point Double
p -> forall a. Additive a => Point a -> Rect a -> Rect a
addPoint Point Double
p (GlyphStyle -> Rect Double
styleBoxGlyph GlyphStyle
s)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Point Double]
a
sbox (PathChart PathStyle
s [PathData Double]
a) = forall a. Subtractive a => a -> Rect a -> Rect a
padRect (Double
0.5 forall a. Num a => a -> a -> a
* forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view forall a. IsLabel "borderSize" a => a
#borderSize PathStyle
s) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PathData Double] -> Maybe (Rect Double)
pathBoxes [PathData Double]
a
sbox (BlankChart [Rect Double]
a) = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect [Rect Double]
a

-- | projects a Chart to a new space from an old rectangular space, preserving linear metric structure.
--
-- >>> projectWith (fmap (2*) one) one r
-- RectChart (RectStyle {borderSize = 1.0e-2, borderColor = Colour 0.02 0.29 0.48 1.00, color = Colour 0.02 0.73 0.80 0.10}) [Rect -1.0 1.0 -1.0 1.0]
projectWith :: Rect Double -> Rect Double -> Chart -> Chart
projectWith :: Rect Double -> Rect Double -> Chart -> Chart
projectWith Rect Double
new Rect Double
old (RectChart RectStyle
s [Rect Double]
a) = RectStyle -> [Rect Double] -> Chart
RectChart RectStyle
s (Rect Double -> Rect Double -> Rect Double -> Rect Double
projectOnR Rect Double
new Rect Double
old forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
a)
projectWith Rect Double
new Rect Double
old (TextChart TextStyle
s [(Text, Point Double)]
a) = TextStyle -> [(Text, Point Double)] -> Chart
TextChart (TextStyle -> TextStyle
projectX TextStyle
s) (forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (Rect Double -> Rect Double -> Point Double -> Point Double
projectOnP Rect Double
new Rect Double
old) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Text, Point Double)]
a)
  where
    projectX :: TextStyle -> TextStyle
    projectX :: TextStyle -> TextStyle
projectX TextStyle
s' = case forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view forall a. IsLabel "scalex" a => a
#scalex TextStyle
s' of
      ScaleX
NoScaleX -> TextStyle
s' forall a b. a -> (a -> b) -> b
& forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over forall a. IsLabel "hsize" a => a
#hsize (forall a. Num a => a -> a -> a
* (forall s. (Space s, Subtractive (Element s)) => s -> Element s
width Range Double
ox forall a. Fractional a => a -> a -> a
/ forall s. (Space s, Subtractive (Element s)) => s -> Element s
width Range Double
nx)) forall a b. a -> (a -> b) -> b
& forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over forall a. IsLabel "vsize" a => a
#vsize (forall a. Num a => a -> a -> a
* (forall s. (Space s, Subtractive (Element s)) => s -> Element s
width Range Double
ox forall a. Fractional a => a -> a -> a
/ forall s. (Space s, Subtractive (Element s)) => s -> Element s
width Range Double
nx))
      ScaleX
ScaleX -> TextStyle
s' forall a b. a -> (a -> b) -> b
& forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over forall a. IsLabel "size" a => a
#size (forall a. Num a => a -> a -> a
* (forall s. (Space s, Subtractive (Element s)) => s -> Element s
width Range Double
nx forall a. Fractional a => a -> a -> a
/ forall s. (Space s, Subtractive (Element s)) => s -> Element s
width Range Double
ox))
    (Ranges Range Double
nx Range Double
_) = Rect Double
new
    (Ranges Range Double
ox Range Double
_) = Rect Double
old
projectWith Rect Double
new Rect Double
old (LineChart LineStyle
s [[Point Double]]
a) = LineStyle -> [[Point Double]] -> Chart
LineChart LineStyle
s (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Rect Double -> Rect Double -> Point Double -> Point Double
projectOnP Rect Double
new Rect Double
old) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [[Point Double]]
a)
projectWith Rect Double
new Rect Double
old (GlyphChart GlyphStyle
s [Point Double]
a) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
s (Rect Double -> Rect Double -> Point Double -> Point Double
projectOnP Rect Double
new Rect Double
old forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Point Double]
a)
projectWith Rect Double
new Rect Double
old (BlankChart [Rect Double]
a) = [Rect Double] -> Chart
BlankChart (Rect Double -> Rect Double -> Rect Double -> Rect Double
projectOnR Rect Double
new Rect Double
old forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
a)
projectWith Rect Double
new Rect Double
old (PathChart PathStyle
s [PathData Double]
a) = PathStyle -> [PathData Double] -> Chart
PathChart PathStyle
s (Rect Double
-> Rect Double -> [PathData Double] -> [PathData Double]
projectPaths Rect Double
new Rect Double
old [PathData Double]
a)

-- | Maybe project a Chart to a new rectangular space from an old rectangular space, if both Rects exist.
maybeProjectWith :: Maybe (Rect Double) -> Maybe (Rect Double) -> Chart -> Chart
maybeProjectWith :: Maybe (Rect Double) -> Maybe (Rect Double) -> Chart -> Chart
maybeProjectWith Maybe (Rect Double)
new Maybe (Rect Double)
old = forall a. a -> Maybe a -> a
fromMaybe forall a. a -> a
id (Rect Double -> Rect Double -> Chart -> Chart
projectWith forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Rect Double)
new forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe (Rect Double)
old)

-- | Move a chart.
moveChart :: Point Double -> Chart -> Chart
moveChart :: Point Double -> Chart -> Chart
moveChart Point Double
p (RectChart RectStyle
s [Rect Double]
a) = RectStyle -> [Rect Double] -> Chart
RectChart RectStyle
s (forall a. Additive a => Point a -> Rect a -> Rect a
addPoint Point Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
a)
moveChart Point Double
p (TextChart TextStyle
s [(Text, Point Double)]
a) = TextStyle -> [(Text, Point Double)] -> Chart
TextChart TextStyle
s (forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (Point Double -> Point Double -> Point Double
addp Point Double
p) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Text, Point Double)]
a)
moveChart Point Double
p (LineChart LineStyle
s [[Point Double]]
a) = LineStyle -> [[Point Double]] -> Chart
LineChart LineStyle
s (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Point Double -> Point Double -> Point Double
addp Point Double
p) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [[Point Double]]
a)
moveChart Point Double
p (GlyphChart GlyphStyle
s [Point Double]
a) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
s (Point Double -> Point Double -> Point Double
addp Point Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Point Double]
a)
moveChart Point Double
p (PathChart PathStyle
s [PathData Double]
a) = PathStyle -> [PathData Double] -> Chart
PathChart PathStyle
s (forall a. Additive a => Point a -> PathData a -> PathData a
movePath Point Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PathData Double]
a)
moveChart Point Double
p (BlankChart [Rect Double]
a) = [Rect Double] -> Chart
BlankChart (forall a. Additive a => Point a -> Rect a -> Rect a
addPoint Point Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
a)

-- | Scale a chart (effecting both the chart data and the style).
scaleChart :: Double -> Chart -> Chart
scaleChart :: Double -> Chart -> Chart
scaleChart Double
p (RectChart RectStyle
s [Rect Double]
a) =
  RectStyle -> [Rect Double] -> Chart
RectChart (RectStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderSize" a => a
#borderSize forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
p)) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Num a => a -> a -> a
* Double
p)) [Rect Double]
a)
scaleChart Double
p (LineChart LineStyle
s [[Point Double]]
a) =
  LineStyle -> [[Point Double]] -> Chart
LineChart (LineStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "size" a => a
#size forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
p)) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Num a => a -> a -> a
* Double
p))) [[Point Double]]
a)
scaleChart Double
p (TextChart TextStyle
s [(Text, Point Double)]
a) =
  TextStyle -> [(Text, Point Double)] -> Chart
TextChart (TextStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "size" a => a
#size forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
p)) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Num a => a -> a -> a
* Double
p))) [(Text, Point Double)]
a)
scaleChart Double
p (GlyphChart GlyphStyle
s [Point Double]
a) =
  GlyphStyle -> [Point Double] -> Chart
GlyphChart (GlyphStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "size" a => a
#size forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
p)) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Num a => a -> a -> a
* Double
p)) [Point Double]
a)
scaleChart Double
p (PathChart PathStyle
s [PathData Double]
a) =
  PathStyle -> [PathData Double] -> Chart
PathChart (PathStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderSize" a => a
#borderSize forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
p)) (forall a. Multiplicative a => a -> PathData a -> PathData a
scalePath Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PathData Double]
a)
scaleChart Double
p (BlankChart [Rect Double]
a) =
  [Rect Double] -> Chart
BlankChart (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Num a => a -> a -> a
* Double
p)) [Rect Double]
a)

-- | Scale just the chart style.
scaleStyle :: Double -> Chart -> Chart
scaleStyle :: Double -> Chart -> Chart
scaleStyle Double
x (LineChart LineStyle
a [[Point Double]]
d) = LineStyle -> [[Point Double]] -> Chart
LineChart (LineStyle
a forall a b. a -> (a -> b) -> b
& forall a. IsLabel "size" a => a
#size forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
x)) [[Point Double]]
d
scaleStyle Double
x (RectChart RectStyle
a [Rect Double]
d) = RectStyle -> [Rect Double] -> Chart
RectChart (RectStyle
a forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderSize" a => a
#borderSize forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
x)) [Rect Double]
d
scaleStyle Double
x (TextChart TextStyle
a [(Text, Point Double)]
d) = TextStyle -> [(Text, Point Double)] -> Chart
TextChart (TextStyle
a forall a b. a -> (a -> b) -> b
& forall a. IsLabel "size" a => a
#size forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
x)) [(Text, Point Double)]
d
scaleStyle Double
x (GlyphChart GlyphStyle
a [Point Double]
d) = GlyphStyle -> [Point Double] -> Chart
GlyphChart (GlyphStyle
a forall a b. a -> (a -> b) -> b
& forall a. IsLabel "size" a => a
#size forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
x)) [Point Double]
d
scaleStyle Double
x (PathChart PathStyle
a [PathData Double]
d) = PathStyle -> [PathData Double] -> Chart
PathChart (PathStyle
a forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderSize" a => a
#borderSize forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ (forall a. Num a => a -> a -> a
* Double
x)) [PathData Double]
d
scaleStyle Double
_ (BlankChart [Rect Double]
d) = [Rect Double] -> Chart
BlankChart [Rect Double]
d

-- | Modify chart colors, applying to both border and main colors.
colourChart :: (Colour -> Colour) -> Chart -> Chart
colourChart :: (Colour -> Colour) -> Chart -> Chart
colourChart Colour -> Colour
f (RectChart RectStyle
s [Rect Double]
d) = RectStyle -> [Rect Double] -> Chart
RectChart RectStyle
s' [Rect Double]
d
  where
    s' :: RectStyle
s' = RectStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "color" a => a
#color forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderColor" a => a
#borderColor forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f
colourChart Colour -> Colour
f (TextChart TextStyle
s [(Text, Point Double)]
d) = TextStyle -> [(Text, Point Double)] -> Chart
TextChart TextStyle
s' [(Text, Point Double)]
d
  where
    s' :: TextStyle
s' = TextStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "color" a => a
#color forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f
colourChart Colour -> Colour
f (LineChart LineStyle
s [[Point Double]]
d) = LineStyle -> [[Point Double]] -> Chart
LineChart LineStyle
s' [[Point Double]]
d
  where
    s' :: LineStyle
s' = LineStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "color" a => a
#color forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f
colourChart Colour -> Colour
f (GlyphChart GlyphStyle
s [Point Double]
d) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
s' [Point Double]
d
  where
    s' :: GlyphStyle
s' = GlyphStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "color" a => a
#color forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderColor" a => a
#borderColor forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f
colourChart Colour -> Colour
f (PathChart PathStyle
s [PathData Double]
d) = PathStyle -> [PathData Double] -> Chart
PathChart PathStyle
s' [PathData Double]
d
  where
    s' :: PathStyle
s' = PathStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "color" a => a
#color forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f forall a b. a -> (a -> b) -> b
& forall a. IsLabel "borderColor" a => a
#borderColor forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
%~ Colour -> Colour
f
colourChart Colour -> Colour
_ (BlankChart [Rect Double]
d) = [Rect Double] -> Chart
BlankChart [Rect Double]
d

-- | Project a chart tree to a new bounding box, guarding against singleton bounds.
projectChartTree :: Rect Double -> [Chart] -> [Chart]
projectChartTree :: Rect Double -> [Chart] -> [Chart]
projectChartTree Rect Double
new [Chart]
cs = case [Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
cs of
  Maybe (Rect Double)
Nothing -> [Chart]
cs
  Just Rect Double
b -> Rect Double -> Rect Double -> Chart -> Chart
projectWith Rect Double
new Rect Double
b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Chart]
cs

-- | Compute the bounding box of a list of charts.
boxes :: [Chart] -> Maybe (Rect Double)
boxes :: [Chart] -> Maybe (Rect Double)
boxes [Chart]
cs = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$ forall a. Maybe a -> [a]
maybeToList forall b c a. (b -> c) -> (a -> b) -> a -> c
. Chart -> Maybe (Rect Double)
box forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Chart]
cs

box_ :: ChartTree -> Maybe (Rect Double)
box_ :: ChartTree -> Maybe (Rect Double)
box_ = [Chart] -> Maybe (Rect Double)
boxes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts'

rebox_ :: ChartTree -> Maybe (Rect Double) -> ChartTree
rebox_ :: ChartTree -> Maybe (Rect Double) -> ChartTree
rebox_ ChartTree
cs Maybe (Rect Double)
r =
  ChartTree
cs
    forall a b. a -> (a -> b) -> b
& forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Traversal' ChartTree Chart
chart' (forall a. a -> Maybe a -> a
fromMaybe forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ Rect Double -> Rect Double -> Chart -> Chart
projectWith forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Rect Double)
r forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ChartTree -> Maybe (Rect Double)
box_ ChartTree
cs)

-- | Lens between a ChartTree and its bounding box.
box' :: Lens' ChartTree (Maybe (Rect Double))
box' :: Lens' ChartTree (Maybe (Rect Double))
box' =
  forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens ChartTree -> Maybe (Rect Double)
box_ ChartTree -> Maybe (Rect Double) -> ChartTree
rebox_

-- | Compute the bounding box of the data and style elements contained in a list of charts.
styleBoxes :: [Chart] -> Maybe (Rect Double)
styleBoxes :: [Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
cs = forall a. Ord a => [Rect a] -> Maybe (Rect a)
foldRect forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$ forall a. Maybe a -> [a]
maybeToList forall b c a. (b -> c) -> (a -> b) -> a -> c
. Chart -> Maybe (Rect Double)
sbox forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Chart]
cs

styleBox_ :: ChartTree -> Maybe (Rect Double)
styleBox_ :: ChartTree -> Maybe (Rect Double)
styleBox_ = [Chart] -> Maybe (Rect Double)
styleBoxes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts'

styleRebox_ :: ChartTree -> Maybe (Rect Double) -> ChartTree
styleRebox_ :: ChartTree -> Maybe (Rect Double) -> ChartTree
styleRebox_ ChartTree
cs Maybe (Rect Double)
r =
  ChartTree
cs
    forall a b. a -> (a -> b) -> b
& forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Traversal' ChartTree Chart
chart' (forall a. a -> Maybe a -> a
fromMaybe forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ Rect Double -> Rect Double -> Chart -> Chart
projectWith forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Rect Double)
r' forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ChartTree -> Maybe (Rect Double)
box_ ChartTree
cs)
  where
    r' :: Maybe (Rect Double)
r' = forall a. Subtractive a => a -> a -> a
(NH.-) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Rect Double)
r forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (forall a. Subtractive a => a -> a -> a
(NH.-) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ChartTree -> Maybe (Rect Double)
styleBox_ ChartTree
cs forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ChartTree -> Maybe (Rect Double)
box_ ChartTree
cs)

-- | Lens between a style bounding box and a ChartTree tree.
--
-- Note that a round trip may be only approximately isomorphic ie
--
-- > forall c r. \c -> view styleBox' . set styleBox r c ~= r
--
-- - SVG is, in general, an additive model eg a border adds a constant amount no matter the scale or aspect. Text charts, in particular, can have small data boxes but large style additions to the box.
--
-- - rescaling of style here is, in juxtaposition, a multiplicative model.
--
-- In practice, this can lead to weird corner cases and unrequited distortion.
--
-- The example below starts with the unit chart, and a simple axis bar, with a dynamic overhang, so that the axis bar represents the x-axis extremity.
--
-- >>> t1 = unnamed [RectChart defaultRectStyle [one]]
-- >>> x1 h = toChartTree $ mempty & set #charts t1 & set (#hudOptions % #chartAspect) (ChartAspect) & set (#hudOptions % #axes) [(1,defaultAxisOptions & over #bar (fmap (set #overhang h)) & set (#ticks % #ttick) Nothing & set (#ticks % #gtick) Nothing & set (#ticks % #ltick) Nothing)]
--
-- With a significant overhang, the axis bar dominates the extrema:
--
-- >>> view styleBox' $ set styleBox' (Just one) (x1 0.1)
-- Just Rect -0.5 0.5 -0.5 0.5
--
-- With no overhang, the style additions caused by the chart dominates:
--
-- >>> view styleBox' $ set styleBox' (Just one) (x1 0)
-- Just Rect -0.5 0.5 -0.5 0.5
--
-- In between:
--
-- >>> view styleBox' $ set styleBox' (Just one) (x1 0.002)
-- Just Rect -0.5000199203187251 0.5000199203187251 -0.5 0.5
--
--
-- If having an exact box is important, try running set styleBox' multiple times eg
--
-- >>> view styleBox' $ foldr ($) (x1 0.002) (replicate 10 (set styleBox' (Just one)))
-- Just Rect -0.5 0.5000000000000001 -0.5 0.4999999999999999
styleBox' :: Lens' ChartTree (Maybe (Rect Double))
styleBox' :: Lens' ChartTree (Maybe (Rect Double))
styleBox' =
  forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens ChartTree -> Maybe (Rect Double)
styleBox_ ChartTree -> Maybe (Rect Double) -> ChartTree
styleRebox_

-- | Create a frame over some charts with (additive) padding.
--
-- >>> frameChart defaultRectStyle 0.1 [BlankChart []]
-- RectChart (RectStyle {borderSize = 1.0e-2, borderColor = Colour 0.02 0.29 0.48 1.00, color = Colour 0.02 0.73 0.80 0.10}) []
frameChart :: RectStyle -> Double -> [Chart] -> Chart
frameChart :: RectStyle -> Double -> [Chart] -> Chart
frameChart RectStyle
rs Double
p [Chart]
cs = RectStyle -> [Rect Double] -> Chart
RectChart RectStyle
rs (forall a. Maybe a -> [a]
maybeToList (forall a. Subtractive a => a -> Rect a -> Rect a
padRect Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
cs))

-- | Additive padding, framing or buffering for a chart list.
padChart :: Double -> [Chart] -> Chart
padChart :: Double -> [Chart] -> Chart
padChart Double
p [Chart]
cs = [Rect Double] -> Chart
BlankChart (forall a. Maybe a -> [a]
maybeToList (forall a. Subtractive a => a -> Rect a -> Rect a
padRect Double
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
cs))

-- | Whether a chart is empty of data to be represented.
isEmptyChart :: Chart -> Bool
isEmptyChart :: Chart -> Bool
isEmptyChart (RectChart RectStyle
_ []) = Bool
True
isEmptyChart (LineChart LineStyle
_ []) = Bool
True
isEmptyChart (GlyphChart GlyphStyle
_ []) = Bool
True
isEmptyChart (TextChart TextStyle
_ []) = Bool
True
isEmptyChart (PathChart PathStyle
_ []) = Bool
True
isEmptyChart (BlankChart [Rect Double]
_) = Bool
True
isEmptyChart Chart
_ = Bool
False

-- | Horizontally stack a list of trees (proceeding to the right) with a gap between
hori :: Double -> [ChartTree] -> ChartTree
hori :: Double -> [ChartTree] -> ChartTree
hori Double
_ [] = forall a. Monoid a => a
mempty
hori Double
gap [ChartTree]
cs = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' ChartTree -> ChartTree -> ChartTree
step forall a. Monoid a => a
mempty [ChartTree]
cs
  where
    step :: ChartTree -> ChartTree -> ChartTree
step ChartTree
x ChartTree
c = ChartTree
x forall a. Semigroup a => a -> a -> a
<> forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Traversal' ChartTree Chart
chart' (Point Double -> Chart -> Chart
moveChart (forall a. a -> a -> Point a
Point (ChartTree -> Double
widthx ChartTree
x) (ChartTree -> Double
aligny ChartTree
x forall a. Num a => a -> a -> a
- ChartTree -> Double
aligny ChartTree
c))) ChartTree
c
    widthx :: ChartTree -> Double
widthx ChartTree
x = case forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts' ChartTree
x of
      [] -> forall a. Additive a => a
zero
      [Chart]
xs -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Additive a => a
zero (\(Rect Double
x' Double
z' Double
_ Double
_) -> Double
z' forall a. Num a => a -> a -> a
- Double
x' forall a. Num a => a -> a -> a
+ Double
gap) ([Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
xs)
    aligny :: ChartTree -> Double
aligny ChartTree
x = case forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts' ChartTree
x of
      [] -> forall a. Additive a => a
zero
      [Chart]
xs -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Additive a => a
zero (\(Rect Double
_ Double
_ Double
y' Double
w') -> (Double
y' forall a. Num a => a -> a -> a
+ Double
w') forall a. Fractional a => a -> a -> a
/ Double
2) ([Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
xs)

-- | Vertically stack a list of trees (proceeding upwards), aligning them to the left
vert :: Double -> [ChartTree] -> ChartTree
vert :: Double -> [ChartTree] -> ChartTree
vert Double
_ [] = forall a. Monoid a => a
mempty
vert Double
gap [ChartTree]
cs = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' ChartTree -> ChartTree -> ChartTree
step forall a. Monoid a => a
mempty [ChartTree]
cs
  where
    step :: ChartTree -> ChartTree -> ChartTree
step ChartTree
x ChartTree
c = ChartTree
x forall a. Semigroup a => a -> a -> a
<> forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Traversal' ChartTree Chart
chart' (Point Double -> Chart -> Chart
moveChart (forall a. a -> a -> Point a
Point (ChartTree -> Double
alignx ChartTree
x forall a. Num a => a -> a -> a
- ChartTree -> Double
alignx ChartTree
c) (ChartTree -> Double
widthy ChartTree
x))) ChartTree
c
    widthy :: ChartTree -> Double
widthy ChartTree
x = case forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts' ChartTree
x of
      [] -> forall a. Additive a => a
zero
      [Chart]
xs -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Additive a => a
zero (\(Rect Double
_ Double
_ Double
y' Double
w') -> Double
w' forall a. Num a => a -> a -> a
- Double
y' forall a. Num a => a -> a -> a
+ Double
gap) ([Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
xs)
    alignx :: ChartTree -> Double
alignx ChartTree
x = case forall k a (is :: IxList) s.
(Is k A_Fold, Monoid a) =>
Optic' k is s a -> s -> a
foldOf Traversal' ChartTree [Chart]
charts' ChartTree
x of
      [] -> forall a. Additive a => a
zero
      [Chart]
xs -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Additive a => a
zero (\(Rect Double
x' Double
_ Double
_ Double
_) -> Double
x') ([Chart] -> Maybe (Rect Double)
styleBoxes [Chart]
xs)

-- | Stack a list of tree charts horizontally, then vertically
stack :: Int -> Double -> [ChartTree] -> ChartTree
stack :: Int -> Double -> [ChartTree] -> ChartTree
stack Int
_ Double
_ [] = forall a. Monoid a => a
mempty
stack Int
n Double
gap [ChartTree]
cs = Double -> [ChartTree] -> ChartTree
vert Double
gap (Double -> [ChartTree] -> ChartTree
hori Double
gap forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ChartTree] -> [[ChartTree]] -> [[ChartTree]]
group' [ChartTree]
cs [])
  where
    group' :: [ChartTree] -> [[ChartTree]] -> [[ChartTree]]
group' [] [[ChartTree]]
acc = forall a. [a] -> [a]
reverse [[ChartTree]]
acc
    group' [ChartTree]
x [[ChartTree]]
acc = [ChartTree] -> [[ChartTree]] -> [[ChartTree]]
group' (forall a. Int -> [a] -> [a]
drop Int
n [ChartTree]
x) (forall a. Int -> [a] -> [a]
take Int
n [ChartTree]
x forall a. a -> [a] -> [a]
: [[ChartTree]]
acc)

-- | Make a new chart tree out of the bounding boxes of a chart tree.
rectangularize :: RectStyle -> ChartTree -> ChartTree
rectangularize :: RectStyle -> ChartTree -> ChartTree
rectangularize RectStyle
r ChartTree
c = Maybe Text -> [ChartTree] -> ChartTree
group (forall a. a -> Maybe a
Just Text
"rectangularize") [forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Traversal' ChartTree Chart
chart' (RectStyle -> Chart -> Chart
rectangularize_ RectStyle
r) ChartTree
c]

rectangularize_ :: RectStyle -> Chart -> Chart
rectangularize_ :: RectStyle -> Chart -> Chart
rectangularize_ RectStyle
rs (TextChart TextStyle
s [(Text, Point Double)]
xs) = TextStyle -> [(Text, Point Double)] -> Chart
TextChart (TextStyle
s forall a b. a -> (a -> b) -> b
& forall a. IsLabel "frame" a => a
#frame forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> b -> s -> t
.~ forall a. a -> Maybe a
Just RectStyle
rs) [(Text, Point Double)]
xs
rectangularize_ RectStyle
rs Chart
c = RectStyle -> [Rect Double] -> Chart
RectChart RectStyle
rs (forall a. Maybe a -> [a]
maybeToList forall a b. (a -> b) -> a -> b
$ Chart -> Maybe (Rect Double)
sbox Chart
c)

-- | Make a new chart tree out of the data points of a chart tree, using the supplied glyphs.
glyphize :: GlyphStyle -> ChartTree -> ChartTree
glyphize :: GlyphStyle -> ChartTree -> ChartTree
glyphize GlyphStyle
g ChartTree
c =
  Maybe Text -> [ChartTree] -> ChartTree
group (forall a. a -> Maybe a
Just Text
"glyphize") [forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Traversal' ChartTree Chart
chart' (GlyphStyle -> Chart -> Chart
glyphize_ GlyphStyle
g) ChartTree
c]

glyphize_ :: GlyphStyle -> Chart -> Chart
glyphize_ :: GlyphStyle -> Chart -> Chart
glyphize_ GlyphStyle
g (TextChart TextStyle
_ [(Text, Point Double)]
xs) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
g (forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Text, Point Double)]
xs)
glyphize_ GlyphStyle
g (PathChart PathStyle
_ [PathData Double]
xs) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
g (forall a. PathData a -> Point a
pointPath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PathData Double]
xs)
glyphize_ GlyphStyle
g (LineChart LineStyle
_ [[Point Double]]
xs) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
g (forall a. Monoid a => [a] -> a
mconcat [[Point Double]]
xs)
glyphize_ GlyphStyle
g (BlankChart [Rect Double]
xs) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
g (forall s. (Space s, Field (Element s)) => s -> Element s
mid forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
xs)
glyphize_ GlyphStyle
g (RectChart RectStyle
_ [Rect Double]
xs) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
g (forall s. (Space s, Field (Element s)) => s -> Element s
mid forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Rect Double]
xs)
glyphize_ GlyphStyle
g (GlyphChart GlyphStyle
_ [Point Double]
xs) = GlyphStyle -> [Point Double] -> Chart
GlyphChart GlyphStyle
g [Point Double]
xs

-- | Modify the text in a text chart.
overText :: (TextStyle -> TextStyle) -> Chart -> Chart
overText :: (TextStyle -> TextStyle) -> Chart -> Chart
overText TextStyle -> TextStyle
f (TextChart TextStyle
s [(Text, Point Double)]
xs) = TextStyle -> [(Text, Point Double)] -> Chart
TextChart (TextStyle -> TextStyle
f TextStyle
s) [(Text, Point Double)]
xs
overText TextStyle -> TextStyle
_ Chart
x = Chart
x

-- | Verticle or Horizontal
data Orientation = Vert | Hori deriving (Orientation -> Orientation -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Orientation -> Orientation -> Bool
$c/= :: Orientation -> Orientation -> Bool
== :: Orientation -> Orientation -> Bool
$c== :: Orientation -> Orientation -> Bool
Eq, Int -> Orientation -> ShowS
[Orientation] -> ShowS
Orientation -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Orientation] -> ShowS
$cshowList :: [Orientation] -> ShowS
show :: Orientation -> String
$cshow :: Orientation -> String
showsPrec :: Int -> Orientation -> ShowS
$cshowsPrec :: Int -> Orientation -> ShowS
Show, forall x. Rep Orientation x -> Orientation
forall x. Orientation -> Rep Orientation x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Orientation x -> Orientation
$cfrom :: forall x. Orientation -> Rep Orientation x
Generic)

-- | Whether to stack chart data
data Stacked = Stacked | NonStacked deriving (Stacked -> Stacked -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Stacked -> Stacked -> Bool
$c/= :: Stacked -> Stacked -> Bool
== :: Stacked -> Stacked -> Bool
$c== :: Stacked -> Stacked -> Bool
Eq, Int -> Stacked -> ShowS
[Stacked] -> ShowS
Stacked -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Stacked] -> ShowS
$cshowList :: [Stacked] -> ShowS
show :: Stacked -> String
$cshow :: Stacked -> String
showsPrec :: Int -> Stacked -> ShowS
$cshowsPrec :: Int -> Stacked -> ShowS
Show, forall x. Rep Stacked x -> Stacked
forall x. Stacked -> Rep Stacked x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Stacked x -> Stacked
$cfrom :: forall x. Stacked -> Rep Stacked x
Generic)

-- | The basis for the x-y ratio of a chart
--
-- Default style features tend towards assuming that the usual height of the overall svg image is around 1, and ChartAspect is based on this assumption, so that a ChartAspect of @FixedAspect 1.5@, say, means a height of 1 and a width of 1.5.
data ChartAspect
  = -- | Rescale charts to a fixed x-y ratio, inclusive of hud and style features
    FixedAspect Double
  | -- | Rescale charts to an overall height of 1, preserving the x-y ratio of the data canvas.
    CanvasAspect Double
  | -- | Rescale charts to a height of 1, preserving the existing x-y ratio of the underlying charts, inclusive of hud and style.
    ChartAspect
  deriving (Int -> ChartAspect -> ShowS
[ChartAspect] -> ShowS
ChartAspect -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ChartAspect] -> ShowS
$cshowList :: [ChartAspect] -> ShowS
show :: ChartAspect -> String
$cshow :: ChartAspect -> String
showsPrec :: Int -> ChartAspect -> ShowS
$cshowsPrec :: Int -> ChartAspect -> ShowS
Show, ChartAspect -> ChartAspect -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChartAspect -> ChartAspect -> Bool
$c/= :: ChartAspect -> ChartAspect -> Bool
== :: ChartAspect -> ChartAspect -> Bool
$c== :: ChartAspect -> ChartAspect -> Bool
Eq, forall x. Rep ChartAspect x -> ChartAspect
forall x. ChartAspect -> Rep ChartAspect x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ChartAspect x -> ChartAspect
$cfrom :: forall x. ChartAspect -> Rep ChartAspect x
Generic)