{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE FunctionalDependencies    #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Plots.Types.Line
-- Copyright   :  (C) 2016 Christopher Chalmers
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Christopher Chalmers
-- Stability   :  experimental
-- Portability :  non-portable
--
-- A line plot is simply a 'Path' used as a plot. This module contains
-- helpers adding path plots. For line plots with markers, see
-- 'Plots.Types.Scatter'.
--
----------------------------------------------------------------------------

module Plots.Types.Line
  ( -- Plot trails/paths
    trailPlot
  , trailPlot'
  , pathPlot
  , pathPlot'

    -- * Line plots from points
  , linePlot
  , linePlot'
  , smoothLinePlot
  , smoothLinePlot'

    -- * Construction utilities

    -- ** Trails
  , mkTrail
  , mkTrailOf

    -- ** Paths
  , mkPath
  , mkPathOf


  ) where

import           Control.Monad.State.Lazy

import qualified Data.Foldable    as F

import           Diagrams.Coordinates.Isomorphic
import           Diagrams.Prelude

import           Plots.Axis
import           Plots.Types

------------------------------------------------------------------------
-- Trails and Paths
------------------------------------------------------------------------

-- | Add a 'Trail' as a 'Plot' to an 'Axis'.
trailPlot
  :: (BaseSpace c ~ v,
      Plotable (Path v n) b,
      MonadState (Axis b c n) m)
  => Trail v n -- ^ trail to plot
  -> State (Plot (Path v n) b) () -- ^ changes to plot options
  -> m () -- ^ add plot to the 'Axis'
trailPlot :: forall (c :: * -> *) (v :: * -> *) n b (m :: * -> *).
(BaseSpace c ~ v, Plotable (Path v n) b,
 MonadState (Axis b c n) m) =>
Trail v n -> State (Plot (Path v n) b) () -> m ()
trailPlot = Path v n -> State (Plot (Path v n) b) () -> m ()
forall (c :: * -> *) (v :: * -> *) n b (m :: * -> *).
(BaseSpace c ~ v, Plotable (Path v n) b,
 MonadState (Axis b c n) m) =>
Path v n -> State (Plot (Path v n) b) () -> m ()
pathPlot (Path v n -> State (Plot (Path v n) b) () -> m ())
-> (Trail v n -> Path v n)
-> Trail v n
-> State (Plot (Path v n) b) ()
-> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Trail v n -> Path v n
forall t.
(ToPath t, Metric (V t), OrderedField (N t)) =>
t -> Path (V t) (N t)
toPath

-- | Add a 'Trail' as a 'Plot' to an 'Axis' without changes to the plot
--   options.
trailPlot'
  :: (BaseSpace c ~ v,
      Plotable (Path v n) b,
      MonadState (Axis b c n) m)
  => Trail v n -- ^ trail to plot
  -> m () -- ^ add plot to the 'Axis'
trailPlot' :: forall (c :: * -> *) (v :: * -> *) n b (m :: * -> *).
(BaseSpace c ~ v, Plotable (Path v n) b,
 MonadState (Axis b c n) m) =>
Trail v n -> m ()
trailPlot' = Path (BaseSpace c) n -> m ()
forall (c :: * -> *) (v :: * -> *) n b (m :: * -> *).
(BaseSpace c ~ v, Plotable (Path v n) b,
 MonadState (Axis b c n) m) =>
Path v n -> m ()
pathPlot' (Path (BaseSpace c) n -> m ())
-> (Trail v n -> Path (BaseSpace c) n) -> Trail v n -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Trail v n -> Path (BaseSpace c) n
forall t.
(ToPath t, Metric (V t), OrderedField (N t)) =>
t -> Path (V t) (N t)
toPath

-- | Add a 'Path' as a 'Plot' to an 'Axis'.
pathPlot
  :: (BaseSpace c ~ v,
      Plotable (Path v n) b,
      MonadState (Axis b c n) m)
  => Path v n -- ^ path to plot
  -> State (Plot (Path v n) b) () -- ^ changes to plot options
  -> m () -- ^ add plot to the 'Axis'
pathPlot :: forall (c :: * -> *) (v :: * -> *) n b (m :: * -> *).
(BaseSpace c ~ v, Plotable (Path v n) b,
 MonadState (Axis b c n) m) =>
Path v n -> State (Plot (Path v n) b) () -> m ()
pathPlot = Path v n -> State (Plot (Path v n) b) () -> m ()
forall (c :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace c) n p, MonadState (Axis b c n) m,
 Plotable p b) =>
