-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.Rendering.Chart.Plot
-- Copyright   :  (c) Tim Docker 2006
-- License     :  BSD-style (see chart/COPYRIGHT)
--
-- Definitions of various types of Plots we can put on a 2D Chart.
--
-- Note that template haskell is used to derive accessor functions
-- (see 'Data.Accessor') for each field of the following data types:
--
--     * 'Plot'
--
--     * 'PlotLines'
--
--     * 'PlotPoints'
--
--     * 'PlotFillBetween'
--
--     * 'PlotErrBars'
--
--     * 'PlotBars'
-- 
--     * 'PlotHidden'
--
--     * 'PlotAnnotation'
--
-- These accessors are not shown in this API documentation.  They have
-- the same name as the field, but with the trailing underscore
-- dropped. Hence for data field f_::F in type D, they have type
--
-- @
--   f :: Data.Accessor.Accessor D F
-- @
--


{-# OPTIONS_GHC -XTemplateHaskell #-}

module Graphics.Rendering.Chart.Plot(
    -- * Plot
    Plot(..),
    joinPlot,
    -- ** Typeclass for casting to plot
    ToPlot(..),
    -- * Point plots
    PlotPoints(..),
    defaultPlotPoints,
    -- * Lines plot
    PlotLines(..),
    defaultPlotLines,
    defaultPlotLineStyle,
    hlinePlot,
    vlinePlot,
    -- * Plot with error bars
    PlotErrBars(..),
    defaultPlotErrBars,
    ErrPoint(..),
    ErrValue(..),
    symErrPoint,
    -- * Plot with filled area
    PlotFillBetween(..),
    defaultPlotFillBetween,
    -- * Bar plots
    PlotBars(..),
    defaultPlotBars,
    PlotBarsStyle(..),
    PlotBarsSpacing(..),
    PlotBarsAlignment(..),
    BarsPlotValue(..),
    -- * Invisible plot
    PlotHidden(..),
    -- Annotation plot
    PlotAnnotation(..),
    defaultPlotAnnotation,

    -- * Accessors
    -- | These accessors are generated by template haskell
    plot_lines_title,
    plot_lines_style,
    plot_lines_values,
    plot_lines_limit_values,

    plot_render,
    plot_legend,
    plot_all_points,

    plot_points_title,
    plot_points_style,
    plot_points_values,

    plot_fillbetween_title,
    plot_fillbetween_style,
    plot_fillbetween_values,

    plot_errbars_title,
    plot_errbars_line_style,
    plot_errbars_tick_length,
    plot_errbars_overhang,
    plot_errbars_values,

    plotBars,
    plot_bars_style,
    plot_bars_item_styles,
    plot_bars_titles,
    plot_bars_spacing,
    plot_bars_alignment,
    plot_bars_reference,
    plot_bars_singleton_width,
    plot_bars_values,

    plot_annotation_hanchor,
    plot_annotation_vanchor,
    plot_annotation_angle,
    plot_annotation_style,
    plot_annotation_values
    ) where

import qualified Graphics.Rendering.Cairo as C
import Graphics.Rendering.Chart.Types
import Graphics.Rendering.Chart.Renderable
import Graphics.Rendering.Chart.Axis
import Control.Monad
import Data.List
import Data.Accessor.Template
import Data.Colour
import Data.Colour.SRGB (sRGB)
import Data.Colour.Names

-- | Interface to control plotting on a 2D area.
data Plot x y = Plot {

    -- | Given the mapping between model space coordinates and device
    --   coordinates, render this plot into a chart.
    plot_render_     :: PointMapFn x y -> CRender (),

    -- | Details for how to show this plot in a legend. For each item
    --   the string is the text to show, and the function renders a
    --   graphical sample of the plot.
    plot_legend_     :: [ (String, Rect -> CRender ()) ],

    -- | All of the model space coordinates to be plotted. These are
    --   used to autoscale the axes where necessary.
    plot_all_points_ :: ([x],[y])
}

-- | A type class abstracting the conversion of a value to a Plot.
class ToPlot a where
   toPlot :: a x y -> Plot x y

-- | Join any two plots together (they will share a legend).
joinPlot :: Plot x y -> Plot x y -> Plot x y
joinPlot Plot{ plot_render_     = renderP
             , plot_legend_     = legendP
             , plot_all_points_ = (xsP,ysP) }
         Plot{ plot_render_     = renderQ
             , plot_legend_     = legendQ
             , plot_all_points_ = (xsQ,ysQ) }

       = Plot{ plot_render_     = \a-> renderP a >> renderQ a
             , plot_legend_     = legendP ++ legendQ
             , plot_all_points_ = ( xsP++xsQ, ysP++ysQ )
             }


----------------------------------------------------------------------

mapXY :: PointMapFn x y -> ((x,y) -> Point)
mapXY f (x,y) = f (LValue x, LValue y)

----------------------------------------------------------------------

-- | Value defining a series of (possibly disjointed) lines,
--   and a style in which to render them.
data PlotLines x y = PlotLines {
    plot_lines_title_        :: String,
    plot_lines_style_        :: CairoLineStyle,
    plot_lines_values_       :: [[(x,y)]],
    plot_lines_limit_values_ :: [[(Limit x, Limit y)]]
}

instance ToPlot PlotLines where
    toPlot p = Plot {
        plot_render_     = renderPlotLines p,
        plot_legend_     = [(plot_lines_title_ p, renderPlotLegendLines p)],
        plot_all_points_ = ( map fst pts ++ xs, map snd pts ++ ys )
    }
      where
        pts = concat (plot_lines_values_ p)
        xs = [ x | (LValue x,_) <- concat (plot_lines_limit_values_ p)]
        ys = [ y | (_,LValue y) <- concat (plot_lines_limit_values_ p)]

renderPlotLines :: PlotLines x y -> PointMapFn x y -> CRender ()
renderPlotLines p pmap = preserveCState $ do
    setLineStyle (plot_lines_style_ p)
    mapM_ (drawLines (mapXY pmap)) (plot_lines_values_ p)
    mapM_ (drawLines pmap) (plot_lines_limit_values_ p)
  where
    drawLines mapfn pts = strokePath (map mapfn pts)

renderPlotLegendLines :: PlotLines x y -> Rect -> CRender ()
renderPlotLegendLines p r@(Rect p1 p2) = preserveCState $ do
    setLineStyle (plot_lines_style_ p)
    let y = (p_y p1 + p_y p2) / 2
    strokePath [Point (p_x p1) y, Point (p_x p2) y]

defaultPlotLineStyle :: CairoLineStyle
defaultPlotLineStyle = (solidLine 1 $ opaque blue){
     line_cap_  = C.LineCapRound,
     line_join_ = C.LineJoinRound
 }

defaultPlotLines :: PlotLines x y
defaultPlotLines = PlotLines {
    plot_lines_title_        = "",
    plot_lines_style_        = defaultPlotLineStyle,
    plot_lines_values_       = [],
    plot_lines_limit_values_ = []
}

-- | Helper function to plot a single horizontal line.
hlinePlot :: String -> CairoLineStyle -> b -> Plot a b
hlinePlot t ls v = toPlot defaultPlotLines {
    plot_lines_title_        = t,
    plot_lines_style_        = ls,
    plot_lines_limit_values_ = [[(LMin, LValue v),(LMax, LValue v)]]
    }

-- | Helper function to plot a single vertical line.
vlinePlot :: String -> CairoLineStyle -> a -> Plot a b
vlinePlot t ls v = toPlot defaultPlotLines {
    plot_lines_title_        = t,
    plot_lines_style_        = ls,
    plot_lines_limit_values_ = [[(LValue v,LMin),(LValue v,LMax)]]
    }

----------------------------------------------------------------------

-- | Value defining a series of datapoints, and a style in
--   which to render them.
data PlotPoints x y = PlotPoints {
    plot_points_title_  :: String,
    plot_points_style_  :: CairoPointStyle,
    plot_points_values_ :: [(x,y)]
}


instance ToPlot PlotPoints where
    toPlot p = Plot {
        plot_render_     = renderPlotPoints p,
        plot_legend_     = [(plot_points_title_ p, renderPlotLegendPoints p)],
        plot_all_points_ = (map fst pts, map snd pts)
    }
      where
        pts = plot_points_values_ p

renderPlotPoints :: PlotPoints x y -> PointMapFn x y -> CRender ()
renderPlotPoints p pmap = preserveCState $ do
    mapM_ (drawPoint.pmap') (plot_points_values_ p)
  where
    pmap' = mapXY pmap
    (CairoPointStyle drawPoint) = (plot_points_style_ p)


renderPlotLegendPoints :: PlotPoints x y -> Rect -> CRender ()
renderPlotLegendPoints p r@(Rect p1 p2) = preserveCState $ do
    drawPoint (Point (p_x p1)              ((p_y p1 + p_y p2)/2))
    drawPoint (Point ((p_x p1 + p_x p2)/2) ((p_y p1 + p_y p2)/2))
    drawPoint (Point (p_x p2)              ((p_y p1 + p_y p2)/2))

  where
    (CairoPointStyle drawPoint) = (plot_points_style_ p)

defaultPlotPoints :: PlotPoints x y
defaultPlotPoints = PlotPoints {
    plot_points_title_  = "",
    plot_points_style_  = defaultPointStyle,
    plot_points_values_ = []
}
----------------------------------------------------------------------
-- | Value specifying a plot filling the area between two sets of Y
--   coordinates, given common X coordinates.

data PlotFillBetween x y = PlotFillBetween {
    plot_fillbetween_title_  :: String,
    plot_fillbetween_style_  :: CairoFillStyle,
    plot_fillbetween_values_ :: [ (x, (y,y))]
}


instance ToPlot PlotFillBetween where
    toPlot p = Plot {
        plot_render_     = renderPlotFillBetween p,
        plot_legend_     = [(plot_fillbetween_title_ p,renderPlotLegendFill p)],
        plot_all_points_ = plotAllPointsFillBetween p
    }

renderPlotFillBetween :: PlotFillBetween x y -> PointMapFn x y -> CRender ()
renderPlotFillBetween p pmap =
    renderPlotFillBetween' p (plot_fillbetween_values_ p) pmap

renderPlotFillBetween' p [] _     = return ()
renderPlotFillBetween' p vs pmap  = preserveCState $ do
    setFillStyle (plot_fillbetween_style_ p)
    fillPath ([p0] ++ p1s ++ reverse p2s ++ [p0])
  where
    pmap'    = mapXY pmap
    (p0:p1s) = map pmap' [ (x,y1) | (x,(y1,y2)) <- vs ]
    p2s      = map pmap' [ (x,y2) | (x,(y1,y2)) <- vs ]

renderPlotLegendFill :: PlotFillBetween x y -> Rect -> CRender ()
renderPlotLegendFill p r = preserveCState $ do
    setFillStyle (plot_fillbetween_style_ p)
    fillPath (rectPath r)

plotAllPointsFillBetween :: PlotFillBetween x y -> ([x],[y])
plotAllPointsFillBetween p = ( [ x | (x,(_,_)) <- pts ]
                             , concat [ [y1,y2] | (_,(y1,y2)) <- pts ] )
  where
    pts = plot_fillbetween_values_ p


defaultPlotFillBetween :: PlotFillBetween x y
defaultPlotFillBetween = PlotFillBetween {
    plot_fillbetween_title_  = "",
    plot_fillbetween_style_  = solidFillStyle (opaque $ sRGB 0.5 0.5 1.0),
    plot_fillbetween_values_ = []
}

----------------------------------------------------------------------

-- | Value for holding a point with associated error bounds for each axis.

data ErrValue x = ErrValue {
      ev_low  :: x,
      ev_best :: x,
      ev_high :: x
} deriving Show

data ErrPoint x y = ErrPoint {
      ep_x :: ErrValue x,
      ep_y :: ErrValue y
} deriving Show

-- | When the error is symmetric, we can simply pass in dx for the error.
symErrPoint :: (Num a, Num b) => a -> b -> a -> b -> ErrPoint a b
symErrPoint x y dx dy = ErrPoint (ErrValue (x-dx) x (x+dx))
                                 (ErrValue (y-dy) y (y+dy))

-- | Value defining a series of error intervals, and a style in
--   which to render them.
data PlotErrBars x y = PlotErrBars {
    plot_errbars_title_       :: String,
    plot_errbars_line_style_  :: CairoLineStyle,
    plot_errbars_tick_length_ :: Double,
    plot_errbars_overhang_    :: Double,
    plot_errbars_values_      :: [ErrPoint x y]
}


instance ToPlot PlotErrBars where
    toPlot p = Plot {
        plot_render_     = renderPlotErrBars p,
        plot_legend_     = [(plot_errbars_title_ p, renderPlotLegendErrBars p)],
        plot_all_points_ = ( concat [ [ev_low x,ev_high x]
                                    | ErrPoint x _ <- pts ]
                           , concat [ [ev_low y,ev_high y]
                                    | ErrPoint _ y <- pts ] )
    }
      where
        pts = plot_errbars_values_ p

renderPlotErrBars :: PlotErrBars x y -> PointMapFn x y -> CRender ()
renderPlotErrBars p pmap = preserveCState $ do
    mapM_ (drawErrBar.epmap) (plot_errbars_values_ p)
  where
    epmap (ErrPoint (ErrValue xl x xh) (ErrValue yl y yh)) =
        ErrPoint (ErrValue xl' x' xh') (ErrValue yl' y' yh')
        where (Point x' y')   = pmap' (x,y)
              (Point xl' yl') = pmap' (xl,yl)
              (Point xh' yh') = pmap' (xh,yh)
    drawErrBar = drawErrBar0 p
    pmap'      = mapXY pmap

drawErrBar0 ps (ErrPoint (ErrValue xl x xh) (ErrValue yl y yh)) = do
        let tl = plot_errbars_tick_length_ ps
        let oh = plot_errbars_overhang_ ps
        setLineStyle (plot_errbars_line_style_ ps)
        c $ C.newPath
        c $ C.moveTo (xl-oh) y
        c $ C.lineTo (xh+oh) y
        c $ C.moveTo x (yl-oh)
        c $ C.lineTo x (yh+oh)
        c $ C.moveTo xl (y-tl)
        c $ C.lineTo xl (y+tl)
        c $ C.moveTo (x-tl) yl
        c $ C.lineTo (x+tl) yl
        c $ C.moveTo xh (y-tl)
        c $ C.lineTo xh (y+tl)
        c $ C.moveTo (x-tl) yh
        c $ C.lineTo (x+tl) yh
	c $ C.stroke

renderPlotLegendErrBars :: PlotErrBars x y -> Rect -> CRender ()
renderPlotLegendErrBars p r@(Rect p1 p2) = preserveCState $ do
    drawErrBar (symErrPoint (p_x p1)              ((p_y p1 + p_y p2)/2) dx dx)
    drawErrBar (symErrPoint ((p_x p1 + p_x p2)/2) ((p_y p1 + p_y p2)/2) dx dx)
    drawErrBar (symErrPoint (p_x p2)              ((p_y p1 + p_y p2)/2) dx dx)

  where
    drawErrBar = drawErrBar0 p
    dx         = min ((p_x p2 - p_x p1)/6) ((p_y p2 - p_y p1)/2)

defaultPlotErrBars :: PlotErrBars x y
defaultPlotErrBars = PlotErrBars {
    plot_errbars_title_       = "",
    plot_errbars_line_style_  = solidLine 1 $ opaque blue,
    plot_errbars_tick_length_ = 3,
    plot_errbars_overhang_    = 0,
    plot_errbars_values_      = []
}

----------------------------------------------------------------------

class PlotValue a => BarsPlotValue a where
    barsReference :: a
    barsAdd       :: a -> a -> a

instance BarsPlotValue Double where
    barsReference = 0
    barsAdd       = (+)
instance BarsPlotValue Int where
    barsReference = 0
    barsAdd       = (+)

data PlotBarsStyle
    = BarsStacked   -- ^ Bars for a fixed x are stacked vertically
                    --   on top of each other.
    | BarsClustered -- ^ Bars for a fixed x are put horizontally
                    --   beside each other.
     deriving (Show)

data PlotBarsSpacing
    = BarsFixWidth Double       -- ^ All bars have the same width in pixels.
    | BarsFixGap Double Double  -- ^ (BarsFixGap g mw) means make the gaps between
                                --   the bars equal to g, but with a minimum bar width
                                --   of mw
     deriving (Show)

-- | How bars for a given (x,[y]) are aligned with respect to screen
--   coordinate corresponding to x (deviceX).
data PlotBarsAlignment = BarsLeft      -- ^ The left edge of bars is at deviceX
                       | BarsCentered  -- ^ The right edge of bars is at deviceX
                       | BarsRight     -- ^ Bars are centered around deviceX
     deriving (Show)

-- | Value describing how to plot a set of bars.
--   Note that the input data is typed [(x,[y])], ie for each x value
--   we plot several y values. Typically the size of each [y] list would
--   be the same.
data PlotBars x y = PlotBars {
   -- | This value specifies whether each value from [y] should be
   --   shown beside or above the previous value.
   plot_bars_style_           :: PlotBarsStyle,

   -- | The style in which to draw each element of [y]. A fill style
   --   is required, and if a linestyle is given, each bar will be
   --   outlined.
   plot_bars_item_styles_     :: [ (CairoFillStyle,Maybe CairoLineStyle) ],

   -- | The title of each element of [y]. These will be shown in the legend.
   plot_bars_titles_          :: [String],

   -- | This value controls how the widths of the bars are
   --   calculated. Either the widths of the bars, or the gaps between
   --   them can be fixed.
   plot_bars_spacing_         :: PlotBarsSpacing,

   -- | This value controls how bars for a fixed x are aligned with
   --   respect to the device coordinate corresponding to x.
   plot_bars_alignment_       :: PlotBarsAlignment,

   -- | The starting level for the chart (normally 0).
   plot_bars_reference_       :: y,

   plot_bars_singleton_width_ :: Double,

   -- | The actual points to be plotted.
   plot_bars_values_          :: [ (x,[y]) ]
}

defaultPlotBars :: BarsPlotValue y => PlotBars x y
defaultPlotBars = PlotBars {
   plot_bars_style_           = BarsClustered,
   plot_bars_item_styles_     = cycle istyles,
   plot_bars_titles_          = [],
   plot_bars_spacing_         = BarsFixGap 10 2,
   plot_bars_alignment_       = BarsCentered,
   plot_bars_values_          = [],
   plot_bars_singleton_width_ = 20,
   plot_bars_reference_       = barsReference
   }
  where
    istyles   = map mkstyle defaultColorSeq
    mkstyle c = (solidFillStyle c, Just (solidLine 1.0 $ opaque black))

plotBars :: (BarsPlotValue y) => PlotBars x y -> Plot x y
plotBars p = Plot {
        plot_render_     = renderPlotBars p,
        plot_legend_     = zip (plot_bars_titles_ p)
                               (map renderPlotLegendBars
                                    (plot_bars_item_styles_ p)),
        plot_all_points_ = allBarPoints p
    }

renderPlotBars :: (BarsPlotValue y) =>
                  PlotBars x y -> PointMapFn x y -> CRender ()
renderPlotBars p pmap = case (plot_bars_style_ p) of
      BarsClustered -> forM_ vals clusteredBars
      BarsStacked   -> forM_ vals stackedBars
  where
    clusteredBars (x,ys) = preserveCState $ do
       forM_ (zip3 [0,1..] ys styles) $ \(i, y, (fstyle,_)) -> do
           setFillStyle fstyle
           fillPath (barPath (offset i) x yref0 y)
           c $ C.fill
       forM_ (zip3 [0,1..] ys styles) $ \(i, y, (_,mlstyle)) -> do
           whenJust mlstyle $ \lstyle -> do
             setLineStyle lstyle
             strokePath (barPath (offset i) x yref0 y)

    offset = case (plot_bars_alignment_ p) of
      BarsLeft     -> \i -> fromIntegral i * width
      BarsRight    -> \i -> fromIntegral (i-nys) * width
      BarsCentered -> \i -> fromIntegral (2*i-nys) * width/2

    stackedBars (x,ys) =  preserveCState $ do
       let y2s = zip (yref0:stack ys) (stack ys)
       let ofs = case (plot_bars_alignment_ p) of {
         BarsLeft     -> 0          ;
         BarsRight    -> (-width)   ;
         BarsCentered -> (-width/2)
         }
       forM_ (zip y2s styles) $ \((y0,y1), (fstyle,_)) -> do
           setFillStyle fstyle
           fillPath (barPath ofs x y0 y1)
       forM_ (zip y2s styles) $ \((y0,y1), (_,mlstyle)) -> do
           whenJust mlstyle $ \lstyle -> do
               setLineStyle lstyle
               strokePath (barPath ofs x y0 y1)

    barPath xos x y0 y1 = do
      let (Point x' y') = pmap' (x,y1)
      let (Point _ y0') = pmap' (x,y0)
      rectPath (Rect (Point (x'+xos) y0') (Point (x'+xos+width) y'))

    yref0 = plot_bars_reference_ p
    vals  = plot_bars_values_ p
    width = case plot_bars_spacing_ p of
        BarsFixGap gap minw -> let w = max (minXInterval - gap) minw in
            case (plot_bars_style_ p) of
                BarsClustered -> w / fromIntegral nys
                BarsStacked -> w
        BarsFixWidth width -> width
    styles = plot_bars_item_styles_ p

    minXInterval = let diffs = zipWith (-) (tail mxs) mxs
                   in if null diffs
                        then plot_bars_singleton_width_ p
                        else minimum diffs
      where
        xs  = fst (allBarPoints p)
        mxs = nub $ sort $ map mapX xs

    nys    = maximum [ length ys | (x,ys) <- vals ]

    pmap'  = mapXY pmap
    mapX x = p_x (pmap' (x,barsReference))

whenJust :: (Monad m) => Maybe a -> (a -> m ()) -> m ()
whenJust (Just a) f = f a
whenJust _        _ = return ()

allBarPoints :: (BarsPlotValue y) => PlotBars x y -> ([x],[y])
allBarPoints p = case (plot_bars_style_ p) of
    BarsClustered -> ( [x| (x,_) <- pts], y0:concat [ys| (_,ys) <- pts] )
    BarsStacked   -> ( [x| (x,_) <- pts], y0:concat [stack ys | (_,ys) <- pts] )
  where
    pts = plot_bars_values_ p
    y0  = plot_bars_reference_ p

stack :: (BarsPlotValue y) => [y] -> [y]
stack ys = scanl1 barsAdd ys


renderPlotLegendBars :: (CairoFillStyle,Maybe CairoLineStyle) -> Rect
                        -> CRender ()
renderPlotLegendBars (fstyle,mlstyle) r@(Rect p1 p2) = do
    setFillStyle fstyle
    fillPath (rectPath r)

----------------------------------------------------------------------

-- | Value defining some hidden x and y values. The values don't
--   get displayed, but still affect axis scaling.
data PlotHidden x y = PlotHidden {
    plot_hidden_x_values_ :: [x],
    plot_hidden_y_values_ :: [y]
}

instance ToPlot PlotHidden where
    toPlot ph = Plot {
        plot_render_     = \_ -> return (),
        plot_legend_     = [],
        plot_all_points_ = (plot_hidden_x_values_ ph, plot_hidden_y_values_ ph)
    }



----------------------------------------------------------------------

-- | Value for describing a series of text annotations
--   to be placed at arbitrary points on the graph. Annotations
--   can be rotated and styled. Rotation angle is given in degrees,
--   rotation is performend around the anchor point.

data PlotAnnotation  x y = PlotAnnotation {
      plot_annotation_hanchor_ :: HTextAnchor,
      plot_annotation_vanchor_ :: VTextAnchor,
      plot_annotation_angle_   :: Double,
      plot_annotation_style_   :: CairoFontStyle,
      plot_annotation_values_  :: [(x,y,String)]
}


instance ToPlot PlotAnnotation where
    toPlot p = Plot {
        plot_render_ = renderAnnotation p,
	plot_legend_ = [],
	plot_all_points_ = (map (\(x,_,_)->x)  vs , map (\(_,y,_)->y) vs)
    }
      where
        vs = plot_annotation_values_ p


renderAnnotation :: PlotAnnotation x y -> PointMapFn x y -> CRender ()

renderAnnotation p pMap = preserveCState $ do
                            setFontStyle style                            
                            mapM_ drawOne values
    where hta = plot_annotation_hanchor_ p
          vta = plot_annotation_vanchor_ p
          values = plot_annotation_values_ p
          angle =  plot_annotation_angle_ p
          style =  plot_annotation_style_ p
          drawOne (x,y,s) = drawTextR hta vta angle point s
              where point = pMap (LValue x, LValue y)

defaultPlotAnnotation = PlotAnnotation {
                          plot_annotation_hanchor_ = HTA_Centre,
                          plot_annotation_vanchor_ = VTA_Centre,
                          plot_annotation_angle_   = 0,
                          plot_annotation_style_   = defaultFontStyle,
                          plot_annotation_values_  = []
}



----------------------------------------------------------------------
-- Template haskell to derive an instance of Data.Accessor.Accessor
-- for each field.
$( deriveAccessors ''Plot )
$( deriveAccessors ''PlotLines )
$( deriveAccessors ''PlotPoints )
$( deriveAccessors ''PlotFillBetween )
$( deriveAccessors ''PlotErrBars )
$( deriveAccessors ''PlotBars )
$( deriveAccessors ''PlotHidden )
$( deriveAccessors ''PlotAnnotation )