diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Tony Day (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Tony Day nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/chart-unit.cabal b/chart-unit.cabal
new file mode 100644
--- /dev/null
+++ b/chart-unit.cabal
@@ -0,0 +1,154 @@
+name:
+  chart-unit
+version:
+  0.1.0.0
+synopsis:
+  A set of native haskell charts.
+description:
+  readme.lhs
+category:
+  charts
+homepage:
+  https://github.com/tonyday567/chart-unit
+license:
+  BSD3
+license-file:
+  LICENSE
+author:
+  Tony Day
+maintainer:
+  tonyday567@gmail.com
+copyright:
+  2016 Tony Day
+build-type:
+  Simple
+cabal-version:
+  >=1.10
+
+library
+  hs-source-dirs:
+    src
+  exposed-modules:
+    Chart.Unit,
+    Chart.Types
+  ghc-options:
+    -funbox-strict-fields
+    -fforce-recomp          
+  build-depends:
+    base >= 4.7 && < 5,
+    colour,
+    containers,
+    data-default,
+    diagrams,
+    diagrams-core,
+    diagrams-lib,
+    diagrams-svg,
+    diagrams-rasterific,
+    foldl,
+    lens,
+    primitive,
+    protolude,
+    text
+  default-language:
+    Haskell2010
+  default-extensions:
+    NoImplicitPrelude,
+    UnicodeSyntax,
+    BangPatterns,
+    BinaryLiterals,
+    DeriveFoldable,
+    DeriveFunctor,
+    DeriveGeneric,
+    DeriveTraversable,
+    DisambiguateRecordFields,
+    EmptyCase,
+    FlexibleContexts,
+    FlexibleInstances,
+    FunctionalDependencies,
+    GADTSyntax,
+    InstanceSigs,
+    KindSignatures,
+    LambdaCase,
+    MonadComprehensions,
+    MultiParamTypeClasses,
+    MultiWayIf,
+    NegativeLiterals,
+    OverloadedStrings,
+    ParallelListComp,
+    PartialTypeSignatures,
+    PatternSynonyms,
+    RankNTypes,
+    RecordWildCards,
+    RecursiveDo,
+    ScopedTypeVariables,
+    TupleSections,
+    TypeFamilies,
+    TypeOperators
+
+executable readme
+  default-language:
+    Haskell2010
+  ghc-options:
+    -funbox-strict-fields
+    -fforce-recomp
+    -threaded
+    -rtsopts
+    -with-rtsopts=-N
+  hs-source-dirs:
+    ./
+  main-is:
+    readme.lhs
+  build-depends:
+    base >= 4.7 && < 5,
+    chart-unit,
+    containers,
+    diagrams,
+    diagrams-core,
+    diagrams-lib,
+    diagrams-rasterific,
+    diagrams-svg,
+    foldl,
+    lens,
+    primitive,
+    protolude,
+    random-fu,
+    text
+  default-extensions:
+    NoImplicitPrelude,
+    UnicodeSyntax,
+    BangPatterns,
+    BinaryLiterals,
+    DeriveFoldable,
+    DeriveFunctor,
+    DeriveGeneric,
+    DeriveTraversable,
+    DisambiguateRecordFields,
+    EmptyCase,
+    FlexibleContexts,
+    FlexibleInstances,
+    FunctionalDependencies,
+    GADTSyntax,
+    InstanceSigs,
+    KindSignatures,
+    LambdaCase,
+    MonadComprehensions,
+    MultiParamTypeClasses,
+    MultiWayIf,
+    NegativeLiterals,
+    OverloadedStrings,
+    ParallelListComp,
+    PartialTypeSignatures,
+    PatternSynonyms,
+    RankNTypes,
+    RecordWildCards,
+    RecursiveDo,
+    ScopedTypeVariables,
+    TupleSections,
+    TypeFamilies,
+    TypeOperators
+
+source-repository head
+  type:
+    git
+  location:
+    https://github.com/tonyday567/chart-unit
diff --git a/readme.lhs b/readme.lhs
new file mode 100644
--- /dev/null
+++ b/readme.lhs
@@ -0,0 +1,226 @@
+```include
+other/header.md
+```
+
+[chart-unit](https://tonyday567.github.io/chart-unit.html) [![Build Status](https://travis-ci.org/tonyday567/chart-unit.png)](https://travis-ci.org/tonyday567/chart-unit)
+===
+
+scratchpad
+---
+
+My newest chart `padsvg $ linesXY def [[(0,0),(1,1)],[(0,0),(1,2)]]`
+
+![](other/scratchpad.svg)
+
+This slowly growing collection of charts:
+
+- renders nicely over a wide chart size range, svg and png formats.
+- render similarly at different scale
+- are opinionated minimalism
+- are unit shapes in the spirit of the [diagrams](http://projects.haskell.org/diagrams/doc/quickstart.html) design space.
+- can be quickly integrated into ad-hoc haskell data analytics, providing a visual feedback loop.
+
+charts
+---
+
+Scatter
+
+![](other/scatter.svg)
+
+Histogram
+
+![](other/hist.svg)
+
+Line
+
+![](other/line.svg)
+
+Lines
+
+![](other/lines.svg)
+
+Labelled Bar Chart
+
+![](other/bar.svg)
+
+rasterific png renders
+---
+
+![](other/scratchpad.png)
+
+Scatter
+
+![](other/scatter.png)
+
+Histogram
+
+![](other/hist.png)
+
+Line
+
+![](other/line.png)
+
+Lines
+
+![](other/lines.png)
+
+Labelled Bar Chart
+
+![](other/bar.png)
+
+> {-# OPTIONS_GHC -Wall #-}
+> {-# OPTIONS_GHC -fno-warn-type-defaults #-}
+> {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+> import Protolude
+> import Control.Monad.Primitive (unsafeInlineIO)
+> import Diagrams.Prelude hiding ((<>))
+> import qualified Control.Foldl as L
+> import qualified Data.Random as R
+> import qualified Data.Map.Strict as Map
+> import qualified Data.Text as Text
+>
+> import Chart.Unit
+
+some test data
+---
+
+Standard normal random variates.  Called ys to distinguish from the horizontal axis of the chart (xs) which are often implicitly [0..]
+
+> ys :: Int -> IO [Double]
+> ys n =
+>   replicateM n $ R.runRVar R.stdNormal R.StdRandom
+>
+
+A bunch of ys, accumulated.
+
+> yss :: (Int, Int) -> [[Double]]
+> yss (n,m) = unsafeInlineIO $ do
+>   yss' <- replicateM m $ ys n
+>   pure $ (drop 1 . L.scan L.sum) <$> yss'
+>
+
+xys is a list of X,Y pairs, correlated normal random variates to add some shape to chart examples.
+
+> rXYs :: Int -> Double -> [(Double,Double)]
+> rXYs n c = unsafeInlineIO $ do
+>   s0 <- replicateM n $ R.runRVar R.stdNormal R.StdRandom
+>   s1 <- replicateM n $ R.runRVar R.stdNormal R.StdRandom
+>   let s1' = zipWith (\x y -> c * x + sqrt (1 - c * c) * y) s0 s1
+>   pure $ zip s0 s1'
+>
+> xys = rXYs 1000 0.8
+>
+
+XY random walk
+
+> rwxy = L.scan (L.Fold (\(x,y) (x',y') -> (x+x',y+y')) (0.0,0.0) identity) (take 100 xys)
+>
+
+xysHist is a histogram of 10000 one-dim random normals.
+
+The data out is a (X,Y) pair list, with mid-point of the bucket as X, and bucket count as Y.
+
+> xysHist :: [(Double,Double)]
+> xysHist = unsafeInlineIO $ do
+>   ys' <- replicateM 10000 $ R.runRVar R.stdNormal R.StdRandom :: IO [Double]
+>   let (f,s,n) = mkTicks' (range1D ys') 100
+>   let cuts = (\x -> f+s*fromIntegral x) <$> [0..n]
+>   let mids = (+(s/2)) <$> cuts
+>   let count = L.Fold (\x a -> Map.insertWith (+) a 1 x) Map.empty identity
+>   let countBool = L.Fold (\x a -> x + if a then 1 else 0) 0 identity
+>   let histMap = L.fold count $ (\x -> L.fold countBool (fmap (x >) cuts)) <$> ys'
+>   let histList = (\x -> Map.findWithDefault 0 x histMap) <$> [0..n]
+>   return (zip mids (fromIntegral <$> histList))
+>
+
+Scale Robustness
+---
+
+xys rendered on the XY plane as dots - a scatter chart with no axes - is invariant to scale.  The data could be multiplied by any scalar, and look exactly the same.
+
+![](other/dots.svg)
+
+Axes break this scale invariance. Ticks and tick labels can hide this to some extent and look almost the same across scales.
+
+![](other/scatter.svg)
+
+This chart will look the same on a data scale change, except for tick magnitudes.
+
+main
+---
+
+>
+> main :: IO ()
+> main = do
+ 
+See develop section below for my workflow.
+
+>   padsvg $
+>       linesXY def [[(0,0),(1,1)],[(0,0),(1,2)]]
+>   fileSvg "other/line.svg" (200,200) $
+>     (lineXY def rwxy)
+>   filePng "other/line.png" (200,200) $
+>     (lineXY def rwxy)
+>   fileSvg "other/lines.svg" (200,200) $
+>     (linesXY def $ zip [0..] <$> yss (1000, 10))
+>   filePng "other/lines.png" (200,200) $
+>     (linesXY def $ zip [0..] <$> yss (1000, 10))
+>   fileSvg "other/dots.svg" (200,200) $
+>     (scatter def xys)
+>   filePng "other/dots.png" (200,200) $
+>     (scatter def xys)
+>   fileSvg "other/scatter.svg" (200,200) $
+>     (scatterXY def xys)
+>   filePng "other/scatter.png" (200,200) $
+>     (scatterXY def xys)
+>   fileSvg "other/bar.svg" (200,200) $
+>     barLabelled def (unsafeInlineIO $ ys 10) (fmap Text.pack <$> take 10 $ (:[]) <$> ['a'..])
+>   filePng "other/bar.png" (200,200) $
+>     barLabelled def (unsafeInlineIO $ ys 10) (fmap Text.pack <$> take 10 $ (:[]) <$> ['a'..])
+>   fileSvg "other/hist.svg" (200,200) $
+>     barRange def xysHist
+>   filePng "other/hist.png" (200,200) $
+>     barRange def xysHist
+
+diagrams development recipe
+---
+
+In constructing new `units`:
+
+- diagrams go from abstract to concrete
+- start with the unitSquare: 4 points, 1x1, origin in the center
+- work out where the origin should be, given the scaling needed.
+- turn the pointful shape into a Trail
+- close the Trail into a SVG-like loop
+- turn the Trail into a QDiagram
+
+You can slide up and down the various diagrams abstraction levels creating transformations at each level.  For example, here's something I use to work at the point level:
+
+> unitp f = unitSquare # f # fromVertices # closeTrail # strokeTrail
+
+workflow
+---
+
+> padsvg :: ChartSvg -> IO ()
+> padsvg t =
+>   fileSvg "other/scratchpad.svg" (400,400) t
+>
+> padpng :: ChartPng -> IO ()
+> padpng t =
+>   filePng "other/scratchpad.png" (400,400) t
+>
+
+Create a markdown version of readme.lhs:
+
+~~~
+pandoc -f markdown+lhs -t html -i readme.lhs -o index.html
+~~~
+
+Then fire up an intero session, and use padq to display coding results on-the-fly, mashing the refresh button on a browser pointed to readme.html.
+
+or go for a compilation loop like:
+
+~~~
+stack install && readme && pandoc -f markdown+lhs -t html -i readme.lhs -o index.html --mathjax --filter pandoc-include && pandoc -f markdown+lhs -t markdown -i readme.lhs -o readme.md --mathjax --filter pandoc-include
+~~~
+
diff --git a/src/Chart/Types.hs b/src/Chart/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Chart/Types.hs
@@ -0,0 +1,137 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Chart.Types where
+
+import Protolude
+import Diagrams.Prelude
+-- import Data.Default
+import Diagrams.Backend.SVG (SVG, renderSVG)
+import Diagrams.Backend.Rasterific (Rasterific, renderRasterific)
+
+type ChartSvg = QDiagram SVG V2 Double Any
+type ChartPng = QDiagram Rasterific V2 Double Any
+
+fileSvg ∷ FilePath → (Double, Double) → ChartSvg → IO ()
+fileSvg f s = renderSVG f (mkSizeSpec (Just <$> r2 s))
+
+filePng ∷ FilePath → (Double,Double) → ChartPng → IO ()
+filePng f s = renderRasterific f (mkSizeSpec (Just <$> r2 s))
+
+rgba :: (Floating a, Ord a) => (a, a, a, a) -> AlphaColour a
+rgba (r,g,b,a) = withOpacity (sRGB (r/255) (g/255) (b/255)) a
+
+data Orientation = X | Y
+
+data Placement = AxisLeft | AxisRight | AxisTop | AxisBottom
+
+data TickStyle = TickNone | TickLabels [Text] | TickNumber Int
+
+data AxisConfig = AxisConfig
+  { _axisOrientation :: Orientation
+  , _axisPlacement :: Placement
+  , _axisHeight :: Double
+  , _axisColor :: AlphaColour Double
+  , _axisMarkSize :: Double -- mark length
+  , _axisMarkColor :: AlphaColour Double
+  , _axisStrutSize :: Double -- distance of label from mark
+  , _axisTextSize :: Double
+  , _axisTextColor :: AlphaColour Double
+  , _axisTickStyle :: TickStyle
+  , _axisAlignedTextRight :: Double
+  , _axisAlignedTextBottom :: Double
+  }
+
+instance Default AxisConfig where
+  def =
+    AxisConfig 
+    X
+    AxisBottom
+    0.02
+    (rgba(94, 19, 94, 0.5))
+    0.02
+    (rgba (0, 102, 200, 0.5))
+    0.02
+    0.04
+    (rgba (30,30,30,0.7))
+    (TickNumber 10)
+    0.5
+    1
+
+makeLenses ''AxisConfig 
+
+data ChartConfig = ChartConfig
+  { _chartPad :: Double
+  , _chartColor :: AlphaColour Double
+  , _chartAxes :: [AxisConfig]
+  }
+
+instance Default ChartConfig where
+  def =
+    ChartConfig
+    1.3
+    (rgba(128, 128, 128, 0.6))
+    [def,
+     axisAlignedTextBottom .~ 0.65 $
+     axisAlignedTextRight .~ 1 $
+     axisOrientation .~ Y $
+     axisPlacement .~ AxisLeft $
+     def]
+
+makeLenses ''ChartConfig
+
+data ScatterConfig = ScatterConfig
+  { _scatterChart :: ChartConfig
+  , _scatterSize :: Double
+  }
+
+instance Default ScatterConfig where
+  def = ScatterConfig (chartColor .~ rgba(128, 128, 128, 0.1) $ def) 0.03
+
+makeLenses ''ScatterConfig
+
+data BarConfig = BarConfig
+  { _barChart :: ChartConfig
+  , _barSep :: Double
+  }
+
+instance Default BarConfig where
+  def = BarConfig (chartColor .~ rgba(59, 89, 152, 0.6) $ def) 0.01
+
+makeLenses ''BarConfig
+
+data LineConfig = LineConfig
+  { _lineChart :: ChartConfig
+  , _lineSize :: Double
+  }
+
+instance Default LineConfig where
+  def = LineConfig (chartColor .~ rgba(59, 89, 152, 0.6) $ def) 0.001
+
+makeLenses ''LineConfig
+
+data OneLine = OneLine
+    { _lColor :: AlphaColour Double
+    , _lSize :: Double
+    }
+
+instance Default OneLine where
+  def = OneLine (rgba(59, 89, 152, 0.6)) 0.001
+
+makeLenses ''OneLine
+
+data LinesConfig = LinesConfig
+  { _linesChart :: ChartConfig
+  , _linesLines :: [OneLine]
+  }
+
+instance Default LinesConfig where
+  def = LinesConfig def [ OneLine (rgba(60,90,150,1)) 0.002
+                        , OneLine (rgba(0,128,255,1)) 0.002
+                        , OneLine (rgba(255,128,0,1)) 0.002
+                        , OneLine (rgba(128,0,255,1)) 0.002
+                        , OneLine (rgba(0,255,255,1)) 0.002
+                        ]
+
+makeLenses ''LinesConfig
diff --git a/src/Chart/Unit.hs b/src/Chart/Unit.hs
new file mode 100644
--- /dev/null
+++ b/src/Chart/Unit.hs
@@ -0,0 +1,275 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+
+module Chart.Unit (
+    range1D,
+    range1Ds,
+    unit,
+    units,
+    unitXY,
+    unitsXY,
+    chartXY,
+    scatter,
+    scatterXY,
+    barRange,
+    barLabelled,
+    bars,
+    line,
+    lines,
+    lineXY,
+    linesXY,
+    axisXY,
+    -- toFile,
+    mkTicks,
+    mkTicks',
+    module Chart.Types,
+    module Control.Lens,
+    module Data.Default
+) where
+
+import Chart.Types
+import qualified Control.Foldl as L
+import Control.Lens hiding (beside, none, (#))
+import Data.Default (def)
+import qualified Data.Text as Text
+import Diagrams.Prelude hiding (unit) 
+import Protolude hiding (min,max)
+import Text.Printf
+import qualified Diagrams.TwoD.Text
+
+range1D :: (Fractional t, Ord t, Foldable f) => f t -> (t, t)
+range1D = L.fold (L.Fold step initial extract)
+  where
+    step Nothing x = Just (x,x)
+    step (Just (min,max)) x =
+      Just (min' x min, max' x max)
+    max' x1 x2 = if x1 > x2 then x1 else x2
+    min' x1 x2 = if x1 < x2 then x1 else x2
+    initial = Nothing
+    extract = fromMaybe (-0.5,0.5)
+
+range1Ds :: (Fractional t, Ord t, Foldable f, Foldable f') => f' (f t) -> (t, t)
+range1Ds xss = L.fold (L.Fold step initial extract) xss
+  where
+    step Nothing x = Just (range1D x)
+    step (Just (min, max)) x =
+      Just (min', max')
+      where
+        (min'', max'') = range1D x
+        min' = if min'' < min then min'' else min
+        max' = if max'' > max then max'' else max
+    initial = Nothing
+    extract = fromMaybe (-0.5,0.5)
+
+-- unit scales and translates to a [-0.5,0.5] range
+unit :: (Fractional b, Functor f, Ord b, Foldable f) => f b -> f b
+unit xs =
+  let (minX,maxX) = range1D xs in
+  (\x -> (x-minX)/(maxX-minX) - 0.5) <$> xs
+
+-- units scales multiple xs to a common range
+units :: (Fractional b, Functor f, Ord b, Foldable f, Functor f', Foldable f') =>
+    f' (f b) -> f' (f b)
+units xss =
+  let (minX,maxX) = range1Ds xss in
+  (fmap (\x -> (x-minX)/(maxX-minX) - 0.5)) <$> xss
+
+-- scale 2d points (XY) to ((-0.5,-0.5), (0.5,0.5))
+unitXY :: (Fractional b, Fractional a, Ord b, Ord a) => [(a, b)] -> [(a, b)]
+unitXY xys = zip (unit $ fst <$> xys) (unit $ snd <$> xys)
+
+-- scale multiple 2d series
+unitsXY :: (Fractional a, Ord a, Fractional b, Ord b) => [[(a, b)]] -> [[(a, b)]]
+unitsXY xyss = zipWith (\x y -> zip x y) xs' ys'
+  where
+    xs = fmap fst <$> xyss
+    ys = fmap snd <$> xyss
+    xs' = units xs
+    ys' = units ys
+
+chartXY :: (Renderable (Path V2 Double) a, (Renderable (Diagrams.TwoD.Text.Text Double) a)) => ChartConfig
+  -> ([(Double, Double)] -> QDiagram a V2 Double Any)
+  -> [(Double, Double)]
+  -> QDiagram a V2 Double Any
+chartXY (ChartConfig p _ axes) chart xys =
+  L.fold (L.Fold step (chart xys) (pad p)) axes
+  where
+    step x a =
+      beside (v (a ^. axisPlacement))
+      x
+      (axisXY a (d (a ^. axisOrientation)))
+
+    v AxisBottom = r2 (0,-1)
+    v AxisTop = r2 (0,1)
+    v AxisLeft = r2 (-1,0)
+    v AxisRight = r2 (1,0)
+
+    d X = range1D $ fst <$> xys
+    d Y = range1D $ snd <$> xys
+
+-- axis rendering
+axisXY :: ((Renderable (Diagrams.TwoD.Text.Text Double) a), Renderable (Path V2 Double) a) => AxisConfig -> (Double,Double) -> QDiagram a V2 Double Any
+axisXY cfg range = centerXY $
+  atPoints
+    (p2 . t <$> tickLocations)
+    ((\x -> mkLabel x cfg) <$> tickLabels)
+  `atop`
+  (axisRect (cfg ^. axisHeight) (-0.5,0.5)
+   # unitRect (cfg ^. axisColor))
+  where
+    t = case cfg ^. axisOrientation of
+      X -> \x -> (x,0)
+      Y -> \y -> (-(cfg ^. axisMarkSize), y)
+    tickLocations = case cfg ^. axisTickStyle of
+      TickNone -> []
+      TickNumber n -> unit $ mkTicks range n
+      TickLabels ls -> unit $ fromIntegral <$> [1..length ls]
+    tickLabels = case cfg ^. axisTickStyle of
+      TickNone -> []
+      TickNumber n -> Text.pack . printf "%7.1g" <$> mkTicks range n
+      TickLabels ls -> ls
+    axisRect h (min, max) = case cfg ^. axisOrientation of
+      X -> moveTo (p2 (max,0)) .
+          strokeTrail .
+          closeTrail .
+          fromVertices .
+          scaleX (max-min) .
+          scaleY h $
+          unitSquare
+      Y -> moveTo (p2 (0,min)) .
+          strokeTrail .
+          closeTrail .
+          fromVertices .
+          scaleY (max-min) .
+          scaleX h $
+          unitSquare
+
+-- somewhat a base class of a wide variety of chart marks
+unitRect ∷ (Floating (N a), Ord (N a), Typeable (N a), HasStyle a, V a ~ V2) ⇒
+    AlphaColour Double → a → a
+unitRect c = fcA c # lcA (withOpacity black 0) # lw none
+
+-- polymorphic dots
+scatter :: (Typeable (N r), Monoid r, Semigroup r, Transformable r,HasStyle r, HasOrigin r, TrailLike r, V r ~ V2, N r ~ Double) =>
+    ScatterConfig -> [(N r, N r)] -> r
+scatter cfg xys =
+  atPoints (p2 <$> unitXY xys)
+    (repeat $ circle (cfg ^. scatterSize) #
+     unitRect (cfg ^. scatterChart ^. chartColor)
+    )
+
+scatterXY :: (Renderable (Path V2 Double) a, (Renderable (Diagrams.TwoD.Text.Text Double) a)) => ScatterConfig -> [(Double,Double)] -> QDiagram a V2 Double Any
+scatterXY cfg xys =
+  chartXY (cfg ^. scatterChart) (scatter cfg) xys
+
+-- bar
+bars :: (Renderable (Path V2 Double) a) => BarConfig -> [Double] -> QDiagram a V2 Double Any
+bars cfg ys =
+  cat' (r2 (1,0)) (with Diagrams.Prelude.& sep .~ cfg ^. barSep)
+  ((\y ->
+    unitSquare
+    # moveOriginTo (p2 (-0.5,-0.5))
+    # if y==0 then scaleY epsilon else scaleY y) <$> ys)
+    # unitRect (cfg ^. barChart ^. chartColor)
+    # centerXY
+    # scaleX (1/fromIntegral (length ys)) # scaleY (1/(max-min))
+  where
+    (min,max) = range1D ys
+    epsilon = 1e-8
+
+barRange :: (Renderable (Path V2 Double) a, (Renderable (Diagrams.TwoD.Text.Text Double) a)) => BarConfig -> [(Double, Double)] -> QDiagram a V2 Double Any
+barRange cfg xys = chartXY (cfg ^. barChart) (\x -> bars cfg (snd <$> x)) xys
+
+barLabelled :: (Renderable (Path V2 Double) a, (Renderable (Diagrams.TwoD.Text.Text Double) a)) => BarConfig -> [Double] -> [Text] -> QDiagram a V2 Double Any
+barLabelled cfg ys labels = barRange
+     ( barChart . chartAxes .~
+       [ axisTickStyle .~
+         TickLabels labels $ def
+       ]
+       $ cfg
+     ) (zip [0..] ys)
+
+-- a line is just a scatter chart rendered with a line (and with a usually stable x-value series)
+line :: (Renderable (Path V2 Double) a) => [(Double,Double)] -> QDiagram a V2 Double Any
+line xys = strokeT $ trailFromVertices $ p2 <$> unitXY xys
+
+lineXY :: (Renderable (Path V2 Double) a, (Renderable (Diagrams.TwoD.Text.Text Double) a)) => LineConfig -> [(Double,Double)] -> QDiagram a V2 Double Any
+lineXY cfg xys =
+    chartXY (cfg ^. lineChart)
+    (\x -> line x # centerXY # lcA (cfg ^. lineChart ^. chartColor) # lwN (cfg ^. lineSize))
+    xys
+
+-- multiple lines with a common range for both x and y values
+lines :: (Renderable (Path V2 Double) a) => LinesConfig -> [[(Double,Double)]] -> QDiagram a V2 Double Any
+lines cfg xyss = centerXY $ mconcat $
+    zipWith (\d c -> d # lcA (c ^. lColor) # lwN (c ^. lSize))
+    (l xyss)
+    (cycle $ cfg ^.linesLines)
+  where
+    l xyss' = strokeT . trailFromVertices . fmap p2 <$> unitsXY xyss'
+
+linesXY :: ((Renderable (Diagrams.TwoD.Text.Text Double) a), Renderable (Path V2 Double) a) =>
+  LinesConfig
+  -> [[(Double, Double)]]
+  -> QDiagram a V2 Double Any
+linesXY cfg@(LinesConfig (ChartConfig p _ axes) _) xyss =
+  L.fold (L.Fold step (lines cfg xyss) (pad p)) axes
+  where
+    step x a =
+      beside (v (a ^. axisPlacement))
+      x
+      (axisXY a (d (a ^. axisOrientation)))
+
+    v AxisBottom = r2 (0,-1)
+    v AxisTop = r2 (0,1)
+    v AxisLeft = r2 (-1,0)
+    v AxisRight = r2 (1,0)
+
+    d X = range1Ds $ fmap fst <$> xyss
+    d Y = range1Ds $ fmap snd <$> xyss
+
+
+mkTicks :: (Double,Double) -> Int -> [Double]
+mkTicks r n = (f +) . (s *) . fromIntegral <$> [0..n']
+  where
+    (f,s,n') = mkTicks' r n
+
+mkTicks' :: (Double,Double) -> Int -> (Double, Double, Int)
+mkTicks' (min, max) n = (f, step', n')
+  where
+    span' = max - min
+    step' = 10 ^^ floor (logBase 10 (span'/fromIntegral n))
+    err = fromIntegral n / span' * step'
+    step
+      | err <= 0.15 = 10 * step'
+      | err <= 0.35 = 5 * step'
+      | err <= 0.75 = 2 * step'
+      | otherwise = step'
+    f = step * fromIntegral (floor (min/step))
+    l = step * fromIntegral (floor (max/step))
+    n' = round ((l - f)/step)
+
+mkLabel :: ((Renderable (Diagrams.TwoD.Text.Text Double) a), Renderable (Path V2 Double) a) => Text -> AxisConfig -> QDiagram a V2 Double Any
+mkLabel label cfg =
+  beside dir
+  (beside dir
+   (rule (cfg ^. axisMarkSize) #
+   lcA (cfg ^. axisMarkColor))
+    s)
+  (Diagrams.Prelude.alignedText
+    (cfg ^. axisAlignedTextRight)
+    (cfg ^. axisAlignedTextBottom)
+    (Text.unpack label) #
+  scale (cfg ^. axisTextSize) #
+  fcA (cfg ^.axisTextColor))
+  where
+    dir = case cfg ^. axisOrientation of
+      X -> r2 (0,-1)
+      Y -> r2 (-1,0)
+    rule = case cfg ^. axisOrientation of
+      X -> vrule
+      Y -> hrule
+    s = case cfg ^. axisOrientation of
+      X -> strutY (cfg ^. axisStrutSize)
+      Y -> strutX (cfg ^. axisStrutSize)
+