p -> State (Plot p b) () -> m ()
addPlotable

-- | Add a 'Path' as a 'Plot' to an 'Axis' without changes to the plot
--   options.
pathPlot'
  :: (BaseSpace c ~ v,
      Plotable (Path v n) b,
      MonadState (Axis b c n) m)
  => Path v n -- ^ path to plot
  -> m () -- ^ add plot to the 'Axis'
pathPlot' :: forall (c :: * -> *) (v :: * -> *) n b (m :: * -> *).
(BaseSpace c ~ v, Plotable (Path v n) b,
 MonadState (Axis b c n) m) =>
Path v n -> m ()
pathPlot' = Path v n -> m ()
forall (v :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace v) n p, MonadState (Axis b v n) m,
 Plotable p b) =>
p -> m ()
addPlotable'

------------------------------------------------------------------------
-- From list of points
------------------------------------------------------------------------

-- | Add a 'Path' plot from a list of points.
linePlot
  :: (BaseSpace c ~ v,
      Metric v,
      F.Foldable f,
      PointLike v n p,
      Plotable (Path v n) b,
      MonadState (Axis b c n) m)
  => f p -- ^ points to turn into trail
  -> State (Plot (Path v n) b) () -- ^ changes to plot options
  -> m () -- ^ add plot to the 'Axis'
linePlot :: forall (c :: * -> *) (v :: * -> *) (f :: * -> *) n p b
       (m :: * -> *).
(BaseSpace c ~ v, Metric v, Foldable f, PointLike v n p,
 Plotable (Path v n) b, MonadState (Axis b c n) m) =>
f p -> State (Plot (Path v n) b) () -> m ()
linePlot = Path v n -> State (Plot (Path v n) b) () -> m ()
forall (c :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace c) n p, MonadState (Axis b c n) m,
 Plotable p b) =>
p -> State (Plot p b) () -> m ()
addPlotable (Path v n -> State (Plot (Path v n) b) () -> m ())
-> (f p -> Path v n) -> f p -> State (Plot (Path v n) b) () -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Located (Trail v n) -> Path v n
forall t.
(ToPath t, Metric (V t), OrderedField (N t)) =>
t -> Path (V t) (N t)
toPath (Located (Trail v n) -> Path v n)
-> (f p -> Located (Trail v n)) -> f p -> Path v n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f p -> Located (Trail v n)
forall (v :: * -> *) n p (f :: * -> *).
(PointLike v n p, OrderedField n, Foldable f) =>
f p -> Located (Trail v n)
mkTrail

-- | Add a 'Path' plot from a list of points.
linePlot'
  :: (BaseSpace c ~ v,
      Metric v,
      F.Foldable f,
      PointLike v n p,
      Plotable (Path v n) b,
      MonadState (Axis b c n) m)
  => f p -- ^ points to turn into trail
  -> m () -- ^ add plot to the 'Axis'
linePlot' :: forall (c :: * -> *) (v :: * -> *) (f :: * -> *) n p b
       (m :: * -> *).
(BaseSpace c ~ v, Metric v, Foldable f, PointLike v n p,
 Plotable (Path v n) b, MonadState (Axis b c n) m) =>
f p -> m ()
linePlot' = Path (BaseSpace c) n -> m ()
forall (v :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace v) n p, MonadState (Axis b v n) m,
 Plotable p b) =>
p -> m ()
addPlotable' (Path (BaseSpace c) n -> m ())
-> (f p -> Path (BaseSpace c) n) -> f p -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Located (Trail (BaseSpace c) n) -> Path (BaseSpace c) n
forall t.
(ToPath t, Metric (V t), OrderedField (N t)) =>
t -> Path (V t) (N t)
toPath (Located (Trail (BaseSpace c) n) -> Path (BaseSpace c) n)
-> (f p -> Located (Trail (BaseSpace c) n))
-> f p
-> Path (BaseSpace c) n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f p -> Located (Trail (BaseSpace c) n)
forall (v :: * -> *) n p (f :: * -> *).
(PointLike v n p, OrderedField n, Foldable f) =>
f p -> Located (Trail v n)
mkTrail

