{-# 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
showList :: [ScaleMode] -> ShowS
$cshowList :: [ScaleMode] -> ShowS
show :: ScaleMode -> String
$cshow :: ScaleMode -> String
showsPrec :: Int -> ScaleMode -> ShowS
$cshowsPrec :: Int -> 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
readListPrec :: ReadPrec [ScaleMode]
$creadListPrec :: ReadPrec [ScaleMode]
readPrec :: ReadPrec ScaleMode
$creadPrec :: ReadPrec ScaleMode
readList :: ReadS [ScaleMode]
$creadList :: ReadS [ScaleMode]
readsPrec :: Int -> ReadS ScaleMode
$creadsPrec :: Int -> ReadS 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
showList :: [UniformScaleStrategy] -> ShowS
$cshowList :: [UniformScaleStrategy] -> ShowS
show :: UniformScaleStrategy -> String
$cshow :: UniformScaleStrategy -> String
showsPrec :: Int -> UniformScaleStrategy -> ShowS
$cshowsPrec :: Int -> 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
readListPrec :: ReadPrec [UniformScaleStrategy]
$creadListPrec :: ReadPrec [UniformScaleStrategy]
readPrec :: ReadPrec UniformScaleStrategy
$creadPrec :: ReadPrec UniformScaleStrategy
readList :: ReadS [UniformScaleStrategy]
$creadList :: ReadS [UniformScaleStrategy]
readsPrec :: Int -> ReadS UniformScaleStrategy
$creadsPrec :: Int -> ReadS 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
showList :: [Extending n] -> ShowS
$cshowList :: forall n. Show n => [Extending n] -> ShowS
show :: Extending n -> String
$cshow :: forall n. Show n => Extending n -> String
showsPrec :: Int -> Extending n -> ShowS
$cshowsPrec :: forall n. Show n => Int -> 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
min :: Extending n -> Extending n -> Extending n
$cmin :: forall n. Ord n => Extending n -> Extending n -> Extending n
max :: Extending n -> Extending n -> Extending n
$cmax :: forall n. Ord n => Extending n -> Extending n -> Extending n
>= :: 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
$c< :: forall n. Ord n => Extending n -> Extending n -> Bool
compare :: Extending n -> Extending n -> Ordering
$ccompare :: forall n. Ord n => Extending n -> Extending n -> Ordering
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
/= :: Extending n -> Extending n -> Bool
$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
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
<$ :: forall a b. a -> Extending b -> Extending a
$c<$ :: forall a b. a -> Extending b -> Extending a
fmap :: forall a b. (a -> b) -> Extending a -> Extending b
$cfmap :: forall a b. (a -> b) -> Extending a -> Extending b
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 :: Maybe (N a)
asRatio = Maybe (N a)
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 :: ScaleMode
asMode = ScaleMode
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 :: LogScale
asLogScale = LogScale
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 :: Extending (N a)
asEnlarge = Extending (N a)
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 :: Maybe (N a)
asBoundMin = Maybe (N a)
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 :: Maybe (N a)
asBoundMax = Maybe (N a)
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 :: Maybe (N a)
asSize = Maybe (N a)
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)
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 = 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
asBackupBoundMin :: n
asBackupBoundMax :: n
asLogScale :: LogScale
asSize :: Maybe n
asBoundMax :: Maybe n
asBoundMin :: Maybe n
asEnlarge :: Extending n
asMode :: ScaleMode
asRatio :: Maybe n
asBackupBoundMin :: forall n. AxisScaling n -> n
asBackupBoundMax :: forall n. AxisScaling n -> n
asLogScale :: forall n. AxisScaling n -> LogScale
asSize :: forall n. AxisScaling n -> Maybe n
asBoundMax :: forall n. AxisScaling n -> Maybe n
asBoundMin :: forall n. AxisScaling n -> Maybe n
asEnlarge :: forall n. AxisScaling n -> Extending n
asMode :: forall n. AxisScaling n -> ScaleMode
asRatio :: forall n. AxisScaling n -> Maybe 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)
  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)

  -- 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 (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 (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
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
_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
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
_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 (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)
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 (f :: * -> *) a. Iso' (Point f a) (f a)
_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 (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
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)
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 (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 (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
showList :: [LogScale] -> ShowS
$cshowList :: [LogScale] -> ShowS
show :: LogScale -> String
$cshow :: LogScale -> String
showsPrec :: Int -> LogScale -> ShowS
$cshowsPrec :: Int -> LogScale -> ShowS
Show, LogScale -> LogScale -> Bool
(LogScale -> LogScale -> Bool)
-> (LogScale -> LogScale -> Bool) -> Eq LogScale
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LogScale -> LogScale -> Bool
$c/= :: LogScale -> LogScale -> Bool
== :: LogScale -> LogScale -> Bool
$c== :: 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 (f :: * -> *) a. Iso' (Point f a) (f a)
_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 (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
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)