{-# LANGUAGE DeriveFunctor         #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards       #-}
{-# LANGUAGE TypeFamilies          #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Plots.Axis.Scale
-- Copyright   :  (C) 2015 Christopher Chalmers
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Christopher Chalmers
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Determine how to scale an axis.
--
----------------------------------------------------------------------------

module Plots.Axis.Scale
  ( -- * Axis scale
    AxisScaling
  , ScaleMode (..)
  , UniformScaleStrategy (..)
  , Extending (..)
  , noExtend
  , HasAxisScaling (..)

   -- ** Log scales
  , LogScale (..)
  , logNumber
  , logPoint
  , logDeform

    -- * Low level calculations
    -- | These functions are used by "Plots.Axis.Render".
  , calculateBounds
  , calculateScaling

  ) where

import           Control.Applicative
import           Control.Lens
import           Data.Bool
import           Data.Default
import           Data.Distributive
import           Data.Maybe
import qualified Data.Foldable as F

import           Diagrams
import           Linear

------------------------------------------------------------------------
-- Axis scale
------------------------------------------------------------------------

-- | How the axis should be scaled when not all dimensions are set.
data ScaleMode
  = AutoScale
  | NoScale
  | Stretch
  | UniformScale UniformScaleStrategy
  deriving (Int -> ScaleMode -> ShowS
[ScaleMode] -> ShowS
ScaleMode -> String
(Int -> ScaleMode -> ShowS)
-> (ScaleMode -> String)
-> ([ScaleMode] -> ShowS)
-> Show ScaleMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ScaleMode -> ShowS
showsPrec :: Int -> ScaleMode -> ShowS
$cshow :: ScaleMode -> String
show :: ScaleMode -> String
$cshowList :: [ScaleMode] -> ShowS
showList :: [ScaleMode] -> ShowS
Show, ReadPrec [ScaleMode]
ReadPrec ScaleMode
Int -> ReadS ScaleMode
ReadS [ScaleMode]
(Int -> ReadS ScaleMode)
-> ReadS [ScaleMode]
-> ReadPrec ScaleMode
-> ReadPrec [ScaleMode]
-> Read ScaleMode
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS ScaleMode
readsPrec :: Int -> ReadS ScaleMode
$creadList :: ReadS [ScaleMode]
readList :: ReadS [ScaleMode]
$creadPrec :: ReadPrec ScaleMode
readPrec :: ReadPrec ScaleMode
$creadListPrec :: ReadPrec [ScaleMode]
readListPrec :: ReadPrec [ScaleMode]
Read)

-- | ?
data UniformScaleStrategy
  = AutoUniformScale
  | UnitOnly
  | ChangeVerticalLimits
  | ChangeHorizontalLimits
  deriving (Int -> UniformScaleStrategy -> ShowS
[UniformScaleStrategy] -> ShowS
UniformScaleStrategy -> String
(Int -> UniformScaleStrategy -> ShowS)
-> (UniformScaleStrategy -> String)
-> ([UniformScaleStrategy] -> ShowS)
-> Show UniformScaleStrategy
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UniformScaleStrategy -> ShowS
showsPrec :: Int -> UniformScaleStrategy -> ShowS
$cshow :: UniformScaleStrategy -> String
show :: UniformScaleStrategy -> String
$cshowList :: [UniformScaleStrategy] -> ShowS
showList :: [UniformScaleStrategy] -> ShowS
Show, ReadPrec [UniformScaleStrategy]
ReadPrec UniformScaleStrategy
Int -> ReadS UniformScaleStrategy
ReadS [UniformScaleStrategy]
(Int -> ReadS UniformScaleStrategy)
-> ReadS [UniformScaleStrategy]
-> ReadPrec UniformScaleStrategy
-> ReadPrec [UniformScaleStrategy]
-> Read UniformScaleStrategy
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS UniformScaleStrategy
readsPrec :: Int -> ReadS UniformScaleStrategy
$creadList :: ReadS [UniformScaleStrategy]
readList :: ReadS [UniformScaleStrategy]
$creadPrec :: ReadPrec UniformScaleStrategy
readPrec :: ReadPrec UniformScaleStrategy
$creadListPrec :: ReadPrec [UniformScaleStrategy]
readListPrec :: ReadPrec [UniformScaleStrategy]
Read)

-- | Data type used that concerns everything to do with the size or
--   scale of the axis.
data AxisScaling n = Scaling
  { forall n. AxisScaling n -> Maybe n
asRatio          :: Maybe n
  , forall n. AxisScaling n -> ScaleMode
asMode           :: ScaleMode
  , forall n. AxisScaling n -> Extending n
asEnlarge        :: Extending n
  , forall n. AxisScaling n -> Maybe n
asBoundMin       :: Maybe n
  , forall n. AxisScaling n -> Maybe n
asBoundMax       :: Maybe n
  , forall n. AxisScaling n -> Maybe n
asSize           :: Maybe n
  , forall n. AxisScaling n -> LogScale
asLogScale       :: LogScale

  -- backup bound in case there's no inferred bounds to go by
  , forall n. AxisScaling n -> n
asBackupBoundMax :: n
  , forall n. AxisScaling n -> n
asBackupBoundMin :: n
  }

type instance N (AxisScaling n) = n

instance Fractional n => Default (AxisScaling n) where
  def :: AxisScaling n
def = Scaling
    { asRatio :: Maybe n
asRatio          = Maybe n
forall a. Maybe a
Nothing
    , asMode :: ScaleMode
asMode           = ScaleMode
AutoScale
    , asEnlarge :: Extending n
asEnlarge        = n -> Extending n
forall n. n -> Extending n
RelativeExtend n
0.1
    , asBoundMin :: Maybe n
asBoundMin       = Maybe n
forall a. Maybe a
Nothing
    , asBoundMax :: Maybe n
asBoundMax       = Maybe n
forall a. Maybe a
Nothing
    , asLogScale :: LogScale
asLogScale       = LogScale
forall a. Default a => a
def
    , asSize :: Maybe n
asSize           = n -> Maybe n
forall a. a -> Maybe a
Just n
400
    , asBackupBoundMax :: n
asBackupBoundMax = n
5
    , asBackupBoundMin :: n
asBackupBoundMin = -n
5
    }

-- | How much to extend the bounds beyond any inferred bounds.
data Extending n
  = AbsoluteExtend n
  | RelativeExtend n
  deriving (Int -> Extending n -> ShowS
[Extending n] -> ShowS
Extending n -> String
(Int -> Extending n -> ShowS)
-> (Extending n -> String)
-> ([Extending n] -> ShowS)
-> Show (Extending n)
forall n. Show n => Int -> Extending n -> ShowS
forall n. Show n => [Extending n] -> ShowS
forall n. Show n => Extending n -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall n. Show n => Int -> Extending n -> ShowS
showsPrec :: Int -> Extending n -> ShowS
$cshow :: forall n. Show n => Extending n -> String
show :: Extending n -> String
$cshowList :: forall n. Show n => [Extending n] -> ShowS
showList :: [Extending n] -> ShowS
Show, Eq (Extending n)
Eq (Extending n) =>
(Extending n -> Extending n -> Ordering)
-> (Extending n -> Extending n -> Bool)
-> (Extending n -> Extending n -> Bool)
-> (Extending n -> Extending n -> Bool)
-> (Extending n -> Extending n -> Bool)
-> (Extending n -> Extending n -> Extending n)
-> (Extending n -> Extending n -> Extending n)
-> Ord (Extending n)
Extending n -> Extending n -> Bool
Extending n -> Extending n -> Ordering
Extending n -> Extending n -> Extending n
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall n. Ord n => Eq (Extending n)
forall n. Ord n => Extending n -> Extending n -> Bool
forall n. Ord n => Extending n -> Extending n -> Ordering
forall n. Ord n => Extending n -> Extending n -> Extending n
$ccompare :: forall n. Ord n => Extending n -> Extending n -> Ordering
compare :: Extending n -> Extending n -> Ordering
$c< :: forall n. Ord n => Extending n -> Extending n -> Bool
< :: Extending n -> Extending n -> Bool
$c<= :: forall n. Ord n => Extending n -> Extending n -> Bool
<= :: Extending n -> Extending n -> Bool
$c> :: forall n. Ord n => Extending n -> Extending n -> Bool
> :: Extending n -> Extending n -> Bool
$c>= :: forall n. Ord n => Extending n -> Extending n -> Bool
>= :: Extending n -> Extending n -> Bool
$cmax :: forall n. Ord n => Extending n -> Extending n -> Extending n
max :: Extending n -> Extending n -> Extending n
$cmin :: forall n. Ord n => Extending n -> Extending n -> Extending n
min :: Extending n -> Extending n -> Extending n
Ord, Extending n -> Extending n -> Bool
(Extending n -> Extending n -> Bool)
-> (Extending n -> Extending n -> Bool) -> Eq (Extending n)
forall n. Eq n => Extending n -> Extending n -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall n. Eq n => Extending n -> Extending n -> Bool
== :: Extending n -> Extending n -> Bool
$c/= :: forall n. Eq n => Extending n -> Extending n -> Bool
/= :: Extending n -> Extending n -> Bool
Eq, (forall a b. (a -> b) -> Extending a -> Extending b)
-> (forall a b. a -> Extending b -> Extending a)
-> Functor Extending
forall a b. a -> Extending b -> Extending a
forall a b. (a -> b) -> Extending a -> Extending b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Extending a -> Extending b
fmap :: forall a b. (a -> b) -> Extending a -> Extending b
$c<$ :: forall a b. a -> Extending b -> Extending a
<$ :: forall a b. a -> Extending b -> Extending a
Functor)

-- | Do not extend the axis beyond the inferred bounds.
noExtend :: Num n => Extending n
noExtend :: forall n. Num n => Extending n
noExtend = n -> Extending n
forall n. n -> Extending n
AbsoluteExtend n
0

-- | Class of things that have an 'AxisScaling'.
class HasAxisScaling f a where
  -- | The way to scale in one direction.
  axisScaling :: LensLike' f a (AxisScaling (N a))

  -- | The ratio relative to other axis. If no ratios are set, the ratio
  --   is not enforced. If at least one is set, 'Nothing' ratios are
  --   @1@.
  scaleAspectRatio :: Functor f => LensLike' f a (Maybe (N a))
  scaleAspectRatio = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((Maybe (N a) -> f (Maybe (N a)))
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a (Maybe (N a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> Maybe (N a))
-> (AxisScaling (N a) -> Maybe (N a) -> AxisScaling (N a))
-> Lens
     (AxisScaling (N a)) (AxisScaling (N a)) (Maybe (N a)) (Maybe (N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> Maybe (N a)
forall n. AxisScaling n -> Maybe n
asRatio (\AxisScaling (N a)
as Maybe (N a)
r -> AxisScaling (N a)
as {asRatio = r})

  -- | The mode to determine how to scale the bounds in a direction.
  --   Choose between 'AutoScale', 'NoScale', 'Stretch' or
  --   'UniformScale'.
  --
  --   'Default' is 'AutoScale'.
  scaleMode :: Functor f => LensLike' f a ScaleMode
  scaleMode = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((ScaleMode -> f ScaleMode)
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a ScaleMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> ScaleMode)
-> (AxisScaling (N a) -> ScaleMode -> AxisScaling (N a))
-> Lens (AxisScaling (N a)) (AxisScaling (N a)) ScaleMode ScaleMode
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> ScaleMode
forall n. AxisScaling n -> ScaleMode
asMode (\AxisScaling (N a)
as ScaleMode
r -> AxisScaling (N a)
as {asMode = r})

  -- | Whether the axis uses 'LogAxis' or 'LinearAxis'.
  --
  --   'Default' is 'LinearAxis'.
  logScale :: Functor f => LensLike' f a LogScale
  logScale = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((LogScale -> f LogScale)
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a LogScale
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> LogScale)
-> (AxisScaling (N a) -> LogScale -> AxisScaling (N a))
-> Lens (AxisScaling (N a)) (AxisScaling (N a)) LogScale LogScale
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> LogScale
forall n. AxisScaling n -> LogScale
asLogScale (\AxisScaling (N a)
as LogScale
r -> AxisScaling (N a)
as {asLogScale = r})

  -- | How much to extend the bounds over infered bounds. This is
  --   ignored if a 'boundMax' or 'boundMin' is set.
  axisExtend :: Functor f => LensLike' f a (Extending (N a))
  axisExtend = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((Extending (N a) -> f (Extending (N a)))
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a (Extending (N a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> Extending (N a))
-> (AxisScaling (N a) -> Extending (N a) -> AxisScaling (N a))
-> Lens
     (AxisScaling (N a))
     (AxisScaling (N a))
     (Extending (N a))
     (Extending (N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> Extending (N a)
forall n. AxisScaling n -> Extending n
asEnlarge (\AxisScaling (N a)
as Extending (N a)
r -> AxisScaling (N a)
as {asEnlarge = r})

  -- | The maximum bound the axis. There are helper functions for
  --   setting a minimum bound for a specific axis.
  --
  -- @
  -- 'Plots.Axis.xMin' :: 'Lens'' ('Axis' b 'V2' 'Double') ('Maybe' 'Double')
  -- 'Plots.Axis.yMin' :: 'Lens'' ('Axis' b 'V2' 'Double') ('Maybe' 'Double')
  -- @
  --
  --   Default is 'Nothing'.
  boundMin :: Functor f => LensLike' f a (Maybe (N a))
  boundMin = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((Maybe (N a) -> f (Maybe (N a)))
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a (Maybe (N a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> Maybe (N a))
-> (AxisScaling (N a) -> Maybe (N a) -> AxisScaling (N a))
-> Lens
     (AxisScaling (N a)) (AxisScaling (N a)) (Maybe (N a)) (Maybe (N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> Maybe (N a)
forall n. AxisScaling n -> Maybe n
asBoundMin (\AxisScaling (N a)
as Maybe (N a)
b -> AxisScaling (N a)
as {asBoundMin = b})

  -- | The maximum bound the axis. There are helper functions for
  --   setting a maximum bound specific axis.
  --
  -- @
  -- 'Plots.Axis.xMax' :: 'Lens'' ('Axis' b 'V2' 'Double') ('Maybe' 'Double')
  -- 'Plots.Axis.yMax' :: 'Lens'' ('Axis' b 'V2' 'Double') ('Maybe' 'Double')
  -- 'Plots.Axis.rMax' :: 'Lens'' ('Axis' b 'Polar 'Double') ('Maybe' 'Double')
  -- @
  --
  --   Default is 'Nothing'.
  boundMax :: Functor f => LensLike' f a (Maybe (N a))
  boundMax = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((Maybe (N a) -> f (Maybe (N a)))
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a (Maybe (N a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> Maybe (N a))
-> (AxisScaling (N a) -> Maybe (N a) -> AxisScaling (N a))
-> Lens
     (AxisScaling (N a)) (AxisScaling (N a)) (Maybe (N a)) (Maybe (N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> Maybe (N a)
forall n. AxisScaling n -> Maybe n
asBoundMax (\AxisScaling (N a)
as Maybe (N a)
b -> AxisScaling (N a)
as {asBoundMax = b})

  -- | The size of the rendered axis. Default is @'Just' 400@.
  renderSize :: Functor f => LensLike' f a (Maybe (N a))
  renderSize = LensLike' f a (AxisScaling (N a))
forall (f :: * -> *) a.
HasAxisScaling f a =>
LensLike' f a (AxisScaling (N a))
axisScaling LensLike' f a (AxisScaling (N a))
-> ((Maybe (N a) -> f (Maybe (N a)))
    -> AxisScaling (N a) -> f (AxisScaling (N a)))
-> LensLike' f a (Maybe (N a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisScaling (N a) -> Maybe (N a))
-> (AxisScaling (N a) -> Maybe (N a) -> AxisScaling (N a))
-> Lens
     (AxisScaling (N a)) (AxisScaling (N a)) (Maybe (N a)) (Maybe (N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisScaling (N a) -> Maybe (N a)
forall n. AxisScaling n -> Maybe n
asSize (\AxisScaling (N a)
as Maybe (N a)
s -> AxisScaling (N a)
as {asSize = s})

  -- -- backup bound in case there's no inferred bounds to go by
  -- asBackupBoundMax :: n
  -- asBackupBoundMax :: n

asSizeSpec :: (HasLinearMap v, Num n, Ord n) => Lens' (v (AxisScaling n)) (SizeSpec v n)
asSizeSpec :: forall (v :: * -> *) n.
(HasLinearMap v, Num n, Ord n) =>
Lens' (v (AxisScaling n)) (SizeSpec v n)
asSizeSpec = LensLike
  (Context (Maybe n) (Maybe n))
  (AxisScaling n)
  (AxisScaling n)
  (Maybe n)
  (Maybe n)
-> Lens
     (v (AxisScaling n)) (v (AxisScaling n)) (v (Maybe n)) (v (Maybe n))
forall (f :: * -> *) a b s t.
Representable f =>
LensLike (Context a b) s t a b -> Lens (f s) (f t) (f a) (f b)
column LensLike
  (Context (Maybe n) (Maybe n))
  (AxisScaling n)
  (AxisScaling n)
  (Maybe n)
  (Maybe n)
LensLike'
  (Context (Maybe n) (Maybe n))
  (AxisScaling n)
  (Maybe (N (AxisScaling n)))
forall (f :: * -> *) a.
(HasAxisScaling f a, Functor f) =>
LensLike' f a (Maybe (N a))
renderSize ((v (Maybe n) -> f (v (Maybe n)))
 -> v (AxisScaling n) -> f (v (AxisScaling n)))
-> ((SizeSpec v n -> f (SizeSpec v n))
    -> v (Maybe n) -> f (v (Maybe n)))
-> (SizeSpec v n -> f (SizeSpec v n))
-> v (AxisScaling n)
-> f (v (AxisScaling n))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v (Maybe n) -> SizeSpec v n)
-> (SizeSpec v n -> v (Maybe n))
-> Iso (v (Maybe n)) (v (Maybe n)) (SizeSpec v n) (SizeSpec v n)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso v (Maybe n) -> SizeSpec v n
forall (v :: * -> *) n.
(Functor v, Num n) =>
v (Maybe n) -> SizeSpec v n
mkSizeSpec SizeSpec v n -> v (Maybe n)
forall (v :: * -> *) n.
(Functor v, Num n, Ord n) =>
SizeSpec v n -> v (Maybe n)
getSpec

instance HasAxisScaling f (AxisScaling n) where
  axisScaling :: LensLike' f (AxisScaling n) (AxisScaling (N (AxisScaling n)))
axisScaling = (AxisScaling n -> f (AxisScaling n))
-> AxisScaling n -> f (AxisScaling n)
LensLike' f (AxisScaling n) (AxisScaling (N (AxisScaling n)))
forall a. a -> a
id

-- calculating bounds --------------------------------------------------

-- | Calculating the bounds for an axis.
calculateBounds
  :: OrderedField n
  => AxisScaling n -- ^ Scaling to use for this axis
  -> Maybe (n, n)  -- ^ Inferred bounds (from any plots)
  -> (n, n)        -- ^ Lower and upper bounds to use for this axis
calculateBounds :: forall n. OrderedField n => AxisScaling n -> Maybe (n, n) -> (n, n)
calculateBounds Scaling {n
Maybe n
LogScale
Extending n
ScaleMode
asRatio :: forall n. AxisScaling n -> Maybe n
asMode :: forall n. AxisScaling n -> ScaleMode
asEnlarge :: forall n. AxisScaling n -> Extending n
asBoundMin :: forall n. AxisScaling n -> Maybe n
asBoundMax :: forall n. AxisScaling n -> Maybe n
asSize :: forall n. AxisScaling n -> Maybe n
asLogScale :: forall n. AxisScaling n -> LogScale
asBackupBoundMax :: forall n. AxisScaling n -> n
asBackupBoundMin :: forall n. AxisScaling n -> n
asRatio :: Maybe n
asMode :: ScaleMode
asEnlarge :: Extending n
asBoundMin :: Maybe n
asBoundMax :: Maybe n
asSize :: Maybe n
asLogScale :: LogScale
asBackupBoundMax :: n
asBackupBoundMin :: n
..} Maybe (n, n)
mInferred = (n
l', n
u') where
  -- bounds are only enlarged when min/max bound wasn't set
  l' :: n
l' = n
l n -> (n -> n) -> n
forall a b. a -> (a -> b) -> b
& Bool -> (n -> n) -> n -> n
forall a. Bool -> (a -> a) -> a -> a
whenever (Maybe n -> Bool
forall a. Maybe a -> Bool
isNothing Maybe n
asBoundMin) (n -> n -> n
forall a. Num a => a -> a -> a
subtract n
x)
         n -> (n -> n) -> n
forall a b. a -> (a -> b) -> b
& Bool -> (n -> n) -> n -> n
forall a. Bool -> (a -> a) -> a -> a
whenever (LogScale
asLogScale LogScale -> LogScale -> Bool
forall a. Eq a => a -> a -> Bool
== LogScale
LogAxis) (n -> n -> n
forall a. Ord a => a -> a -> a
max n
1e-6)
         n -> (n -> n) -> n
forall a b. a -> (a -> b) -> b
& n -> n -> n
forall a. Ord a => a -> a -> a
min (n
u n -> n -> n
forall a. Num a => a -> a -> a
- n
1e-6)
  u' :: n
u' = n
u n -> (n -> n) -> n
forall a b. a -> (a -> b) -> b
& Bool -> (n -> n) -> n -> n
forall a. Bool -> (a -> a) -> a -> a
whenever (Maybe n -> Bool
forall a. Maybe a -> Bool
isNothing Maybe n
asBoundMax) (n -> n -> n
forall a. Num a => a -> a -> a
+ n
x)
         n -> (n -> n) -> n
forall a b. a -> (a -> b) -> b
& n -> n -> n
forall a. Ord a => a -> a -> a
max (n
l n -> n -> n
forall a. Num a => a -> a -> a
+ n
1e-6)

  -- amount to enlarge axis by
  x :: n
x = case Extending n
asEnlarge of
    AbsoluteExtend n
a -> n
a
    RelativeExtend n
a -> (n
u n -> n -> n
forall a. Num a => a -> a -> a
- n
l) n -> n -> n
forall a. Num a => a -> a -> a
* n
a

  -- pre-enlarged bounds are looked at in the following order:
  --   - concrete bounds from max/boundMin
  --   - inferred bounds from plot envelopes
  --   - backup bounds
  l :: n
l = n -> Maybe n -> n
forall a. a -> Maybe a -> a
fromMaybe n
asBackupBoundMin (Maybe n -> n) -> Maybe n -> n
forall a b. (a -> b) -> a -> b
$ Maybe n
asBoundMin Maybe n -> Maybe n -> Maybe n
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe n
lI
  u :: n
u = n -> Maybe n -> n
forall a. a -> Maybe a -> a
fromMaybe n
asBackupBoundMax (Maybe n -> n) -> Maybe n -> n
forall a b. (a -> b) -> a -> b
$ Maybe n
asBoundMax Maybe n -> Maybe n -> Maybe n
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe n
uI
  lI :: Maybe n
lI = Getting (First n) (Maybe (n, n)) n -> Maybe (n, n) -> Maybe n
forall s (m :: * -> *) a.
MonadReader s m =>
Getting (First a) s a -> m (Maybe a)
preview (((n, n) -> Const (First n) (n, n))
-> Maybe (n, n) -> Const (First n) (Maybe (n, n))
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold Int (Maybe (n, n)) (n, n)
folded (((n, n) -> Const (First n) (n, n))
 -> Maybe (n, n) -> Const (First n) (Maybe (n, n)))
-> ((n -> Const (First n) n) -> (n, n) -> Const (First n) (n, n))
-> Getting (First n) (Maybe (n, n)) n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> Const (First n) n) -> (n, n) -> Const (First n) (n, n)
forall s t a b. Field1 s t a b => Lens s t a b
Lens (n, n) (n, n) n n
_1) Maybe (n, n)
mInferred
  uI :: Maybe n
uI = Getting (First n) (Maybe (n, n)) n -> Maybe (n, n) -> Maybe n
forall s (m :: * -> *) a.
MonadReader s m =>
Getting (First a) s a -> m (Maybe a)
preview (((n, n) -> Const (First n) (n, n))
-> Maybe (n, n) -> Const (First n) (Maybe (n, n))
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold Int (Maybe (n, n)) (n, n)
folded (((n, n) -> Const (First n) (n, n))
 -> Maybe (n, n) -> Const (First n) (Maybe (n, n)))
-> ((n -> Const (First n) n) -> (n, n) -> Const (First n) (n, n))
-> Getting (First n) (Maybe (n, n)) n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> Const (First n) n) -> (n, n) -> Const (First n) (n, n)
forall s t a b. Field2 s t a b => Lens s t a b
Lens (n, n) (n, n) n n
_2) Maybe (n, n)
mInferred

-- | Calculate the scaling for the axis.
--
--   The result returns:
--
--     - The final bounds for the axis
--     - scale to match desired 'scaleAspectRatio'
--     - scale to match desired 'asSizeSpec'
calculateScaling
  :: (HasLinearMap v, OrderedField n, Applicative v)
  => v (AxisScaling n) -- ^ axis scaling options
  -> BoundingBox v n   -- ^ bounding box from the axis plots
  -> (v (n,n), Transformation v n, Transformation v n)
calculateScaling :: forall (v :: * -> *) n.
(HasLinearMap v, OrderedField n, Applicative v) =>
v (AxisScaling n)
-> BoundingBox v n
-> (v (n, n), Transformation v n, Transformation v n)
calculateScaling v (AxisScaling n)
aScaling BoundingBox v n
bb = (v (n, n)
bounds, Transformation v n
aspectScaling, Transformation v n
sizeScaling) where

  -- final bounds of the axis
  bounds :: v (n, n)
bounds   = AxisScaling n -> Maybe (n, n) -> (n, n)
forall n. OrderedField n => AxisScaling n -> Maybe (n, n) -> (n, n)
calculateBounds (AxisScaling n -> Maybe (n, n) -> (n, n))
-> v (AxisScaling n) -> v (Maybe (n, n) -> (n, n))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> v (AxisScaling n)
aScaling v (Maybe (n, n) -> (n, n)) -> v (Maybe (n, n)) -> v (n, n)
forall a b. v (a -> b) -> v a -> v b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe (v (n, n)) -> v (Maybe (n, n))
forall (g :: * -> *) (f :: * -> *) a.
(Distributive g, Functor f) =>
f (g a) -> g (f a)
forall (f :: * -> *) a. Functor f => f (v a) -> v (f a)
distribute Maybe (v (n, n))
inferred
  inferred :: Maybe (v (n, n))
inferred = Getting (v (n, n)) (Point v (n, n)) (v (n, n))
-> Point v (n, n) -> v (n, n)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (v (n, n)) (Point v (n, n)) (v (n, n))
forall (f1 :: * -> *) a (g :: * -> *) b (p :: * -> * -> *)
       (f2 :: * -> *).
(Profunctor p, Functor f2) =>
p (f1 a) (f2 (g b)) -> p (Point f1 a) (f2 (Point g b))
_Point (Point v (n, n) -> v (n, n))
-> ((Point v n, Point v n) -> Point v (n, n))
-> (Point v n, Point v n)
-> v (n, n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point v n -> Point v n -> Point v (n, n))
-> (Point v n, Point v n) -> Point v (n, n)
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((n -> n -> (n, n)) -> Point v n -> Point v n -> Point v (n, n)
forall a b c. (a -> b -> c) -> Point v a -> Point v b -> Point v c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (,)) ((Point v n, Point v n) -> v (n, n))
-> Maybe (Point v n, Point v n) -> Maybe (v (n, n))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BoundingBox v n -> Maybe (Point v n, Point v n)
forall (v :: * -> *) n.
BoundingBox v n -> Maybe (Point v n, Point v n)
getCorners BoundingBox v n
bb

  -- the scaling used to meet the desired aspect ratio
  aspectScaling :: Transformation v n
aspectScaling
    -- If any of the aspect ratios are committed we use the aspect ratio from
    -- aScaling. Otherwise no ratios are set, ignore them and scale
    -- such that each axis is the same length
    | Getting Any (v (AxisScaling n)) (Maybe (N (AxisScaling n)))
-> (Maybe (N (AxisScaling n)) -> Bool) -> v (AxisScaling n) -> Bool
forall s a. Getting Any s a -> (a -> Bool) -> s -> Bool
anyOf ((AxisScaling n -> Const Any (AxisScaling n))
-> v (AxisScaling n) -> Const Any (v (AxisScaling n))
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold Int (v (AxisScaling n)) (AxisScaling n)
folded ((AxisScaling n -> Const Any (AxisScaling n))
 -> v (AxisScaling n) -> Const Any (v (AxisScaling n)))
-> ((Maybe (N (AxisScaling n))
     -> Const Any (Maybe (N (AxisScaling n))))
    -> AxisScaling n -> Const Any (AxisScaling n))
-> Getting Any (v (AxisScaling n)) (Maybe (N (AxisScaling n)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe (N (AxisScaling n))
 -> Const Any (Maybe (N (AxisScaling n))))
-> AxisScaling n -> Const Any (AxisScaling n)
forall (f :: * -> *) a.
(HasAxisScaling f a, Functor f) =>
LensLike' f a (Maybe (N a))
scaleAspectRatio) Maybe (N (AxisScaling n)) -> Bool
forall a. Maybe a -> Bool
isJust v (AxisScaling n)
aScaling
                = v n -> Transformation v n
forall (v :: * -> *) n.
(Additive v, Fractional n) =>
v n -> Transformation v n
vectorScaling (v n -> Transformation v n) -> v n -> Transformation v n
forall a b. (a -> b) -> a -> b
$ Getting n (AxisScaling n) n -> AxisScaling n -> n
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (LensLike' (Const n) (AxisScaling n) (Maybe (N (AxisScaling n)))
forall (f :: * -> *) a.
(HasAxisScaling f a, Functor f) =>
LensLike' f a (Maybe (N a))
scaleAspectRatio LensLike' (Const n) (AxisScaling n) (Maybe (N (AxisScaling n)))
-> ((n -> Const n n)
    -> Maybe (N (AxisScaling n))
    -> Const n (Maybe (N (AxisScaling n))))
-> Getting n (AxisScaling n) n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. N (AxisScaling n)
-> Iso' (Maybe (N (AxisScaling n))) (N (AxisScaling n))
forall a. Eq a => a -> Iso' (Maybe a) a
non N (AxisScaling n)
1) (AxisScaling n -> n) -> v (AxisScaling n) -> v n
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> v (AxisScaling n)
aScaling
    | Bool
otherwise = Transformation v n -> Transformation v n
forall (v :: * -> *) n.
(Functor v, Num n) =>
Transformation v n -> Transformation v n
inv (Transformation v n -> Transformation v n)
-> Transformation v n -> Transformation v n
forall a b. (a -> b) -> a -> b
$ v n -> Transformation v n
forall (v :: * -> *) n.
(Additive v, Fractional n) =>
v n -> Transformation v n
vectorScaling v n
v

  -- scaling used so the axis fits in the size spec
  sizeScaling :: Transformation v n
sizeScaling = SizeSpec v n -> v n -> Transformation v n
forall (v :: * -> *) n.
(Additive v, Foldable v, Fractional n, Ord n) =>
SizeSpec v n -> v n -> Transformation v n
requiredScaling SizeSpec v n
szSpec v n
v'
  -- the vector that points from the lower bound to the upper bound of the
  -- axis
  v :: v n
v  = (n -> n -> n) -> (n, n) -> n
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((n -> n -> n) -> n -> n -> n
forall a b c. (a -> b -> c) -> b -> a -> c
flip (-)) ((n, n) -> n) -> v (n, n) -> v n
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> v (n, n)
bounds
  v' :: v n
v' = Transformation v n -> v n -> v n
forall (v :: * -> *) n. Transformation v n -> v n -> v n
apply Transformation v n
aspectScaling v n
v
  szSpec :: SizeSpec v n
szSpec = Getting (SizeSpec v n) (v (AxisScaling n)) (SizeSpec v n)
-> v (AxisScaling n) -> SizeSpec v n
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (SizeSpec v n) (v (AxisScaling n)) (SizeSpec v n)
Lens' (v (AxisScaling n)) (SizeSpec v n)
forall (v :: * -> *) n.
(HasLinearMap v, Num n, Ord n) =>
Lens' (v (AxisScaling n)) (SizeSpec v n)
asSizeSpec v (AxisScaling n)
aScaling

-- | Scale transformation using the respective scale coefficients in the vector.
vectorScaling :: (Additive v, Fractional n) => v n -> Transformation v n
vectorScaling :: forall (v :: * -> *) n.
(Additive v, Fractional n) =>
v n -> Transformation v n
vectorScaling v n
v = (v n :-: v n) -> (v n :-: v n) -> Transformation v n
forall (v :: * -> *) n.
(Additive v, Num n) =>
(v n :-: v n) -> (v n :-: v n) -> Transformation v n
fromLinear v n :-: v n
f v n :-: v n
f
  where f :: v n :-: v n
f = (n -> n -> n) -> v n -> v n -> v n
forall a b c. (a -> b -> c) -> v a -> v b -> v c
forall (f :: * -> *) a b c.
Additive f =>
(a -> b -> c) -> f a -> f b -> f c
liftI2 n -> n -> n
forall a. Num a => a -> a -> a
(*) v n
v (v n -> v n) -> (v n -> v n) -> v n :-: v n
forall u v. (u -> v) -> (v -> u) -> u :-: v
<-> (n -> n -> n) -> v n -> v n -> v n
forall a b c. (a -> b -> c) -> v a -> v b -> v c
forall (f :: * -> *) a b c.
Additive f =>
(a -> b -> c) -> f a -> f b -> f c
liftI2 ((n -> n -> n) -> n -> n -> n
forall a b c. (a -> b -> c) -> b -> a -> c
flip n -> n -> n
forall a. Fractional a => a -> a -> a
(/)) v n
v

-- | Apply a function if the predicate is true.
whenever :: Bool -> (a -> a) -> a -> a
whenever :: forall a. Bool -> (a -> a) -> a -> a
whenever Bool
b a -> a
f = (a -> a) -> (a -> a) -> Bool -> a -> a
forall a. a -> a -> Bool -> a
bool a -> a
forall a. a -> a
id a -> a
f Bool
b

-- Logarithmic scaling -------------------------------------------------

-- Logarithmic scales are achieved by having 'LinearAxis' or 'LogAxis'
-- for each of the axes. When rendering the plots, they have axes the
-- log scheme. Some plots (like scatter) can easily do this whereas
-- others (like diagram plot) it's nearly impossible for, so they don't
-- bother.
--
-- Support for Log axis still needs a lot of work and debugging.

-- | Should the axis be on a logarithmic scale. The 'Default' is
--   'LinearAxis'.
data LogScale = LinearAxis | LogAxis
  deriving (Int -> LogScale -> ShowS
[LogScale] -> ShowS
LogScale -> String
(Int -> LogScale -> ShowS)
-> (LogScale -> String) -> ([LogScale] -> ShowS) -> Show LogScale
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LogScale -> ShowS
showsPrec :: Int -> LogScale -> ShowS
$cshow :: LogScale -> String
show :: LogScale -> String
$cshowList :: [LogScale] -> ShowS
showList :: [LogScale] -> ShowS
Show, LogScale -> LogScale -> Bool
(LogScale -> LogScale -> Bool)
-> (LogScale -> LogScale -> Bool) -> Eq LogScale
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LogScale -> LogScale -> Bool
== :: LogScale -> LogScale -> Bool
$c/= :: LogScale -> LogScale -> Bool
/= :: LogScale -> LogScale -> Bool
Eq)

instance Default LogScale where
  def :: LogScale
def = LogScale
LinearAxis

-- | Log the number for 'LogAxis', do nothing for 'LinearAxis'.
logNumber :: Floating a => LogScale -> a -> a
logNumber :: forall a. Floating a => LogScale -> a -> a
logNumber LogScale
LinearAxis = a -> a
forall a. a -> a
id
logNumber LogScale
LogAxis    = a -> a
forall a. Floating a => a -> a
log
{-# INLINE logNumber #-}

-- | Transform a point according to the axis scale. Does nothing for
--   linear scales.
logPoint :: (Additive v, Floating n) => v LogScale -> Point v n -> Point v n
logPoint :: forall (v :: * -> *) n.
(Additive v, Floating n) =>
v LogScale -> Point v n -> Point v n
logPoint v LogScale
v = (v n -> Identity (v n)) -> Point v n -> Identity (Point v n)
forall (f1 :: * -> *) a (g :: * -> *) b (p :: * -> * -> *)
       (f2 :: * -> *).
(Profunctor p, Functor f2) =>
p (f1 a) (f2 (g b)) -> p (Point f1 a) (f2 (Point g b))
_Point ((v n -> Identity (v n)) -> Point v n -> Identity (Point v n))
-> (v n -> v n) -> Point v n -> Point v n
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (LogScale -> n -> n) -> v LogScale -> v n -> v n
forall a b c. (a -> b -> c) -> v a -> v b -> v c
forall (f :: * -> *) a b c.
Additive f =>
(a -> b -> c) -> f a -> f b -> f c
liftI2 LogScale -> n -> n
forall a. Floating a => LogScale -> a -> a
logNumber v LogScale
v
{-# INLINE logPoint #-}

-- | Deform an object according to the axis scale. Does nothing for
--   linear scales.
logDeform :: (InSpace v n a, F.Foldable v, Floating n, Deformable a a)
          => v LogScale -> a -> a
logDeform :: forall (v :: * -> *) n a.
(InSpace v n a, Foldable v, Floating n, Deformable a a) =>
v LogScale -> a -> a
logDeform v LogScale
v
  | Getting All (v LogScale) LogScale
-> (LogScale -> Bool) -> v LogScale -> Bool
forall s a. Getting All s a -> (a -> Bool) -> s -> Bool
allOf Getting All (v LogScale) LogScale
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold Int (v LogScale) LogScale
folded (LogScale -> LogScale -> Bool
forall a. Eq a => a -> a -> Bool
== LogScale
LinearAxis) v LogScale
v = a -> a
forall a. a -> a
id
  | Bool
otherwise                      = Deformation (V a) (V a) (N a) -> a -> a
forall a b.
Deformable a b =>
Deformation (V a) (V b) (N a) -> a -> b
deform ((Point (V a) (N a) -> Point (V a) (N a))
-> Deformation (V a) (V a) (N a)
forall (v :: * -> *) (u :: * -> *) n.
(Point v n -> Point u n) -> Deformation v u n
Deformation ((Point (V a) (N a) -> Point (V a) (N a))
 -> Deformation (V a) (V a) (N a))
-> (Point (V a) (N a) -> Point (V a) (N a))
-> Deformation (V a) (V a) (N a)
forall a b. (a -> b) -> a -> b
$ v LogScale -> Point v n -> Point v n
forall (v :: * -> *) n.
(Additive v, Floating n) =>
v LogScale -> Point v n -> Point v n
logPoint v LogScale
v)