chart-unit-0.5.1: src/Chart/Glyph.hs
{-# OPTIONS_GHC -Wall #-}
-- | Glyphs are (typically) small shapes symbolically representing a data point.
module Chart.Glyph
( GlyphOptions(..)
, hline_
, vline_
, glyph_
, glyphs
, lglyphs
, glyphChart
, glyphChart_
, lglyphChart
, lglyphChart_
, circle
, square
, triangle
) where
import Chart.Core
import Chart.Text
import Diagrams.Prelude hiding (Color, D, scaleX, scaleY)
import NumHask.Pair
import NumHask.Prelude hiding (shape)
import NumHask.Rect
-- | The actual shape of a glyph can be any Chart element
data GlyphOptions b = GlyphOptions
{ glyphSize :: Double -- ^ glyph radius
, glyphColor :: AlphaColour Double
, glyphBorderColor :: AlphaColour Double
, glyphBorderSize :: Double -- ^ normalized
, glyphShape :: Double -> Chart b
}
instance Default (GlyphOptions b) where
def = GlyphOptions 0.03 ublue ugrey 0.015 circle
-- | Vertical line glyph shape with a reasonable thickness at "vline_ 1"
vline_ :: Double -> Double -> Chart b
vline_ fatness x = vrule x # scaleX (1.6 / 0.5 * fatness)
-- | Horizontal line glyph shape with a reasonable thickness as "hline_ 1"
hline_ :: Double -> Double -> Chart b
hline_ fatness x = hrule x # scaleY (1.6 / 0.5 * fatness)
-- | Create a glyph.
--
-- > let glyph_Example = glyph_ def
--
-- 
--
glyph_ :: GlyphOptions b -> Chart b
glyph_ (GlyphOptions s c bc bs shape) = shape s # fcA c # lcA bc # lwN bs
-- | Create positioned glyphs.
--
-- > let ps = [Pair (x/10) ((sin x)/10) | x<-[0..10]]
-- > glyphs def ps
--
-- 
--
glyphs :: (R2 r, Traversable f) => GlyphOptions b -> f (r Double) -> Chart b
glyphs opts xs = mconcat $ toList $ (\x -> positioned x (glyph_ opts)) <$> xs
-- | A chart of glyphs
glyphChart ::
(Traversable f)
=> [GlyphOptions b]
-> Aspect
-> Rect Double
-> [f (Pair Double)]
-> Chart b
glyphChart optss (Aspect asp) r xyss =
mconcat $ zipWith glyphs optss (projectss r asp xyss)
-- | A chart of glyphs scaled to its own range
--
-- > let gopts = [def,def {glyphBorderColor=withOpacity red 0.2, glyphShape=triangle}]
-- > let p_1 = [Pair x (sin (x/10)) | x<-[0..100]]
-- > let p_2 = [Pair x (cos (x/10)) | x<-[0..100]]
-- > glyphChart_ gopts widescreen [p_1,p_2]
--
-- 
--
glyphChart_ ::
(Traversable f)
=> [GlyphOptions b]
-> Aspect
-> [f (Pair Double)]
-> Chart b
glyphChart_ optss asp xyss = glyphChart optss asp (range xyss) xyss
-- | Create labelled, positioned glyphs.
--
-- > lglyphs def def $ zip (show <$> [0..]) ps
--
-- 
--
lglyphs ::
(R2 r, Traversable f)
=> LabelOptions
-> GlyphOptions b
-> f (Text, r Double)
-> Chart b
lglyphs lopts gopts xs =
mconcat $
toList $ (\(t, x) -> moveTo (p_ x) $ labelled lopts t (glyph_ gopts)) <$> xs
-- | A chart of labelled glyphs
lglyphChart ::
(Traversable f)
=> [LabelOptions]
-> [GlyphOptions b]
-> Aspect
-> Rect Double
-> [f (Text, Pair Double)]
-> Chart b
lglyphChart ls gs (Aspect asp) r xyss =
mconcat $
getZipList $
lglyphs <$> ZipList ls <*> ZipList gs <*>
ZipList
(zipWith
zip
(map fst . toList <$> xyss)
(projectss r asp (map snd . toList <$> xyss)))
-- | A chart of labelled glyphs scaled to its own range
--
-- > let g = Pair <$> [0..5] <*> [0..5] :: [Pair Int]
-- > let xs = [(\(p@(Pair x y)) -> ((show x <> "," <> show y), fromIntegral <$> p)) <$> g]
-- > lglyphChart_ [def {labelGap=0.01}] [def] sixbyfour xs
--
-- 
--
lglyphChart_ ::
(Traversable f)
=> [LabelOptions]
-> [GlyphOptions b]
-> Aspect
-> [f (Text, Pair Double)]
-> Chart b
lglyphChart_ ls gs asp xyss =
lglyphChart ls gs asp (range (map snd . toList <$> xyss)) xyss