-- | Add a smooth 'Path' plot from a list of points using 'cubicSpline'.
smoothLinePlot
  :: (BaseSpace c ~ v,
      F.Foldable f,
      Metric v,
      PointLike v n p,
      Plotable (Path v n) b,
      Fractional (v n), -- needs fixing in diagrams-lib
      MonadState (Axis b c n) m)
  => f p -- ^ points to turn into trail
  -> State (Plot (Path v n) b) () -- ^ changes to plot options
  -> m () -- ^ add plot to the 'Axis'
smoothLinePlot :: forall (c :: * -> *) (v :: * -> *) (f :: * -> *) n p b
       (m :: * -> *).
(BaseSpace c ~ v, Foldable f, Metric v, PointLike v n p,
 Plotable (Path v n) b, Fractional (v n),
 MonadState (Axis b c n) m) =>
f p -> State (Plot (Path v n) b) () -> m ()
smoothLinePlot = Path v n -> State (Plot (Path v n) b) () -> m ()
forall (c :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace c) n p, MonadState (Axis b c n) m,
 Plotable p b) =>
p -> State (Plot p b) () -> m ()
addPlotable (Path v n -> State (Plot (Path v n) b) () -> m ())
-> (f p -> Path v n) -> f p -> State (Plot (Path v n) b) () -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> [Point v n] -> Path v n
forall t (v :: * -> *) n.
(V t ~ v, N t ~ n, TrailLike t, Fractional (v n)) =>
Bool -> [Point v n] -> t
cubicSpline Bool
False ([Point v n] -> Path v n)
-> (f p -> [Point v n]) -> f p -> Path v n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting (Endo [Point v n]) (f p) (Point v n) -> f p -> [Point v n]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf ((p -> Const (Endo [Point v n]) p)
-> f p -> Const (Endo [Point v n]) (f p)
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
folded ((p -> Const (Endo [Point v n]) p)
 -> f p -> Const (Endo [Point v n]) (f p))
-> ((Point v n -> Const (Endo [Point v n]) (Point v n))
    -> p -> Const (Endo [Point v n]) p)
-> Getting (Endo [Point v n]) (f p) (Point v n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point v n -> Const (Endo [Point v n]) (Point v n))
-> p -> Const (Endo [Point v n]) p
forall (v :: * -> *) n a. PointLike v n a => Iso' a (Point v n)
unpointLike)

-- | Add a smooth 'Path' plot from a list of points using 'cubicSpline'
--   without changes to the plot options.
smoothLinePlot'
  :: (BaseSpace c ~ v,
      F.Foldable f,
      PointLike v n p,
      Plotable (Path v n) b,
      Fractional (v n), -- needs fixing in diagrams-lib
      MonadState (Axis b c n) m)
  => f p -- ^ points to turn into trail
  -> m () -- ^ add plot to the 'Axis'
smoothLinePlot' :: forall (c :: * -> *) (v :: * -> *) (f :: * -> *) n p b
       (m :: * -> *).
(BaseSpace c ~ v, Foldable f, PointLike v n p,
 Plotable (Path v n) b, Fractional (v n),
 MonadState (Axis b c n) m) =>
f p -> m ()
smoothLinePlot' f p
xs = f p -> State (Plot (Path (BaseSpace c) n) b) () -> m ()
forall (c :: * -> *) (v :: * -> *) (f :: * -> *) n p b
       (m :: * -> *).
(BaseSpace c ~ v, Foldable f, Metric v, PointLike v n p,
 Plotable (Path v n) b, Fractional (v n),
 MonadState (Axis b c n) m) =>
f p -> State (Plot (Path v n) b) () -> m ()
smoothLinePlot f p
xs (() -> State (Plot (Path (BaseSpace c) n) b) ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())

------------------------------------------------------------------------
-- Trail and path
------------------------------------------------------------------------

-- | Construct a localed trail from a list of foldable of points.
mkTrail :: (PointLike v n p, OrderedField n, F.Foldable f) => f p -> Located (Trail v n)
mkTrail :: forall (v :: * -> *) n p (f :: * -> *).
(PointLike v n p, OrderedField n, Foldable f) =>
f p -> Located (Trail v n)
mkTrail = Fold (f p) p -> f p -> Located (Trail v n)
forall (v :: * -> *) n p s.
(PointLike v n p, OrderedField n) =>
Fold s p -> s -> Located (Trail v n)
mkTrailOf Fold (f p) p
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
folded

