dataframe-viz 1.3.2.1 → 1.4.0.0
raw patch · 5 files changed
+65/−25 lines, 5 filesdep ~dataframe-core
Dependency ranges changed: dataframe-core
Files
- README.md +3/−3
- dataframe-viz.cabal +2/−2
- src/DataFrame/Display.hs +3/−0
- src/DataFrame/Display/Internal/VegaLite.hs +30/−6
- src/DataFrame/Display/Web/Chart/Typed.hs +27/−14
README.md view
@@ -66,9 +66,9 @@ , ("region", fromList (["INLAND","NEAR BAY","INLAND","NEAR OCEAN","ISLAND","INLAND","NEAR BAY","INLAND"] :: [Text])) ] -income = F.col @Double "income"-value = F.col @Double "value"-region = F.col @Text "region"+income = F.double "income"+value = F.double "value"+region = F.text "region" -- show a Vega-Lite spec without its (verbose) inlined data. -- Returns String so scripths prints it raw rather than show-escaped.
dataframe-viz.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.4 name: dataframe-viz-version: 1.3.2.1+version: 1.4.0.0 synopsis: Visualisation/plotting helpers for the dataframe ecosystem. description: Display harness plus terminal and web plotters. Built on top of@@ -37,7 +37,7 @@ build-depends: base >= 4 && < 5, aeson >= 0.11.0.0 && < 3, containers >= 0.6.7 && < 0.10,- dataframe-core >= 2.6 && < 2.7,+ dataframe-core >= 2.7 && < 2.8, directory >= 1.3.0.0 && < 2, granite >= 0.6 && < 1, process ^>= 1.6,
src/DataFrame/Display.hs view
@@ -22,3 +22,6 @@ -- | Render a 'DataFrame' to stdout according to 'DisplayOptions'. display :: DisplayOptions -> D.DataFrame -> IO () display opts = T.putStrLn . D.asTextWith Plain (displayTruncate opts)++displayRows :: Int -> D.DataFrame -> IO ()+displayRows n = T.putStrLn . D.asTextWith Plain (Just D.defaultTruncateConfig{D.maxRows = n})
src/DataFrame/Display/Internal/VegaLite.hs view
@@ -51,7 +51,13 @@ import Type.Reflection (TypeRep, tyConName, typeRep, typeRepTyCon, pattern App) import Control.Exception (throw)-import DataFrame.Internal.Column (Column, Columnable)+import DataFrame.Internal.Column (+ Column (MergedColumn),+ Columnable,+ bitmapTestBit,+ columnBitmap,+ materializeMerged,+ ) import DataFrame.Internal.DataFrame (DataFrame, dataframeDimensions, getColumn) import DataFrame.Internal.Expression (Expr (Col)) import DataFrame.Internal.Interpreter (Ctx (..), eval, materialize)@@ -223,9 +229,17 @@ v <- eval (FlatCtx df) expr pure $ materialize @a (fst (dataframeDimensions df)) v +-- | A column's values as JSON, with null slots as 'Null'. columnToValues :: FieldType -> Column -> [Value]-columnToValues Quantitative col = map toJSON (columnToDoubles col)-columnToValues _ col = map (toJSON :: T.Text -> Value) (columnToStrings col)+columnToValues ft col = case col of+ MergedColumn _ _ -> columnToValues ft (materializeMerged col)+ _ -> maskNulls (raw ft)+ where+ raw Quantitative = map toJSON (columnToDoubles col)+ raw _ = map (toJSON :: T.Text -> Value) (columnToStrings col)+ maskNulls vs = case columnBitmap col of+ Nothing -> vs+ Just bm -> zipWith (\i v -> if bitmapTestBit bm i then v else Null) [0 ..] vs -- | A nominal field built directly from text values (for pre-computed data). textField :: T.Text -> [T.Text] -> ResolvedField@@ -278,7 +292,9 @@ channelValue e = object $ catMaybes- [ if T.null (ceField e) then Nothing else Just ("field" .= ceField e)+ [ if T.null (ceField e)+ then Nothing+ else Just ("field" .= fieldRef (ceField e)) , Just ("type" .= fieldTypeName (ceType e)) , fmap ("aggregate" .=) (ceAggregate e) , if ceBin e then Just ("bin" .= True) else Nothing@@ -307,9 +323,17 @@ transformValue :: Transform -> Value transformValue (RegressionT yField xField) =- object ["regression" .= yField, "on" .= xField]+ object ["regression" .= fieldRef yField, "on" .= fieldRef xField] transformValue (DensityT field) =- object ["density" .= field]+ object ["density" .= fieldRef field]++-- | A column as a Vega-Lite field; escapes @.@, @[@, @]@ (else nested).+fieldRef :: T.Text -> T.Text+fieldRef = T.concatMap esc+ where+ esc c+ | c `elem` ['.', '[', ']', '\\'] = T.pack ['\\', c]+ | otherwise = T.singleton c -- | Build the @data.values@ array of row objects, deduplicating fields by name. inlineRows :: [ResolvedField] -> Value
src/DataFrame/Display/Web/Chart/Typed.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-} -- | Schema-checked typed-expression analogue of "DataFrame.Display.Web.Chart". module DataFrame.Display.Web.Chart.Typed (@@ -58,10 +59,11 @@ ) import qualified DataFrame.Display.Web.Chart as C import DataFrame.Internal.Column (Columnable)+import DataFrame.Internal.Expression.Operators.Nullable (BaseType) import DataFrame.Typed.Types (TExpr (..), TypedDataFrame (..)) import GHC.TypeLits (Symbol) --- | A typed chart: a phantom-@cols@ wrapper over the untyped builder.+-- | A typed chart over the untyped builder; encoded exprs must be non-null. newtype Chart (cols :: [(Symbol, Type)]) = Chart C.Chart -- | Start a typed chart from a typed frame.@@ -73,12 +75,14 @@ mark m (Chart c) = Chart (C.mark m c) -- | Encode a typed expression on a channel (field type inferred from its type).-enc :: (Columnable a) => Channel -> TExpr cols a -> Chart cols -> Chart cols+enc ::+ (Columnable a, a ~ BaseType a) =>+ Channel -> TExpr cols a -> Chart cols -> Chart cols enc ch te (Chart c) = Chart (C.enc ch (unTExpr te) c) -- | Like 'enc' but force the Vega-Lite field type. encAs ::- (Columnable a) =>+ (Columnable a, a ~ BaseType a) => Channel -> TExpr cols a -> FieldType -> Chart cols -> Chart cols encAs ch te ft (Chart c) = Chart (C.encAs ch (unTExpr te) ft c) @@ -100,12 +104,18 @@ includeZero ch b (Chart c) = Chart (C.includeZero ch b c) -- | Facet into small multiples by a column (alias for 'column').-facet :: (Columnable a) => TExpr cols a -> Chart cols -> Chart cols+facet ::+ (Columnable a, a ~ BaseType a) => TExpr cols a -> Chart cols -> Chart cols facet = column --- | Facet across columns / down rows.-column, row :: (Columnable a) => TExpr cols a -> Chart cols -> Chart cols+-- | Facet across columns.+column ::+ (Columnable a, a ~ BaseType a) => TExpr cols a -> Chart cols -> Chart cols column te (Chart c) = Chart (C.column (unTExpr te) c)++-- | Facet down rows.+row ::+ (Columnable a, a ~ BaseType a) => TExpr cols a -> Chart cols -> Chart cols row te (Chart c) = Chart (C.row (unTExpr te) c) -- | Set the chart title.@@ -122,12 +132,13 @@ -- | Add a least-squares regression line fitting @y@ on @x@. regression ::- (Columnable a, Columnable b) =>+ (Columnable a, Columnable b, a ~ BaseType a, b ~ BaseType b) => TExpr cols a -> TExpr cols b -> Chart cols -> Chart cols regression xE yE (Chart c) = Chart (C.regression (unTExpr xE) (unTExpr yE) c) -- | Kernel-density estimate of an expression, drawn as an area.-density :: (Columnable a) => TExpr cols a -> Chart cols -> Chart cols+density ::+ (Columnable a, a ~ BaseType a) => TExpr cols a -> Chart cols -> Chart cols density e (Chart c) = Chart (C.density (unTExpr e) c) -- | The Vega-Lite spec as an aeson 'Value' (escape hatch, e.g. for hvega).@@ -144,28 +155,30 @@ -- | Scatter plot of two typed expressions. scatter ::- (Columnable a, Columnable b) =>+ (Columnable a, Columnable b, a ~ BaseType a, b ~ BaseType b) => TExpr cols a -> TExpr cols b -> TypedDataFrame cols -> IO () scatter xE yE tdf = C.scatter (unTExpr xE) (unTExpr yE) (unTDF tdf) --- | Count of rows per category, as bars.+-- | Count of rows per category, as bars; a nullable column counts its nulls. bar :: (Columnable a) => TExpr cols a -> TypedDataFrame cols -> IO () bar xE tdf = C.bar (unTExpr xE) (unTDF tdf) -- | Histogram of a numeric expression.-histogram :: (Columnable a) => TExpr cols a -> TypedDataFrame cols -> IO ()+histogram ::+ (Columnable a, a ~ BaseType a) => TExpr cols a -> TypedDataFrame cols -> IO () histogram xE tdf = C.histogram (unTExpr xE) (unTDF tdf) -- | Line chart of @y@ over @x@. line ::- (Columnable a, Columnable b) =>+ (Columnable a, Columnable b, a ~ BaseType a, b ~ BaseType b) => TExpr cols a -> TExpr cols b -> TypedDataFrame cols -> IO () line xE yE tdf = C.line (unTExpr xE) (unTExpr yE) (unTDF tdf) --- | Pie chart counting rows per category.+-- | Pie chart counting rows per category; a nullable column counts its nulls. pie :: (Columnable a) => TExpr cols a -> TypedDataFrame cols -> IO () pie cE tdf = C.pie (unTExpr cE) (unTDF tdf) -- | Box-and-whisker plot of a numeric expression.-box :: (Columnable a) => TExpr cols a -> TypedDataFrame cols -> IO ()+box ::+ (Columnable a, a ~ BaseType a) => TExpr cols a -> TypedDataFrame cols -> IO () box yE tdf = C.box (unTExpr yE) (unTDF tdf)