module Graphics.Rendering.Plot.Light.PlotTypes.Scatter where import Graphics.Rendering.Plot.Light.Internal import Graphics.Rendering.Plot.Light.Internal.Utils import Data.Fixed import Data.Maybe (fromMaybe) import Control.Monad (forM_) import Text.Blaze.Svg import Text.Blaze.Svg.Renderer.String (renderSvg) import qualified Data.Colour as C -- import qualified Data.Colour.Palette.BrewerSet as CP import qualified Data.Colour.Names as C import qualified Data.Text as T import qualified Data.Text.IO as T -- | Scatter plot -- -- Every point in the plot has the same parameters, as declared in the `ScatterPointData` record scatter :: (Foldable t, Show a, RealFrac a) => ScatterPointData a -> t (Point a) -> Svg scatter (ScatterPointData glshape w sw fcol alpha) ps = forM_ ps $ glyph w sw glshape fcol alpha -- | Parametric scatter plot -- -- The parameters of every point in the scatter plot are modulated according to the label, using the three functions. -- -- This can be used to produce rich infographics, in which e.g. the colour and size of the glyphs carry additional information. scatterLP :: (Foldable t, RealFrac a, Show a) => (l -> b -> a) -- ^ Modifies the glyph size -> (l -> b -> a) -- ^ Modifies the glyph stroke width -> (l -> C.Colour Double -> C.Colour Double) -- ^ Modifies the glyph colour -> (l -> b -> a) -- ^ Modifies the glyph opacity -> ScatterPointData b -- ^ Glyph style defaults -> t (LabeledPoint l a) -- ^ Data -> Svg scatterLP f g h i spdat lps = forM_ lps (scatterLP1 f g h i spdat) scatterLP1 :: (Show a, RealFrac a) => (l -> b -> a) -- ^ Modifies the glyph size -> (l -> b -> a) -- ^ Modifies the glyph stroke width -> (l -> C.Colour Double -> C.Colour Double) -- ^ Modifies the glyph colour -> (l -> b -> a) -- ^ Modifies the glyph opacity -> ScatterPointData b -> LabeledPoint l a -> Svg scatterLP1 f g h i spdat lp = glyph w' sw' sh col' a' (_lp lp) where ScatterPointData sh w' sw' col' a' = modifyScatterPoint f g h i spdat lp scatterLPBar :: (RealFrac t, Enum t, RealFrac b, Show b) => FigureData b -> b -- ^ Legend width -> t -- ^ Data value lower bound -> t -- ^ Data value upper bound -> Int -- ^ Number of legend entries -> LegendPosition_ -- ^ Legend position in the figure -> b -- ^ Legend length -> (t -> b -> b) -- ^ Modifies the glyph size -> (t -> b -> b) -- ^ Modifies the glyph stroke width -> (t -> C.Colour Double -> C.Colour Double) -- ^ Modifies the glyph colour -> (t -> b -> b) -- ^ Modifies the glyph opacity -> ScatterPointData b -- ^ Glyph style defaults -> Svg scatterLPBar fdat w vmin vmax n legpos legh f g h i spdat = legendBar fdat w vmin vmax n legpos legh fun where wglyph = spSize spdat fun _ _ _ _ _ lp@(LabeledPoint p val) = do scatterLP1 f g h i spdat lp text 0 (figLabelFontSize fdat) C.black TAStart (T.pack $ show (rr val :: Fixed E3)) (V2 (2 * wglyph) (0.5 * wglyph)) p -- | Parameters for a scatterplot glyph data ScatterPointData a = ScatterPointData { spGlyphShape :: GlyphShape_ -- ^ Glyph shape , spSize :: a -- ^ Glyph size , spStrokeWidth :: a -- ^ Glyph stroke width , spColour :: C.Colour Double -- ^ Glyph colour , spAlpha :: a -- ^ Glyph opacity } deriving (Eq, Show) modifyScatterPoint :: (l -> b -> c) -- ^ Modifies glyph size -> (l -> b -> c) -- ^ Modifies glyph stroke width -> (l -> C.Colour Double -> C.Colour Double) -- ^ Modifies glyph colour -> (l -> b -> c) -- ^ Modifies glyph opacity -> ScatterPointData b -> LabeledPoint l d -> ScatterPointData c modifyScatterPoint f g h i (ScatterPointData glsh sz w col alpha) lp = ScatterPointData glsh (f lab sz) (g lab w) (h lab col) (i lab alpha) where lab = _lplabel lp -- | Glyph shape data GlyphShape_ = Square | Circle | Cross | Plus deriving (Eq, Show, Enum) -- | Scatterplot glyph shapes glyph :: (Show a, RealFrac a) => a -- ^ Width -> a -- ^ Stroke width -> GlyphShape_ -- ^ Glyph shape -> C.Colour Double -- ^ Glyph colour -> a -- ^ Opacity -> Point a -- ^ Position -> Svg glyph w sw sh col alpha p = let cf = shapeColNoBorder col alpha in case sh of Square -> squareCentered w cf p Circle -> circle w cf p Cross -> crossGlyph w sw col p Plus -> plusGlyph w sw col p -- -- | Utility function for cycling glyph colours and shapes (i.e. unique combinations of these make it easy to tell different datasets apart) -- cycleGlyphCols :: (CP.ColorCat, Int) -> Int -> [(CP.Kolor, GlyphShape_)] -- cycleGlyphCols (pal, n) nsets = take nsets $ zip (cycle $ CP.brewerSet pal n ) (cycle [Square, Circle ..])