-- | Construct a localed trail from a fold over points.
mkTrailOf :: (PointLike v n p, OrderedField n) => Fold s p -> s -> Located (Trail v n)
mkTrailOf :: forall (v :: * -> *) n p s.
(PointLike v n p, OrderedField n) =>
Fold s p -> s -> Located (Trail v n)
mkTrailOf Fold s p
f s
ps = [Point (V (Located (Trail v n))) (N (Located (Trail v n)))]
-> Located (Trail v n)
forall t. TrailLike t => [Point (V t) (N t)] -> t
fromVertices ([Point (V (Located (Trail v n))) (N (Located (Trail v n)))]
 -> Located (Trail v n))
-> [Point (V (Located (Trail v n))) (N (Located (Trail v n)))]
-> Located (Trail v n)
forall a b. (a -> b) -> a -> b
$ Getting (Endo [Point v n]) s (Point v n) -> s -> [Point v n]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf ((p -> Const (Endo [Point v n]) p)
-> s -> Const (Endo [Point v n]) s
Fold s p
f ((p -> Const (Endo [Point v n]) p)
 -> s -> Const (Endo [Point v n]) s)
-> ((Point v n -> Const (Endo [Point v n]) (Point v n))
    -> p -> Const (Endo [Point v n]) p)
-> Getting (Endo [Point v n]) s (Point v n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point v n -> Const (Endo [Point v n]) (Point v n))
-> p -> Const (Endo [Point v n]) p
forall (v :: * -> *) n a. PointLike v n a => Iso' a (Point v n)
unpointLike) s
ps

-- | Construct a localed trail from a fold over points.
mkPath :: (PointLike v n p, OrderedField n, F.Foldable f, F.Foldable g) => g (f p) -> Path v n
mkPath :: forall (v :: * -> *) n p (f :: * -> *) (g :: * -> *).
(PointLike v n p, OrderedField n, Foldable f, Foldable g) =>
g (f p) -> Path v n
mkPath g (f p)
pss = [Located (Trail v n)]
-> Path (V [Located (Trail v n)]) (N [Located (Trail v n)])
forall t.
(ToPath t, Metric (V t), OrderedField (N t)) =>
t -> Path (V t) (N t)
toPath ([Located (Trail v n)]
 -> Path (V [Located (Trail v n)]) (N [Located (Trail v n)]))
-> [Located (Trail v n)]
-> Path (V [Located (Trail v n)]) (N [Located (Trail v n)])
forall a b. (a -> b) -> a -> b
$ (f p -> Located (Trail v n)) -> [f p] -> [Located (Trail v n)]
forall a b. (a -> b) -> [a] -> [b]
map f p -> Located (Trail v n)
forall (v :: * -> *) n p (f :: * -> *).
(PointLike v n p, OrderedField n, Foldable f) =>
f p -> Located (Trail v n)
mkTrail (g (f p) -> [f p]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList g (f p)
pss)

-- | Construct a localed trail from a fold over points.
mkPathOf :: (PointLike v n p, OrderedField n) => Fold s t -> Fold t p -> s -> Path v n
mkPathOf :: forall (v :: * -> *) n p s t.
(PointLike v n p, OrderedField n) =>
Fold s t -> Fold t p -> s -> Path v n
mkPathOf Fold s t
f1 Fold t p
f2 s
as = [Located (Trail v n)] -> Path v n
forall (v :: * -> *) n. [Located (Trail v n)] -> Path v n
Path ([Located (Trail v n)] -> Path v n)
-> [Located (Trail v n)] -> Path v n
forall a b. (a -> b) -> a -> b
$ (t -> Located (Trail v n)) -> [t] -> [Located (Trail v n)]
forall a b. (a -> b) -> [a] -> [b]
map (Fold t p -> t -> Located (Trail v n)
forall (v :: * -> *) n p s.
(PointLike v n p, OrderedField n) =>
Fold s p -> s -> Located (Trail v n)
mkTrailOf Fold t p
f2) (Getting (Endo [t]) s t -> s -> [t]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf Getting (Endo [t]) s t
Fold s t
f1 s
as)