{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoFieldSelectors #-}
module DataFrame.Display.Terminal.Plot (
Agg (..),
Bar (..),
mkBar,
bar,
Histogram (..),
mkHistogram,
histogram,
Scatter (..),
mkScatter,
scatter,
Line (..),
mkLine,
line,
Pie (..),
mkPie,
pie,
Box (..),
mkBox,
box,
heatmap,
correlationMatrix,
plotHistogram,
plotScatter,
plotBars,
plotLines,
plotPie,
plotBoxPlots,
plotStackedBars,
plotHeatmap,
extractNumericColumn,
extractStringColumn,
) where
import Control.Monad (forM)
import qualified Data.List as L
import qualified Data.Text as T
import qualified Data.Text.IO as T
import GHC.Stack (HasCallStack)
import DataFrame.Display.Internal.Common (
Agg (..),
aggLabel,
aggregateByGroup,
extractNumericColumn,
extractStringColumn,
groupWithOther,
groupWithOtherForPie,
isNumericColumn,
)
import DataFrame.Internal.DataFrame (DataFrame (..), columnNames)
import Granite (Plot, defPlot)
import qualified Granite
data Bar = Bar
{ Bar -> Text
x :: T.Text
, Bar -> Maybe Text
y :: Maybe T.Text
, Bar -> Agg
agg :: Agg
, Bar -> Maybe Int
topN :: Maybe Int
, Bar -> Maybe Text
title :: Maybe T.Text
, Bar -> Plot
plot :: Plot
}
mkBar :: T.Text -> Bar
mkBar :: Text -> Bar
mkBar Text
c =
Bar
{ x :: Text
x = Text
c
, y :: Maybe Text
y = Maybe Text
forall a. Maybe a
Nothing
, agg :: Agg
agg = Agg
Sum
, topN :: Maybe Int
topN = Maybe Int
forall a. Maybe a
Nothing
, title :: Maybe Text
title = Maybe Text
forall a. Maybe a
Nothing
, plot :: Plot
plot = Plot
defPlot
}
bar :: (HasCallStack) => Bar -> DataFrame -> IO ()
bar :: HasCallStack => Bar -> DataFrame -> IO ()
bar Bar
spec DataFrame
df = do
let effectiveAgg :: Agg
effectiveAgg = case Bar
spec.y of
Maybe Text
Nothing -> Agg
Count
Just Text
_ -> Bar
spec.agg
rows :: [(Text, Double)]
rows = HasCallStack =>
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
aggregateByGroup Agg
effectiveAgg Bar
spec.x Bar
spec.y DataFrame
df
rows' :: [(Text, Double)]
rows' = [(Text, Double)]
-> (Int -> [(Text, Double)]) -> Maybe Int -> [(Text, Double)]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [(Text, Double)]
rows (Int -> [(Text, Double)] -> [(Text, Double)]
`groupWithOther` [(Text, Double)]
rows) Bar
spec.topN
t :: Text
t = case Bar
spec.title of
Just Text
s -> Text
s
Maybe Text
Nothing -> Agg -> Maybe Text -> Text -> Text
autoTitle Agg
effectiveAgg Bar
spec.y Bar
spec.x
cfg :: Plot
cfg = Bar
spec.plot{Granite.plotTitle = t}
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, Double)] -> Plot -> Text
Granite.bars [(Text, Double)]
rows' Plot
cfg
data Histogram = Histogram
{ Histogram -> Text
x :: T.Text
, Histogram -> Int
bins :: Int
, Histogram -> Maybe Text
title :: Maybe T.Text
, Histogram -> Plot
plot :: Plot
}
mkHistogram :: T.Text -> Histogram
mkHistogram :: Text -> Histogram
mkHistogram Text
c =
Histogram
{ x :: Text
x = Text
c
, bins :: Int
bins = Int
30
, title :: Maybe Text
title = Maybe Text
forall a. Maybe a
Nothing
, plot :: Plot
plot = Plot
defPlot
}
histogram :: (HasCallStack) => Histogram -> DataFrame -> IO ()
histogram :: HasCallStack => Histogram -> DataFrame -> IO ()
histogram Histogram
spec DataFrame
df = do
let values :: [Double]
values = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Histogram
spec.x DataFrame
df
(Double
lo, Double
hi) = if [Double] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Double]
values then (Double
0, Double
1) else ([Double] -> Double
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Double]
values, [Double] -> Double
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Double]
values)
t :: Text
t = case Histogram
spec.title of
Just Text
s -> Text
s
Maybe Text
Nothing -> Text
"histogram of " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Histogram
spec.x
cfg :: Plot
cfg = Histogram
spec.plot{Granite.plotTitle = t}
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ Bins -> [Double] -> Plot -> Text
Granite.histogram (Int -> Double -> Double -> Bins
Granite.bins Histogram
spec.bins Double
lo Double
hi) [Double]
values Plot
cfg
data Scatter = Scatter
{ Scatter -> Text
x :: T.Text
, Scatter -> Text
y :: T.Text
, Scatter -> Maybe Text
color :: Maybe T.Text
, Scatter -> Maybe Text
title :: Maybe T.Text
, Scatter -> Plot
plot :: Plot
}
mkScatter :: T.Text -> T.Text -> Scatter
mkScatter :: Text -> Text -> Scatter
mkScatter Text
xc Text
yc =
Scatter
{ x :: Text
x = Text
xc
, y :: Text
y = Text
yc
, color :: Maybe Text
color = Maybe Text
forall a. Maybe a
Nothing
, title :: Maybe Text
title = Maybe Text
forall a. Maybe a
Nothing
, plot :: Plot
plot = Plot
defPlot
}
scatter :: (HasCallStack) => Scatter -> DataFrame -> IO ()
scatter :: HasCallStack => Scatter -> DataFrame -> IO ()
scatter Scatter
spec DataFrame
df = do
let t :: Text
t = case Scatter
spec.title of
Just Text
s -> Text
s
Maybe Text
Nothing -> Scatter
spec.x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" vs " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Scatter
spec.y
cfg :: Plot
cfg = Scatter
spec.plot{Granite.plotTitle = t}
xVals :: [Double]
xVals = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Scatter
spec.x DataFrame
df
yVals :: [Double]
yVals = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Scatter
spec.y DataFrame
df
case Scatter
spec.color of
Maybe Text
Nothing ->
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, [(Double, Double)])] -> Plot -> Text
Granite.scatter [(Scatter
spec.x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" vs " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Scatter
spec.y, [Double] -> [Double] -> [(Double, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Double]
xVals [Double]
yVals)] Plot
cfg
Just Text
grp -> do
let groupVals :: [Text]
groupVals = HasCallStack => Text -> DataFrame -> [Text]
Text -> DataFrame -> [Text]
extractStringColumn Text
grp DataFrame
df
triples :: [(Text, Double, Double)]
triples = [Text] -> [Double] -> [Double] -> [(Text, Double, Double)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [Text]
groupVals [Double]
xVals [Double]
yVals
uniqGroups :: [Text]
uniqGroups = [Text] -> [Text]
forall a. Eq a => [a] -> [a]
L.nub [Text]
groupVals
series :: [(Text, [(Double, Double)])]
series =
[ (Text
g, [(Double
xv, Double
yv) | (Text
gv, Double
xv, Double
yv) <- [(Text, Double, Double)]
triples, Text
gv Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
g])
| Text
g <- [Text]
uniqGroups
]
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, [(Double, Double)])] -> Plot -> Text
Granite.scatter [(Text, [(Double, Double)])]
series Plot
cfg
data Line = Line
{ Line -> Text
x :: T.Text
, Line -> [Text]
y :: [T.Text]
, Line -> Maybe Text
title :: Maybe T.Text
, Line -> Plot
plot :: Plot
}
mkLine :: T.Text -> [T.Text] -> Line
mkLine :: Text -> [Text] -> Line
mkLine Text
xc [Text]
ys =
Line
{ x :: Text
x = Text
xc
, y :: [Text]
y = [Text]
ys
, title :: Maybe Text
title = Maybe Text
forall a. Maybe a
Nothing
, plot :: Plot
plot = Plot
defPlot
}
line :: (HasCallStack) => Line -> DataFrame -> IO ()
line :: HasCallStack => Line -> DataFrame -> IO ()
line Line
spec DataFrame
df = do
let t :: Text
t = case Line
spec.title of
Just Text
s -> Text
s
Maybe Text
Nothing -> case Line
spec.y of
[Text
single] -> Text
single Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" over " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Line
spec.x
[Text]
_ -> Text -> [Text] -> Text
T.intercalate Text
", " Line
spec.y Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" over " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Line
spec.x
cfg :: Plot
cfg = Line
spec.plot{Granite.plotTitle = t}
xVals :: [Double]
xVals = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Line
spec.x DataFrame
df
[(Text, [(Double, Double)])]
seriesData <- [Text]
-> (Text -> IO (Text, [(Double, Double)]))
-> IO [(Text, [(Double, Double)])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM Line
spec.y ((Text -> IO (Text, [(Double, Double)]))
-> IO [(Text, [(Double, Double)])])
-> (Text -> IO (Text, [(Double, Double)]))
-> IO [(Text, [(Double, Double)])]
forall a b. (a -> b) -> a -> b
$ \Text
col -> do
let values :: [Double]
values = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Text
col DataFrame
df
(Text, [(Double, Double)]) -> IO (Text, [(Double, Double)])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
col, [Double] -> [Double] -> [(Double, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Double]
xVals [Double]
values)
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, [(Double, Double)])] -> Plot -> Text
Granite.lineGraph [(Text, [(Double, Double)])]
seriesData Plot
cfg
data Pie = Pie
{ Pie -> Text
values :: T.Text
, Pie -> Maybe Text
names :: Maybe T.Text
, Pie -> Agg
agg :: Agg
, Pie -> Maybe Int
topN :: Maybe Int
, Pie -> Maybe Text
title :: Maybe T.Text
, Pie -> Plot
plot :: Plot
}
mkPie :: T.Text -> Pie
mkPie :: Text -> Pie
mkPie Text
c =
Pie
{ values :: Text
values = Text
c
, names :: Maybe Text
names = Maybe Text
forall a. Maybe a
Nothing
, agg :: Agg
agg = Agg
Count
, topN :: Maybe Int
topN = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
8
, title :: Maybe Text
title = Maybe Text
forall a. Maybe a
Nothing
, plot :: Plot
plot = Plot
defPlot
}
pie :: (HasCallStack) => Pie -> DataFrame -> IO ()
pie :: HasCallStack => Pie -> DataFrame -> IO ()
pie Pie
spec DataFrame
df = do
let vCol :: Text
vCol = Pie
spec.values
mNames :: Maybe Text
mNames = Pie
spec.names
a :: Agg
a = Pie
spec.agg
t :: Text
t = case Pie
spec.title of
Just Text
s -> Text
s
Maybe Text
Nothing -> case Maybe Text
mNames of
Just Text
n -> Agg -> Text
aggLabel Agg
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"(" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
vCol Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
") by " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
n
Maybe Text
Nothing -> Agg -> Text
aggLabel Agg
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" of " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
vCol
cfg :: Plot
cfg = Pie
spec.plot{Granite.plotTitle = t}
rows :: [(Text, Double)]
rows = case (Agg
a, Maybe Text
mNames) of
(Agg
Count, Maybe Text
Nothing) -> HasCallStack =>
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
aggregateByGroup Agg
Count Text
vCol Maybe Text
forall a. Maybe a
Nothing DataFrame
df
(Agg
Count, Just Text
n) -> HasCallStack =>
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
aggregateByGroup Agg
Count Text
n Maybe Text
forall a. Maybe a
Nothing DataFrame
df
(Agg
_, Maybe Text
Nothing) ->
let xs :: [Double]
xs = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Text
vCol DataFrame
df
in [Text] -> [Double] -> [(Text, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [[Char] -> Text
T.pack ([Char]
"Item " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
i) | Int
i <- [Int
1 .. [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs :: Int]] [Double]
xs
(Agg
_, Just Text
n) -> HasCallStack =>
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
aggregateByGroup Agg
a Text
n (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
vCol) DataFrame
df
rows' :: [(Text, Double)]
rows' = [(Text, Double)]
-> (Int -> [(Text, Double)]) -> Maybe Int -> [(Text, Double)]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [(Text, Double)]
rows (Int -> [(Text, Double)] -> [(Text, Double)]
`groupWithOtherForPie` [(Text, Double)]
rows) Pie
spec.topN
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, Double)] -> Plot -> Text
Granite.pie [(Text, Double)]
rows' Plot
cfg
data Box = Box
{ Box -> [Text]
y :: [T.Text]
, Box -> Maybe Text
title :: Maybe T.Text
, Box -> Plot
plot :: Plot
}
mkBox :: [T.Text] -> Box
mkBox :: [Text] -> Box
mkBox [Text]
ys =
Box
{ y :: [Text]
y = [Text]
ys
, title :: Maybe Text
title = Maybe Text
forall a. Maybe a
Nothing
, plot :: Plot
plot = Plot
defPlot
}
box :: (HasCallStack) => Box -> DataFrame -> IO ()
box :: HasCallStack => Box -> DataFrame -> IO ()
box Box
spec DataFrame
df = do
let t :: Text
t = case Box
spec.title of
Just Text
s -> Text
s
Maybe Text
Nothing -> Text
"box plot of " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
", " Box
spec.y
cfg :: Plot
cfg = Box
spec.plot{Granite.plotTitle = t}
[(Text, [Double])]
boxData <- [Text] -> (Text -> IO (Text, [Double])) -> IO [(Text, [Double])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM Box
spec.y ((Text -> IO (Text, [Double])) -> IO [(Text, [Double])])
-> (Text -> IO (Text, [Double])) -> IO [(Text, [Double])]
forall a b. (a -> b) -> a -> b
$ \Text
col -> (Text, [Double]) -> IO (Text, [Double])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
col, HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Text
col DataFrame
df)
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, [Double])] -> Plot -> Text
Granite.boxPlot [(Text, [Double])]
boxData Plot
cfg
heatmap :: (HasCallStack) => DataFrame -> IO ()
heatmap :: HasCallStack => DataFrame -> IO ()
heatmap DataFrame
df = do
let numericCols :: [Text]
numericCols = (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (DataFrame -> Text -> Bool
isNumericColumn DataFrame
df) (DataFrame -> [Text]
columnNames DataFrame
df)
matrix :: [[Double]]
matrix = (Text -> [Double]) -> [Text] -> [[Double]]
forall a b. (a -> b) -> [a] -> [b]
map (HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
`extractNumericColumn` DataFrame
df) [Text]
numericCols
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [[Double]] -> Plot -> Text
Granite.heatmap [[Double]]
matrix Plot
defPlot
correlationMatrix :: (HasCallStack) => DataFrame -> IO ()
correlationMatrix :: HasCallStack => DataFrame -> IO ()
correlationMatrix DataFrame
df = do
let numericCols :: [Text]
numericCols = (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (DataFrame -> Text -> Bool
isNumericColumn DataFrame
df) (DataFrame -> [Text]
columnNames DataFrame
df)
cols :: [[Double]]
cols = (Text -> [Double]) -> [Text] -> [[Double]]
forall a b. (a -> b) -> [a] -> [b]
map (HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
`extractNumericColumn` DataFrame
df) [Text]
numericCols
correlations :: [[Double]]
correlations =
[ [[Double] -> [Double] -> Double
forall {a}. Floating a => [a] -> [a] -> a
corr [Double]
xs [Double]
ys | [Double]
ys <- [[Double]]
cols]
| [Double]
xs <- [[Double]]
cols
]
[(Int, Text)] -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> [Text] -> [(Int, Text)]
forall a b. [a] -> [b] -> [(a, b)]
zip [(Int
0 :: Int) ..] [Text]
numericCols)
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$
[[Double]] -> Plot -> Text
Granite.heatmap [[Double]]
correlations (Plot
defPlot{Granite.plotTitle = "correlation matrix"})
where
corr :: [a] -> [a] -> a
corr [a]
xs [a]
ys =
let n :: a
n = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> a) -> Int -> a
forall a b. (a -> b) -> a -> b
$ [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs
meanX :: a
meanX = [a] -> a
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [a]
xs a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
n
meanY :: a
meanY = [a] -> a
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [a]
ys a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
n
covXY :: a
covXY = [a] -> a
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [(a
a a -> a -> a
forall a. Num a => a -> a -> a
- a
meanX) a -> a -> a
forall a. Num a => a -> a -> a
* (a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
meanY) | (a
a, a
b) <- [a] -> [a] -> [(a, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
xs [a]
ys] a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
n
stdX :: a
stdX = a -> a
forall a. Floating a => a -> a
sqrt (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ [a] -> a
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [(a
a a -> a -> a
forall a. Num a => a -> a -> a
- a
meanX) a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int) | a
a <- [a]
xs] a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
n
stdY :: a
stdY = a -> a
forall a. Floating a => a -> a
sqrt (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ [a] -> a
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [(a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
meanY) a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int) | a
b <- [a]
ys] a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
n
in a
covXY a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
stdX a -> a -> a
forall a. Num a => a -> a -> a
* a
stdY)
autoTitle :: Agg -> Maybe T.Text -> T.Text -> T.Text
autoTitle :: Agg -> Maybe Text -> Text -> Text
autoTitle Agg
Count Maybe Text
_ Text
groupCol = Text
"count by " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
groupCol
autoTitle Agg
a (Just Text
yCol) Text
groupCol = Agg -> Text
aggLabel Agg
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"(" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
yCol Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
") by " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
groupCol
autoTitle Agg
a Maybe Text
Nothing Text
groupCol = Agg -> Text
aggLabel Agg
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" by " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
groupCol
plotHistogram :: (HasCallStack) => T.Text -> DataFrame -> IO ()
plotHistogram :: HasCallStack => Text -> DataFrame -> IO ()
plotHistogram Text
c = HasCallStack => Histogram -> DataFrame -> IO ()
Histogram -> DataFrame -> IO ()
histogram (Text -> Histogram
mkHistogram Text
c)
{-# DEPRECATED plotHistogram "use 'histogram (mkHistogram col)' instead" #-}
plotScatter :: (HasCallStack) => T.Text -> T.Text -> DataFrame -> IO ()
plotScatter :: HasCallStack => Text -> Text -> DataFrame -> IO ()
plotScatter Text
xc Text
yc = HasCallStack => Scatter -> DataFrame -> IO ()
Scatter -> DataFrame -> IO ()
scatter (Text -> Text -> Scatter
mkScatter Text
xc Text
yc)
{-# DEPRECATED plotScatter "use 'scatter (mkScatter xCol yCol)' instead" #-}
plotBars :: (HasCallStack) => T.Text -> DataFrame -> IO ()
plotBars :: HasCallStack => Text -> DataFrame -> IO ()
plotBars Text
c = HasCallStack => Bar -> DataFrame -> IO ()
Bar -> DataFrame -> IO ()
bar (Text -> Bar
mkBar Text
c)
{-# DEPRECATED plotBars "use 'bar (mkBar col)' instead" #-}
plotLines :: (HasCallStack) => T.Text -> [T.Text] -> DataFrame -> IO ()
plotLines :: HasCallStack => Text -> [Text] -> DataFrame -> IO ()
plotLines Text
xc [Text]
ys = HasCallStack => Line -> DataFrame -> IO ()
Line -> DataFrame -> IO ()
line (Text -> [Text] -> Line
mkLine Text
xc [Text]
ys)
{-# DEPRECATED plotLines "use 'line (mkLine xCol yCols)' instead" #-}
plotPie :: (HasCallStack) => T.Text -> Maybe T.Text -> DataFrame -> IO ()
plotPie :: HasCallStack => Text -> Maybe Text -> DataFrame -> IO ()
plotPie Text
c Maybe Text
mLabel =
let s :: Pie
s = Text -> Pie
mkPie Text
c
in HasCallStack => Pie -> DataFrame -> IO ()
Pie -> DataFrame -> IO ()
pie Pie
s{names = mLabel}
{-# DEPRECATED plotPie "use 'pie (mkPie col)' instead" #-}
plotBoxPlots :: (HasCallStack) => [T.Text] -> DataFrame -> IO ()
plotBoxPlots :: HasCallStack => [Text] -> DataFrame -> IO ()
plotBoxPlots [Text]
ys = HasCallStack => Box -> DataFrame -> IO ()
Box -> DataFrame -> IO ()
box ([Text] -> Box
mkBox [Text]
ys)
{-# DEPRECATED plotBoxPlots "use 'box (mkBox cols)' instead" #-}
plotStackedBars :: (HasCallStack) => T.Text -> [T.Text] -> DataFrame -> IO ()
plotStackedBars :: HasCallStack => Text -> [Text] -> DataFrame -> IO ()
plotStackedBars Text
categoryCol [Text]
valueColumns DataFrame
df = do
let categories :: [Text]
categories = HasCallStack => Text -> DataFrame -> [Text]
Text -> DataFrame -> [Text]
extractStringColumn Text
categoryCol DataFrame
df
uniqueCategories :: [Text]
uniqueCategories = [Text] -> [Text]
forall a. Eq a => [a] -> [a]
L.nub [Text]
categories
[(Text, [(Text, Double)])]
stackData <- [Text]
-> (Text -> IO (Text, [(Text, Double)]))
-> IO [(Text, [(Text, Double)])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [Text]
uniqueCategories ((Text -> IO (Text, [(Text, Double)]))
-> IO [(Text, [(Text, Double)])])
-> (Text -> IO (Text, [(Text, Double)]))
-> IO [(Text, [(Text, Double)])]
forall a b. (a -> b) -> a -> b
$ \Text
cat -> do
let indices :: [Int]
indices = [Int
i | (Int
i, Text
c) <- [Int] -> [Text] -> [(Int, Text)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] [Text]
categories, Text
c Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
cat]
[(Text, Double)]
seriesData <- [Text] -> (Text -> IO (Text, Double)) -> IO [(Text, Double)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [Text]
valueColumns ((Text -> IO (Text, Double)) -> IO [(Text, Double)])
-> (Text -> IO (Text, Double)) -> IO [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ \Text
col -> do
let allValues :: [Double]
allValues = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Text
col DataFrame
df
vs :: [Double]
vs = [[Double]
allValues [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
i | Int
i <- [Int]
indices, Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
allValues]
(Text, Double) -> IO (Text, Double)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
col, [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Double]
vs)
(Text, [(Text, Double)]) -> IO (Text, [(Text, Double)])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
cat, [(Text, Double)]
seriesData)
Text -> IO ()
T.putStrLn (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ [(Text, [(Text, Double)])] -> Plot -> Text
Granite.stackedBars [(Text, [(Text, Double)])]
stackData Plot
defPlot
plotHeatmap :: (HasCallStack) => DataFrame -> IO ()
plotHeatmap :: HasCallStack => DataFrame -> IO ()
plotHeatmap = HasCallStack => DataFrame -> IO ()
DataFrame -> IO ()
heatmap
{-# DEPRECATED plotHeatmap "use 'heatmap' instead" #-}